513 lines
13 KiB
C++
513 lines
13 KiB
C++
#include "stdafx.h"
|
|
// sonador 10.2.1 팻 시스템 구현
|
|
#include "SGameLocalPet.h"
|
|
#include "SPetStateMachine.h"
|
|
#include "GameDefine.h"
|
|
#include "KSeqAvatarEx.h"
|
|
#include "SGameAniType.h"
|
|
#include "SSkillDB.h"
|
|
#include "SGameInput.h"
|
|
#include "SStringDB.h"
|
|
#include "SGameMessage.h"
|
|
//#include "SGameMessageUI.h"
|
|
#include "LuaVM.h"
|
|
#include <toolkit/XStringUtil.h>
|
|
#include "SChatType.h"
|
|
#include "SGameItem.h"
|
|
#include "SGameUIMgr.h"
|
|
#include "SMessengerMgr.h"
|
|
#include "SDebug_Util.h"
|
|
#include "SLog.h"
|
|
|
|
#include "SGameScript.h"
|
|
#include "SGame.h"
|
|
//#include "SAvatarProperty.h"
|
|
|
|
SGameLocalPet::SGameLocalPet( int nPetID )
|
|
: SGamePet ( nPetID )
|
|
, m_dwUpdateTime ( 0 )
|
|
, m_dwFindDetour ( 0 )
|
|
, m_dwFindDetourTick ( 200 )
|
|
, m_dwBeginScriptTime ( 0 )
|
|
, m_dwCallScriptTime ( 500 ) // 게임 로컬 펫 스크립트 호출 주기 1초에서 0.5초로 변경 (줍기 속도 개선. 2013-12-12)
|
|
, m_bPickItemMode ( false ) // sonador #2.1.2.4.3 팻 조작 UI 연동
|
|
, m_fPickItemDistance ( ITEM_TAKE_RANGE ) //
|
|
, m_vMasterLastPos( 0, 0, 0 )
|
|
{
|
|
m_bLocalPet = true;
|
|
m_pStateVM = new SLocalPetStateMachine();
|
|
m_pStateVM->SetReceiver( this );
|
|
m_arMySize = GetSize( this );
|
|
m_dwItemPickCommandTime = 0;
|
|
}
|
|
|
|
SGameLocalPet::~SGameLocalPet()
|
|
{
|
|
}
|
|
|
|
/// 2010.10.13 - prodongi
|
|
void SGameLocalPet::Destroy()
|
|
{
|
|
SGamePet::Destroy();
|
|
m_queueIgnoredItems.clear();
|
|
}
|
|
|
|
bool SGameLocalPet::Process( DWORD time, unsigned long procBitSet )
|
|
{
|
|
m_dwCurrentTime = time;
|
|
|
|
/*
|
|
/* 펫은 보낼 필요없더라.
|
|
// udpate rarely
|
|
if( m_dwUpdateTime == 0 )
|
|
m_dwUpdateTime = time;
|
|
else if( ( time - m_dwUpdateTime ) >= UPDATE_TIME )
|
|
{
|
|
m_dwUpdateTime = time;
|
|
// send udpate message to server
|
|
TS_CS_UPDATE msg;
|
|
msg.handle = GetArID();
|
|
SendMsg( &msg );
|
|
}
|
|
*/
|
|
|
|
SGamePet::Process( time, procBitSet );
|
|
|
|
if( time - m_dwBeginScriptTime > m_dwCallScriptTime )
|
|
{
|
|
UpdateStateByScript();
|
|
m_dwBeginScriptTime = time; // sonador #2.1.2.4.3 팻 조작 UI 연동
|
|
}
|
|
|
|
if( m_pStateVM )
|
|
m_pStateVM->Process( time );
|
|
|
|
if ((m_pStateVM->GetCurrentState() != SObjectState::STATE_IDLE) && m_dwItemPickCommandTime != 0)
|
|
{
|
|
if (m_dwCurrentTime - m_dwItemPickCommandTime > 7000)
|
|
{
|
|
SDEBUGLOG("펫이 아이템을 회수 못하고 있음, 강제로 상태 리셋 \n");
|
|
m_dwItemPickCommandTime = 0;
|
|
m_pStateVM->StopCurrentState();
|
|
}
|
|
}
|
|
|
|
if (!m_queueIgnoredItems.empty())
|
|
{
|
|
if (m_dwCurrentTime - m_queueIgnoredItems.front().m_dwIgnoredTime > 5 * 60 * 1000) // 10분
|
|
{
|
|
SDEBUGLOG("무시 리스트에서 1개제거\n");
|
|
m_queueIgnoredItems.pop_front(); // 1프레임에 1개씩만 제거한다. 어차피 1프레임에 1개이상 제거될 일 없으니 코드 단순하게.
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SGameLocalPet::UpdateStateByScript()
|
|
{
|
|
if( m_pStateVM == 0 ) return;
|
|
|
|
if( IsIng() || IsReservation() ) return;
|
|
|
|
// Fraun performance tweak
|
|
std::string Function;
|
|
switch( m_pStateVM->GetCurrentState() )
|
|
{
|
|
case SObjectState::STATE_NONE:
|
|
case SObjectState::STATE_IDLE:
|
|
{
|
|
STRUCT_CREATURE_CMD_SCRIPT Idle;
|
|
|
|
Idle.nCmdScipt = STRUCT_CREATURE_CMD_SCRIPT::CMD_IDLE;
|
|
Idle.cHandle = GetArID();
|
|
|
|
SGame* pGame = GetActGame();
|
|
if (pGame) pGame->SendCreatureCmdScript(Idle);
|
|
break;
|
|
}
|
|
case SObjectState::STATE_MOVE:
|
|
{
|
|
STRUCT_CREATURE_CMD_SCRIPT Move;
|
|
|
|
Move.nCmdScipt = STRUCT_CREATURE_CMD_SCRIPT::CMD_MOVE;
|
|
Move.cHandle = GetArID();
|
|
Move.nCreaturePosition = 1;
|
|
|
|
SGame* pGame = GetActGame();
|
|
if (pGame) pGame->SendCreatureCmdScript(Move);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SGameLocalPet::HasStateHeld()
|
|
{
|
|
if( IsIng() || IsReservation() )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameLocalPet::IsFarFrom( SGameAvatarEx* Target, DISTANCE_TYPE Type )
|
|
{
|
|
float fDistance = GetDistance( GetCurPosWithChangeDir(), Target->GetCurPosWithChangeDir() );
|
|
float fRange = (float)Type + m_arMySize;
|
|
if( fDistance > fRange )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void SGameLocalPet::CmdIdle()
|
|
{
|
|
if( HasStateHeld() )
|
|
return;
|
|
|
|
if( m_pMasterPlayer )
|
|
{
|
|
if( m_bPickItemMode && !m_pMasterPlayer->IsDead() ) // #2.1.2.4.2
|
|
{
|
|
const int PET_MAX_TAKE_ITEM_SEARCH_COUNT = INT_MAX; // 검색최대 갯수
|
|
|
|
float fDistance = 0.f;
|
|
vector<SGameAvatarEx*> vecItems;
|
|
vector<float> vecDist;
|
|
m_pMsgHandler->GetItemObjects_For_PetAutoGather( *m_pMasterPlayer->GetPosition(), m_fPickItemDistance, vecItems, *GetPosition(), vecDist, PET_MAX_TAKE_ITEM_SEARCH_COUNT );
|
|
|
|
if (!vecItems.empty())
|
|
{
|
|
float maxDist = FLT_MAX;
|
|
int index = -1;
|
|
/// 2010.10.13 - prodongi
|
|
bool isInIgnoredList = false;
|
|
for (size_t i=0; i<vecItems.size(); i++)
|
|
{
|
|
float someBigDist = 0;
|
|
bool bIgnore = false;
|
|
const SGameAvatarEx* curItem = vecItems[i];
|
|
|
|
for (size_t j=0; j<m_queueIgnoredItems.size(); j++)
|
|
{
|
|
if (m_queueIgnoredItems[j].m_hItem == curItem->GetArID())
|
|
{
|
|
// if (m_dwCurrentTime - m_queueIgnoredItems[j].m_dwLastAttemptedTime > 30 * 1000) // 30초
|
|
{
|
|
someBigDist = 100000;
|
|
m_queueIgnoredItems[j].m_nTryCount++;
|
|
SDEBUGLOG("Considering ignored item: %d / trycount: %d \n", m_queueIgnoredItems[j].m_hItem, m_queueIgnoredItems[j].m_nTryCount);
|
|
|
|
if (m_queueIgnoredItems[j].m_nTryCount >= 2) // 3번까지는 시도해본다.
|
|
{
|
|
m_queueIgnoredItems[j].m_nTryCount = 0;
|
|
m_queueIgnoredItems[j].m_dwLastAttemptedTime = m_dwCurrentTime;
|
|
}
|
|
}
|
|
// else
|
|
// bIgnore = true;
|
|
|
|
/// 2010.10.13 - prodongi
|
|
bIgnore = true;
|
|
break;
|
|
}
|
|
}
|
|
// if (bIgnore) continue;
|
|
|
|
if (vecDist[i] + someBigDist < maxDist ) // 리스트에 있는 아이템을 무조건 무시가 아니라 최하순위로 고려
|
|
{
|
|
/// 2010.10.13 - prodongi
|
|
isInIgnoredList = bIgnore;
|
|
index = i;
|
|
maxDist = vecDist[i] + someBigDist;
|
|
}
|
|
}
|
|
if (index != -1)
|
|
{
|
|
SGameItem* pItemObj = static_cast< SGameItem* >( vecItems[index] );
|
|
|
|
// 2011.10.18 : servantes : SPartyMgr 관리 클래스
|
|
int nPartyID = static_cast< CPartyListMgr* >( GameUIMgrInstance.GetUIMgr( SGameUIInstance::PARTY_MGR ) )->GetPartyID();
|
|
if( pItemObj->IsPickable( m_pMasterPlayer->GetArID(), nPartyID ) )
|
|
{
|
|
///
|
|
/// 2010.10.13 왜 m_queueIgnoredItems에 들어 있는지 체크를 안 하는가???? - prodongi
|
|
///
|
|
|
|
SInputTakeItem inputTakeItem( pItemObj->GetArID(), fDistance );
|
|
OnInput( &inputTakeItem );
|
|
|
|
/// 2010.10.13 무시 리스트에 없는 것만 새로 추가한다 - prodongi
|
|
if (!isInIgnoredList)
|
|
{
|
|
IgnoredItem item;
|
|
item.m_nTryCount = 0;
|
|
item.m_dwIgnoredTime = m_dwCurrentTime;
|
|
item.m_dwLastAttemptedTime = 0;
|
|
item.m_hItem = pItemObj->GetArID();
|
|
m_queueIgnoredItems.push_back(item);
|
|
}
|
|
|
|
m_dwItemPickCommandTime = m_dwCurrentTime;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 주변에 아이템이 없다면 무시 리스트를 초기화 한다.
|
|
m_queueIgnoredItems.clear();
|
|
}
|
|
|
|
//SGameObject* pItem = m_pMsgHandler->GetItemObject( *m_pMasterPlayer->GetPosition(), fDistance, -1, m_fPickItemDistance );
|
|
//if( pItem )
|
|
//{
|
|
// SGameItem* pItemObj = static_cast< SGameItem* >( pItem );
|
|
// int nPartyID = static_cast< SPartyMgr* >( GameUIMgrInstance.GetUIMgr( SGameUIInstance::PARTY_MGR ) )->GetPartyID();
|
|
// if( pItemObj->IsPickable( m_pMasterPlayer->GetArID(), nPartyID ) )
|
|
// {
|
|
// SInputTakeItem inputTakeItem( pItem->GetArID(), fDistance );
|
|
// OnInput( &inputTakeItem );
|
|
// return;
|
|
// }
|
|
//}
|
|
}
|
|
|
|
if( IsFarFrom( m_pMasterPlayer, DISTANCE_3 ) || m_vMasterLastPos != *m_pMasterPlayer->GetPosition() )
|
|
{
|
|
CmdMove();
|
|
}
|
|
else
|
|
{
|
|
SetViewVectorStateIdle( m_pMasterPlayer->GetViewVector() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameLocalPet::CmdMove()
|
|
{
|
|
if( HasStateHeld() )
|
|
return;
|
|
|
|
if( m_pMasterPlayer )
|
|
{
|
|
if( IsFarFrom( m_pMasterPlayer, DISTANCE_15 ) )
|
|
InputCmd_MoveToFitPosition( true );
|
|
else
|
|
InputCmd_MoveToFitPosition( false );
|
|
|
|
m_vMasterLastPos = *m_pMasterPlayer->GetPosition();
|
|
}
|
|
}
|
|
|
|
void SGameLocalPet::OnInput( class SGameInput* input )
|
|
{
|
|
if( !m_pStateVM )
|
|
return;
|
|
m_pStateVM->OnInput( input );
|
|
|
|
// TODO: processing input by id
|
|
int inputID = input->GetInputID();
|
|
}
|
|
|
|
bool SGameLocalPet::GetFitPosition( K3DVector& out )
|
|
{
|
|
// TODO: locate pet behind the master player
|
|
K3DVector vUp( 0, 0, -1.f );
|
|
K3DVectorCross( out, m_pMasterPlayer->GetViewVector(), vUp );
|
|
out = m_pMasterPlayer->GetCurPosWithChangeDir() + ( out * m_arMySize );
|
|
return true;
|
|
}
|
|
|
|
AR_UNIT SGameLocalPet::GetSize( SGameObject *object )
|
|
{
|
|
AR_UNIT size = object->GetSize() / 2.f;
|
|
AR_UNIT scale = object->GetScale();
|
|
|
|
return size * scale * GameRule::DEFAULT_UNIT_SIZE;
|
|
}
|
|
|
|
void SGameLocalPet::ReqTakeItem( AR_HANDLE handle )
|
|
{
|
|
SDEBUGLOG("ReqTakeItem \n");
|
|
|
|
{
|
|
// 목표로한 아이템을 줍는다.
|
|
TS_CS_TAKE_ITEM msg;
|
|
msg.item_handle = handle;
|
|
msg.taker_handle = GetArID(); // sonador #2.1.2.4.3 팻 조작 UI 연동
|
|
|
|
SendMsg( &msg );
|
|
}
|
|
|
|
// 현재 위치에서 바로 주울 수 있는 n개의 아이템을 검색하여 줍는다.
|
|
const int PET_ADDITIONAL_MAX_TAKE_ITEM_COUNT = INT_MAX; // 팻이 한번에 아이템을 추가로 주울수 있는 갯수
|
|
if( PET_ADDITIONAL_MAX_TAKE_ITEM_COUNT > 0 )
|
|
{
|
|
vector<SGameAvatarEx*> vecItems;
|
|
vector<float> vecDist;
|
|
m_pMsgHandler->GetItemObjects_For_PetAutoGather( *GetPosition(), GameRule::MAX_TAKE_ITEM_RANGE, vecItems, *GetPosition(), vecDist, PET_ADDITIONAL_MAX_TAKE_ITEM_COUNT );
|
|
|
|
if (!vecItems.empty())
|
|
{
|
|
auto pos = vecItems.cbegin();
|
|
auto end = vecItems.cend();
|
|
for( ; pos != end; ++pos )
|
|
{
|
|
SGameItem* pItemObj = static_cast< SGameItem* >( *pos );
|
|
|
|
// 무시된 아이템 제외
|
|
auto ignored_pos = m_queueIgnoredItems.cbegin();
|
|
auto ignored_end = m_queueIgnoredItems.cend();
|
|
bool ignored_flag = false;
|
|
for( ; ignored_pos != ignored_end; ++ignored_pos )
|
|
{
|
|
const IgnoredItem& ignored_item = (*ignored_pos);
|
|
if (ignored_item.m_hItem == pItemObj->GetArID())
|
|
{
|
|
ignored_flag = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( ignored_flag == false )
|
|
{
|
|
// 2011.10.18 : servantes : SPartyMgr 관리 클래스
|
|
int nPartyID = static_cast< CPartyListMgr* >( GameUIMgrInstance.GetUIMgr( SGameUIInstance::PARTY_MGR ) )->GetPartyID();
|
|
if( pItemObj->GetArID() != handle && pItemObj->IsPickable( m_pMasterPlayer->GetArID(), nPartyID ) )
|
|
{
|
|
IgnoredItem item;
|
|
item.m_nTryCount = 0;
|
|
item.m_dwIgnoredTime = m_dwCurrentTime;
|
|
item.m_dwLastAttemptedTime = 0;
|
|
item.m_hItem = pItemObj->GetArID();
|
|
m_queueIgnoredItems.push_back(item);
|
|
|
|
TS_CS_TAKE_ITEM msg;
|
|
msg.item_handle = pItemObj->GetArID();
|
|
msg.taker_handle = GetArID();
|
|
|
|
SendMsg( &msg );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameLocalPet::ReqMove( AR_HANDLE handle, const ArPosition& target, bool speedSync, bool chase )
|
|
{
|
|
SDEBUGLOG("ReqMove \n");
|
|
if( IsUsingSkill() || 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, speedSync );
|
|
else
|
|
SGameObject::ReqMove( handle, target, &target, 1, speedSync );
|
|
|
|
DeleteReqPoint();
|
|
}
|
|
|
|
void SGameLocalPet::ReqCast( AR_HANDLE target, int skillID, int skillLv, K3DVector const& targetPos )
|
|
{
|
|
if( IsIng() )
|
|
return;
|
|
|
|
_SKILL_FX* skillFx = GetSkillStageDB().GetSkillStageData( skillID );
|
|
if( !skillFx )
|
|
{
|
|
assert( 0 && "스킬 ID 확인 : 스킬 유형이 없다!!!" );
|
|
return;
|
|
}
|
|
|
|
TS_CS_SKILL msg;
|
|
msg.caster = GetArID();
|
|
msg.target = 0;
|
|
msg.skill_id = skillID;
|
|
msg.skill_level = skillLv;
|
|
msg.x = targetPos.x;
|
|
msg.y = targetPos.y;
|
|
msg.z = targetPos.z;
|
|
|
|
SendMsg( &msg );
|
|
}
|
|
|
|
void SGameLocalPet::ReqCancelAction()
|
|
{
|
|
TS_CS_CANCEL_ACTION msg;
|
|
msg.handle = GetArID();
|
|
SendMsg( &msg );
|
|
}
|
|
|
|
void SGameLocalPet::InputCmd_MoveToFitPosition( bool syncWithMasterPlayer, bool immediately )
|
|
{
|
|
K3DVector out, nextPos;
|
|
if( GetFitPosition( out ) == false ) return;
|
|
|
|
if( !immediately )
|
|
{
|
|
if( m_dwTime - m_dwFindDetour > m_dwFindDetourTick )
|
|
{
|
|
SInputMove input( out, syncWithMasterPlayer );
|
|
OnInput( &input );
|
|
|
|
m_dwFindDetour = m_dwTime;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SInputMove input( out, syncWithMasterPlayer );
|
|
OnInput( &input );
|
|
}
|
|
}
|
|
|
|
//void SGameLocalPet::SetBestPositionEx( bool immediately )
|
|
//{
|
|
// K3DVector out, nextPos;
|
|
// if( GetFitPosition( out ) == false ) return;
|
|
//
|
|
// if( !immediately )
|
|
// {
|
|
// if( m_dwTime - m_dwFindDetour > m_dwFindDetourTick )
|
|
// {
|
|
// SInputMove input( out, false );
|
|
// OnInput( &input );
|
|
//
|
|
// m_dwFindDetour = m_dwTime;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// SInputMove input( out, false );
|
|
// OnInput( &input );
|
|
// }
|
|
//}
|
|
|
|
//팻 자동 줍기 가능 거리 설정 // sonador #2.1.2.4.3 팻 조작 UI 연동
|
|
void SGameLocalPet::SetAutoPickItemDistanceByMeter( float meter )
|
|
{
|
|
m_fPickItemDistance = meter * GameRule::DEFAULT_UNIT_SIZE;
|
|
}
|
|
|
|
|
|
void SGameLocalPet::DeleteItemFromIgnoreQueue(AR_HANDLE id)
|
|
{
|
|
for (std::deque<IgnoredItem>::iterator i=m_queueIgnoredItems.begin(); i!=m_queueIgnoredItems.end(); ++i)
|
|
{
|
|
if ((*i).m_hItem == id)
|
|
{
|
|
SDEBUGLOG("Removed from ignore list: %d", id);
|
|
m_queueIgnoredItems.erase(i);
|
|
SDEBUGLOG("Item ignore list: ");
|
|
for (size_t i=0; i<m_queueIgnoredItems.size(); i++)
|
|
SDEBUGLOG("( %d ) ", m_queueIgnoredItems[i].m_hItem);
|
|
SDEBUGLOG("\n");
|
|
|
|
break;
|
|
}
|
|
}
|
|
} |