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

946 lines
24 KiB
C++

#include "stdafx.h"
#include ".\SGameLocalPlayer.h"
#include "GameDefine.h"
#include "KSeqAvatarEx.h"
#include "SGameAniType.h"
#include "SAvatarProperty.h"
#include "SAvatarStateMachine.h"
#include "SSkillDB.h"
#include "SGameMessage.h"
//#include "SGameMessageUI.h"
#include "SSKillStageType.h"
#include <toolkit/XStringUtil.h>
#include "SChatType.h"
#include "SStringDB.h"
#include "SMotionDB.h"
#include "SGameWorld.h"
#include ".\SGameLocalCreature.h"
#include "SDebug_Util.h"
#include "Arena\\ArenaJoinSituationChecker.h"
#include "SGameSystem.h"
extern SGameSystem * g_pCurrentGameSystem;
#include "SUISysMsgDefine.h"
AR_TIME SGameLocalPlayer::CREATURE_MOUNT_COOLTIME = 200;
void SGameLocalPlayer::sKMoveTargetList::add(K3DVector const& pos)
{
if (m_list.size() >= sKMoveTargetList::MAX_LIST_NUM)
m_list.erase(m_list.begin());
m_list.push_back(pos);
}
bool SGameLocalPlayer::sKMoveTargetList::is(K3DVector const& pos) const
{
std::vector<K3DVector>::const_iterator it = std::find(m_list.begin(), m_list.end(), pos);
if (it != m_list.end())
{
return true;
}
return false;
}
bool SGameLocalPlayer::sKMoveTargetList::erase(K3DVector const& pos)
{
std::vector<K3DVector>::iterator it = std::find(m_list.begin(), m_list.end(), pos);
if (it != m_list.end())
{
m_list.erase( it );
return true;
}
return false;
}
SGameLocalPlayer::SGameLocalPlayer() : SGamePlayer()
, m_bDeadDialog( false )
, m_bDeadMsgInDeathMatch( false )
, m_bSendResurrecMsgInDeathMatch( false )
, m_bDeadMsgInDeathMatchTime( 0 )
, m_bDeadMsgInDeathMatchTime2( 0 )
, m_dwUpdateTime( 0 ) //서버 업데이트 시간
, m_dwDeadDialogTime( 0 )
, m_nPrevHP( 1 )
, m_pWayPointList( NULL )
, m_nWayPointSize( 0 )
, m_nCurrentWayPoint( -1 )
, m_nTotalLak( 0 )
, m_nTotalBonusLak( 0 )
, m_nAbsorbLak( 0 )
, m_nBonusLakType( 0 ) // sonador 3.10.2 PC 방 혜택 관련 라크 획득 시스템 메시지 변경
, m_nBonusLakPercentage( 0 ) //
, m_nPKModeState( PK_MODE_OFF )
, m_instanceArenaStatus(IAS_NORMAL)
, m_pPending_poslist(NULL)
, m_nPending_handle( 0 )
{
m_pStateVM = new SLocalPlayerStateMachine;
m_pStateVM->SetReceiver( this );
m_pLocalPlayer = this;
m_bFootsteps = true;
m_bLocal = true;
m_creatureMountedTime = 0;
if (m_pPending_poslist==NULL)
{ m_pPending_poslist = new ArPosition[PENDINGSIZE];
}
m_dwActivateSkillTime = timeGetTime();
}
SGameLocalPlayer::~SGameLocalPlayer()
{
if( m_pStateVM ) m_pStateVM->SetReceiver( NULL );
if ( m_pPending_poslist )
delete []m_pPending_poslist;
}
void SGameLocalPlayer::OnInput( class SGameInput * pInput )
{
if( !m_pStateVM ) return;
m_pStateVM->OnInput( pInput );
}
void SGameLocalPlayer::NPlayAnimation( int nType , int nAniType, float fPlayRate )
{
/* if( nType == 11 )
{
assert(0);
}
_oprint( "로컬 NPlayAnimation : %d\n", nType );*/
if ((m_nNewCurAniType==ANI_WALK || m_nNewCurAniType==ANI_RUN) && (nType>=ANI_FIRE_MAGIC01 && nType<=ANI_FIRE_MAGIC05)) return;
assert( nType && "Local::NPlayAnimation Ani value is abnormal." );
SGamePlayer::NPlayAnimation( nType , nAniType, fPlayRate );
}
bool SGameLocalPlayer::Render( unsigned long uRenderBitVector, KViewportObject** ppViewportList, int nViewportCount )
{
return SGameAvatarEx::Render( uRenderBitVector, ppViewportList, nViewportCount );
}
bool SGameLocalPlayer::Process( DWORD dwTime, unsigned long uProcessBitVector )
{
if( m_bRefreshInven )
{
m_bRefreshInven = false;
//인벤토리에 셋팅
SIMSG_UI_MAINPLAYER_INFO msg;
msg.pSeqForm = GetSeqForm();
msg.pCobName = GetCobFileName();
msg.handle = GetArID();
msg.bRefresh = true;
msg.pAniName = GetMotionSetDB().GetAni( GetObjType(), ANI_DEFAULT01, GetRace(), GetSex(), m_nAniClass );
if( msg.pAniName )
{
CStringUtil::GetStrKey( msg.pAniName, '_', m_strTempAniKey );
msg.pAniName = m_strTempAniKey.c_str();
}
SendGameMsg( &msg );
}
// { TODO : 죽었을때 다이얼로그 처리
if( /*m_nPrevHP &&*/ IsDead() )
{
/*int x = GetPosition()->x;
int y = GetPosition()->y;
//데스매치중이다.
if(
( x >= 193536 && x <= 201600
&& y >= 104832 && y <= 112896)
|| ( x >= 201600 && x <= 209664
&& y >= 104832 && y <= 112896)
|| ( x >= 193536 && x <= 201600
&& y >= 96768 && y <= 104832)
|| ( x >= 201600 && x <= 209664
&& y >= 96768 && y <= 104832)
|| ( x >= 193536 && x <= 201600
&& y >= 88704 && y <= 96768)
|| ( x >= 201600 && x <= 209664
&& y >= 88704 && y <= 96768)
|| ( x >= 193536 && x <= 201600
&& y >= 80640 && y <= 88704)
|| ( x >= 201600 && x <= 209664
&& y >= 80640 && y <= 88704)
) // 데스매치*/
#ifndef _EQUATION
if(IsInDeathMatch())
{
//10초후에 부활한다고 한다.
if (!m_bDeadMsgInDeathMatch)
{
m_bDeadMsgInDeathMatch = true;
m_bSendResurrecMsgInDeathMatch = false;
m_bDeadMsgInDeathMatchTime = dwTime;
m_bDeadMsgInDeathMatchTime2 = dwTime;
}
}
else
#endif
{
if( !m_bDeadDialog )
{
m_bDeadDialog = true;
// AziaMafia Temps pour Rez
m_dwDeadDialogTime = GetSafeTickCount() + 100; //5000 : Une boîte de dialogue apparaît disant qu'il est mort après 5 secondes
}
}
}
else
{
#ifndef _EQUATION
if(m_bDeadMsgInDeathMatch && !IsDead() )
{
m_bDeadMsgInDeathMatch = false;
m_bSendResurrecMsgInDeathMatch = false;
}
#endif
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" ) );
}
}
// }
// m_nPrevHP = GetHP();
#ifndef _EQUATION
if( m_bDeadMsgInDeathMatch )
{
if( dwTime - m_bDeadMsgInDeathMatchTime > 11000 )
{
if( !m_bSendResurrecMsgInDeathMatch )
{
//서버에 메시지 전송 하고 이제 대기한다.
m_bSendResurrecMsgInDeathMatch = true;
SendGameMsg( &SMSG_RESURRECTION( 0,0,false, true) );
}
}
else
{
//부활메시지를 뿌린다.
if( dwTime - m_bDeadMsgInDeathMatchTime2 > 1000)
{
int ttt = 10 - (DWORD)((m_bDeadMsgInDeathMatchTime2 - m_bDeadMsgInDeathMatchTime)/1000);
if(ttt >= 0)
{
m_bDeadMsgInDeathMatchTime2 += 1000;
std::string strRemain = GetStringDB().GetString( 9202 );
XStringUtil::Replace( strRemain, "#@time@#", CStringUtil::StringFormat( "%d", ttt ));
SMSG_CHATTING chatmsg;
chatmsg.handle = 0;
chatmsg.nChatType = CHAT_NOTICE;
chatmsg.szSender = "@NOTICE";//"notice";
chatmsg.strText = strRemain;
chatmsg.nNoticeOnly = 0;
SendGameMsg( &chatmsg );
}
}
}
}
#endif
// AziaMafia Instant Rez ?
//if( IsDead() && m_dwDeadDialogTime && m_dwDeadDialogTime < GetSafeTickCount() )
if (IsDead() && m_dwDeadDialogTime && m_dwDeadDialogTime < GetSafeTickCount())
{
m_dwDeadDialogTime = 0;
SendGameMsg( &SMSG_SEND_DATA( "close_all_message_box" ) );
int nStringID = 809; //전투 불능 상태입니다. <br> 마을로 귀환하시려면 확인 버튼을 누르세요.
int nCurrentLocation = GetCurrentLocation();
if( nCurrentLocation == PLAYER_IN_DUNGEON_SIEGE || nCurrentLocation == PLAYER_IN_DUNGEON_RAID )
nStringID = 822; //전투 불능 상태입니다. <br> 확인 버튼을 누르면 부활지점에서 부활합니다.
else if( nCurrentLocation == PLAYER_IN_MATCH )
nStringID = 963; //전투 불능 상태입니다.<br>확인 버튼을 누르면 경험치 소모 없이 제자리에서 부활합니다.
else if (PLAYER_IN_ARENA == nCurrentLocation)
nStringID = 2480;
if( GetStateFlag() & FLAG_STATE::FLAG_STATE_RESURRECTION )
{
StateInfoEx* pStateInfo = GetStateDBInfo( STATE_TYPE::STATE_RESURRECTION );
if( pStateInfo )
SendGameMsg( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::MSGBOX_DEAD, GetArID(), false, S(nStringID), true, GetStringDB().GetString( pStateInfo->name_id ) ) );
else
SendGameMsg( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::MSGBOX_DEAD, GetArID(), false, S(nStringID) ) );
}
else
SendGameMsg( &SIMSG_REQ_OPEN_MSGBOX( SIMSG_REQ_OPEN_MSGBOX::MSGBOX_DEAD, 0, false, S(nStringID) ) );
/// 2012.05.21 - prodongi
checkValidArenaJoinSituationAtDead();
}
SGamePlayer::Process( dwTime, uProcessBitVector );
if( m_pStateVM )
{
m_pStateVM->Process( m_dwTime );
}
if( m_dwUpdateTime == 0 )
{
m_dwUpdateTime = m_dwTime;
}
else
{
if( (m_dwTime - m_dwUpdateTime)>=UPDATE_TIME )
{
int cur = GetArTime();;
static int last = 0;
if (cur>last+400 || cur<last)
{
m_dwUpdateTime = m_dwTime;
//서버에 메세지 보냄
TS_CS_UPDATE msg;
msg.handle = GetArID();
msg.ar_time = cur;
time_t nowtime;
time(&nowtime);
msg.rtc = nowtime;
SendMsg( &msg );
last = cur;
}
}
}
if( m_pWayPointList && m_nWayPointSize > 0 )
CheckWayPoint();
return true;
}
void SGameLocalPlayer::SetAttackMode()
{
if( !(GetStatus() & TS_ENTER::PlayerInfo::FLAG_BATTLE_MODE) )
{
ReqBattle(); //서버에 상태 바뀜 전송
}
}
void SGameLocalPlayer::CheckPrevState()
{
if( m_pStateVM == NULL ) return;
TS_ATTACK_REQUEST msg;
msg.handle = GetArID();
msg.target_handle = m_pStateVM->GetAttackTarget();
SendMsg( &msg );
}
void SGameLocalPlayer::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 SGameLocalPlayer::ReqMove( AR_HANDLE handle, const ArPosition & target, bool bSpeedSync, bool bChase )
{
//TODO : 이 곳에서 검사를 하면, 문제가 생겨서 일단 제거. 상태 머신 안으로 들어가야 할 듯 하다.
//전에 요청한 위치보다 FREQ_MOVE_LIMIT 만큼은 커야 한다.
//float fLen = K3DVectorGetLength( K3DVector(m_vTargetPos.x, m_vTargetPos.y, 0.f), K3DVector(target.x, target.y, 0.f) );
//if( fLen < FREQ_MOVE_LIMIT )
//{
// return;
//}
//사용 중인 스킬이 있어서 이동 불가
if( !IsUseSkill_complete() )
return;
if( IsUsingSkill() )
return;
//뭔가를 하는중인가?
if( IsIng() )
return;
m_vTargetPos.x = target.x;
m_vTargetPos.y = target.y;
WORD wTile=0;
GetHeight( m_vTargetPos.x, m_vTargetPos.y, m_vTargetPos.z,wTile );
//SetMoveTargetPos( m_vTargetPos.x, m_vTargetPos.y, m_vTargetPos.z, bChase );
int nDetourSize = GetAllDetourPointSize();
//if( nDetourSize > 1 )
//{
// SGameObject::ReqMove( handle, target, GetAllDetourPoint(), nDetourSize, bSpeedSync );
ReqGameObjectMove( handle, target, GetAllDetourPoint(), nDetourSize, bSpeedSync );
//
// }
//else
//if ( nDetourSize == 1 )
//{
// ReqGameObjectMove( handle, target, GetAllDetourPoint(), 1, bSpeedSync );
//}
//else
//{ SGameObject::ReqMove( handle, target, &target, 1, bSpeedSync );
//}
DeleteReqPoint();
SGameLocalCreature::SetIdleProcess( true );
stopKMove();
// _oprint( "Local ReqMove : %d %f %f %f\n", nDetourSize, target.x, target.y, target.z );
}
void SGameLocalPlayer::reqKMove(AR_HANDLE handle, const K3DVector & target, bool bSpeedSync, bool bChase )
{
// AziaMafia FixSkill
/*if( !IsUseSkill_complete() )
return;
if( IsUsingSkill() )
return;
//뭔가를 하는중인가?
if( IsIng() )
return;
AziaMafia FixSkill end
*/
m_vTargetPos.x = target.x;
m_vTargetPos.y = target.y;
WORD wTile=0;
GetHeight( m_vTargetPos.x, m_vTargetPos.y, m_vTargetPos.z,wTile );
ArPosition _target;
_target.x = target.x;
_target.y = target.y;
_target.z = target.z;
ReqGameObjectMove( handle, _target, &_target, 1, bSpeedSync );
SGameLocalCreature::SetIdleProcess( true );
}
static DWORD dwLastMoveTime = timeGetTime();
void SGameLocalPlayer::ReqGameObjectMove( AR_HANDLE handle, const ArPosition & target, const ArPosition * poslist, int count, bool bSpeedSync )
{
//static int pending_handle = 0;
static int pending_count = 0;
static ArPosition pending_target = ArPosition(0,0);
//static ArPosition *pending_poslist = NULL;
//static ArPosition last_req_pos = ArPosition(0,0);
unsigned int cur_tick = timeGetTime();
if (cur_tick - m_dwActivateSkillTime < 1000 ) return;
if (target.x == 0 && target.y==0)
{
if ( m_nPending_handle && cur_tick - dwLastMoveTime > 200 && ( cur_tick - m_dwActivateSkillTime > 2000 ) )
{
SGameObject::ReqMove( m_nPending_handle, pending_target, m_pPending_poslist, pending_count, true );
dwLastMoveTime = cur_tick;
m_nPending_handle = 0;
pending_count = 0;
} else
{
SGameWorld* pGameWorld = dynamicCast<SGameWorld*>(g_pCurrentGameSystem->GetGame());
if( pGameWorld==0) return;
if (pGameWorld->GetGameManager()->IsShowLoadingWnd() )
{ dwLastMoveTime = cur_tick;
resetPending_poslist();
pending_count = 0;
return;
}
if (IsMoving()==0) return;
if (cur_tick - dwLastMoveTime < 1000 ) return;
dwLastMoveTime = cur_tick;
int ts = GetAllDetourPointSize();
if (ts<=0)
return;
int step = GetDetourStep();
if (step==0 || step==ts)
{ step>0 ? step=step-1 : step=0 ;
int currentX, currentY;
currentX = GetPosition()->x;
currentY = GetPosition()->y;
int xd = currentX - m_pPending_poslist[step].x;
int yd = currentY - m_pPending_poslist[step].y;
int dis = (xd*xd) + (yd*yd);
if ( dis >= 3000000 )
return;
SGameObject::ReqMove( GetArID(), pending_target, &m_pPending_poslist[step], 1, true );
}
}
return;
}
// Timer Process End
// Input Porcess Start
if (count>=PENDINGSIZE) return;
if( count >= 1 )
{
if ( ( cur_tick - dwLastMoveTime > 200 || count>1 ) )
{
dwLastMoveTime = cur_tick;
SGameObject::ReqMove( handle, target, poslist, count, bSpeedSync );
m_nPending_handle = 0;
pending_target.x = (int)target.x;
pending_target.y = (int)target.y;
pending_count = count;
for (int i=0;i<count;i++)
{ m_pPending_poslist[i]= poslist[i];
}
} else
{
m_nPending_handle = handle;
pending_target.x = (int)target.x;
pending_target.y = (int)target.y;
pending_count = count;
for (int i=0;i<count;i++)
{ m_pPending_poslist[i]= poslist[i];
}
}
} else
{
ArPosition current;
current.x = GetPosition()->x;
current.y = GetPosition()->y;
current.z = GetPosition()->z;
//pending_count = 0;
dwLastMoveTime = cur_tick;
resetPending_poslist();
SGameObject::ReqMove( handle, current, &current, 1, bSpeedSync );
//SGameObject::ReqMove( handle, target, &target, 1, bSpeedSync );
//pending_handle = 0;
//pending_target = target;
//pending_count = 0;
}
}
void SGameLocalPlayer::setCameraRoll(float angle)
{
SGameAvatarEx::setCameraRoll(angle);
SGameAvatarEx* creature = GetRiderCreatureObject();
if (creature)
{
creature->setCameraRoll(angle);
}
}
void SGameLocalPlayer::addKMoveTargetList(K3DVector const& targetPos)
{
m_kmoveTargetList.add(targetPos);
}
bool SGameLocalPlayer::isKMoveTargetList(std::vector<ArPosition> const& targetPosList) const
{
if (targetPosList.empty())
return false;
ArPosition pos = targetPosList.back();
return m_kmoveTargetList.is(K3DVector(pos.x, pos.y, 0.0f));
}
void SGameLocalPlayer::eraseKMoveTargetList(std::vector<ArPosition> const& targetPosList)
{
if (targetPosList.empty())
return;
ArPosition pos = targetPosList.back();
m_kmoveTargetList.erase(K3DVector(pos.x, pos.y, 0.0f));
}
void SGameLocalPlayer::clearMoveTargetList()
{
m_kmoveTargetList.clear();
}
void SGameLocalPlayer::ReqAttack( AR_HANDLE target ) // target == 0 공격 중지 요청
{
assert( target && "ReqAttack : Target ID Invalid!!!" );
if( m_pArObject && !m_pArObject->FinishedReqRegionUpdate() )
return;
//#ifndef NDEBUG
// SGameObject * pTarget = GetGameObject( target );
// if( pTarget )
// {
// float fDistance;
// K3DVector tpos = *pTarget->GetPosition();
// K3DVector spos = *GetPosition();
// 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
// _oprint( "[ReqAttack : %u]\n", target );
//if( target == 0 )
//{
// int a = 2;
// a = 3;
//}
// AziaMafia Mafia Fix Skill
/*
if( !IsUseSkill_complete() )
return;
if( IsUsingSkill() )
return;
*/
//뭔가를 하는중인가?
if( IsIng() ) return;
// TODO : 우선 임시로 막아 두자
if( IsMount() || IsMountMode() ) return;
TS_ATTACK_REQUEST msg;
msg.handle = GetArID();
msg.target_handle = target;
SendMsg( &msg );
}
void SGameLocalPlayer::ReqCast( AR_HANDLE target, int nSkillID, int nSkillLv, K3DVector const& targetPos )
{
// _oprint( "====>스킬 요청 %d %d\n", nSkillID, nSkillLv );
//TODO : 사용 중인 스킬의 모션이 있는가 판별.
//_SKILL_FX* pSkillFX = GetSkillStageDB().GetSkillStageData( info.nSkillID );
//if( !pSkillFX )
//{
// return;
//}
//if( pSkillFX->nCasting_Type_Id != 1 )
//{
// pSkillFX->nCasting_Start_Motion_Id;
//}
if( !IsUseSkill_complete() )
return;
if( IsUsingSkill() )
{
if( IsAttackingByBow() == false )
return;
}
//뭔가를 하는중인가?
if( IsIng() )
return;
_SKILL_FX* pSkillFX = GetSkillStageDB().GetSkillStageData( nSkillID );
if( !pSkillFX )
{
assert(0 && "스킬 ID 확인 : 스킬 유형이 없다!!!" );
return;
}
if( pSkillFX->szType == 0 || pSkillFX->szDeal_Damage == 1 ) //전투 기술이면 또는 해로운 기술 이면, 전투 모드로 전환
SetAttackMode();
SkillBaseEx* pSkill = GetSkillDB().GetSkillData(nSkillID);
SGameAvatarEx* pLocal = g_pCurrentGameSystem->GetLocalPlayer();
if (pSkill && pLocal)
{ if (pSkill->cost_energy_per_skl == 1)
{ nSkillLv = pLocal->m_nEnergy;//
}
}
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 );
//사용 여부를 인터페이스에 알리자~
}
static DWORD dwCancelLastTime = GetSafeTickCount();
void SGameLocalPlayer::ReqCancelAction()
{
// _oprint( "SGameLocalPlayer::ReqCancelAction()\n" );
if ( GetSafeTickCount() - dwCancelLastTime > 200 )
{
// _oprint( "SGameLocalPlayer::ReqCancelAction()\n" );
TS_CS_CANCEL_ACTION msg;
msg.handle = GetArID();
SendMsg( &msg );
dwCancelLastTime = GetSafeTickCount();
}
}
void SGameLocalPlayer::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 SGameLocalPlayer::ReqSit()
{
if( IsMount() && IsMountMode() ) return;
if( IsIng() ) return;
RqChatting( CHAT_NORMAL, m_pProperty->Name, "/sitdown" );
}
void SGameLocalPlayer::ReqStandUp()
{
if( IsMount() && IsMountMode() ) return;
if( IsIng() ) return;
RqChatting( CHAT_NORMAL, m_pProperty->Name, "/standup" );
}
void SGameLocalPlayer::ReqNormal()
{
if( IsMount() && IsMountMode() ) return;
if( IsIng() ) return;
std::string str;
XStringUtil::Format(str, "%u", GetArID() );
RqChatting( CHAT_NORMAL, str.c_str(), "/normal" );
}
void SGameLocalPlayer::ReqBattle()
{
if( IsMount() && IsMountMode() ) return;
if( IsIng() ) return;
std::string str;
XStringUtil::Format(str, "%u", GetArID() );
RqChatting( CHAT_NORMAL, str.c_str(), "/battle" );
SGamePlayer::SetAttackMode();
}
void SGameLocalPlayer::ReqMount()
{
if( IsIng() ) return;
if (!checkCreatureMountCooltime()) return ;
RqChatting( CHAT_NORMAL, m_pProperty->Name, "/mount_creature" );
}
void SGameLocalPlayer::ReqUnMount()
{
if( IsIng() ) return;
if (!checkCreatureMountCooltime()) return ;
RqChatting( CHAT_NORMAL, m_pProperty->Name, "/unmount_creature" );
}
void SGameLocalPlayer::ReqEmotion()
{
//서버로 보내기
}
void SGameLocalPlayer::ReqUseItem( AR_HANDLE hTargetHandle, AR_HANDLE hItemHandle, int nSkillID, AR_HANDLE hItemUseTargetHandle, const char* lpText )
{
_SKILL_FX* pSkillFX = GetSkillStageDB().GetSkillStageData( nSkillID );
if( pSkillFX )
{
//전투 기술이면 또는 해로운 기술 이면, 전투 모드로 전환
if( pSkillFX->szType == 0 || pSkillFX->szDeal_Damage == 1 )
SetAttackMode();
}
TS_CS_USE_ITEM msg;
msg.target_handle = hTargetHandle;
//로그인 되어있고, 시야에 없는 파티원등에게 사용 시
if( hItemUseTargetHandle > 0 )
msg.target_handle = hItemUseTargetHandle;
msg.item_handle = hItemHandle;
assert(32>::strlen(lpText));
if( 32>::strlen(lpText) )
::memcpy( msg.szParameter, lpText, ::strlen(lpText) );
SendMsg( &msg );
}
void SGameLocalPlayer::SetWayPointList( K3DVector* pWayPointList, int nWayPointSize )
{
ClearWayPointList();
m_pWayPointList = pWayPointList;
m_nWayPointSize = nWayPointSize;
m_nCurrentWayPoint = -1;
K3DVector vPos = GetCurPosWithChangeDir();
float fOldDis = 9999999.0f;
for( int nCount = 0; nCount < m_nWayPointSize; nCount++ )
{
float fDistance = GetDistance( vPos, m_pWayPointList[nCount] );
if( fDistance < fOldDis )
{
fOldDis = fDistance;
m_nCurrentWayPoint = nCount;
}
}
//현재 웨이포인트가 마지막인가? 없는 웨이 포인트인가? 웨이 포인트와 플레이어의 거리가 5미터 이내인가?
if( m_nCurrentWayPoint < m_nWayPointSize && m_nCurrentWayPoint > -1 &&
fOldDis < (float)GameRule::DEFAULT_UNIT_SIZE * 5 )
{
//각도를 구하자
if( m_nCurrentWayPoint < m_nWayPointSize - 1 ) //다음 위치가 있어야 한다
{
K3DVector vVec1 = m_pWayPointList[m_nCurrentWayPoint+1] - m_pWayPointList[m_nCurrentWayPoint];
K3DVector vVec2 = vPos - m_pWayPointList[m_nCurrentWayPoint];
vVec1.Normalize();
vVec2.Normalize();
float fAngle = K3DVectorDot( vVec1, vVec2 );
//현재 위치로 이동할지 아니면 바로 다음 위치로 이동할지 결정
if( fAngle > 0 ) m_nCurrentWayPoint++;
}
//길찾기 땜에 잠시 주석처리 하자
// ReqMove( GetArID(), ArPosition( m_pWayPointList[m_nCurrentWayPoint].x, m_pWayPointList[m_nCurrentWayPoint].y, 0 ), GetAllDetourPoint(), GetDetourSize(), true, true );
}
else
ClearWayPointList();
}
void SGameLocalPlayer::CheckWayPoint()
{
if( m_nCurrentWayPoint < m_nWayPointSize )
{
float fDistance = GetDistance( GetCurPosWithChangeDir(), m_pWayPointList[m_nCurrentWayPoint] );
if( fDistance < (float)GameRule::DEFAULT_UNIT_SIZE * 3 )
{
if( ++m_nCurrentWayPoint < m_nWayPointSize )
{
//길찾기 땜에 잠시 주석처리 하자
// ReqMove( GetArID(), ArPosition( m_pWayPointList[m_nCurrentWayPoint].x, m_pWayPointList[m_nCurrentWayPoint].y, 0 ), GetAllDetourPoint(), GetDetourSize(), true, true );
}
else
ClearWayPointList();
}
}
else
ClearWayPointList();
}
void SGameLocalPlayer::ClearWayPointList()
{
m_pWayPointList = NULL;
m_nWayPointSize = 0;
m_nCurrentWayPoint = -1;
}
void SGameLocalPlayer::SetStatus( unsigned status )
{
if( status & TS_ENTER::PlayerInfo::FLAG_PK_ON )
{
if( !(GetStatus() & TS_ENTER::PlayerInfo::FLAG_PK_ON) )
{
SetPKMode( true );
SetPKModeState( PK_MODE_ON );
}
}
else
{
//현재 PKON상태 였다면 OFF로
if( GetStatus() & TS_ENTER::PlayerInfo::FLAG_PK_ON )
{
SetPKMode( false );
SetPKModeState( PK_MODE_OFF );
}
}
SGameAvatarEx::SetStatus( status );
}
void SGameLocalPlayer::stopKMove()
{
if (m_pMsgHandler)
m_pMsgHandler->stopKMove();
}
/// 2012.05.21 - prodongi
void SGameLocalPlayer::checkValidArenaJoinSituationAtDead()
{
sArenaJoinSituationCondition situationCondition;
/// way
situationCondition.m_notificationWays = cArenaJoinSituationChecker::WAY_NOTIFICATION_WND;
/// situation
situationCondition.add(cArenaJoinSituationChecker::SITUATION_ARENA_WAITING, S(2456));
situationCondition.add(cArenaJoinSituationChecker::SITUATION_ARENA_WAITING_COUNT, S(2456));
g_pCurrentGameSystem->isValidArenaJoinSituation(situationCondition);
}
bool SGameLocalPlayer::checkCreatureMountCooltime()
{
AR_TIME curTime = GetArTime();
AR_TIME e = curTime - m_creatureMountedTime;
if (e < CREATURE_MOUNT_COOLTIME)
{
SendGameInterfaceMsg( &SIMSG_UI_DISPLAY_SYS_MSG( SYS_MSG_OTHER_ACTION_WAIT ) );
return false;
}
m_creatureMountedTime = curTime;
return true;
}
void SGameLocalPlayer::resetPending_poslist()
{
m_nPending_handle = 0;
if ( m_pPending_poslist )
memset ( m_pPending_poslist, 0, sizeof(m_pPending_poslist)*PENDINGSIZE );
}