Files
2026-06-01 12:46:52 +02:00

464 lines
13 KiB
C++

#pragma once
#include <windows.h>
#include <assert.h>
//#include <vector>
#include <map>
#include <queue>
#include <mmo/ArType.h>
#include "K3DTypes.h"
#include "SkillBase.h"
#include "CreatureBase.h"
#include "SGameInput.h"
// 2010.06.15 - prodongi
#include "GameDefine.h"
#define Mode_Normal (1 << 0)
#define Mode_Attack (1 << 1)
#define Mode_Mount (1 << 2)
#define Mode_All ((1 << 3) - 1)
// 2010.06.15 GameDefine.h로 옮김 - prodongi
//#define FORCE_CHIP_SKILL_ID 6008
using namespace GAME_INPUT;
struct SStateInfo
{
SStateInfo()
{
Reset();
}
~SStateInfo()
{
vAttackInfoList.clear();
vSkillResult.clear();
}
void Reset()
{
hItemUseTarget = 0;
hTarget = 0;
hSelf = 0;
hItem = 0;
bIsMovePos = true;
nSkillID = 0;
nSkillLv = 0;
nRepeat = 0;
dwStartTime = dwDuration = 0;
bMultiple = false;
fRange = 0.f;
target_count = 0;
fire_count = 0;
fSpellRange = 0.f;
dwSpeed = 0;
SpeedSync = true;
UnMountFlag = 0;
vSelfPos = K3DVector(0,0,0);
vTargetPos = K3DVector(0,0,0);
attack_action = 0;
attack_flag = 0;
count = 0;
autoattack = false;
chase = false;
// 2010.05.24 - prodongi
isValidToCorpse = false;
/// 2010.10.21 - prodongi
isRegionTarget = false;
vRegionTargetPos = K3DVector(0, 0, 0);
vAttackInfoList.clear();
vSkillResult.clear();
}
std::string strItemUseText;
AR_HANDLE hItemUseTarget; ///< 보이지 않는 타겟에게 아이템 사용 시 설정
AR_HANDLE hTarget;
AR_HANDLE hSelf;
AR_HANDLE hItem;
K3DVector vSelfPos;
K3DVector vTargetPos;
bool bIsMovePos;
int nSkillID;
int nSkillLv;
bool bMultiple; ///< true 실시간 연타, 일반 공격일때 이도류 인지 판별
AR_UNIT range; ///< 스킬 효과 범위
unsigned char target_count; ///< 타겟 갯수
unsigned char fire_count;
int nRepeat; ///< 갯수
AR_UNIT fRange; ///< 사거리
AR_UNIT fSpellRange; ///< 마거리
DWORD dwStartTime; ///< 시작시간
DWORD dwDuration; ///< 지속 시간
bool SpeedSync; ///< 플레이어와 속도를 맞출지 체크
char UnMountFlag; ///< 언마운트 관련
DWORD dwSpeed; ///< 이속, 공속
std::vector<SkillResult> vSkillResult; ///< 스킬 데미지
char attack_action;
char attack_flag;
char count;
std::vector< ATTACK_INFO > vAttackInfoList;
bool autoattack;
bool chase;
std::string target_name;
// 2010.05.24 - prodongi
bool isValidToCorpse;
bool isRegionTarget; /// 2010.10.21 - prodongi
K3DVector vRegionTargetPos;
};
struct PENDING_INPUT_STATE
{
SStateInfo sInfostate;
int nInputID;
PENDING_INPUT_STATE( SStateInfo* infostate, int inputid ) : nInputID( inputid )
{
sInfostate.hItemUseTarget = infostate->hItemUseTarget;
sInfostate.hSelf = infostate->hSelf;
sInfostate.vSelfPos = infostate->vSelfPos;
sInfostate.bIsMovePos = infostate->bIsMovePos;
sInfostate.vTargetPos = infostate->vTargetPos;
sInfostate.hTarget = infostate->hTarget;
sInfostate.fRange = infostate->fRange;
sInfostate.hItem = infostate->hItem;
sInfostate.hTarget = infostate->hTarget;
sInfostate.nSkillID = infostate->nSkillID;
sInfostate.nSkillLv = infostate->nSkillLv;
sInfostate.fRange = infostate->fRange;
sInfostate.fSpellRange = infostate->fSpellRange;
}
};
class SObjectStateMachine;
class SObjectState
{
public:
/// 상태
enum ID
{
STATE_NONE = 0, ///< 없음 (사용되지 않음)
STATE_IDLE, ///< 아이들
STATE_ATTACK, ///< 공격 (1회)
STATE_MOVE, ///< 이동
STATE_CHASE, ///< 추격
STATE_CAST, ///< 캐스팅
STATE_THROW, ///< 던지기
STATE_FIRE, ///< 시전
STATE_SKILL_END, ///< 시전 종료
STATE_SIT, ///< 앉기
STATE_STAND_UP, ///< 서기 //추가 해야 한다.
STATE_TAKEITEM, ///< 아이템 줍기 //추가 해야 한다.
STATE_USEITEM, ///< 아이템 사용
STATE_CAST_CANCEL, ///< 캐스팅 취소
STATE_AIMING, ///< 활 조준
STATE_SHOOTING, ///< 활쏘기
STATE_ATTACK_END, ///< 공격 종료
STATE_MOUNT, ///< 올라탄상태
STATE_UNMOUNT, ///< 내리기
};
/// 다른 명령 요청시 허용 여부
enum REQCOMMAND_PERMIT
{
PERMIT_IMMEDIATELY, ///< 즉시 허용
PERMIT_FORBIDDEN, ///< 불가
PERMIT_PENDING, ///< 대기
};
/// Initialize
SObjectState( ID State )
: m_State( State )
, m_bMotionCancelInfo( false ) { }
virtual ~SObjectState() { }
struct REQCOMMAND_INFO
{
ID m_ReqCommand;
REQCOMMAND_PERMIT m_Permission;
REQCOMMAND_INFO( ID ReqCommand, REQCOMMAND_PERMIT Permission )
: m_ReqCommand( ReqCommand ), m_Permission( Permission ) { }
};
void AddRequestCommand( ID ReqCommand, REQCOMMAND_PERMIT Permission )
{
for( REQCOMINFO_VECTOR::iterator it = m_RequestCommandInfo.begin(); it != m_RequestCommandInfo.end(); it++ )
if( (*it).m_ReqCommand == ReqCommand ) { (*it).m_Permission = Permission; return; }
m_RequestCommandInfo.push_back( REQCOMMAND_INFO( ReqCommand, Permission ) );
}
/// Methods
REQCOMMAND_PERMIT GetRequestPermission( ID ReqCommand ) const
{
for( REQCOMINFO_VECTOR::const_iterator it = m_RequestCommandInfo.begin(); it != m_RequestCommandInfo.end(); it++ )
if( (*it).m_ReqCommand == ReqCommand ) return (*it).m_Permission;
assert( false );
return PERMIT_IMMEDIATELY;
}
bool GetMotionCancelInfo( ) { return m_bMotionCancelInfo; }
void SetMotionCancelInfo( bool bMotionCancel ) { m_bMotionCancelInfo = bMotionCancel; }
ID GetID() const { return m_State; }
void SetInfo( const SStateInfo &info ) { m_infoState = info; }
const SStateInfo &GetInfo() const { return m_infoState; }
bool CheckModePermission( unsigned long cur_mode )
{
return (GetMode() & cur_mode) ? true : false ;
}
void SetMode( unsigned long nModeBitVector ) { m_nModeBitVector = nModeBitVector; }
unsigned long GetMode() { return m_nModeBitVector; }
private:
ID m_State;
SStateInfo m_infoState;
unsigned long m_nModeBitVector; ///< Mode Flag
bool m_bMotionCancelInfo;
typedef std::vector<REQCOMMAND_INFO> REQCOMINFO_VECTOR;
REQCOMINFO_VECTOR m_RequestCommandInfo;
friend SObjectStateMachine;
};
class SGameObject;
class SGameAvatarEx;
class SObjectStateMachine
{
public:
SObjectStateMachine();
virtual ~SObjectStateMachine();
/// 처리 안된 사용자 입력
virtual void PendingInput( struct PENDING_INPUT_STATE* pPendinginputstate ) {}
/// 사용자 입력(키보드, 마우스)
virtual void OnInput( class SGameInput * pInput ) = 0;
/// 사용자 입력 응답(Server)
virtual void OnNetInput( struct SGameMessage * pMsg ) = 0;
/// Receiver Setting
void SetReceiver( SGameAvatarEx *pObject )
{
m_pReceiver = pObject;
}
SGameAvatarEx *GetReceiver()
{
return m_pReceiver;
}
/// 상태 체크
SObjectState::REQCOMMAND_PERMIT CheckNextPermission( SObjectState::ID state );
/// 현재 상태
SObjectState::ID GetCurrentState() const
{ return m_idCurState; }
const SStateInfo &GetCurrentStateInfo() const
{ return m_infoCurrent; }
SObjectState::ID GetPrevState() const
{ return m_idPrevState; }
bool CheckMovingState( SObjectState::ID id ) const
{
return ( id == SObjectState::STATE_CHASE || id == SObjectState::STATE_MOVE );
}
/// 특정 행동을 할경우 그 행동이 지금 가능한가를 검사한다
bool IsPossible()
{
}
bool IsMoving() const
{
return (m_idCurState == SObjectState::STATE_CHASE || m_idCurState == SObjectState::STATE_MOVE);
}
bool IsCasting() const
{
return (m_idCurState == SObjectState::STATE_CAST ||
m_idCurState == SObjectState::STATE_AIMING ||
m_idCurState == SObjectState::STATE_SHOOTING );
}
bool IsAttack() const
{
return ( m_idCurState == SObjectState::STATE_ATTACK );
}
/// 올라타는 중이거나 내려오는 중일때
bool IsMount() const
{
return (m_idCurState == SObjectState::STATE_MOUNT ||
m_idCurState == SObjectState::STATE_UNMOUNT);
}
/// 완전히 올라탄 상태
bool IsMountMode() const
{
return (m_nMode == MODE_MOUNT);
}
/// 대기 중인 다음 상태
SObjectState::ID GetPendingState() const { return m_idPendingState; }
/// 현재 상태가 시작된 시간
DWORD GetCurrentStateStartTime() const { return m_dwCurrentStateStartTime; }
/// 새로운 상태 시작 요청
bool RequestNewState( SObjectState::ID NewState, const SStateInfo &infoState );
/// 현재 상태 중지 ( 대기 중인 다음 상태로 넘어가도록 한다. )
void StopCurrentState();
/// 특정 상태에 다음 상태를 설정해 준다. ( 예> chase인 경우 )
void SetNextState( SObjectState::ID State, const SStateInfo &NextState );
SObjectState::ID GetNextStateID() { return m_idNextState; }
const SStateInfo &GetNextStateInfo() { return m_infoNext; }
void ClearNextState() { m_idNextState = SObjectState::STATE_NONE; }
virtual void Process( DWORD dwTime );
/// 유틸
float GetTargetDist( SGameObject *pTarget );
K3DVector GetChasePos( SGameAvatarEx* pTarget, K3DVector* pTargetPos, float fTargetSize, const SStateInfo &infoState, SObjectState::ID NewState );
//K3DVector GetChasePos( SGameObject *pTarget, K3DVertex vTarget, float fRange );
K3DVector GetChasePos();
bool IsRange( K3DVector & my_pos, float fmy_size, const K3DVector & pos, float ftarget_size, float fRange, bool bCollisionToLine, int & fResultLength );
/// 모드, 또는 Layer 라고도 함.
enum
{
MODE_NORMAL = (1 << 0), ///< 기본
MODE_ATTACK = (1 << 1), ///< 공격 상태
MODE_MOUNT = (1 << 2), ///< 크리쳐 마운트 상태
};
void SetMode( int nMode )
{
if( m_idCurState == SObjectState::STATE_MOUNT ||
m_idCurState == SObjectState::STATE_UNMOUNT )
{
if( nMode == MODE_ATTACK ||
nMode == MODE_NORMAL)
{
int x = 0;
}
}
m_nMode = nMode;
m_dwAttackTime = 0;
}
int GetMode() { return m_nMode; }
void SetAttackLock( bool bAttackLock );
bool IsAttackLock() { return m_bLockAttack; }
AR_HANDLE GetTargetHandle() { return m_hTargetHandle; }
AR_HANDLE GetAttackTarget() { return m_hAttackTarget; }
void SetDefaultPrevState() { m_idPrevState = SObjectState::STATE_IDLE; }
SObjectState::ID GetCreatureState() const { return m_idCreatureState; }
bool IsCombatState( SObjectState::ID newstate );
void Dead();
void ClearPendingNextState();
void InputFreezing();
void InputThawing();
void ClearInfo();
protected:
virtual void SendServerReq( SObjectState::ID state, const SStateInfo &infoState ) = 0;
bool ProximityAttack( SObjectState::ID stateId );
bool NotProximityAttack( SObjectState::ID stateId );
bool IsBowAttack();
AR_UNIT GetSize( SGameAvatarEx *pObject );
void ClearAllState();
typedef std::map<SObjectState::ID, SObjectState*> OBJSTATE_MAP;
OBJSTATE_MAP m_StateMap;
SGameAvatarEx* m_pReceiver;
SObjectState* m_pCurrentState;
SObjectState::ID m_idCurState;
SStateInfo m_infoCurrent;
SObjectState::ID m_idPendingState;
SStateInfo m_infoPending;
SObjectState::ID m_idDefaultState;
SStateInfo m_infoDefault;
SObjectState::ID m_idNextState;
SStateInfo m_infoNext;
SObjectState::ID m_idCreatureState; ///< 크리처 전용( StartNewState 에서 바뀐 상태만 저장한다 )
SObjectState::ID m_idPrevState; ///< 이전 상태를(SKILL EVENT 제외) 저장한다
bool m_bLockAttack;
AR_HANDLE m_hTargetHandle;
AR_HANDLE m_hAttackTarget; ///< 공격 중인 대상
DWORD m_dwTime;
DWORD m_dwCurrentStateStartTime;
//전투 대기 중 일때 영향 받는 리스트 알아 두자.
int m_nMode; ///< 전투대기 상태 , 공격을 받거나, 내가 공격 시작하면 설정 된다.
DWORD m_dwAttackTime; ///< 전투대기 지속 시간, 지속시간은 30초
SObjectState* GetObjState( const SObjectState::ID State ) const;
void StartNewState( SObjectState::ID state, const SStateInfo &infoState );
void SetPendingState( SObjectState::ID state, const SStateInfo &infoState );
void ClearPending();
void AddState( SObjectState* pObjState );
void RemoveState( const SObjectState::ID State );
/// 반드시 AddState()가 다 끝난 뒤에 호출해야 한다.
void SetDefaultState( const SObjectState::ID State, const SStateInfo &info );
K3DVector GetCreatureChasePos( SGameAvatarEx* pReceiver, SGameAvatarEx* pTarget, K3DVector* pTargetPos, const SStateInfo &infoState, SObjectState::ID NewState );
// 2010.06.15 - prodongi
void setAutoAttack(bool autoAttack);
enum
{
NEED_STOP_POS = 0,
INSPECTED_STOP_POS,
NOT_NEED_STOP_POS,
};
int m_nNeedStopPos; ///< 정지할 위치가 필요한가
DWORD m_dwFindDetour;
queue< PENDING_INPUT_STATE > m_queInputState;
bool m_bAutoAttack;
DWORD m_dwAttackDelayTime;
bool m_bInputFreezing;
};