2V3-a: walk with the keyboard through the ported player chain
PythonPlayer, PythonPlayerInput{,Keyboard,Mouse}, PythonPlayerEventHandler,
PythonPlayerSkill, PythonPlayerModule and GameType are verbatim copies; the
`player` stub module and the pending PythonPlayer/GameType stand-ins are gone.
Unported callees (CPythonSkill, CItemData, CItemManager, CPythonItem, ...) are
pending stubs. 64-bit fixes: emotion icon handles use Py_BuildPointer, and
PyDict_Next takes Py_ssize_t.
The actor did not move because GrannyUpdateModelMatrix passed the model matrix
through. Walk/run motions use constant root-motion extraction
(AccumulationFlags=AccumulationExtracted, LoopTranslation e.g. (0,-300,0) for
the warrior run, same as the .msa Accumulation). libgr2 now reads both fields
from TrackGroups[0], and the runtime moves by LoopTranslation over each
control's local-clock span, blended by control weight. VDA extraction is not
implemented.
port.login_flow presses DIK_UP; the actor walks more than 100 cm, and the fake
server parses CG packets and sees CG_MOVE FUNC_MOVE, then FUNC_WAIT at the new
position. port.login_live against the real server walked 132 cm.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
157f7c3bb4
commit
ff0983d3c8
@@ -0,0 +1,112 @@
|
||||
#include "StdAfx.h"
|
||||
#include "GameType.h"
|
||||
|
||||
std::string g_strResourcePath = "d:/ymir work/";
|
||||
std::string g_strImagePath = "d:/ymir work/ui/";
|
||||
|
||||
std::string g_strGuildSymbolPathName = "mark/10/";
|
||||
|
||||
// DEFAULT_FONT
|
||||
static std::string gs_strDefaultFontName = "\261\274\270\262\303\274:12.fnt";
|
||||
static std::string gs_strDefaultItalicFontName = "\261\274\270\262\303\274:12i.fnt";
|
||||
static CResource* gs_pkDefaultFont = NULL;
|
||||
static CResource* gs_pkDefaultItalicFont = NULL;
|
||||
|
||||
static bool gs_isReloadDefaultFont = false;
|
||||
|
||||
void DefaultFont_Startup()
|
||||
{
|
||||
gs_pkDefaultFont = NULL;
|
||||
}
|
||||
|
||||
void DefaultFont_Cleanup()
|
||||
{
|
||||
if (gs_pkDefaultFont)
|
||||
gs_pkDefaultFont->Release();
|
||||
}
|
||||
|
||||
void DefaultFont_SetName(const char * c_szFontName)
|
||||
{
|
||||
gs_strDefaultFontName = c_szFontName;
|
||||
gs_strDefaultFontName += ".fnt";
|
||||
|
||||
gs_strDefaultItalicFontName = c_szFontName;
|
||||
if(strchr(c_szFontName, ':'))
|
||||
gs_strDefaultItalicFontName += "i";
|
||||
gs_strDefaultItalicFontName += ".fnt";
|
||||
|
||||
gs_isReloadDefaultFont = true;
|
||||
}
|
||||
|
||||
bool ReloadDefaultFonts()
|
||||
{
|
||||
CResourceManager& rkResMgr = CResourceManager::Instance();
|
||||
|
||||
gs_isReloadDefaultFont = false;
|
||||
|
||||
CResource* pkNewFont = rkResMgr.GetResourcePointer(gs_strDefaultFontName.c_str());
|
||||
pkNewFont->AddReference();
|
||||
if (gs_pkDefaultFont)
|
||||
gs_pkDefaultFont->Release();
|
||||
gs_pkDefaultFont = pkNewFont;
|
||||
|
||||
CResource* pkNewItalicFont = rkResMgr.GetResourcePointer(gs_strDefaultItalicFontName.c_str());
|
||||
pkNewItalicFont->AddReference();
|
||||
if (gs_pkDefaultItalicFont)
|
||||
gs_pkDefaultItalicFont->Release();
|
||||
gs_pkDefaultItalicFont = pkNewItalicFont;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CResource* DefaultFont_GetResource()
|
||||
{
|
||||
if (!gs_pkDefaultFont || gs_isReloadDefaultFont)
|
||||
ReloadDefaultFonts();
|
||||
return gs_pkDefaultFont;
|
||||
}
|
||||
|
||||
CResource* DefaultItalicFont_GetResource()
|
||||
{
|
||||
if (!gs_pkDefaultItalicFont || gs_isReloadDefaultFont)
|
||||
ReloadDefaultFonts();
|
||||
return gs_pkDefaultItalicFont;
|
||||
}
|
||||
|
||||
// END_OF_DEFAULT_FONT
|
||||
|
||||
void SetGuildSymbolPath(const char * c_szPathName)
|
||||
{
|
||||
g_strGuildSymbolPathName = "mark/";
|
||||
g_strGuildSymbolPathName += c_szPathName;
|
||||
g_strGuildSymbolPathName += "/";
|
||||
}
|
||||
|
||||
const char * GetGuildSymbolFileName(DWORD dwGuildID)
|
||||
{
|
||||
return _getf("%s%03d.jpg", g_strGuildSymbolPathName.c_str(), dwGuildID);
|
||||
}
|
||||
|
||||
BYTE c_aSlotTypeToInvenType[SLOT_TYPE_MAX] =
|
||||
{
|
||||
RESERVED_WINDOW, // SLOT_TYPE_NONE
|
||||
INVENTORY, // SLOT_TYPE_INVENTORY
|
||||
RESERVED_WINDOW, // SLOT_TYPE_SKILL
|
||||
RESERVED_WINDOW, // SLOT_TYPE_EMOTION
|
||||
RESERVED_WINDOW, // SLOT_TYPE_SHOP
|
||||
RESERVED_WINDOW, // SLOT_TYPE_EXCHANGE_OWNER
|
||||
RESERVED_WINDOW, // SLOT_TYPE_EXCHANGE_TARGET
|
||||
RESERVED_WINDOW, // SLOT_TYPE_QUICK_SLOT
|
||||
RESERVED_WINDOW, // SLOT_TYPE_SAFEBOX <- SAFEBOX, MALL의 경우 하드 코딩되어있는 LEGACY 코드를 유지함.
|
||||
RESERVED_WINDOW, // SLOT_TYPE_PRIVATE_SHOP
|
||||
RESERVED_WINDOW, // SLOT_TYPE_MALL <- SAFEBOX, MALL의 경우 하드 코딩되어있는 LEGACY 코드를 유지함.
|
||||
DRAGON_SOUL_INVENTORY, // SLOT_TYPE_DRAGON_SOUL_INVENTORY
|
||||
};
|
||||
|
||||
BYTE SlotTypeToInvenType(BYTE bSlotType)
|
||||
{
|
||||
if (bSlotType >= SLOT_TYPE_MAX)
|
||||
return RESERVED_WINDOW;
|
||||
else
|
||||
return c_aSlotTypeToInvenType[bSlotType];
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,280 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PythonPlayerEventHandler.h"
|
||||
#include "PythonPlayer.h"
|
||||
#include "PythonCharacterManager.h"
|
||||
#include "PythonNetworkStream.h"
|
||||
|
||||
CPythonPlayerEventHandler& CPythonPlayerEventHandler::GetSingleton()
|
||||
{
|
||||
static CPythonPlayerEventHandler s_kPlayerEventHandler;
|
||||
return s_kPlayerEventHandler;
|
||||
}
|
||||
|
||||
CPythonPlayerEventHandler::~CPythonPlayerEventHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnClearAffects()
|
||||
{
|
||||
CPythonPlayer::Instance().ClearAffects();
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnSetAffect(UINT uAffect)
|
||||
{
|
||||
CPythonPlayer::Instance().SetAffect(uAffect);
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnResetAffect(UINT uAffect)
|
||||
{
|
||||
CPythonPlayer::Instance().ResetAffect(uAffect);
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnSyncing(const SState& c_rkState)
|
||||
{
|
||||
const TPixelPosition& c_rkPPosCurSyncing=c_rkState.kPPosSelf;
|
||||
m_kPPosPrevWaiting=c_rkPPosCurSyncing;
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnWaiting(const SState& c_rkState)
|
||||
{
|
||||
DWORD dwCurTime=ELTimer_GetMSec();
|
||||
if (m_dwNextWaitingNotifyTime>dwCurTime)
|
||||
return;
|
||||
|
||||
m_dwNextWaitingNotifyTime=dwCurTime+100;
|
||||
|
||||
const TPixelPosition& c_rkPPosCurWaiting=c_rkState.kPPosSelf;
|
||||
float dx=m_kPPosPrevWaiting.x-c_rkPPosCurWaiting.x;
|
||||
float dy=m_kPPosPrevWaiting.y-c_rkPPosCurWaiting.y;
|
||||
float len=sqrt(dx*dx+dy*dy);
|
||||
|
||||
if (len<1.0f)
|
||||
return;
|
||||
|
||||
m_kPPosPrevWaiting=c_rkPPosCurWaiting;
|
||||
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendCharacterStatePacket(c_rkState.kPPosSelf, c_rkState.fAdvRotSelf, CInstanceBase::FUNC_WAIT, 0);
|
||||
|
||||
//Trace("waiting\n");
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnMoving(const SState& c_rkState)
|
||||
{
|
||||
DWORD dwCurTime=ELTimer_GetMSec();
|
||||
if (m_dwNextMovingNotifyTime>dwCurTime)
|
||||
return;
|
||||
|
||||
m_dwNextMovingNotifyTime=dwCurTime+300;
|
||||
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendCharacterStatePacket(c_rkState.kPPosSelf, c_rkState.fAdvRotSelf, CInstanceBase::FUNC_MOVE, 0);
|
||||
|
||||
// Trace("moving\n");
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnMove(const SState& c_rkState)
|
||||
{
|
||||
DWORD dwCurTime=ELTimer_GetMSec();
|
||||
m_dwNextWaitingNotifyTime=dwCurTime+100;
|
||||
m_dwNextMovingNotifyTime=dwCurTime+300;
|
||||
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendCharacterStatePacket(c_rkState.kPPosSelf, c_rkState.fAdvRotSelf, CInstanceBase::FUNC_MOVE, 0);
|
||||
|
||||
// Trace("move\n");
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnStop(const SState& c_rkState)
|
||||
{
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendCharacterStatePacket(c_rkState.kPPosSelf, c_rkState.fAdvRotSelf, CInstanceBase::FUNC_WAIT, 0);
|
||||
|
||||
// Trace("stop\n");
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnWarp(const SState& c_rkState)
|
||||
{
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendCharacterStatePacket(c_rkState.kPPosSelf, c_rkState.fAdvRotSelf, CInstanceBase::FUNC_WAIT, 0);
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnAttack(const SState& c_rkState, WORD wMotionIndex)
|
||||
{
|
||||
// Tracef("CPythonPlayerEventHandler::OnAttack [%d]\n", wMotionIndex);
|
||||
assert(wMotionIndex < 255);
|
||||
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendCharacterStatePacket(c_rkState.kPPosSelf, c_rkState.fAdvRotSelf, CInstanceBase::FUNC_COMBO, wMotionIndex);
|
||||
|
||||
#ifdef __ATTACK_SPEED_CHECK__
|
||||
static DWORD s_dwLastTime=timeGetTime();
|
||||
|
||||
DWORD dwCurTime=timeGetTime();
|
||||
Tracef("%d\n", dwCurTime-s_dwLastTime);
|
||||
s_dwLastTime=dwCurTime;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnUseSkill(const SState& c_rkState, UINT uMotSkill, UINT uArg)
|
||||
{
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendCharacterStatePacket(c_rkState.kPPosSelf, c_rkState.fAdvRotSelf, CInstanceBase::FUNC_SKILL|uMotSkill, uArg);
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnUpdate()
|
||||
{
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnChangeShape()
|
||||
{
|
||||
CPythonPlayer::Instance().NEW_Stop();
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::OnHit(UINT uSkill, CActorInstance& rkActorVictim, BOOL isSendPacket)
|
||||
{
|
||||
DWORD dwVIDVictim=rkActorVictim.GetVirtualID();
|
||||
|
||||
// Update Target
|
||||
CPythonPlayer::Instance().SetTarget(dwVIDVictim, FALSE);
|
||||
// Update Target
|
||||
|
||||
if (isSendPacket)
|
||||
{
|
||||
//#define ATTACK_TIME_LOG
|
||||
#ifdef ATTACK_TIME_LOG
|
||||
static std::map<DWORD, float> s_prevTimed;
|
||||
float curTime = timeGetTime() / 1000.0f;
|
||||
bool isFirst = false;
|
||||
if (s_prevTimed.end() == s_prevTimed.find(dwVIDVictim))
|
||||
{
|
||||
s_prevTimed[dwVIDVictim] = curTime;
|
||||
isFirst = true;
|
||||
}
|
||||
float diffTime = curTime-s_prevTimed[dwVIDVictim];
|
||||
if (diffTime < 0.1f && !isFirst)
|
||||
{
|
||||
TraceError("ATTACK(SPEED_HACK): %.4f(%.4f) %d", curTime, diffTime, dwVIDVictim);
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceError("ATTACK: %.4f(%.4f) %d", curTime, diffTime, dwVIDVictim);
|
||||
}
|
||||
|
||||
s_prevTimed[dwVIDVictim] = curTime;
|
||||
#endif
|
||||
CPythonNetworkStream& rkStream=CPythonNetworkStream::Instance();
|
||||
rkStream.SendAttackPacket(uSkill, dwVIDVictim);
|
||||
}
|
||||
|
||||
if (!rkActorVictim.IsPushing())
|
||||
return;
|
||||
|
||||
// 거대 몬스터 밀림 제외
|
||||
extern bool IS_HUGE_RACE(unsigned int vnum);
|
||||
if (IS_HUGE_RACE(rkActorVictim.GetRace()))
|
||||
return;
|
||||
|
||||
|
||||
CPythonCharacterManager::Instance().AdjustCollisionWithOtherObjects(&rkActorVictim);
|
||||
|
||||
const TPixelPosition& kPPosLast=rkActorVictim.NEW_GetLastPixelPositionRef();
|
||||
|
||||
SVictim kVictim;
|
||||
kVictim.m_dwVID=dwVIDVictim;
|
||||
kVictim.m_lPixelX=long(kPPosLast.x);
|
||||
kVictim.m_lPixelY=long(kPPosLast.y);
|
||||
|
||||
rkActorVictim.TEMP_Push(kVictim.m_lPixelX, kVictim.m_lPixelY);
|
||||
|
||||
m_kVctkVictim.push_back(kVictim);
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::FlushVictimList()
|
||||
{
|
||||
if (m_kVctkVictim.empty())
|
||||
return;
|
||||
|
||||
// #0000682: [M2EU] 대진각 스킬 사용시 튕김
|
||||
unsigned int SYNC_POSITION_COUNT_LIMIT = 16;
|
||||
unsigned int uiVictimCount = m_kVctkVictim.size();
|
||||
|
||||
CPythonNetworkStream& rkStream=CPythonNetworkStream::Instance();
|
||||
|
||||
TPacketCGSyncPosition kPacketSyncPos;
|
||||
kPacketSyncPos.bHeader=HEADER_CG_SYNC_POSITION;
|
||||
kPacketSyncPos.wSize=sizeof(kPacketSyncPos)+sizeof(TPacketCGSyncPositionElement) * uiVictimCount;
|
||||
|
||||
rkStream.Send(sizeof(kPacketSyncPos), &kPacketSyncPos);
|
||||
|
||||
for (unsigned int i = 0; i < uiVictimCount; ++i)
|
||||
{
|
||||
const SVictim& rkVictim = m_kVctkVictim[i];
|
||||
rkStream.SendSyncPositionElementPacket(rkVictim.m_dwVID, rkVictim.m_lPixelX, rkVictim.m_lPixelY);
|
||||
}
|
||||
|
||||
rkStream.SendSequence();
|
||||
m_kVctkVictim.clear();
|
||||
}
|
||||
|
||||
CPythonPlayerEventHandler::CPythonPlayerEventHandler()
|
||||
{
|
||||
m_dwPrevComboIndex=0;
|
||||
m_dwNextMovingNotifyTime=0;
|
||||
m_dwNextWaitingNotifyTime=0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CPythonPlayerEventHandler::CNormalBowAttack_FlyEventHandler_AutoClear::OnSetFlyTarget()
|
||||
{
|
||||
SState s;
|
||||
m_pInstMain->NEW_GetPixelPosition(&s.kPPosSelf);
|
||||
s.fAdvRotSelf=m_pInstMain->GetGraphicThingInstancePtr()->GetTargetRotation();
|
||||
|
||||
CPythonNetworkStream& rpns=CPythonNetworkStream::Instance();
|
||||
rpns.SendFlyTargetingPacket(m_pInstTarget->GetVirtualID(), m_pInstTarget->GetGraphicThingInstancePtr()->OnGetFlyTargetPosition());
|
||||
}
|
||||
void CPythonPlayerEventHandler::CNormalBowAttack_FlyEventHandler_AutoClear::OnShoot(DWORD dwSkillIndex)
|
||||
{
|
||||
CPythonNetworkStream& rpns=CPythonNetworkStream::Instance();
|
||||
rpns.SendShootPacket(dwSkillIndex);
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::CNormalBowAttack_FlyEventHandler_AutoClear::Set(CPythonPlayerEventHandler * pParent, CInstanceBase * pInstMain, CInstanceBase * pInstTarget)
|
||||
{
|
||||
m_pParent=(pParent);
|
||||
m_pInstMain=(pInstMain);
|
||||
m_pInstTarget=(pInstTarget);
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::CNormalBowAttack_FlyEventHandler_AutoClear::SetTarget(CInstanceBase* pInstTarget)
|
||||
{
|
||||
m_pInstTarget = pInstTarget;
|
||||
}
|
||||
|
||||
void CPythonPlayerEventHandler::CNormalBowAttack_FlyEventHandler_AutoClear::OnExplodingAtAnotherTarget(DWORD dwSkillIndex, DWORD dwVID)
|
||||
{
|
||||
return;
|
||||
|
||||
Tracef("Shoot : \264\331\270\245 target\277\241 \270\302\276\322\275\300\264\317\264\331 : %d, %d\n", dwSkillIndex, dwVID);
|
||||
|
||||
CPythonNetworkStream& rkStream=CPythonNetworkStream::Instance();
|
||||
rkStream.SendAttackPacket(dwSkillIndex, dwVID);
|
||||
|
||||
CPythonCharacterManager& rkChrMgr = CPythonCharacterManager::Instance();
|
||||
CInstanceBase * pInstance = rkChrMgr.GetInstancePtr(dwVID);
|
||||
if (pInstance)
|
||||
{
|
||||
pInstance->GetGraphicThingInstanceRef().OnShootDamage();
|
||||
}
|
||||
}
|
||||
void CPythonPlayerEventHandler::CNormalBowAttack_FlyEventHandler_AutoClear::OnExplodingAtTarget(DWORD dwSkillIndex)
|
||||
{
|
||||
// Tracef("Shoot : 원하는 target에 맞았습니다 : %d, %d\n", dwSkillIndex, m_pInstTarget->GetVirtualID());
|
||||
// CPythonNetworkStream& rkStream=CPythonNetworkStream::Instance();
|
||||
// rkStream.SendAttackPacket(dwSkillIndex, m_pInstTarget->GetVirtualID());
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include "../GameLib/ActorInstance.h"
|
||||
#include "../GameLib/FlyHandler.h"
|
||||
|
||||
#include "PythonNetworkStream.h"
|
||||
#include "InstanceBase.h"
|
||||
|
||||
class CPythonPlayerEventHandler : public CActorInstance::IEventHandler
|
||||
{
|
||||
public:
|
||||
static CPythonPlayerEventHandler& GetSingleton();
|
||||
|
||||
public:
|
||||
virtual ~CPythonPlayerEventHandler();
|
||||
|
||||
virtual void OnSyncing(const SState& c_rkState);
|
||||
virtual void OnWaiting(const SState& c_rkState);
|
||||
virtual void OnMoving(const SState& c_rkState);
|
||||
virtual void OnMove(const SState& c_rkState);
|
||||
virtual void OnStop(const SState& c_rkState);
|
||||
virtual void OnWarp(const SState& c_rkState);
|
||||
virtual void OnClearAffects();
|
||||
virtual void OnSetAffect(UINT uAffect);
|
||||
virtual void OnResetAffect(UINT uAffect);
|
||||
virtual void OnAttack(const SState& c_rkState, WORD wMotionIndex);
|
||||
virtual void OnUseSkill(const SState& c_rkState, UINT uMotSkill, UINT uArg);
|
||||
virtual void OnUpdate();
|
||||
virtual void OnChangeShape();
|
||||
virtual void OnHit(UINT uSkill, CActorInstance& rkActorVictim, BOOL isSendPacket);
|
||||
|
||||
void FlushVictimList();
|
||||
|
||||
protected:
|
||||
CPythonPlayerEventHandler();
|
||||
|
||||
protected:
|
||||
struct SVictim
|
||||
{
|
||||
DWORD m_dwVID;
|
||||
long m_lPixelX;
|
||||
long m_lPixelY;
|
||||
};
|
||||
|
||||
protected:
|
||||
std::vector<SVictim> m_kVctkVictim;
|
||||
|
||||
DWORD m_dwPrevComboIndex;
|
||||
DWORD m_dwNextWaitingNotifyTime;
|
||||
DWORD m_dwNextMovingNotifyTime;
|
||||
TPixelPosition m_kPPosPrevWaiting;
|
||||
|
||||
private:
|
||||
class CNormalBowAttack_FlyEventHandler_AutoClear : public IFlyEventHandler
|
||||
{
|
||||
public:
|
||||
CNormalBowAttack_FlyEventHandler_AutoClear() {}
|
||||
virtual ~CNormalBowAttack_FlyEventHandler_AutoClear() {}
|
||||
|
||||
void Set(CPythonPlayerEventHandler * pParent, CInstanceBase * pInstMain, CInstanceBase * pInstTarget);
|
||||
void SetTarget(CInstanceBase* pInstTarget);
|
||||
|
||||
virtual void OnSetFlyTarget();
|
||||
virtual void OnShoot(DWORD dwSkillIndex);
|
||||
|
||||
virtual void OnNoTarget() { /*Tracenf("Shoot : target이 없습니다.");*/ }
|
||||
virtual void OnExplodingOutOfRange() { /*Tracenf("Shoot : 사정거리가 끝났습니다.");*/ }
|
||||
virtual void OnExplodingAtBackground() { /*Tracenf("Shoot : 배경에 맞았습니다.");*/ }
|
||||
virtual void OnExplodingAtAnotherTarget(DWORD dwSkillIndex, DWORD dwVID);
|
||||
virtual void OnExplodingAtTarget(DWORD dwSkillIndex);
|
||||
|
||||
protected:
|
||||
CPythonPlayerEventHandler * m_pParent;
|
||||
CInstanceBase * m_pInstMain;
|
||||
CInstanceBase * m_pInstTarget;
|
||||
} m_NormalBowAttack_FlyEventHandler_AutoClear;
|
||||
|
||||
public:
|
||||
IFlyEventHandler * GetNormalBowAttackFlyEventHandler(CInstanceBase* pInstMain, CInstanceBase* pInstTarget)
|
||||
{
|
||||
m_NormalBowAttack_FlyEventHandler_AutoClear.Set(this,pInstMain,pInstTarget);
|
||||
return &m_NormalBowAttack_FlyEventHandler_AutoClear;
|
||||
}
|
||||
|
||||
void ChangeFlyTarget(CInstanceBase* pInstTarget)
|
||||
{
|
||||
m_NormalBowAttack_FlyEventHandler_AutoClear.SetTarget(pInstTarget);
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,134 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PythonPlayer.h"
|
||||
|
||||
#include "InstanceBase.h"
|
||||
|
||||
void CPythonPlayer::SetAttackKeyState(bool isPress)
|
||||
{
|
||||
if (isPress)
|
||||
{
|
||||
CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
|
||||
if (pkInstMain)
|
||||
if (pkInstMain->IsFishingMode())
|
||||
{
|
||||
NEW_Fishing();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_isAtkKey=isPress;
|
||||
}
|
||||
|
||||
void CPythonPlayer::NEW_SetSingleDIKKeyState(int eDIKKey, bool isPress)
|
||||
{
|
||||
if (NEW_CancelFishing())
|
||||
return;
|
||||
|
||||
switch (eDIKKey)
|
||||
{
|
||||
case DIK_UP:
|
||||
NEW_SetSingleDirKeyState(DIR_UP, isPress);
|
||||
break;
|
||||
case DIK_DOWN:
|
||||
NEW_SetSingleDirKeyState(DIR_DOWN, isPress);
|
||||
break;
|
||||
case DIK_LEFT:
|
||||
NEW_SetSingleDirKeyState(DIR_LEFT, isPress);
|
||||
break;
|
||||
case DIK_RIGHT:
|
||||
NEW_SetSingleDirKeyState(DIR_RIGHT, isPress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CPythonPlayer::NEW_SetSingleDirKeyState(int eDirKey, bool isPress)
|
||||
{
|
||||
switch (eDirKey)
|
||||
{
|
||||
case DIR_UP:
|
||||
m_isUp=isPress;
|
||||
break;
|
||||
case DIR_DOWN:
|
||||
m_isDown=isPress;
|
||||
break;
|
||||
case DIR_LEFT:
|
||||
m_isLeft=isPress;
|
||||
break;
|
||||
case DIR_RIGHT:
|
||||
m_isRight=isPress;
|
||||
break;
|
||||
}
|
||||
|
||||
m_isDirKey=(m_isUp || m_isDown || m_isLeft || m_isRight);
|
||||
|
||||
NEW_SetMultiDirKeyState(m_isLeft, m_isRight, m_isUp, m_isDown);
|
||||
}
|
||||
|
||||
void CPythonPlayer::NEW_SetMultiDirKeyState(bool isLeft, bool isRight, bool isUp, bool isDown)
|
||||
{
|
||||
if (!__CanMove())
|
||||
return;
|
||||
|
||||
bool isAny=(isLeft || isRight || isUp || isDown);
|
||||
|
||||
if (isAny)
|
||||
{
|
||||
float fDirRot=0.0f;
|
||||
NEW_GetMultiKeyDirRotation(isLeft, isRight, isUp, isDown, &fDirRot);
|
||||
|
||||
if (!NEW_MoveToDirection(fDirRot))
|
||||
{
|
||||
Tracen("CPythonPlayer::NEW_SetMultiKeyState - NEW_Move -> ERROR");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NEW_Stop();
|
||||
}
|
||||
}
|
||||
|
||||
float CPythonPlayer::GetDegreeFromDirection(int iUD, int iLR)
|
||||
{
|
||||
switch(iUD)
|
||||
{
|
||||
case KEYBOARD_UD_UP:
|
||||
if (KEYBOARD_LR_LEFT == iLR)
|
||||
{
|
||||
return +45.0f;
|
||||
}
|
||||
else if (KEYBOARD_LR_RIGHT == iLR)
|
||||
{
|
||||
return -45.0f;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
break;
|
||||
|
||||
case KEYBOARD_UD_DOWN:
|
||||
if (KEYBOARD_LR_LEFT == iLR)
|
||||
{
|
||||
return +135.0f;
|
||||
}
|
||||
else if (KEYBOARD_LR_RIGHT == iLR)
|
||||
{
|
||||
return -135.0f;
|
||||
}
|
||||
|
||||
return +180.0f;
|
||||
break;
|
||||
|
||||
case KEYBOARD_UD_NONE:
|
||||
if (KEYBOARD_LR_LEFT == iLR)
|
||||
{
|
||||
return +90.0f;
|
||||
}
|
||||
else if (KEYBOARD_LR_RIGHT == iLR)
|
||||
{
|
||||
return -90.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PythonPlayer.h"
|
||||
#include "PythonApplication.h"
|
||||
|
||||
#include "../EterLib/Camera.h"
|
||||
|
||||
void CPythonPlayer::NEW_SetMouseMoveState(int eMBS)
|
||||
{
|
||||
if (MBS_PRESS==eMBS)
|
||||
{
|
||||
NEW_MoveToMouseScreenDirection();
|
||||
|
||||
m_isDirMov=true;
|
||||
}
|
||||
else if (MBS_CLICK==eMBS)
|
||||
{
|
||||
NEW_Stop();
|
||||
|
||||
m_isDirMov=false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CPythonPlayer::NEW_MoveToMouseScreenDirection()
|
||||
{
|
||||
UI::CWindowManager& rkWndMgr=UI::CWindowManager::Instance();
|
||||
|
||||
long lMouseX;
|
||||
long lMouseY;
|
||||
rkWndMgr.GetMousePosition(lMouseX, lMouseY);
|
||||
|
||||
long lScrWidth = rkWndMgr.GetScreenWidth();
|
||||
long lScrHeight = rkWndMgr.GetScreenHeight();
|
||||
float fMouseX=lMouseX/float(lScrWidth);
|
||||
float fMouseY=lMouseY/float(lScrHeight);
|
||||
|
||||
float fDirRot;
|
||||
NEW_GetMouseDirRotation(fMouseX, fMouseY, &fDirRot);
|
||||
|
||||
return NEW_MoveToDirection(fDirRot);
|
||||
}
|
||||
|
||||
void CPythonPlayer::NEW_SetMouseCameraState(int eMBS)
|
||||
{
|
||||
CPythonApplication & rkApp = CPythonApplication::Instance();
|
||||
CPythonBackground & rkBG = CPythonBackground::Instance();
|
||||
CCamera* pkCmrCur=CCameraManager::Instance().GetCurrentCamera();
|
||||
|
||||
if (pkCmrCur)
|
||||
{
|
||||
if (MBS_PRESS==eMBS)
|
||||
{
|
||||
UI::CWindowManager& rkWndMgr=UI::CWindowManager::Instance();
|
||||
|
||||
long lMouseX;
|
||||
long lMouseY;
|
||||
rkWndMgr.GetMousePosition(lMouseX, lMouseY);
|
||||
|
||||
pkCmrCur->BeginDrag(lMouseX, lMouseY);
|
||||
|
||||
if ( !rkBG.IsMapReady() )
|
||||
return;
|
||||
|
||||
rkApp.SetCursorNum(CPythonApplication::CAMERA_ROTATE);
|
||||
if ( CPythonApplication::CURSOR_MODE_HARDWARE == rkApp.GetCursorMode())
|
||||
rkApp.SetCursorVisible(FALSE, true);
|
||||
|
||||
}
|
||||
else if (MBS_CLICK==eMBS)
|
||||
{
|
||||
bool isCameraDrag=pkCmrCur->EndDrag();
|
||||
|
||||
if ( !rkBG.IsMapReady() )
|
||||
return;
|
||||
|
||||
rkApp.SetCursorNum(CPythonApplication::NORMAL);
|
||||
if ( CPythonApplication::CURSOR_MODE_HARDWARE == rkApp.GetCursorMode())
|
||||
rkApp.SetCursorVisible(TRUE);
|
||||
|
||||
if (!isCameraDrag)
|
||||
{
|
||||
__ChangeTargetToPickedInstance();
|
||||
|
||||
CInstanceBase * pkInstPicked;
|
||||
if (__GetPickedActorPtr(&pkInstPicked))
|
||||
{
|
||||
OpenCharacterMenu(pkInstPicked->GetVirtualID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CPythonPlayer::NEW_SetMouseSmartState(int eMBS, bool isAuto)
|
||||
{
|
||||
CInstanceBase* pkInstMain=NEW_GetMainActorPtr();
|
||||
if (!pkInstMain) return;
|
||||
|
||||
// PrivateShop
|
||||
if (IsOpenPrivateShop())
|
||||
{
|
||||
// ShopPacket 이 오기전 잠깐 동안
|
||||
m_isSmtMov=false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Emotion
|
||||
if (__IsProcessingEmotion())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// AFFECT_STUN 처리
|
||||
if (pkInstMain->IsSleep())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (MBS_PRESS==eMBS)
|
||||
{
|
||||
m_isSmtMov=true;
|
||||
|
||||
__OnPressSmart(*pkInstMain, isAuto);
|
||||
}
|
||||
else if (MBS_CLICK==eMBS)
|
||||
{
|
||||
m_isSmtMov=false;
|
||||
|
||||
__OnClickSmart(*pkInstMain, isAuto);
|
||||
}
|
||||
}
|
||||
|
||||
void CPythonPlayer::__OnPressSmart(CInstanceBase& rkInstMain, bool isAuto)
|
||||
{
|
||||
DWORD dwPickedItemID;
|
||||
DWORD dwPickedActorID;
|
||||
TPixelPosition kPPosPickedGround;
|
||||
|
||||
bool isPickedItemID=__GetPickedItemID(&dwPickedItemID);
|
||||
bool isPickedActorID=__GetPickedActorID(&dwPickedActorID);
|
||||
bool isPickedGroundPos=__GetPickedGroundPos(&kPPosPickedGround);
|
||||
|
||||
if (isPickedItemID)
|
||||
{
|
||||
__OnPressItem(rkInstMain, dwPickedItemID);
|
||||
}
|
||||
else if (isPickedActorID && dwPickedActorID != GetMainCharacterIndex())
|
||||
{
|
||||
__OnPressActor(rkInstMain, dwPickedActorID, isAuto);
|
||||
}
|
||||
else if (isPickedGroundPos)
|
||||
{
|
||||
__OnPressGround(rkInstMain, kPPosPickedGround);
|
||||
}
|
||||
else
|
||||
{
|
||||
__OnPressScreen(rkInstMain);
|
||||
}
|
||||
}
|
||||
|
||||
void CPythonPlayer::__OnClickSmart(CInstanceBase& rkInstMain, bool isAuto)
|
||||
{
|
||||
DWORD dwPickedItemID;
|
||||
DWORD dwPickedActorID;
|
||||
TPixelPosition kPPosPickedGround;
|
||||
if (__GetPickedItemID(&dwPickedItemID))
|
||||
{
|
||||
__OnClickItem(rkInstMain, dwPickedItemID);
|
||||
}
|
||||
else if (__GetPickedActorID(&dwPickedActorID))
|
||||
{
|
||||
__OnClickActor(rkInstMain, dwPickedActorID, isAuto);
|
||||
}
|
||||
else if (__GetPickedGroundPos(&kPPosPickedGround))
|
||||
{
|
||||
__OnClickGround(rkInstMain, kPPosPickedGround);
|
||||
}
|
||||
else
|
||||
{
|
||||
rkInstMain.NEW_Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void CPythonPlayer::__ShowPickedEffect(const TPixelPosition& c_rkPPosPickedGround)
|
||||
{
|
||||
#ifdef __MOVIE_MODE__
|
||||
CInstanceBase* pkInstMain=NEW_GetMainActorPtr();
|
||||
if (!pkInstMain) return;
|
||||
|
||||
if (pkInstMain->IsMovieMode())
|
||||
return;
|
||||
#endif
|
||||
NEW_ShowEffect(EFFECT_PICK, c_rkPPosPickedGround);
|
||||
}
|
||||
|
||||
bool CPythonPlayer::NEW_SetMouseFunc(int eMBT, int eMBF)
|
||||
{
|
||||
if (eMBT>=MBT_NUM)
|
||||
return false;
|
||||
|
||||
m_aeMBFButton[eMBT]=eMBF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CPythonPlayer::NEW_GetMouseFunc(int eMBT)
|
||||
{
|
||||
if (eMBT>=MBT_NUM)
|
||||
return false;
|
||||
|
||||
return m_aeMBFButton[eMBT];
|
||||
}
|
||||
|
||||
void CPythonPlayer::SetQuickCameraMode(bool isEnable)
|
||||
{
|
||||
if (isEnable)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
NEW_SetMouseCameraState(MBS_CLICK);
|
||||
}
|
||||
}
|
||||
|
||||
bool CPythonPlayer::NEW_SetMouseState(int eMBT, int eMBS)
|
||||
{
|
||||
if (eMBT>=MBT_NUM)
|
||||
return false;
|
||||
|
||||
int eMBF=m_aeMBFButton[eMBT];
|
||||
switch (eMBF)
|
||||
{
|
||||
case MBF_MOVE:
|
||||
if (__CanMove())
|
||||
NEW_SetMouseMoveState(eMBS);
|
||||
break;
|
||||
case MBF_SMART:
|
||||
if (CPythonApplication::Instance().IsPressed(DIK_LCONTROL) || CPythonApplication::Instance().IsPressed(DIK_RCONTROL))
|
||||
{
|
||||
NEW_Attack();
|
||||
}
|
||||
else
|
||||
{
|
||||
NEW_SetMouseSmartState(eMBS, false);
|
||||
}
|
||||
break;
|
||||
case MBF_CAMERA:
|
||||
NEW_SetMouseCameraState(eMBS);
|
||||
break;
|
||||
case MBF_AUTO:
|
||||
NEW_SetMouseSmartState(eMBS, true);
|
||||
break;
|
||||
case MBF_ATTACK:
|
||||
NEW_Attack();
|
||||
break;
|
||||
case MBF_SKILL:
|
||||
if (CPythonApplication::Instance().IsPressed(DIK_LCONTROL))
|
||||
{
|
||||
NEW_SetMouseCameraState(eMBS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MBS_PRESS == eMBS)
|
||||
{
|
||||
__ChangeTargetToPickedInstance();
|
||||
__UseCurrentSkill();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPythonPlayer::NEW_SetMouseMiddleButtonState(int eMBState)
|
||||
{
|
||||
NEW_SetMouseCameraState(eMBState);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CPythonPlayer::NEW_RefreshMouseWalkingDirection()
|
||||
{
|
||||
CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
|
||||
if (!pkInstMain) return;
|
||||
|
||||
switch (m_eReservedMode)
|
||||
{
|
||||
case MODE_CLICK_ITEM:
|
||||
{
|
||||
CPythonItem& rkIT=CPythonItem::Instance();
|
||||
|
||||
TPixelPosition kPPosPickedItem;
|
||||
if (rkIT.GetGroundItemPosition(m_dwIIDReserved, &kPPosPickedItem))
|
||||
{
|
||||
if (pkInstMain->NEW_GetDistanceFromDestPixelPosition(kPPosPickedItem)<20.0f)
|
||||
{
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
|
||||
TPixelPosition kPPosCur;
|
||||
pkInstMain->NEW_GetPixelPosition(&kPPosCur);
|
||||
|
||||
float fCurRot=pkInstMain->GetRotation();
|
||||
rkNetStream.SendCharacterStatePacket(kPPosCur, fCurRot, CInstanceBase::FUNC_WAIT, 0);
|
||||
SendClickItemPacket(m_dwIIDReserved);
|
||||
|
||||
pkInstMain->NEW_Stop();
|
||||
|
||||
__ClearReservedAction();
|
||||
}
|
||||
else
|
||||
{
|
||||
pkInstMain->NEW_MoveToDestPixelPositionDirection(kPPosPickedItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__ClearReservedAction();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MODE_CLICK_ACTOR:
|
||||
{
|
||||
__ReserveProcess_ClickActor();
|
||||
break;
|
||||
}
|
||||
|
||||
case MODE_CLICK_POSITION:
|
||||
{
|
||||
if (!pkInstMain->isLock())
|
||||
if (NEW_IsEmptyReservedDelayTime(CPythonApplication::Instance().GetGlobalElapsedTime()))
|
||||
{
|
||||
pkInstMain->NEW_MoveToDestPixelPositionDirection(m_kPPosReserved);
|
||||
__ClearReservedAction();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MODE_USE_SKILL:
|
||||
{
|
||||
CInstanceBase* pkInstReserved=NEW_FindActorPtr(m_dwVIDReserved);
|
||||
if (pkInstReserved)
|
||||
{
|
||||
float fDistance=pkInstMain->GetDistance(pkInstReserved);
|
||||
|
||||
// #0000806: [M2EU] 수룡에게 무사(나한군) 탄환격 스킬 사용 안됨
|
||||
extern bool IS_HUGE_RACE(unsigned int vnum);
|
||||
if (IS_HUGE_RACE(pkInstReserved->GetRace())) // 거대 종족은 근접을 못함
|
||||
{
|
||||
fDistance -= 200.0f; // TEMP: 일단 하드 코딩 처리. 정석적으로는 바운드 스피어를 고려해야함
|
||||
}
|
||||
|
||||
if (fDistance < float(m_dwSkillRangeReserved))
|
||||
{
|
||||
// 접근 도중 Target 이 바뀌어 있을 수도 있다 - [levites]
|
||||
SetTarget(m_dwVIDReserved);
|
||||
if (__UseSkill(m_dwSkillSlotIndexReserved))
|
||||
__ClearReservedAction();
|
||||
}
|
||||
else
|
||||
{
|
||||
pkInstMain->NEW_MoveToDestInstanceDirection(*pkInstReserved);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__ClearReservedAction();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_isSmtMov)
|
||||
__OnPressSmart(*pkInstMain, false);
|
||||
|
||||
if (m_isDirMov)
|
||||
NEW_MoveToMouseScreenDirection();
|
||||
|
||||
if (m_isDirKey)
|
||||
NEW_SetMultiDirKeyState(m_isLeft, m_isRight, m_isUp, m_isDown);
|
||||
|
||||
if (m_isAtkKey)
|
||||
NEW_Attack();
|
||||
|
||||
m_iComboOld=pkInstMain->GetComboIndex();
|
||||
}
|
||||
|
||||
BOOL CPythonPlayer::__IsRightButtonSkillMode()
|
||||
{
|
||||
return MBF_SKILL == m_aeMBFButton[MBT_RIGHT];
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,991 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PythonPlayer.h"
|
||||
#include "PythonTextTail.h"
|
||||
#include "PythonNetworkStream.h"
|
||||
#include "InstanceBase.h"
|
||||
#include "PythonChat.h"
|
||||
#include "PythonGuild.h"
|
||||
#include "../GameLib/ItemManager.h"
|
||||
|
||||
void CPythonPlayer::ClearAffects()
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "ClearAffects", Py_BuildValue("()"));
|
||||
}
|
||||
|
||||
void CPythonPlayer::SetAffect(UINT uAffect)
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "SetAffect", Py_BuildValue("(i)", uAffect));
|
||||
|
||||
/////
|
||||
|
||||
DWORD dwSkillIndex;
|
||||
if (!AffectIndexToSkillIndex(uAffect, &dwSkillIndex))
|
||||
return;
|
||||
|
||||
CPythonSkill::TSkillData * pSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
|
||||
return;
|
||||
|
||||
if (!pSkillData->IsToggleSkill())
|
||||
return;
|
||||
|
||||
DWORD dwSkillSlotIndex;
|
||||
if (!GetSkillSlotIndex(dwSkillIndex, &dwSkillSlotIndex))
|
||||
return;
|
||||
|
||||
__ActivateSkillSlot(dwSkillSlotIndex);
|
||||
}
|
||||
|
||||
void CPythonPlayer::ResetAffect(UINT uAffect)
|
||||
{
|
||||
// 2004.07.17.myevan.스킬 아닌 이펙트가 안 사라지는 문제
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "ResetAffect", Py_BuildValue("(i)", uAffect));
|
||||
|
||||
DWORD dwSkillIndex;
|
||||
if (!AffectIndexToSkillIndex(uAffect, &dwSkillIndex))
|
||||
return;
|
||||
|
||||
CPythonSkill::TSkillData * pSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
|
||||
return;
|
||||
|
||||
if (!pSkillData->IsToggleSkill())
|
||||
return;
|
||||
|
||||
DWORD dwSkillSlotIndex;
|
||||
if (!GetSkillSlotIndex(dwSkillIndex, &dwSkillSlotIndex))
|
||||
return;
|
||||
|
||||
__DeactivateSkillSlot(dwSkillSlotIndex);
|
||||
}
|
||||
|
||||
bool CPythonPlayer::FindSkillSlotIndexBySkillIndex(DWORD dwSkillIndex, DWORD * pdwSkillSlotIndex)
|
||||
{
|
||||
for (int i = 0; i < SKILL_MAX_NUM; ++i)
|
||||
{
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[i];
|
||||
if (dwSkillIndex == rkSkillInst.dwIndex)
|
||||
{
|
||||
*pdwSkillSlotIndex = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPythonPlayer::ChangeCurrentSkillNumberOnly(DWORD dwSlotIndex)
|
||||
{
|
||||
if (dwSlotIndex >= SKILL_MAX_NUM)
|
||||
return;
|
||||
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];
|
||||
|
||||
CPythonSkill::TSkillData * pSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
|
||||
return;
|
||||
|
||||
if (!pSkillData->IsCanUseSkill())
|
||||
return;
|
||||
|
||||
if (!__IsRightButtonSkillMode())
|
||||
{
|
||||
if (!__IsTarget())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_TARGET"));
|
||||
return;
|
||||
}
|
||||
|
||||
ClickSkillSlot(dwSlotIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dwcurSkillSlotIndex = dwSlotIndex;
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "ChangeCurrentSkill", Py_BuildValue("(i)", dwSlotIndex));
|
||||
}
|
||||
}
|
||||
|
||||
void CPythonPlayer::ClickSkillSlot(DWORD dwSlotIndex)
|
||||
{
|
||||
if (dwSlotIndex >= SKILL_MAX_NUM)
|
||||
return;
|
||||
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];
|
||||
|
||||
CPythonSkill::TSkillData * pSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
|
||||
return;
|
||||
|
||||
if (CPythonSkill::SKILL_TYPE_GUILD == pSkillData->byType)
|
||||
{
|
||||
UseGuildSkill(dwSlotIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pSkillData->IsCanUseSkill())
|
||||
return;
|
||||
|
||||
if (pSkillData->IsStandingSkill())
|
||||
{
|
||||
if (pSkillData->IsToggleSkill())
|
||||
{
|
||||
if (IsSkillActive(dwSlotIndex))
|
||||
{
|
||||
CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
|
||||
if (!pkInstMain)
|
||||
return;
|
||||
if (pkInstMain->IsUsingSkill())
|
||||
return;
|
||||
|
||||
CPythonNetworkStream::Instance().SendUseSkillPacket(rkSkillInst.dwIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
__UseSkill(dwSlotIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dwcurSkillSlotIndex == dwSlotIndex)
|
||||
{
|
||||
__UseSkill(m_dwcurSkillSlotIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!__IsRightButtonSkillMode())
|
||||
{
|
||||
__UseSkill(dwSlotIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dwcurSkillSlotIndex = dwSlotIndex;
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "ChangeCurrentSkill", Py_BuildValue("(i)", dwSlotIndex));
|
||||
}
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CheckSkillUsable(DWORD dwSlotIndex)
|
||||
{
|
||||
CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
|
||||
if (!pkInstMain)
|
||||
return false;
|
||||
|
||||
if (dwSlotIndex >= SKILL_MAX_NUM)
|
||||
return false;
|
||||
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];
|
||||
|
||||
CPythonSkill::TSkillData * pSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
|
||||
return false;
|
||||
|
||||
if (pkInstMain->IsMountingHorse())
|
||||
{
|
||||
if (!pSkillData->IsHorseSkill())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_HORSE_SKILL"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSkillData->IsHorseSkill())
|
||||
{
|
||||
if (!pkInstMain->IsMountingHorse())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "HAVE_TO_RIDE"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 2004.07.26.levites - 안전지대에서 공격 못하도록 수정
|
||||
// NOTE : 공격 스킬은 안전지대에서 사용하지 못합니다 - [levites]
|
||||
if (pSkillData->IsAttackSkill())
|
||||
{
|
||||
if (pkInstMain->IsInSafe())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "IN_SAFE"));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE : 패시브 스킬은 사용하지 못합니다 - [levites]
|
||||
if (!pSkillData->IsCanUseSkill())
|
||||
return false;
|
||||
// if (CPythonSkill::SKILL_TYPE_PASSIVE == pSkillData->byType)
|
||||
// return false;
|
||||
|
||||
// NOTE : [Only Assassin] 빈병이 있는지 체크 합니다.
|
||||
if (pSkillData->IsNeedEmptyBottle())
|
||||
{
|
||||
if (!__HasItem(27995))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_EMPTY_BOTTLE"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE : [Only Assassin] 독병이 있는지 체크 합니다.
|
||||
if (pSkillData->IsNeedPoisonBottle())
|
||||
{
|
||||
if (!__HasItem(27996))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_POISON_BOTTLE"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE : 낚시 중일때는 스킬을 사용하지 못합니다.
|
||||
if (pkInstMain->IsFishingMode())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "REMOVE_FISHING_ROD"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE : 레벨 체크
|
||||
if (m_sysIsLevelLimit)
|
||||
{
|
||||
if (rkSkillInst.iLevel <= 0)
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_YET_LEARN"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE : 들고 있는 무기 체크
|
||||
if (!pSkillData->CanUseWeaponType(pkInstMain->GetWeaponType()))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_MATCHABLE_WEAPON"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pSkillData->IsHorseSkill()) // HORSE 스킬 중에 화살을 쓰지 않는 스킬이 있기 때문에
|
||||
{
|
||||
if (__CheckShortArrow(rkSkillInst, *pSkillData))
|
||||
return false;
|
||||
|
||||
// NOTE : 활이 필요할 경우 화살 개수 체크
|
||||
if (pSkillData->IsNeedBow())
|
||||
{
|
||||
if (!__HasEnoughArrow())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (__CheckDashAffect(*pkInstMain))
|
||||
{
|
||||
if (!pSkillData->IsChargeSkill())
|
||||
{
|
||||
if (__CheckRestSkillCoolTime(dwSlotIndex))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "WAIT_COOLTIME"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (__CheckRestSkillCoolTime(dwSlotIndex))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "WAIT_COOLTIME"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__CheckShortLife(rkSkillInst, *pSkillData))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_ENOUGH_HP"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__CheckShortMana(rkSkillInst, *pSkillData))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_ENOUGH_SP"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CheckShortArrow(TSkillInstance & rkSkillInst, CPythonSkill::TSkillData& rkSkillData)
|
||||
{
|
||||
if (!rkSkillData.IsNeedBow())
|
||||
return false;
|
||||
|
||||
if (__HasEnoughArrow())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CheckShortMana(TSkillInstance& rkSkillInst, CPythonSkill::TSkillData& rkSkillData)
|
||||
{
|
||||
extern const DWORD c_iSkillIndex_Summon;
|
||||
if (c_iSkillIndex_Summon == rkSkillInst.dwIndex)
|
||||
return false;
|
||||
|
||||
int iNeedSP = rkSkillData.GetNeedSP(rkSkillInst.fcurEfficientPercentage);
|
||||
int icurSP = GetStatus(POINT_SP);
|
||||
|
||||
// NOTE : ToggleSkill 이 아닌데 소모 SP 가 0 이다.
|
||||
if (!rkSkillData.IsToggleSkill())
|
||||
{
|
||||
if (iNeedSP == 0)
|
||||
{
|
||||
CPythonChat::Instance().AppendChat(CHAT_TYPE_INFO, "!!! Find strange game data. Please reinstall metin2.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (rkSkillData.CanUseIfNotEnough())
|
||||
{
|
||||
if (icurSP <= 0)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (-1 != iNeedSP)
|
||||
if (iNeedSP > icurSP)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CheckShortLife(TSkillInstance& rkSkillInst, CPythonSkill::TSkillData& rkSkillData)
|
||||
{
|
||||
if (!rkSkillData.IsUseHPSkill())
|
||||
return false;
|
||||
|
||||
DWORD dwNeedHP = rkSkillData.GetNeedSP(rkSkillInst.fcurEfficientPercentage);
|
||||
if (dwNeedHP <= GetStatus(POINT_HP))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CheckRestSkillCoolTime(DWORD dwSlotIndex)
|
||||
{
|
||||
if (!m_sysIsCoolTime)
|
||||
return false;
|
||||
|
||||
if (dwSlotIndex >= SKILL_MAX_NUM)
|
||||
return false;
|
||||
|
||||
float fElapsedTime = CTimer::Instance().GetCurrentSecond() - m_playerStatus.aSkill[dwSlotIndex].fLastUsedTime;
|
||||
if (fElapsedTime >= m_playerStatus.aSkill[dwSlotIndex].fCoolTime)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CheckDashAffect(CInstanceBase& rkInstMain)
|
||||
{
|
||||
return rkInstMain.IsAffect(CInstanceBase::AFFECT_DASH);
|
||||
}
|
||||
|
||||
void CPythonPlayer::__UseCurrentSkill()
|
||||
{
|
||||
__UseSkill(m_dwcurSkillSlotIndex);
|
||||
}
|
||||
|
||||
DWORD CPythonPlayer::__GetSkillTargetRange(CPythonSkill::TSkillData& rkSkillData)
|
||||
{
|
||||
return rkSkillData.GetTargetRange() + GetStatus(POINT_BOW_DISTANCE)*100;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__ProcessEnemySkillTargetRange(CInstanceBase& rkInstMain, CInstanceBase& rkInstTarget, CPythonSkill::TSkillData& rkSkillData, DWORD dwSkillSlotIndex)
|
||||
{
|
||||
DWORD dwSkillTargetRange=__GetSkillTargetRange(rkSkillData);
|
||||
float fSkillTargetRange = float(dwSkillTargetRange);
|
||||
if (fSkillTargetRange <= 0.0f)
|
||||
return true;
|
||||
|
||||
// #0000806: [M2EU] 수룡에게 무사(나한군) 탄환격 스킬 사용 안됨
|
||||
float fTargetDistance = rkInstMain.GetDistance(&rkInstTarget);
|
||||
|
||||
extern bool IS_HUGE_RACE(unsigned int vnum);
|
||||
if (IS_HUGE_RACE(rkInstTarget.GetRace()))
|
||||
{
|
||||
fTargetDistance -= 200.0f; // TEMP: 일단 하드 코딩 처리. 정석적으로는 바운드 스피어를 고려해야함
|
||||
}
|
||||
|
||||
if (fTargetDistance >= fSkillTargetRange)
|
||||
{
|
||||
if (rkSkillData.IsChargeSkill())
|
||||
{
|
||||
if (!__IsReservedUseSkill(dwSkillSlotIndex))
|
||||
__SendUseSkill(dwSkillSlotIndex, 0);
|
||||
}
|
||||
|
||||
__ReserveUseSkill(rkInstTarget.GetVirtualID(), dwSkillSlotIndex, dwSkillTargetRange);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2004.07.05.myevan. 궁신탄영 사용시 맵에 끼임. 사용하기전 갈수 있는곳 체크
|
||||
TPixelPosition kPPosTarget;
|
||||
rkInstTarget.NEW_GetPixelPosition(&kPPosTarget);
|
||||
|
||||
IBackground& rkBG=IBackground::Instance();
|
||||
if (rkBG.IsBlock(kPPosTarget.x, kPPosTarget.y))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_APPROACH"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CanUseSkill()
|
||||
{
|
||||
CInstanceBase* pkInstMain=NEW_GetMainActorPtr();
|
||||
if (!pkInstMain)
|
||||
return false;
|
||||
|
||||
if (IsObserverMode())
|
||||
return false;
|
||||
|
||||
// Fix me
|
||||
// 뉴마운트. 승마스킬레벨 20 미만인 경우, 고급 마운트를 타고 승마 관련 스킬 못 쓰도록 못하도록 하드 코딩...
|
||||
// 나중에 시간 나면 can use skill 체크를 서버에서 해주자...
|
||||
if (pkInstMain->IsMountingHorse() && (GetSkillGrade(109) < 1 && GetSkillLevel(109) < 20))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return pkInstMain->CanUseSkill();
|
||||
}
|
||||
|
||||
|
||||
bool CPythonPlayer::__UseSkill(DWORD dwSlotIndex)
|
||||
{
|
||||
// PrivateShop
|
||||
if (IsOpenPrivateShop())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!__CanUseSkill())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dwSlotIndex >= SKILL_MAX_NUM)
|
||||
{
|
||||
Tracenf("CPythonPlayer::__UseSkill(dwSlotIndex=%d) It's not available skill slot number", dwSlotIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];
|
||||
|
||||
if (__CheckSpecialSkill(rkSkillInst.dwIndex))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CPythonSkill::TSkillData * pSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pSkillData))
|
||||
{
|
||||
Tracenf("CPythonPlayer::__UseSkill(dwSlotIndex=%d) There is no skill data", dwSlotIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pSkillData->IsToggleSkill())
|
||||
{
|
||||
if (IsSkillActive(dwSlotIndex))
|
||||
{
|
||||
CPythonNetworkStream::Instance().SendUseSkillPacket(rkSkillInst.dwIndex, dwSlotIndex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!__CheckSkillUsable(dwSlotIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
|
||||
if (!pkInstMain)
|
||||
{
|
||||
Tracenf("CPythonPlayer::__UseSkill(dwSlotIndex=%d) There is no main player", dwSlotIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkInstMain->IsUsingSkill())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CInstanceBase * pkInstTarget = NULL;
|
||||
|
||||
// NOTE : 타겟이 필요한 경우
|
||||
if (pSkillData->IsNeedTarget() ||
|
||||
pSkillData->CanChangeDirection() ||
|
||||
pSkillData->IsAutoSearchTarget())
|
||||
{
|
||||
if (pSkillData->IsNeedCorpse())
|
||||
pkInstTarget=__GetDeadTargetInstancePtr();
|
||||
else
|
||||
pkInstTarget=__GetAliveTargetInstancePtr();
|
||||
|
||||
// 현재 타겟이 없으면..
|
||||
if (!pkInstTarget)
|
||||
{
|
||||
// 업데이트하고..
|
||||
__ChangeTargetToPickedInstance();
|
||||
|
||||
// 다시 얻어낸다.
|
||||
if (pSkillData->IsNeedCorpse())
|
||||
pkInstTarget=__GetDeadTargetInstancePtr();
|
||||
else
|
||||
pkInstTarget=__GetAliveTargetInstancePtr();
|
||||
}
|
||||
|
||||
if (pkInstTarget)
|
||||
{
|
||||
if (pSkillData->IsOnlyForAlliance())
|
||||
{
|
||||
if (pkInstMain == pkInstTarget)
|
||||
{
|
||||
if (!pSkillData->CanUseForMe())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_USE_SELF"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!pkInstMain->IsAttackableInstance(*pkInstTarget) && pkInstTarget->IsPC())
|
||||
{
|
||||
DWORD dwSkillRange = __GetSkillTargetRange(*pSkillData);
|
||||
|
||||
if (dwSkillRange > 0)
|
||||
{
|
||||
float fDistance=pkInstMain->GetDistance(pkInstTarget);
|
||||
if (fDistance>=float(dwSkillRange))
|
||||
{
|
||||
__ReserveUseSkill(pkInstTarget->GetVirtualID(), dwSlotIndex, dwSkillRange);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pSkillData->CanUseForMe())
|
||||
{
|
||||
pkInstTarget = pkInstMain;
|
||||
Tracef(" [ALERT] \265\277\267\341\277\241\260\324 \273\347\277\353\307\317\264\302 \261\342\274\372\300\323\277\241\265\265 \300\373\277\241\260\324 \305\270\260\331\306\303 \265\307\276\356\300\326\276\356\274\255 \300\332\275\305\277\241\260\324\267\316 \300\347\274\263\301\244\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "ONLY_FOR_ALLIANCE"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pkInstTarget->IsInSafe())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_ATTACK_ENEMY_IN_SAFE_AREA"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkInstMain->IsAttackableInstance(*pkInstTarget))
|
||||
{
|
||||
if (!__ProcessEnemySkillTargetRange(*pkInstMain, *pkInstTarget, *pSkillData, dwSlotIndex))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "CANNOT_ATTACK"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pkInstMain->SetFlyTargetInstance(*pkInstTarget);
|
||||
|
||||
if (pkInstMain != pkInstTarget)
|
||||
{
|
||||
if (pkInstMain->IsFlyTargetObject())
|
||||
{
|
||||
pkInstMain->NEW_LookAtFlyTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
pkInstMain->NEW_LookAtDestInstance(*pkInstTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pSkillData->IsAutoSearchTarget())
|
||||
{
|
||||
if (pkInstMain->NEW_GetFrontInstance(&pkInstTarget, 2000.0f))
|
||||
{
|
||||
SetTarget(pkInstTarget->GetVirtualID());
|
||||
if (!__ProcessEnemySkillTargetRange(*pkInstMain, *pkInstTarget, *pSkillData, dwSlotIndex))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_TARGET"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSkillData->CanUseForMe())
|
||||
{
|
||||
pkInstTarget = pkInstMain;
|
||||
pkInstMain->SetFlyTargetInstance(*pkInstMain);
|
||||
Tracef(" [ALERT] \305\270\260\331\300\314 \276\370\276\356\274\255 \307\303\267\271\300\314\276\356\277\241\260\324 \273\347\277\353\307\325\264\317\264\331\n");
|
||||
}
|
||||
else if (pSkillData->IsNeedCorpse())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "ONLY_FOR_CORPSE"));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NEED_TARGET"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pSkillData->CanChangeDirection())
|
||||
{
|
||||
DWORD dwPickedActorID;
|
||||
TPixelPosition kPPosPickedGround;
|
||||
|
||||
if (pkInstTarget && pkInstTarget!=pkInstMain)
|
||||
{
|
||||
pkInstMain->NEW_LookAtDestInstance(*pkInstTarget);
|
||||
}
|
||||
else if (__GetPickedActorID(&dwPickedActorID))
|
||||
{
|
||||
CInstanceBase* pkInstVictim=NEW_FindActorPtr(dwPickedActorID);
|
||||
if (pkInstVictim)
|
||||
pkInstMain->NEW_LookAtDestInstance(*pkInstVictim);
|
||||
}
|
||||
else if (__GetPickedGroundPos(&kPPosPickedGround))
|
||||
{
|
||||
pkInstMain->NEW_LookAtDestPixelPosition(kPPosPickedGround);
|
||||
}
|
||||
else
|
||||
{
|
||||
Tracenf("CPythonPlayer::__UseSkill(%d) - \310\255\270\351 \261\342\301\330 \271\346\307\342 \274\263\301\244\300\273 \307\330\276\337\307\324", dwSlotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// 관격술 처리
|
||||
DWORD dwTargetMaxCount = pSkillData->GetTargetCount(rkSkillInst.fcurEfficientPercentage);
|
||||
DWORD dwRange = __GetSkillTargetRange(*pSkillData);
|
||||
if (dwTargetMaxCount>0 && pkInstTarget)
|
||||
{
|
||||
DWORD dwTargetCount=1;
|
||||
std::vector<CInstanceBase*> kVct_pkInstTarget;
|
||||
|
||||
if (pSkillData->IsFanRange())
|
||||
{
|
||||
if (pkInstMain->NEW_GetInstanceVectorInFanRange(float(dwRange), *pkInstTarget, &kVct_pkInstTarget))
|
||||
{
|
||||
std::vector<CInstanceBase*>::iterator i;
|
||||
for (i=kVct_pkInstTarget.begin(); i!=kVct_pkInstTarget.end(); ++i)
|
||||
{
|
||||
if (dwTargetCount>=dwTargetMaxCount)
|
||||
break;
|
||||
|
||||
CInstanceBase* pkInstEach=*i;
|
||||
|
||||
if (pkInstTarget!=pkInstEach && !pkInstEach->IsDead())
|
||||
{
|
||||
pkInstMain->AddFlyTargetInstance(*pkInstEach);
|
||||
CPythonNetworkStream::Instance().SendAddFlyTargetingPacket(pkInstEach->GetVirtualID(), pkInstEach->GetGraphicThingInstanceRef().OnGetFlyTargetPosition());
|
||||
|
||||
dwTargetCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pSkillData->IsCircleRange())
|
||||
{
|
||||
if (pkInstMain->NEW_GetInstanceVectorInCircleRange(float(dwRange), &kVct_pkInstTarget))
|
||||
{
|
||||
std::vector<CInstanceBase*>::iterator i;
|
||||
for (i=kVct_pkInstTarget.begin(); i!=kVct_pkInstTarget.end(); ++i)
|
||||
{
|
||||
if (dwTargetCount>=dwTargetMaxCount)
|
||||
break;
|
||||
|
||||
CInstanceBase* pkInstEach=*i;
|
||||
|
||||
if (pkInstTarget!=pkInstEach && !pkInstEach->IsDead())
|
||||
{
|
||||
pkInstMain->AddFlyTargetInstance(*pkInstEach);
|
||||
CPythonNetworkStream::Instance().SendAddFlyTargetingPacket(pkInstEach->GetVirtualID(), pkInstEach->GetGraphicThingInstanceRef().OnGetFlyTargetPosition());
|
||||
|
||||
dwTargetCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dwTargetCount<dwTargetMaxCount)
|
||||
{
|
||||
while (dwTargetCount<dwTargetMaxCount)
|
||||
{
|
||||
TPixelPosition kPPosDst;
|
||||
pkInstMain->NEW_GetRandomPositionInFanRange(*pkInstTarget, &kPPosDst);
|
||||
|
||||
kPPosDst.x=kPPosDst.x;
|
||||
kPPosDst.y=-kPPosDst.y;
|
||||
|
||||
pkInstMain->AddFlyTargetPosition(kPPosDst);
|
||||
CPythonNetworkStream::Instance().SendAddFlyTargetingPacket(0, kPPosDst);
|
||||
|
||||
dwTargetCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////
|
||||
// NOTE : 멀리서 적을 클릭해놓고 스킬을 쓰면 스킬을 쓴뒤 바로 적을 공격하는 문제를 수정하기 위한 코드 - [levites]
|
||||
__ClearReservedAction();
|
||||
/////
|
||||
|
||||
if (!pSkillData->IsNoMotion())
|
||||
{
|
||||
DWORD dwMotionIndex = pSkillData->GetSkillMotionIndex(rkSkillInst.iGrade);
|
||||
DWORD dwLoopCount = pSkillData->GetMotionLoopCount(rkSkillInst.fcurEfficientPercentage);
|
||||
if (!pkInstMain->NEW_UseSkill(rkSkillInst.dwIndex, dwMotionIndex, dwLoopCount, pSkillData->IsMovingSkill() ? true : false))
|
||||
{
|
||||
Tracenf("CPythonPlayer::__UseSkill(%d) - pkInstMain->NEW_UseSkill - ERROR", dwSlotIndex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwTargetVID=pkInstTarget ? pkInstTarget->GetVirtualID() : 0;
|
||||
|
||||
__SendUseSkill(dwSlotIndex, dwTargetVID);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPythonPlayer::__SendUseSkill(DWORD dwSkillSlotIndex, DWORD dwTargetVID)
|
||||
{
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];
|
||||
|
||||
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
|
||||
rkNetStream.SendUseSkillPacket(rkSkillInst.dwIndex, dwTargetVID);
|
||||
|
||||
__RunCoolTime(dwSkillSlotIndex);
|
||||
}
|
||||
|
||||
BYTE CPythonPlayer::__GetSkillType(DWORD dwSkillSlotIndex)
|
||||
{
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];
|
||||
|
||||
CPythonSkill::TSkillData * pkSkillData;
|
||||
CPythonSkill& rkPythonSkill = CPythonSkill::Instance();
|
||||
if (!rkPythonSkill.GetSkillData(rkSkillInst.dwIndex, &pkSkillData))
|
||||
{
|
||||
//TraceError("CPythonPlayer::__GetSkillType(dwSkillSlotIndex=%d) - NOT CHECK", dwSkillSlotIndex);
|
||||
return 0;
|
||||
}
|
||||
return pkSkillData->GetType();
|
||||
}
|
||||
|
||||
void CPythonPlayer::__RunCoolTime(DWORD dwSkillSlotIndex)
|
||||
{
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];
|
||||
|
||||
CPythonSkill::TSkillData * pkSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(rkSkillInst.dwIndex, &pkSkillData))
|
||||
{
|
||||
TraceError("CPythonPlayer::__SendUseSkill(dwSkillSlotIndex=%d) - NOT CHECK", dwSkillSlotIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
CPythonSkill::TSkillData& rkSkillData=*pkSkillData;
|
||||
|
||||
rkSkillInst.fCoolTime = rkSkillData.GetSkillCoolTime(rkSkillInst.fcurEfficientPercentage);
|
||||
rkSkillInst.fLastUsedTime = CTimer::Instance().GetCurrentSecond();
|
||||
|
||||
int iSpd = 100 - GetStatus(POINT_CASTING_SPEED);
|
||||
if (iSpd > 0)
|
||||
iSpd = 100 + iSpd;
|
||||
else if (iSpd < 0)
|
||||
iSpd = 10000 / (100 - iSpd);
|
||||
else
|
||||
iSpd = 100;
|
||||
|
||||
rkSkillInst.fCoolTime = rkSkillInst.fCoolTime * iSpd / 100;
|
||||
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "RunUseSkillEvent", Py_BuildValue("(if)", dwSkillSlotIndex, rkSkillInst.fCoolTime));
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__HasEnoughArrow()
|
||||
{
|
||||
CItemData * pItemData;
|
||||
if (CItemManager::Instance().GetItemDataPointer(GetItemIndex(TItemPos(INVENTORY, c_Equipment_Arrow)), &pItemData))
|
||||
if (CItemData::ITEM_TYPE_WEAPON == pItemData->GetType())
|
||||
if (CItemData::WEAPON_ARROW == pItemData->GetSubType())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotShotError", Py_BuildValue("(is)", GetMainCharacterIndex(), "EMPTY_ARROW"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__HasItem(DWORD dwItemID)
|
||||
{
|
||||
for (int i = 0; i < c_Inventory_Count; ++i)
|
||||
{
|
||||
if (dwItemID == GetItemIndex(TItemPos (INVENTORY, i)))
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < c_DragonSoul_Inventory_Count; ++i)
|
||||
{
|
||||
if (dwItemID == GetItemIndex(TItemPos (DRAGON_SOUL_INVENTORY, i)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern const DWORD c_iSkillIndex_Tongsol;
|
||||
extern const DWORD c_iSkillIndex_Fishing;
|
||||
extern const DWORD c_iSkillIndex_Mining;
|
||||
extern const DWORD c_iSkillIndex_Making;
|
||||
extern const DWORD c_iSkillIndex_Combo;
|
||||
extern const DWORD c_iSkillIndex_Language1;
|
||||
extern const DWORD c_iSkillIndex_Language2;
|
||||
extern const DWORD c_iSkillIndex_Language3;
|
||||
extern const DWORD c_iSkillIndex_Polymorph;
|
||||
|
||||
void CPythonPlayer::UseGuildSkill(DWORD dwSkillSlotIndex)
|
||||
{
|
||||
CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
|
||||
if (!pkInstMain)
|
||||
return;
|
||||
if (!pkInstMain->CanUseSkill())
|
||||
return;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (dwSkillSlotIndex >= SKILL_MAX_NUM)
|
||||
{
|
||||
Tracenf("CPythonPlayer::UseGuildSkill(dwSkillSlotIndex=%d) It's not available skill slot number", dwSkillSlotIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
TSkillInstance & rkSkillInst = m_playerStatus.aSkill[dwSkillSlotIndex];
|
||||
|
||||
DWORD dwSkillIndex = rkSkillInst.dwIndex;
|
||||
|
||||
CPythonSkill::TSkillData * pSkillData;
|
||||
if (!CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
|
||||
return;
|
||||
|
||||
if (__CheckRestSkillCoolTime(dwSkillSlotIndex))
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "WAIT_COOLTIME"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pSkillData->IsOnlyForGuildWar())
|
||||
{
|
||||
if (!CPythonGuild::Instance().IsDoingGuildWar())
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "ONLY_FOR_GUILD_WAR"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwMotionIndex = pSkillData->GetSkillMotionIndex();
|
||||
if (!pkInstMain->NEW_UseSkill(dwSkillIndex, dwMotionIndex, 1, false))
|
||||
{
|
||||
Tracenf("CPythonPlayer::UseGuildSkill(%d) - pkInstMain->NEW_UseSkill - ERROR", dwSkillIndex);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CPythonNetworkStream::Instance().SendGuildUseSkillPacket(dwSkillIndex, 0);
|
||||
__RunCoolTime(dwSkillSlotIndex);
|
||||
}
|
||||
|
||||
void CPythonPlayer::SetComboSkillFlag(BOOL bFlag)
|
||||
{
|
||||
DWORD dwSlotIndex;
|
||||
if (!GetSkillSlotIndex(c_iSkillIndex_Combo, &dwSlotIndex))
|
||||
{
|
||||
Tracef("CPythonPlayer::SetComboSkillFlag(killIndex=%d) - Can't Find Slot Index\n", c_iSkillIndex_Combo);
|
||||
return;
|
||||
}
|
||||
|
||||
int iLevel = GetSkillLevel(dwSlotIndex);
|
||||
if (iLevel <= 0)
|
||||
{
|
||||
Tracef("CPythonPlayer::SetComboSkillFlag(skillIndex=%d, skillLevel=%d) - Invalid Combo Skill Level\n", c_iSkillIndex_Combo, iLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
iLevel = MIN(iLevel, 2);
|
||||
|
||||
CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
|
||||
if (!pkInstMain)
|
||||
return;
|
||||
|
||||
if (bFlag)
|
||||
{
|
||||
pkInstMain->SetComboType(iLevel);
|
||||
__ActivateSkillSlot(dwSlotIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
pkInstMain->SetComboType(0);
|
||||
__DeactivateSkillSlot(dwSlotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
bool CPythonPlayer::__CheckSpecialSkill(DWORD dwSkillIndex)
|
||||
{
|
||||
CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
|
||||
if (!pkInstMain)
|
||||
return false;
|
||||
|
||||
// Fishing
|
||||
if (c_iSkillIndex_Fishing == dwSkillIndex)
|
||||
{
|
||||
if (pkInstMain->IsFishingMode())
|
||||
{
|
||||
NEW_Fishing();
|
||||
}
|
||||
else
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "EQUIP_FISHING_ROD"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Combo
|
||||
else if (c_iSkillIndex_Combo == dwSkillIndex)
|
||||
{
|
||||
DWORD dwSlotIndex;
|
||||
if (!GetSkillSlotIndex(dwSkillIndex, &dwSlotIndex))
|
||||
return false;
|
||||
|
||||
int iLevel = GetSkillLevel(dwSlotIndex);
|
||||
if (iLevel > 0)
|
||||
{
|
||||
CPythonNetworkStream::Instance().SendUseSkillPacket(dwSkillIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotUseSkill", Py_BuildValue("(is)", GetMainCharacterIndex(), "NOT_YET_LEARN"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -46,5 +46,6 @@ void initpack();
|
||||
void initapp();
|
||||
void initchr();
|
||||
void initchrmgr();
|
||||
void initPlayer();
|
||||
void initChat();
|
||||
void initnet();
|
||||
|
||||
Reference in New Issue
Block a user