Files
Leviathan/Client/Game/game/Player/SGameLocalCreature.cpp
T
2026-06-01 12:46:52 +02:00

1044 lines
26 KiB
C++

#include "stdafx.h"
#include ".\SGameLocalCreature.h"
#include "GameDefine.h"
#include "KSeqAvatarEx.h"
#include "SBasicStat.h"
#include "SMonsterDB.h"
#include "SCreatureDB.h"
#include "SGameAniType.h"
#include "SAvatarProperty.h"
#include "SCreatureStateMachine.h"
#include "SSkillDB.h"
#include "SSKillStageType.h"
#include "SGameInput.h"
#include "SGameMessage.h"
#include "SStringDB.h"
#include "SGameMessage.h"
//#include "SGameMessageUI.h"
#include "LuaVM.h"
#include <toolkit/XStringUtil.h>
#include "SChatType.h"
#include "SDebug_Util.h"
#include <time.h>
#include <stdio.h>
bool SGameLocalCreature::s_bIdleProc = true;
SGameLocalCreature::SGameLocalCreature( int nCreatureID, unsigned char ucEnhance ) : SGameCreature( nCreatureID, ucEnhance )
, m_dwTryMoveTime( 0 )
, m_pMasterPlayer( NULL )
, m_hMaster( NULL )
, m_dwUpdateTime( 0 ) //서버 업데이트 시간
, m_dwBeginScriptTime( 0 )
, m_dwCallScriptTime( 1000 )
, m_vMasterLastPos( 0, 0, 0 )
, m_hTargetMonster( NULL )
, m_fLeftNRight( -1.0f )
, m_nCreatureState( STATE_NSTANDBY )
, m_nCreatureMode( BATTLE_MODE_OFF )
, m_dwFindDetour( 0 )
, m_dwFindDetourTick( 200 )
, m_arMasterSize( 0 )
, m_dwEscHitTime( 0 )
, m_EscHitCount( 0 )
, m_bDeadDialog( false )
, m_dwDeadDialogTime( 0 )
{
m_pStateVM = new SLocalCreatureStateMachine;
m_pStateVM->SetReceiver( this );
m_bLocalCreature = true;
m_arMySize = GetSize( this );
m_bFootsteps = true;
}
SGameLocalCreature::~SGameLocalCreature()
{
if( m_pStateVM ) m_pStateVM->SetReceiver( NULL );
if( m_bDeadDialog && IsDead() )
{
bool bClose = true;
if( m_pMasterPlayer )
{
//주인이 죽었다면 닫지 말자
if( m_pMasterPlayer->IsDead() )
bClose = false;
}
if( bClose )
{
m_bDeadDialog = false;
m_dwDeadDialogTime = 0;
SendGameMsg( &SMSG_SEND_DATA( "close_all_message_box" ) );
SendGameMsg( &SMSG_SEND_DATA( "close_rebirth_message_box" ) );
SendGameMsg( &SMSG_SEND_DATA( "close_rebirth_PVP_message_box" ) );
}
}
}
bool SGameLocalCreature::Deactivate()
{
if( m_bDeadDialog && IsDead() )
{
bool bClose = true;
if( m_pMasterPlayer )
{
//주인이 죽었다면 닫지 말자
if( m_pMasterPlayer->IsDead() )
bClose = false;
}
if( bClose )
{
m_bDeadDialog = false;
m_dwDeadDialogTime = 0;
SendGameMsg( &SMSG_SEND_DATA( "close_all_message_box" ) );
SendGameMsg( &SMSG_SEND_DATA( "close_rebirth_message_box" ) );
SendGameMsg( &SMSG_SEND_DATA( "close_rebirth_PVP_message_box" ) );
}
}
return SGameAvatarEx::Deactivate();
}
//IDLE 상태일때 테이머의 방향 벡터로 크리처의 방향을 구한다
void SGameLocalCreature::SetViewVectorStateIdle( const K3DVector &tpos )
{
float fTargetRoll = atan2( tpos.y, tpos.x );
if( fTargetRoll != m_fTargetRoll )
{
m_fTargetRoll = fTargetRoll;
m_dwPrevTime = m_dwTime;
m_bUseRot = true;
StandingDegree();
}
}
void SGameLocalCreature::SetMaster( AR_HANDLE hMaster, SGameAvatarEx * pMaster )
{
m_hMaster = hMaster;
m_pMasterPlayer = pMaster;
if( m_pMasterPlayer )
m_arMasterSize = GetSize( m_pMasterPlayer );
}
void SGameLocalCreature::SetTargetMonster( AR_HANDLE hMonster )
{
m_hTargetMonster = hMonster;
}
void SGameLocalCreature::CheckPrevState()
{
if( m_pStateVM == NULL ) return;
TS_ATTACK_REQUEST msg;
msg.handle = GetArID();
msg.target_handle = m_pStateVM->GetAttackTarget();
SendMsg( &msg );
}
bool SGameLocalCreature::Process( DWORD dwTime, unsigned long uProcessBitVector )
{
//시야에서 사라졌을때에도 지속적으로 서버에 TS_CS_UPDATE를 보내준다
if( m_dwUpdateTime == 0 )
{
m_dwUpdateTime = dwTime;
}
else
{
if( (dwTime - m_dwUpdateTime)>=UPDATE_TIME )
{
m_dwUpdateTime = dwTime; // sonador 7.0.27 로컬 크리쳐 업데이트 주기 오류 수정
//서버에 메세지 보냄
TS_CS_UPDATE msg;
msg.handle = GetArID();
msg.ar_time = GetArTime();
time_t nowtime;
time(&nowtime);
msg.rtc = nowtime;
SendMsg( &msg );
}
}
if( m_bIsActivated && m_bIsInit )
{
if( IsDead() )
{
if( !m_bDeadDialog )
{
m_bDeadDialog = true;
m_dwDeadDialogTime = GetSafeTickCount() + 5000; // 5초후에 죽었다고 다이얼로그 띄움
}
}
else
{
if( m_bDeadDialog && !IsDead() )
{
// 다이얼로그 닫자
m_bDeadDialog = false;
m_dwDeadDialogTime = 0;
SendGameMsg( &SMSG_SEND_DATA( "close_all_message_box" ) );
SendGameMsg( &SMSG_SEND_DATA( "close_rebirth_message_box" ) );
SendGameMsg( &SMSG_SEND_DATA( "close_rebirth_PVP_message_box" ) );
}
}
if( IsDead() && m_dwDeadDialogTime && m_dwDeadDialogTime < GetSafeTickCount() )
{
bool bShowDlg = true;
if( m_pMasterPlayer )
{
//주인이 죽어있다면 다이얼로그 안띄우기
if( m_pMasterPlayer->IsDead() )
{
m_bDeadDialog = false;
bShowDlg = false;
}
}
m_dwDeadDialogTime = 0;
if( bShowDlg )
{
int nStringID = 809; //전투 불능 상태입니다. <br> 마을로 귀환하시려면 확인 버튼을 누르세요.
if( GetStateFlag() & FLAG_STATE::FLAG_STATE_RESURRECTION )
{
SendGameMsg( &SMSG_SEND_DATA( "close_all_message_box" ) );
StateInfoEx* pStateInfo = GetStateDBInfo( STATE_TYPE::STATE_RESURRECTION );
if( pStateInfo )
SendGameMsg( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::MSGBOX_DEAD, GetArID(), false, S(nStringID), false, GetStringDB().GetString( pStateInfo->name_id ) ) );
else
SendGameMsg( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::MSGBOX_DEAD, GetArID(), false, S(nStringID), false ) );
}
}
}
}
SGameCreature::Process( dwTime, uProcessBitVector ); // sonador 1.8.15 다른 플레이어의 크리처 스킬 연출 오류 수정
if( dwTime - m_dwBeginScriptTime >= m_dwCallScriptTime)
{
CheckCurrentState();
m_dwBeginScriptTime = dwTime;
}
if( m_pStateVM )
{
m_pStateVM->Process( m_dwTime );
}
m_dwEscHitTime = dwTime;
return true;
}
void SGameLocalCreature::Dead()
{
m_hTargetMonster = 0;
SetTargetMonster( m_hTargetMonster );
SetCreatureBattleModeOff();
SGameCreature::Dead();
}
void SGameLocalCreature::CheckCurrentState()
{
if( m_pStateVM == NULL ) return;
if( IsMountMode() || IsIng() || IsReservation() ) return;
std::string strState;
if( IsStandbyState() )
XStringUtil::Format( strState, "%s( %u )", "call_creature_standby", GetArID() );
else
{
switch( m_pStateVM->GetCreatureState() )
{
case SObjectState::STATE_ATTACK :
XStringUtil::Format( strState, "%s( %u, %u, %u )", "call_creature_attack", m_pMasterPlayer->GetArID(), GetArID(), m_hTargetMonster );
break;
case SObjectState::STATE_MOVE :
{
if( m_nCreatureMode == BATTLE_MODE_OFF )
XStringUtil::Format( strState, "%s( %u )", "call_creature_move", GetArID() );
}
break;
case SObjectState::STATE_IDLE :
{
if( m_nCreatureMode == BATTLE_MODE_OFF )
XStringUtil::Format( strState, "%s( %u, %u )", "call_creature_idle", m_pMasterPlayer->GetArID(), GetArID() );
else
{
SGameAvatarEx* pTargetMonster = (SGameAvatarEx*)GetGameObject(m_hTargetMonster);
if( pTargetMonster )
ReqAttack( m_hTargetMonster );
else
{
SetTargetMonster( m_hTargetMonster = 0 );
SetCreatureBattleModeOff();
}
}
}
break;
}
}
if( strState.length() )
LUA()->RunString( strState.c_str() );
}
void SGameLocalCreature::OnInput( class SGameInput * pInput )
{
if( !m_pStateVM ) return;
m_pStateVM->OnInput( pInput );
//공격 명령 또는 스킬명령 이 왔는가?
//다른 명령일 경우, 테이머를 쫓아 가도록 설정 한다.
static DWORD dwEscHitTime = 0;
int nInputID = pInput->GetInputID();
if( nInputID == RQ_CAST_CANCEL )
{
if( dwEscHitTime == 0 ) dwEscHitTime = m_dwEscHitTime;
if( (m_dwEscHitTime - dwEscHitTime) <= 1000 )
{
++m_EscHitCount;
if( m_EscHitCount >= 3 )
{
CreatureBackDownSpeedOfCreature();
SetUnHold();
dwEscHitTime = 0;
m_EscHitCount = 0;
}
}
else
{
dwEscHitTime = m_dwEscHitTime;
m_EscHitCount = 1;
}
}
else
{
dwEscHitTime = 0;
m_EscHitCount = 0;
}
}
void SGameLocalCreature::ReqTakeItem( AR_HANDLE handle )
{
TS_CS_TAKE_ITEM msg;
msg.item_handle = handle;
msg.taker_handle = GetArID(); // sonador #2.1.2.4.3 팻 조작 UI 연동
SendMsg( &msg );
}
void SGameLocalCreature::ReqMove( AR_HANDLE handle, const ArPosition & target, bool bSpeedSync, bool bChase )
{
// _oprint( "ReqMove : %f %f %f\n", target.x, target.y, target.z );
//전에 요청한 위치보다 FREQ_MOVE_LIMIT 만큼은 커야 한다.
float fLen = GetDistance( K3DVector(m_vTargetPos.x, m_vTargetPos.y, 0.f), K3DVector(target.x, target.y, 0.f) );
if( fLen < FREQ_MOVE_LIMIT )
{
// return;
}
//사용 중인 스킬이 있어서 이동 불가
if( IsUsingSkill() )
return;
if(IsMount()||IsIng()) return;
m_vTargetPos.x = target.x;
m_vTargetPos.y = target.y;
m_vTargetPos.z = target.z;
int nDetourSize = GetAllDetourPointSize();
if( nDetourSize > 0 )
SGameObject::ReqMove( handle, target, GetAllDetourPoint(), nDetourSize, bSpeedSync );
else
SGameObject::ReqMove( handle, target, &target, 1, bSpeedSync );
DeleteReqPoint();
}
void SGameLocalCreature::ReqAttack( AR_HANDLE target )
{
assert( target && "ReqAttack : Target ID Invalid!!!" );
//#ifndef NDEBUG
// SGameObject * pTarget = GetGameObject( target );
// if( pTarget )
// {
// float fDistance;
// K3DVector tpos = *pTarget->GetPosition();
// K3DVector spos = *GetPositionh();
// fDistance = K3DVectorGetLength( tpos, spos ); //전체 거리
//
// _oprint( "[s크기 : %f %f], [t크기 %f %f]\n", GetSize()/2.f, GetScale(), pTarget->GetSize()/2.f, pTarget->GetScale() );
// _oprint( "[사거리 : %f], [거리 %f], <tpos %f %f %f >, <spos %f %f %f > \n", GetAttackRange(), fDistance, tpos.x, tpos.y, tpos.z, spos.x, spos.y, spos.z );
// }
//#endif
if(IsMount()||IsIng()) return;
TS_ATTACK_REQUEST msg;
msg.handle = GetArID();
msg.target_handle = target;
SendMsg( &msg );
}
void SGameLocalCreature::ReqCast( AR_HANDLE target, int nSkillID, int nSkillLv, K3DVector const& targetPos )
{
// _oprint( "====>스킬 요청 %d %d\n", nSkillID, nSkillLv );
//소환, 역소환 예외~
//if( nSkillID==4001 || nSkillID==4002 )
//{
// TS_CS_SUMMON msg;
// msg.card_handle = target;
// msg.is_summon = (nSkillID==4001) ? 1 : 0;
// SendMsg( &msg );
// return;
//}
if(IsMount()||IsIng()) return;
_SKILL_FX* pSkillFX = GetSkillStageDB().GetSkillStageData( nSkillID );
if( !pSkillFX )
{
assert(0 && "스킬 ID 확인 : 스킬 유형이 없다!!!" );
SetCreatureBattleModeOff();
return;
}
if( pSkillFX->szType == 0 || pSkillFX->szDeal_Damage == 1 ) //전투 기술이면 또는 해로운 기술 이면, 전투 모드로 전환
SetAttackMode();
TS_CS_SKILL msg;
msg.caster = GetArID();
msg.skill_id = nSkillID;
msg.target = target;
msg.skill_level= nSkillLv;
msg.x = targetPos.x;
msg.y = targetPos.y;
msg.z = targetPos.z;
SendMsg( &msg );
//사용 여부를 인터페이스에 알리자~
}
void SGameLocalCreature::ReqCancelAction()
{
TS_CS_CANCEL_ACTION msg;
msg.handle = GetArID(); //자신이 취소
SendMsg( &msg );
}
void SGameLocalCreature::ReqThrow( AR_HANDLE target, AR_HANDLE itemhandle )
{
//던지는게 가능한 아이템인지 검사는 Input에서 필터링 하는 것이 맞음.
//TS_CS_USE_ITEM use_msg;
//use_msg.item_handle = itemhandle;
//use_msg.target_handle = target;
//SendMsg( &use_msg );
}
void SGameLocalCreature::ReqSit()
{
if(!CheckState()) return;
if( IsMount() ) return;
RqChatting( CHAT_NORMAL, m_pProperty->Name, "/앉기" );
}
void SGameLocalCreature::ReqStandUp()
{
if(!CheckState()) return;
if( IsMount() ) return;
RqChatting( CHAT_NORMAL, m_pProperty->Name, "/서기" );
}
void SGameLocalCreature::ReqNormal()
{
if(!CheckState()) return;
if( IsMount() ) return;
std::string str;
XStringUtil::Format(str, "%u", GetArID() );
RqChatting( CHAT_NORMAL, str.c_str(), "/normal" );
}
void SGameLocalCreature::ReqBattle()
{
if(!CheckState()) return;
if( IsMount() ) return;
std::string str;
XStringUtil::Format(str, "%u", GetArID() );
RqChatting( CHAT_NORMAL, str.c_str(), "/battle" );
}
bool SGameLocalCreature::CheckDistance( CREATE_DISTANCE_TYPE nType, SGameAvatarEx* pTarget )
{
float fDistance = GetDistance( GetCurPosWithChangeDir(), pTarget->GetCurPosWithChangeDir() );
float fRange = (float)nType + m_arMySize /*+ GetSize( pTarget )*/;
if( fDistance > fRange )
{
return true;
}
return false;
}
AR_UNIT SGameLocalCreature::GetSize( SGameObject *pObject )
{
AR_UNIT size = pObject->GetSize()/2.f; // 캐릭터 사이즈는 지름이라 2 나눈다.
AR_UNIT scale = pObject->GetScale(); // 캐릭터 사이즈 비율
return size*scale * GameRule::DEFAULT_UNIT_SIZE; // 실제 좌표로 변환
}
//대기 상태
//테이머가 명령을 내릴때까지 대기상태를 유지한다
void SGameLocalCreature::CmdStandBy()
{
if(!CheckState()) return;
if( m_pMasterPlayer )
{
if( m_nCreatureState == STATE_RECALL_COUNTDOWN )
{
//1분이 경과 되기 전에 테이머와이 거리가 150M 이하로 거리가 좁혀졌다면 따르기로 전환
if( !CheckDistance( DISTANCE_150, m_pMasterPlayer ) )
{
m_nCreatureState = STATE_NSTANDBY;
CmdMove();
}
}
else
{
//대기 상태중 플레이어와 150M 이상 거리가 발생한다면 역소환 준비 한다
if( CheckDistance( DISTANCE_150, m_pMasterPlayer ) )
m_nCreatureState = STATE_RECALL_COUNTDOWN;
}
}
}
//준비 상태
//테이머가 이동하면 거리에 따라 같이 이동한다
void SGameLocalCreature::CmdIdle()
{
if( !s_bIdleProc ) return;
if(!CheckState()) return;
if( m_pMasterPlayer && !IsStandbyState() )
{
//테이머와 3M 이상 벌어질경우
if( CheckDistance( DISTANCE_3, m_pMasterPlayer ) || m_vMasterLastPos != *m_pMasterPlayer->GetPosition() )
{
CmdMove();
}
//테이머와 150M 이상 벌어질 경우 대기 상태로 전환
else if( CheckDistance( DISTANCE_150, m_pMasterPlayer ) )
{
m_nCreatureState = STATE_RECALL_COUNTDOWN;
}
else
{
//테이머가 이동이 완료된 후에 크리처 방향 설정
// if( !m_pMasterPlayer->IsMoving() )
SetViewVectorStateIdle( m_pMasterPlayer->GetViewVector() );
}
}
}
//공격 중
void SGameLocalCreature::CmdAttack()
{
if(!CheckState()) return;
float fDistance = 0.f;
SGameAvatarEx* pTargetMonster = (SGameAvatarEx*)GetGameObject(m_hTargetMonster);
if( pTargetMonster )
{
//대상몬스터와 크리처가 50M이상 떨어져 있다면 따르기 상태로 전환
if( CheckDistance( DISTANCE_50, pTargetMonster ) )
{
CmdMove();
}
}
if( m_pMasterPlayer )
{
//테이머와 크리처가 150M이상 떨어져 있다면 대기 상태로 전환후 1분후 자동 리콜
if( CheckDistance( DISTANCE_150, m_pMasterPlayer ) )
{
m_nCreatureState = STATE_STANDBY;
}
}
}
//거리를 체크한후 이동명령을 보낼지 결정한다
void SGameLocalCreature::CmdMove()
{
if(!CheckState()) return;
if( m_pMasterPlayer && !IsStandbyState() )
{
if( CheckDistance( DISTANCE_15, m_pMasterPlayer ) )
{
//플레이어 속도로 이동 하도록 수정됨
SetBestPosition();
// SetBestPositionEx();
}
else
{
SetBestPosition();
}
m_vMasterLastPos = *m_pMasterPlayer->GetPosition();
}
}
//소환수의 가장 적절한 포지션을 구한다 플레이어 속도로 이동
void SGameLocalCreature::SetBestPosition( bool bImmediately )
{
K3DVector vOut, vNextPos;
if( GetCreaturePosition( &vOut ) == false ) return;
if( !bImmediately )
{
// if( NeedNewDetourPoint() )
{
if( m_dwTime - m_dwFindDetour > m_dwFindDetourTick )
{
//TODO : 크리처 길찾기 무시
// FindDetour( vOut, false, true );
// MoveDetour( vNextPos );
SInputMove input( vOut );
OnInput( &input );
m_dwFindDetour = m_dwTime;
}
}
}
else
{
//TODO : 크리처 길찾기 무시
//즉시 반응 해야 할경우
// FindDetour( vOut, false, true );
// MoveDetour( vNextPos );
SInputMove input( vOut );
OnInput( &input );
}
}
//소환수의 가장 적절한 포지션을 구한다, 크리처 속도로 이동
void SGameLocalCreature::SetBestPositionEx( bool bImmediately )
{
K3DVector vOut, vNextPos;
if( GetCreaturePosition( &vOut ) == false ) return;
if( !bImmediately )
{
// if( NeedNewDetourPoint() )
{
if( m_dwTime - m_dwFindDetour > m_dwFindDetourTick )
{
//TODO : 크리처 길찾기 무시
// FindDetour( vOut, false, true );
// MoveDetour( vNextPos );
SInputMove input( vOut, false );
OnInput( &input );
m_dwFindDetour = m_dwTime;
}
}
}
else
{
//TODO : 크리처 길찾기 무시
// //즉시 반응 해야 할경우
// FindDetour( vOut, false, true );
// MoveDetour( vNextPos );
SInputMove input( vOut, false );
OnInput( &input );
}
}
bool SGameLocalCreature::GetCreaturePosition( K3DVector* pOut )
{
// float fDistance = K3DVectorGetLength( vOut, GetCurPos() );
//크리처와 테이머의 거리가 7M이하 가까워 졌다면 최종 위치를 구한다
// if( fDistance <= (float)GameRule::DEFAULT_UNIT_SIZE * 7 ) //매번 호출하는게 아니여서 오차가 생긴다
// {
//테이머가 바라보는 방향을 기준으로 좌측 이나 우측으로 1M, 후방 1M 이동
*pOut = m_pMasterPlayer->GetCurPosWithChangeDir();
K3DVector vUpVector = K3DVector( 0.f, 0.f, m_fLeftNRight );
K3DVector vViewVector = -m_pMasterPlayer->GetViewVector();
K3DVectorCross( vUpVector, vViewVector, vUpVector );
*pOut += ( vUpVector + vViewVector ) * m_arMySize;
// }
return true;
}
bool SGameLocalCreature::NeedNewDetourPoint()
{
size_t numDetourPoints = GetDetourSize();
int x = 0;
int y = 0;
//길찾기로 찾은 경로의 마지막 위치을 가져온다
if( GetDetourPoint(numDetourPoints - 1, x, y) )
{
K3DVector vFinalPos = K3DVector( x, y, 0.f );
float fDistance = GetDistance( m_pMasterPlayer->GetCurPosWithChangeDir(), vFinalPos );
if( fDistance < (float)DISTANCE_3 )
{
return false;
}
}
return true;
}
void SGameLocalCreature::SetHold()
{
SetCreatureBattleModeOff();
//대기 상태로 전환
if(!CheckState()) return;
m_nCreatureState = STATE_STANDBY;
}
void SGameLocalCreature::SetUnHold()
{
SetCreatureBattleModeOff();
//대기 상태가 해지되면 따르기로 전환
if( IsStandbyState() )
m_nCreatureState = STATE_NSTANDBY;
}
void SGameLocalCreature::AddNLeaveSummon()
{
if( m_pStateVM == NULL ) return;
if(!CheckState()) return;
if( m_nCreatureMode == BATTLE_MODE_ON ) return;
//IDLE상태 이거나 MOVE상태일때 바로 자기 자리를 찾아간다
if( m_pStateVM->GetCurrentState() == SObjectState::STATE_IDLE ||
m_pStateVM->GetCurrentState() == SObjectState::STATE_MOVE )
SetBestPosition();
}
void SGameLocalCreature::CreatureBackDownSpeedOfPlayer()
{
//플레이어 속도로 퇴각하자
if(!CheckState()) return;
SetBestPosition( true );
}
void SGameLocalCreature::CreatureBackDownSpeedOfCreature()
{
if( m_pStateVM == NULL ) return;
//크리처 속도로 퇴각하자
if(!CheckState()) return;
if(m_pMasterPlayer)
{
if( !CheckDistance( DISTANCE_3, m_pMasterPlayer ) )
{
return;
}
}
if( IsStandbyState() ||
m_pStateVM->GetCurrentState() == SObjectState::STATE_CHASE ||
m_pStateVM->GetCurrentState() == SObjectState::STATE_ATTACK )
{
//플레이어 속도로 이동 하도록 수정됨
SetBestPosition( true );
// SetBestPositionEx( true );
}
}
bool SGameLocalCreature::CheckState()
{
//마운트 상태이거나 마운트중이거나 Ing중이거나 삭제 대기 중이거나
if( IsMount() || IsMountMode() || IsIng() || IsReservation() ) return false;
return true;
}
bool SGameLocalCreature::IsStandbyState()
{
//대기중이거나 역소환 하려고 카운트 다운중이거나
if( m_nCreatureState == STATE_STANDBY || m_nCreatureState == STATE_RECALL_COUNTDOWN )
return true;
return false;
}
void SGameLocalCreature::SetCreatureBattleModeOff()
{
m_nCreatureMode = BATTLE_MODE_OFF;
}
void SGameLocalCreature::SetCreatureBattleModeOn()
{
m_nCreatureMode = BATTLE_MODE_ON;
}
///////////////////////////////////////////////////////////
/////운송 수단용 크리처
SGameCreatureForTransport::SGameCreatureForTransport( int nCreatureID, unsigned char ucEnhance ) : SGameCreature( nCreatureID, ucEnhance )
, m_pMasterPlayer( NULL )
, m_hMaster( 0 )
{
m_bFootsteps = true;
m_pStateVM = new SLocalCreatureStateMachine;
m_pStateVM->SetReceiver( this );
}
SGameCreatureForTransport::~SGameCreatureForTransport()
{
}
void SGameCreatureForTransport::SetMaster( AR_HANDLE hMaster, SGameAvatarEx * pMaster )
{
m_hMaster = hMaster;
m_pMasterPlayer = pMaster;
if( m_pMasterPlayer )
m_bLocalCreature = m_pMasterPlayer->IsLocalPlayer();
else
m_bLocalCreature = false;
}
void SGameCreatureForTransport::SetViewVectorStateIdle( const K3DVector &tpos )
{
m_pMasterPlayer = (SGameAvatarEx*)GetGameObject(m_hMaster);
if( m_pMasterPlayer )
{
if( m_pMasterPlayer->IsMoving() )
{
struct ArcadiaClient* pArClient = m_pMasterPlayer->GetArClient();
if( pArClient )
{
const ArPosition& cursteppos = pArClient->GetMyPos().GetDirection();
m_vNextPos = K3DVector( cursteppos.x, cursteppos.y, 0.f );
SetViewVector( m_vNextPos );
}
else
{
_Object& arObj = m_pMasterPlayer->GetArObject();
const ArPosition& cursteppos = arObj.mv.GetDirection();
m_vNextPos = K3DVector( cursteppos.x, cursteppos.y, 0.f );
SetViewVector( m_vNextPos );
}
}
else
{
K3DVector vView = m_pMasterPlayer->GetViewVector();
m_fTargetRoll = atan2( vView.y, vView.x );
m_dwPrevTime = m_dwTime;
m_bUseRot = true;
}
}
}
bool SGameCreatureForTransport::Process( DWORD time, unsigned long uProcessBitVector )
{
m_pMasterPlayer = (SGameAvatarEx*)GetGameObject(m_hMaster);
if( m_pMasterPlayer )
{
struct ArcadiaClient* pArClient = m_pMasterPlayer->GetArClient();
if( pArClient )
{
const ArMoveVector& pos = pArClient->GetMyPos();
SetArObjectPos( pos.x, pos.y, 0.0f, pArClient->GetLayer() );
if( pArClient->GetMyPos().HasDirectionChanged() )
{
const ArPosition& cursteppos = pArClient->GetMyPos().GetDirection();
m_vNextPos = K3DVector( cursteppos.x, cursteppos.y, 0.f );
SetViewVector( m_vNextPos );
}
GetArObject().mv.SetMoving( pArClient->GetMyPos().IsMoving() );
}
else
{
_Object& arObj = m_pMasterPlayer->GetArObject();
SetArObjectPos( arObj.mv.x, arObj.mv.y, 0.0f, arObj.layer );
if( arObj.mv.HasDirectionChanged() )
{
const ArPosition& cursteppos = arObj.mv.GetDirection();
m_vNextPos = K3DVector( cursteppos.x, cursteppos.y, 0.f );
SetViewVector( m_vNextPos );
}
GetArObject().mv.SetMoving( arObj.mv.IsMoving() );
}
}
SGameAvatarEx::Process( time );
return true;
}
void SGameCreatureForTransport::OnChangeState( SObjectState::ID stateid, const SStateInfo &info )
{
switch( stateid )
{
case SObjectState::STATE_IDLE:
{
if( GetCurrAnimationID() == ANI_RUN ||
GetCurrAnimationID() == ANI_WALK )
{
Default();
}
}
break;
case SObjectState::STATE_MOVE:
{
if( info.dwSpeed == 0 )
{
return;
}
SetAniLock( false );
if(info.dwSpeed < m_fWalkSpeed)
{
CalcCreatureWalkPlayRate( (float)info.dwSpeed );
Walk(true);
}
else
{
CalcCreatureRunPlayRate( (float)info.dwSpeed );
Run();
}
}
break;
}
}
///////////////////////////////////////////////////////////
//Dummy Creature
SGameDummyCreature::SGameDummyCreature( int nCreatureID, unsigned char ucEnhance ) : SGameCreature( nCreatureID, ucEnhance )
{
m_pStateVM = new SOtherCreatureStateMachine; //상태 머신
m_pStateVM->SetReceiver( this );
m_nMode = 0;
SetScale( 1.0f );
}
SGameDummyCreature::~SGameDummyCreature()
{
}
void SGameDummyCreature::SetDBData()
{
m_fPlayRate = DEFAULT_ANI_PLAY_RATE;
m_fSpeed = DEFAULT_MOVE_SPEED;
}
void SGameDummyCreature::OnChangeState( SObjectState::ID stateid, const SStateInfo &info )
{
switch( stateid )
{
case SObjectState::STATE_MOVE :
{
if( info.dwSpeed == 0 )
{
//달리다 죽은 것이므로 Ani 처리는 스킵한다.
return;
}
//SetViewVector( info.vTargetPos );
SetAniLock( false );
switch( m_nMode )
{
case 0 :
{
if( info.dwSpeed >= 10 )
{
Run();
}
else
{
Walk(true);
}
}
break;
case 1 :
Walk(true);
break;
case 2 :
Run();
break;
}
}
break; // 이동
default:
{
SGameCreature::OnChangeState( stateid, info );
}
break;
}
}
void SGameDummyCreature::SetDummyCreatureSpeed( float fPerSpeed )
{
m_fSpeed = GetCalcMoveSpeed( fPerSpeed );
}
void SGameDummyCreature::SetDummyCreaturePlayRate( float fPerPlayRate )
{
m_fPlayRate = GetCalcPlayRate( fPerPlayRate );
}
void SGameDummyCreature::SetDummyCreatureSpeedWithPlayRate( float fPerSpeed )
{
m_fSpeed = GetCalcMoveSpeed( fPerSpeed );
m_fPlayRate = DEFAULT_ANI_PLAY_RATE * (m_fSpeed / DEFAULT_MOVE_SPEED);
}
void SGameDummyCreature::SetDummyCreatureMode( int nMode )
{
m_nMode = nMode;
}
float SGameDummyCreature::GetCalcMoveSpeed( float fPerSpeed )
{
return (DEFAULT_MOVE_SPEED * fPerSpeed) / 100.0f;
}
float SGameDummyCreature::GetCalcPlayRate( float fPerPlayRate )
{
return (DEFAULT_ANI_PLAY_RATE * fPerPlayRate) / 100.0f;
}
float SGameDummyCreature::GetPlayRatePercentage( float fSpeed )
{
return (fSpeed / DEFAULT_MOVE_SPEED) * 100.0f;
}