MRMJ-1: Messenger & Skills fixes

This commit is contained in:
Mind Rapist
2025-12-14 05:12:39 +02:00
parent 436db01a80
commit 7b08687023
46 changed files with 1258 additions and 60 deletions

62
.gitignore vendored
View File

@@ -1 +1,63 @@
/build/
# =======================================================
# FULLY CASE-INSENSITIVE BACKUP EXCLUSIONS
# Matches all files and folders ending in:
# _BK, _BAK, .BK, .BAK (and all case permutations)
# =======================================================
# -------------------------------------------------------
# 1. EXCLUSIONS ENDING IN .BK / _BK
# -------------------------------------------------------
# Files/Folders ending in _BK (e.g., File_Bk, Folder_bK)
*_BK
*_Bk
*_bK
*_bk
# Files ending in .BK (e.g., File.BK, File.bK)
*.BK
*.Bk
*.bK
*.bk
# Files ending in "double extension" .X.BK (e.g., File.txt.Bk)
*.*.BK
*.*.Bk
*.*.bK
*.*.bk
# -------------------------------------------------------
# 2. EXCLUSIONS ENDING IN .BAK / _BAK
# -------------------------------------------------------
# Files/Folders ending in _BAK (e.g., File_BAK, Folder_bak)
*_BAK
*_BAk
*_BaK
*_Bak
*_bAK
*_bAk
*_baK
*_bak
# Files ending in .BAK (e.g., File.BAK, File.bak)
*.BAK
*.BAk
*.BaK
*.Bak
*.bAK
*.bAk
*.baK
*.bak
# Files ending in "double extension" .X.BAK (e.g., File.txt.Bak)
*.*.BAK
*.*.BAk
*.*.BaK
*.*.Bak
*.*.bAK
*.*.bAk
*.*.baK
*.*.bak

View File

@@ -10,16 +10,20 @@ This repository contains the source code necessary to compile the game client ex
---
## ✨ Key Source Code Fixes
## Changelog 📋
The following fixes address critical issues related to locale compilation and texture loading, ensuring compatibility with new content and correct language output.
### 🐛 Bug Fixes
* **Character Selection:** Corrected the display of character stats and ensured gauge bars accurately reflect the character's stats during the selection phase.
* **Changing skill group:** Fixed an issue involving incorrect skill dictionary clearing/restructuring when changing a skill group. This previously caused the client to be unable to find the correct skill slot after a skill group reset, preventing the display of newly added points on level-up and/or clearing cooldown and active state when used and applied new point (if clearing cooldowns for level-0 skills enabled).
### 🖼 Texture and Resource Loading Fix
* **Fix: Missing Texture Cache:** Resolved an issue in `UserInterface/UserInterface.cpp` by adding the necessary missing resource directory names (`"_texcache"`) within the `PackInitialize` function.
* **Impact:** This ensures that texture files for mobs and terrain for the new maps (Cape, Bay, Dawn, Thunder) are displayed.
### 🌐 Build Configuration Fix
* **Fix: Locale Build Typos:** Corrected a critical typo in `UserInterface/locale.cpp` where the `RelWithDebInfo` build configuration incorrectly referenced `tr (1253)`.
* **Impact:** The value was updated to **`gr (1253)`** to correctly reference the Greek locale option before game launch.
### Feature Improvements
* **Messenger System:**
* **Live Removal Updates:** The client now receives immediate live updates when a player is removed by a friend, improving synchronization.
* **Skill Cooldowns and States:** Enhanced reliability and persistence across numerous client actions:
* **Persistence:** Cooldowns and active slot effects are now correctly maintained when changing the Character Window view, switching skill tabs, mounting/unmounting, leveling up a skill or relogging. This persistence is ensured for togglable, non-togglable, and togglable skills with cooldowns.
* **Grade Transfer:** Cooldowns and active slot states are correctly transferred when a skill's grade is changed (e.g., to Master or Perfect).
* **Reset Logic:** Skill cooldowns are cleared and/or active slots are disabled when a skill is reset (individually or via a skill group reset).
* **Support Skills:** Support skill levels are correctly maintained when the active skill group is changed/reset.
* **Horse Skills:** Implemented special handling to ensure horse skill cooldowns are cleared when their level is changed to 0 (via commands like `/setsk`).
* **Combo Skills:** Combo skills are automatically disabled if their level is changed to 0 (via commands like `/setsk`).
* **.gitignore file:** Ignoring all files and directories ending in `_BAK` or `.BAK` (case-insensitive)

View File

@@ -269,6 +269,9 @@ void CEffectInstance::Clear()
void CEffectInstance::__Initialize()
{
#ifdef __ENABLE_STEALTH_FIX__
ReleaseAlwaysHidden();
#endif
m_isAlive = FALSE;
m_dwFrame = 0;
m_pSoundInstanceVector = NULL;

View File

@@ -4,6 +4,7 @@
#include "Eterlib/Pool.h"
#include "AudioLib/Type.h"
#include "StdAfx.h"
#include "EffectElementBaseInstance.h"
#include "EffectData.h"
#include "EffectMeshInstance.h"
@@ -41,6 +42,14 @@ class CEffectInstance : public CGraphicObjectInstance
bool LessRenderOrder(CEffectInstance* pkEftInst);
void SetEffectDataPointer(CEffectData * pEffectData);
#ifdef __ENABLE_STEALTH_FIX__ //EXP
// Returns the pointer to the effect data associated with this instance.
CEffectData* GetEffectDataPointer() const
{
return m_pkEftData;
}
#endif
void Clear();
BOOL isAlive();
@@ -85,6 +94,7 @@ class CEffectInstance : public CGraphicObjectInstance
float m_fLastTime;
public:
static CDynamicPool<CEffectInstance> ms_kPool;
static int ms_iRenderingEffectCount;
};

View File

@@ -351,6 +351,24 @@ void CEffectManager::HideEffect()
m_pSelectedEffectInstance->Hide();
}
#ifdef __ENABLE_STEALTH_FIX__
void CEffectManager::ApplyAlwaysHidden()
{
if (!m_pSelectedEffectInstance)
return;
m_pSelectedEffectInstance->ApplyAlwaysHidden();
}
void CEffectManager::ReleaseAlwaysHidden()
{
if (!m_pSelectedEffectInstance)
return;
m_pSelectedEffectInstance->ReleaseAlwaysHidden();
}
#endif
bool CEffectManager::GetEffectData(DWORD dwID, CEffectData ** ppEffect)
{
TEffectDataMap::iterator itor = m_kEftDataMap.find(dwID);
@@ -462,5 +480,25 @@ CEffectManager::~CEffectManager()
Destroy();
}
#ifdef __ENABLE_STEALTH_FIX__ //EXP
DWORD CEffectManager::GetSelectedEffectDataCRC() const
{
if (!m_pSelectedEffectInstance)
return 0;
CEffectData* pData = m_pSelectedEffectInstance->GetEffectDataPointer();
if (!pData)
return 0;
const char* cszFile = pData->GetFileName();
if (!cszFile || !cszFile[0])
return 0;
std::string str;
StringPath(cszFile, str);
return GetCaseCRC32(str.c_str(), (int)str.length());
}
#endif
// just for map effect

View File

@@ -1,5 +1,6 @@
#pragma once
#include "StdAfx.h"
#include "EffectInstance.h"
class CEffectManager : public CScreen, public CSingleton<CEffectManager>
@@ -56,6 +57,11 @@ class CEffectManager : public CScreen, public CSingleton<CEffectManager>
void ShowEffect();
void HideEffect();
#ifdef __ENABLE_STEALTH_FIX__
void ApplyAlwaysHidden();
void ReleaseAlwaysHidden();
#endif
// Temporary function
DWORD GetRandomEffect();
int GetEmptyIndex();
@@ -69,6 +75,11 @@ class CEffectManager : public CScreen, public CSingleton<CEffectManager>
int GetRenderingEffectCount();
#ifdef __ENABLE_STEALTH_FIX__ //EXP
// Return the CRC of the effect-data for the selected effect instance.
DWORD GetSelectedEffectDataCRC() const;
#endif
protected:
void __Initialize();

View File

@@ -14,6 +14,8 @@
#include "AudioLib/StdAfx.h"
#include "UserInterface/Locale_inc.h"
/*
#include "FrameController.h"

View File

@@ -200,9 +200,24 @@ void CGraphicObjectInstance::Hide()
{
m_isVisible = false;
}
#ifdef __ENABLE_STEALTH_FIX__
void CGraphicObjectInstance::ApplyAlwaysHidden() {
m_isAlwaysHidden = true;
}
void CGraphicObjectInstance::ReleaseAlwaysHidden() {
m_isAlwaysHidden = false;
}
#endif
bool CGraphicObjectInstance::isShow()
{
#ifdef __ENABLE_STEALTH_FIX__
return m_isVisible && !m_isAlwaysHidden;
#else
return m_isVisible;
#endif
}
//
@@ -276,6 +291,11 @@ void CGraphicObjectInstance::Initialize()
m_isVisible = TRUE;
m_BlockCamera = false;
#ifdef __ENABLE_STEALTH_FIX__
m_isAlwaysHidden = false;
#endif
m_v3Position.x = m_v3Position.y = m_v3Position.z = 0.0f;
m_v3Scale.x = m_v3Scale.y = m_v3Scale.z = 1.0f;

View File

@@ -57,6 +57,12 @@ class CGraphicObjectInstance : public CGraphicCollisionObject
void Hide();
bool isShow();
#ifdef __ENABLE_STEALTH_FIX__
void ApplyAlwaysHidden();
void ReleaseAlwaysHidden();
#endif
// Camera Block
void BlockCamera(bool bBlock) {m_BlockCamera = bBlock;}
bool BlockCamera() { return m_BlockCamera; }
@@ -109,6 +115,10 @@ class CGraphicObjectInstance : public CGraphicCollisionObject
D3DXMATRIX m_mRotation;
bool m_isVisible;
#ifdef __ENABLE_STEALTH_FIX__
bool m_isAlwaysHidden;
#endif
D3DXMATRIX m_worldMatrix;
// Camera Block

View File

@@ -36,6 +36,8 @@
#include "EterBase/Debug.h"
#include "EterLocale/CodePageId.h"
#include "UserInterface/Locale_inc.h"
#ifndef VC_EXTRALEAN
#include <winsock.h>
#endif

View File

@@ -4,6 +4,11 @@
#include "PythonWindow.h"
#include "PythonSlotWindow.h"
#ifdef FIX_REFRESH_SKILL_COOLDOWN
#include "UserInterface/PythonSkill.h"
#include "UserInterface/PythonPlayer.h"
#endif
//#define __RENDER_SLOT_AREA__
using namespace UI;
@@ -204,6 +209,14 @@ void CSlotWindow::SetSlotType(DWORD dwType)
m_dwSlotType = dwType;
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
DWORD CSlotWindow::GetSlotType() const
{
return m_dwSlotType;
}
#endif
void CSlotWindow::SetSlotStyle(DWORD dwStyle)
{
m_dwSlotStyle = dwStyle;
@@ -499,6 +512,7 @@ void CSlotWindow::SetSlotCountNew(DWORD dwIndex, DWORD dwGrade, DWORD dwCount)
void CSlotWindow::SetSlotCoolTime(DWORD dwIndex, float fCoolTime, float fElapsedTime)
{
TSlot * pSlot;
if (!GetSlotPointer(dwIndex, &pSlot))
return;
@@ -506,9 +520,94 @@ void CSlotWindow::SetSlotCoolTime(DWORD dwIndex, float fCoolTime, float fElapsed
pSlot->fStartCoolTime = CTimer::Instance().GetCurrentSecond() - fElapsedTime;
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void CSlotWindow::StoreSlotCoolTime(DWORD dwKey, DWORD dwSlotIndex, float fCoolTime, float fElapsedTime)
{
std::map<DWORD, SStoreCoolDown>::iterator it = m_CoolDownStore[dwKey].find(dwSlotIndex);
if (it != m_CoolDownStore[dwKey].end())
{
it->second.fCoolTime = fCoolTime;
it->second.fElapsedTime = CTimer::Instance().GetCurrentSecond() - fElapsedTime;
it->second.bActive = false;
}
else
{
SStoreCoolDown m_storeCoolDown;
m_storeCoolDown.fCoolTime = fCoolTime;
m_storeCoolDown.fElapsedTime = CTimer::Instance().GetCurrentSecond() - fElapsedTime;
m_storeCoolDown.bActive = false;
m_CoolDownStore[dwKey].insert(std::map<DWORD, SStoreCoolDown>::value_type(dwSlotIndex, m_storeCoolDown));
}
}
void CSlotWindow::RestoreSlotCoolTime(DWORD dwKey)
{
for (std::map<DWORD, SStoreCoolDown>::iterator it = m_CoolDownStore[dwKey].begin(); it != m_CoolDownStore[dwKey].end(); it++)
{
TSlot* pSlot;
if (!GetSlotPointer(it->first, &pSlot))
return;
pSlot->fCoolTime = it->second.fCoolTime;
pSlot->fStartCoolTime = it->second.fElapsedTime;
if (it->second.bActive)
ActivateSlot(it->first);
else
DeactivateSlot(it->first);
}
}
void CSlotWindow::TransferSlotCoolTime(DWORD dwIndex1, DWORD dwIndex2)
{
std::map<DWORD, SStoreCoolDown>::iterator it = m_CoolDownStore[CPythonSkill::SKILL_TYPE_ACTIVE].find(dwIndex1);
if (it != m_CoolDownStore[CPythonSkill::SKILL_TYPE_ACTIVE].end())
{
TSlot* pSlot1;
if (!GetSlotPointer(dwIndex1, &pSlot1))
return;
TSlot* pSlot2;
if (!GetSlotPointer(dwIndex2, &pSlot2))
return;
// Replacing the cooldown from slot 1 to slot 2 and removing the slot 1 from the map.
SStoreCoolDown slotCooldown = it->second;
int iDestSkillGrade = CPythonPlayer::Instance().GetSkillGrade(dwIndex2);
int iDestSkillLevel = CPythonPlayer::Instance().GetSkillLevel(dwIndex2);
m_CoolDownStore[CPythonSkill::SKILL_TYPE_ACTIVE][dwIndex2] = slotCooldown;
m_CoolDownStore[CPythonSkill::SKILL_TYPE_ACTIVE].erase(dwIndex1);
// Removing the cooldown from the slot 1.
pSlot1->fCoolTime = 0;
pSlot1->fStartCoolTime = 0;
if (slotCooldown.bActive)
ActivateSlot(dwIndex2);
if (iDestSkillLevel > 0)
{
// Setting the cooldown from slot 1 to slot 2.
pSlot2->fCoolTime = slotCooldown.fCoolTime;
pSlot2->fStartCoolTime = slotCooldown.fElapsedTime;
}
}
}
#endif
void CSlotWindow::ActivateSlot(DWORD dwIndex)
{
TSlot * pSlot;
if (!GetSlotPointer(dwIndex, &pSlot))
return;
@@ -518,20 +617,36 @@ void CSlotWindow::ActivateSlot(DWORD dwIndex)
{
__CreateSlotEnableEffect();
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
std::map<DWORD, SStoreCoolDown>::iterator it = m_CoolDownStore[1].find(dwIndex);
if (it != m_CoolDownStore[1].end())
it->second.bActive = true;
#endif
}
void CSlotWindow::DeactivateSlot(DWORD dwIndex)
{
TSlot * pSlot;
if (!GetSlotPointer(dwIndex, &pSlot))
return;
pSlot->bActive = FALSE;
#ifdef FIX_REFRESH_SKILL_COOLDOWN
std::map<DWORD, SStoreCoolDown>::iterator it = m_CoolDownStore[1].find(dwIndex);
if (it != m_CoolDownStore[1].end())
it->second.bActive = false;
#endif
}
void CSlotWindow::ClearSlot(DWORD dwIndex)
{
TSlot * pSlot;
if (!GetSlotPointer(dwIndex, &pSlot))
return;
@@ -1262,6 +1377,17 @@ void CSlotWindow::ReserveDestroyCoolTimeFinishEffect(DWORD dwSlotIndex)
m_ReserveDestroyEffectDeque.push_back(dwSlotIndex);
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void CSlotWindow::ClearStoredSlotCoolTime(DWORD dwKey, DWORD dwSlotIndex)
{
std::map<DWORD, SStoreCoolDown>& store = m_CoolDownStore[dwKey];
std::map<DWORD, SStoreCoolDown>::iterator it = store.find(dwSlotIndex);
if (it != store.end())
store.erase(it);
}
#endif
DWORD CSlotWindow::Type()
{
static int s_Type = GetCRC32("CSlotWindow", strlen("CSlotWindow"));
@@ -1383,6 +1509,11 @@ void CSlotWindow::__Initialize()
m_dwSlotStyle = SLOT_STYLE_PICK_UP;
m_dwToolTipSlotNumber = SLOT_NUMBER_NONE;
#ifdef FIX_REFRESH_SKILL_COOLDOWN
m_CoolDownStore.clear();
#endif
m_isUseMode = FALSE;
m_isUsableItem = FALSE;

View File

@@ -75,6 +75,10 @@ namespace UI
} TSlot;
typedef std::list<TSlot> TSlotList;
typedef TSlotList::iterator TSlotListIterator;
#ifdef FIX_REFRESH_SKILL_COOLDOWN
typedef struct SStoreCoolDown { float fCoolTime; float fElapsedTime; bool bActive; };
#endif
public:
CSlotWindow(PyObject * ppyObject);
@@ -84,6 +88,9 @@ namespace UI
// Manage Slot
void SetSlotType(DWORD dwType);
#ifdef FIX_REFRESH_SKILL_COOLDOWN
DWORD GetSlotType() const;
#endif
void SetSlotStyle(DWORD dwStyle);
void AppendSlot(DWORD dwIndex, int ixPosition, int iyPosition, int ixCellSize, int iyCellSize);
@@ -107,6 +114,11 @@ namespace UI
void SetSlotCount(DWORD dwIndex, DWORD dwCount);
void SetSlotCountNew(DWORD dwIndex, DWORD dwGrade, DWORD dwCount);
void SetSlotCoolTime(DWORD dwIndex, float fCoolTime, float fElapsedTime = 0.0f);
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void StoreSlotCoolTime(DWORD dwKey, DWORD dwSlotIndex, float fCoolTime, float fElapsedTime = .0f);
void RestoreSlotCoolTime(DWORD dwKey);
void TransferSlotCoolTime(DWORD dwIndex1, DWORD dwIndex2);
#endif
void ActivateSlot(DWORD dwIndex);
void DeactivateSlot(DWORD dwIndex);
void RefreshSlot();
@@ -150,6 +162,10 @@ namespace UI
// CallBack
void ReserveDestroyCoolTimeFinishEffect(DWORD dwSlotIndex);
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void ClearStoredSlotCoolTime(DWORD dwKey, DWORD dwSlotIndex);
#endif
protected:
void __Initialize();
void __CreateToggleSlotImage();
@@ -199,6 +215,9 @@ namespace UI
std::list<DWORD> m_dwSelectedSlotIndexList;
TSlotList m_SlotList;
DWORD m_dwToolTipSlotNumber;
#ifdef FIX_REFRESH_SKILL_COOLDOWN
std::map<DWORD, std::map<DWORD, SStoreCoolDown>> m_CoolDownStore;
#endif
BOOL m_isUseMode;
BOOL m_isUsableItem;

View File

@@ -81,6 +81,9 @@ namespace UI
bool HasParent() { return m_pParent ? true : false; }
bool HasChild() { return m_pChildList.empty() ? false : true; }
int GetChildCount() { return m_pChildList.size(); }
#ifdef FIX_REFRESH_SKILL_COOLDOWN
const TWindowContainer& GetChildList() const { return m_pChildList; }
#endif
CWindow * GetRoot();
CWindow * GetParent();

View File

@@ -652,6 +652,39 @@ namespace UI
m_pRightCaptureWindow = NULL;
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void CWindowManager::ClearStoredSlotCoolTimeInAllSlotWindows(DWORD dwKey, DWORD dwSlotIndex)
{
// recursively walk the window tree starting from layers and clear stored cooldown entries
std::function<void(CWindow*)> recurse;
recurse = [&](CWindow* pWin)
{
if (!pWin)
return;
// If this is a slot window, call its helper
if (pWin->IsType(UI::CSlotWindow::Type()))
{
UI::CSlotWindow * pSlotWin = static_cast<UI::CSlotWindow*>(pWin);
pSlotWin->ClearStoredSlotCoolTime(dwKey, dwSlotIndex);
}
// Visit children
for (CWindow* pChild : pWin->GetChildList())
{
recurse(pChild);
}
};
// Walk all layer roots
for (CWindow* pLayer : m_LayerWindowList)
{
recurse(pLayer);
}
}
#endif
void CWindowManager::SetResolution(int hres, int vres)
{
if (hres<=0 || vres<=0)

View File

@@ -106,6 +106,10 @@ namespace UI
void SetTop(CWindow * pWin);
void SetTopUIWindow();
void ResetCapture();
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void ClearStoredSlotCoolTimeInAllSlotWindows(DWORD dwKey, DWORD dwSlotIndex);
#endif
void Update();
void Render();

View File

@@ -1254,6 +1254,80 @@ PyObject * wndMgrSetSlotCoolTime(PyObject * poSelf, PyObject * poArgs)
return Py_BuildNone();
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
PyObject* wndMgrStoreSlotCoolTime(PyObject* poSelf, PyObject* poArgs)
{
UI::CWindow* pWin;
if (!PyTuple_GetWindow(poArgs, 0, &pWin))
return Py_BuildException();
int iKey;
if (!PyTuple_GetInteger(poArgs, 1, &iKey))
return Py_BuildException();
int iSlotIndex;
if (!PyTuple_GetInteger(poArgs, 2, &iSlotIndex))
return Py_BuildException();
float fCoolTime;
if (!PyTuple_GetFloat(poArgs, 3, &fCoolTime))
return Py_BuildException();
float fElapsedTime = 0.0f;
PyTuple_GetFloat(poArgs, 4, &fElapsedTime);
if (!pWin->IsType(UI::CSlotWindow::Type()))
return Py_BuildException();
UI::CSlotWindow* pSlotWin = (UI::CSlotWindow*)pWin;
pSlotWin->StoreSlotCoolTime(iKey, iSlotIndex, fCoolTime, fElapsedTime);
return Py_BuildNone();
}
PyObject* wndMgrRestoreSlotCoolTime(PyObject* poSelf, PyObject* poArgs)
{
UI::CWindow* pWin;
if (!PyTuple_GetWindow(poArgs, 0, &pWin))
return Py_BuildException();
int iKey;
if (!PyTuple_GetInteger(poArgs, 1, &iKey))
return Py_BuildException();
if (!pWin->IsType(UI::CSlotWindow::Type()))
return Py_BuildException();
UI::CSlotWindow* pSlotWin = (UI::CSlotWindow*)pWin;
pSlotWin->RestoreSlotCoolTime(iKey);
return Py_BuildNone();
}
PyObject* wndMgrTransferSlotCoolTime(PyObject* poSelf, PyObject* poArgs)
{
UI::CWindow* pWin;
if (!PyTuple_GetWindow(poArgs, 0, &pWin))
return Py_BuildException();
int iIndex1;
if (!PyTuple_GetInteger(poArgs, 1, &iIndex1))
return Py_BuildException();
int iIndex2;
if (!PyTuple_GetInteger(poArgs, 2, &iIndex2))
return Py_BuildException();
if (!pWin->IsType(UI::CSlotWindow::Type()))
return Py_BuildException();
UI::CSlotWindow* pSlotWin = (UI::CSlotWindow*)pWin;
pSlotWin->TransferSlotCoolTime(iIndex1, iIndex2);
return Py_BuildNone();
}
#endif
PyObject * wndMgrSetToggleSlot(PyObject * poSelf, PyObject * poArgs)
{
assert(!"wndMgrSetToggleSlot");
@@ -2423,6 +2497,11 @@ void initwndMgr()
{ "SetSlotCount", wndMgrSetSlotCount, METH_VARARGS },
{ "SetSlotCountNew", wndMgrSetSlotCountNew, METH_VARARGS },
{ "SetSlotCoolTime", wndMgrSetSlotCoolTime, METH_VARARGS },
#ifdef FIX_REFRESH_SKILL_COOLDOWN
{ "StoreSlotCoolTime", wndMgrStoreSlotCoolTime, METH_VARARGS },
{ "RestoreSlotCoolTime", wndMgrRestoreSlotCoolTime, METH_VARARGS },
{ "TransferSlotCoolTime", wndMgrTransferSlotCoolTime, METH_VARARGS },
#endif
{ "SetToggleSlot", wndMgrSetToggleSlot, METH_VARARGS },
{ "ActivateSlot", wndMgrActivateSlot, METH_VARARGS },
{ "DeactivateSlot", wndMgrDeactivateSlot, METH_VARARGS },

View File

@@ -362,10 +362,22 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
BOOL IsActEmotion();
DWORD GetComboIndex();
float GetAttackingElapsedTime();
#ifdef FIX_POS_SYNC
void SetBlendingPosition(const TPixelPosition& c_rPosition, float fBlendingTime = 1.0f);
#else
void SetBlendingPosition(const TPixelPosition & c_rPosition, float fBlendingTime = 1.0f);
#endif
void ResetBlendingPosition();
void GetBlendingPosition(TPixelPosition * pPosition);
#ifdef FIX_POS_SYNC
struct BlendingPosition {
D3DXVECTOR3 source;
D3DXVECTOR3 dest;
float duration;
};
#endif
BOOL NormalAttack(float fDirRot, float fBlendTime = 0.1f);
BOOL ComboAttack(DWORD wMotionIndex, float fDirRot, float fBlendTime = 0.1f);
@@ -479,6 +491,12 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
void RenderCollisionData();
void RenderToShadowMap();
#ifdef FIX_POS_SYNC
void ClientAttack(DWORD dwVID);
void ServerAttack(DWORD dwVID);
bool ProcessingClientAttack(DWORD dwVID);
bool ServerAttackCameFirst(DWORD dwVID);
#endif
protected:
void __AdjustCollisionMovement(const CGraphicObjectInstance * c_pGraphicObjectInstance);
@@ -497,6 +515,9 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
float GetHeight();
void ShowAllAttachingEffect();
void HideAllAttachingEffect();
#ifdef __ENABLE_STEALTH_FIX__ //EXP
void HideAllAttachingEffectForEunhyeong();
#endif
void ClearAttachingEffect();
// Fishing
@@ -603,6 +624,10 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
void __ClearCombo();
void __OnEndCombo();
#ifdef FIX_POS_SYNC
void __Push(const TPixelPosition& c_rkPPosDst, unsigned int unDuration);
#endif
void __ProcessDataAttackSuccess(const NRaceData::TAttackData & c_rAttackData, CActorInstance & rVictim, const D3DXVECTOR3 & c_rv3Position, UINT uiSkill = 0, BOOL isSendPacket = TRUE);
void __ProcessMotionEventAttackSuccess(DWORD dwMotionKey, BYTE byEventIndex, CActorInstance & rVictim);
void __ProcessMotionAttackSuccess(DWORD dwMotionKey, CActorInstance & rVictim);
@@ -610,7 +635,11 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
void __HitStone(CActorInstance& rVictim);
void __HitGood(CActorInstance& rVictim);
#ifdef FIX_POS_SYNC
void __HitGreate(CActorInstance& rVictim, UINT uiSkill);
#else
void __HitGreate(CActorInstance& rVictim);
#endif
void __PushDirect(CActorInstance & rVictim);
void __PushCircle(CActorInstance & rVictim);

View File

@@ -580,27 +580,90 @@ void CActorInstance::ShowAllAttachingEffect()
{
CEffectManager::Instance().SelectEffectInstance(it->dwEffectIndex);
CEffectManager::Instance().ShowEffect();
#ifdef __ENABLE_STEALTH_FIX__
CEffectManager::Instance().ReleaseAlwaysHidden();
//CEffectManager::Instance().Update();
#endif
}
}
void CActorInstance::HideAllAttachingEffect()
{
std::list<TAttachingEffect>::iterator it;
for(it = m_AttachingEffectList.begin(); it!= m_AttachingEffectList.end();++it)
for(it = m_AttachingEffectList.begin(); it!= m_AttachingEffectList.end(); ++it)
{
CEffectManager::Instance().SelectEffectInstance(it->dwEffectIndex);
CEffectManager::Instance().HideEffect();
#ifdef __ENABLE_STEALTH_FIX__
CEffectManager::Instance().ApplyAlwaysHidden();
#endif
}
}
#ifdef __ENABLE_STEALTH_FIX__ //EXP
void CActorInstance::HideAllAttachingEffectForEunhyeong()
{
std::list<TAttachingEffect>::iterator it;
CEffectManager& mgr = CEffectManager::Instance();
for (it = m_AttachingEffectList.begin(); it != m_AttachingEffectList.end(); ++it)
{
mgr.SelectEffectInstance(it->dwEffectIndex);
DWORD crc = mgr.GetSelectedEffectDataCRC();
CEffectData* pData = nullptr;
bool isEunh = false;
if (crc != 0 && mgr.GetEffectData(crc, &pData) && pData)
{
std::string fname = pData->GetFileName();
std::string fnameLower = fname;
// normalize for case-insensitive search and path separators
for (char& c: fnameLower)
{
if (c == '\\') c = '/';
c = (char)tolower((unsigned char)c);
}
// Match any eunhyeongbeop variant (eunhyeongbeop, eunhyeongbeop_2, eunhyeongbeop_3, etc.)
if (fnameLower.find("eunhyeongbeop") != std::string::npos)
isEunh = true;
Tracef("Effect Instance %u -> file=%s crc=0x%08X\n", it->dwEffectIndex, fname.c_str(), crc);
}
else
{
Tracef("Effect Instance %u -> no effect-data (crc=0x%08X)\n", it->dwEffectIndex, crc);
}
// If this attaching effect is an eunhyeongbeop variant, do NOT hide it (show it).
if (isEunh)
{
mgr.SelectEffectInstance(it->dwEffectIndex);
mgr.ShowEffect();
mgr.ReleaseAlwaysHidden();
continue;
}
CEffectManager::Instance().SelectEffectInstance(it->dwEffectIndex);
CEffectManager::Instance().HideEffect();
CEffectManager::Instance().ApplyAlwaysHidden();
}
}
#endif
void CActorInstance::__ClearAttachingEffect()
{
m_bEffectInitialized = false;
std::list<TAttachingEffect>::iterator it;
for(it = m_AttachingEffectList.begin(); it!= m_AttachingEffectList.end();++it)
for(it = m_AttachingEffectList.begin(); it!= m_AttachingEffectList.end(); ++it)
{
CEffectManager::Instance().DestroyEffectInstance(it->dwEffectIndex);
}
m_AttachingEffectList.clear();
}

View File

@@ -314,6 +314,76 @@ void CActorInstance::__ClearCombo()
m_pkCurRaceMotionData = NULL;
}
#ifdef FIX_POS_SYNC
void CActorInstance::__Push(const TPixelPosition& c_rkPPosDst, unsigned int unDuration)
{
DWORD dwVID = GetVirtualID();
Tracenf("VID %d SyncPixelPosition %f %f", dwVID, c_rkPPosDst.x, c_rkPPosDst.y);
if (unDuration == 0)
unDuration = 1000;
const D3DXVECTOR3& c_rv3Src = GetPosition();
const D3DXVECTOR3 c_v3Delta = c_rkPPosDst - c_rv3Src;
SetBlendingPosition(c_rkPPostDst, float(unDuration) / 1000);
if (!IsUsingSkill() && !IsResistFallen())
{
int len = sqrt(c_v3Delta.x * c_v3Delta.x + c_v3Delta.y * c_v3Delta.y);
if (len > 150.0f)
{
InterceptOnceMotion(CRaceMotionData::NAME_DAMAGE_FLYING);
PushOnceMotion(CRaceMotionData::NAME_STAND_UP);
}
}
}
void CActorInstance::ClientAttack(DWORD dwVID)
{
if (m_mapAttackSync.find(dwVID) == m_mapAttackSync.end()) {
m_mapAttackSync.insert(std::make_pair(dwVID, -1));
}
else
{
if (m_mapAttackSync[dwVID] == 1)
{
m_mapAttackSync.erase(dwVID);
return;
}
m_mapAttackSync[dwVID]--;
}
}
// server attack increases
void CActorInstance::ServerAttack(DWORD dwVID)
{
if (m_mapAttackSync.find(dwVID) == m_mapAttackSync.end()) {
m_mapAttackSync.insert(std::make_pair(dwVID, 1));
}
else
{
if (m_mapAttackSync[dwVID] == -1)
{
m_mapAttackSync.erase(dwVID);
return;
}
m_mapAttackSync[dwVID]++;
}
}
bool CActorInstance::ProcessingClientAttack(DWORD dwVID)
{
return m_mapAttackSync.find(dwVID) != m_mapAttackSync.end() && m_mapAttackSync[dwVID] < 0;
}
//
bool CActorInstance::ServerAttackCameFirst(DWORD dwVID)
{
return m_mapAttackSync.find(dwVID) != m_mapAttackSync.end() && m_mapAttackSync[dwVID] > 0;
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CActorInstance::isAttacking()
@@ -610,15 +680,33 @@ void CActorInstance::__ProcessDataAttackSuccess(const NRaceData::TAttackData & c
InsertDelay(c_rAttackData.fStiffenTime);
#ifdef FIX_POS_SYNC
BlendingPosition sBlending;
memset(&sBlending, 0, sizeof(sBlending));
sBlending.source = rVictim.NEW_GetCurPixelPositionRef();
#endif
if (__CanPushDestActor(rVictim) && c_rAttackData.fExternalForce > 0.0f)
{
__PushCircle(rVictim);
// VICTIM_COLLISION_TEST
const D3DXVECTOR3& kVictimPos = rVictim.GetPosition();
rVictim.m_PhysicsObject.IncreaseExternalForce(kVictimPos, c_rAttackData.fExternalForce); //*nForceRatio/100.0f);
#ifdef FIX_POS_SYNC
const bool bServerAttackAlreadyCame = rVictim.ServerAttackCameFirst(GetVirtualID());
rVictim.ClientAttack(GetVirtualID());
// VICTIM_COLLISION_TEST_END
if (!bServerAttackAlreadyCame)
{
#endif
__PushCircle(rVictim);
// VICTIM_COLLISION_TEST
const D3DXVECTOR3& kVictimPos = rVictim.GetPosition();
rVictim.m_PhysicsObject.IncreaseExternalForce(kVictimPos, c_rAttackData.fExternalForce); //*nForceRatio/100.0f);
// VICTIM_COLLISION_TEST_END
#ifdef FIX_POS_SYNC
rVictim.GetBlendingPosition(&(sBlending.dest));
sBlending.duration = rVictim.m_PhysicsObject.GetRemainingTime();
}
#endif
}
// Invisible Time
@@ -690,7 +778,11 @@ void CActorInstance::__ProcessDataAttackSuccess(const NRaceData::TAttackData & c
}
else if (NRaceData::HIT_TYPE_GREAT == c_rAttackData.iHittingType)
{
#ifdef FIX_POS_SYNC
__HitGreate(rVictim, uiSkill);
#else
__HitGreate(rVictim);
#endif
}
else
{
@@ -820,10 +912,18 @@ void CActorInstance::__HitGood(CActorInstance& rVictim)
}
}
#ifdef FIX_POS_SYNC
void CActorInstance::__HitGreate(CActorInstance& rVictim, UINT uiSkill)
#else
void CActorInstance::__HitGreate(CActorInstance& rVictim)
#endif
{
// DISABLE_KNOCKDOWN_ATTACK
#ifdef FIX_POS_SYNC
if (!uiSkill && rVictim.IsKnockDown())
#else
if (rVictim.IsKnockDown())
#endif
return;
if (rVictim.__IsStandUpMotion())
return;
@@ -907,16 +1007,24 @@ void CActorInstance::GetBlendingPosition(TPixelPosition * pPosition)
{
if (m_PhysicsObject.isBlending())
{
#ifdef FIX_POS_SYNC
m_PhysicsObject.GetFinalPosition(pPosition);
#else
m_PhysicsObject.GetLastPosition(pPosition);
pPosition->x += m_x;
pPosition->y += m_y;
pPosition->z += m_z;
#endif
}
else
{
#ifdef FIX_POS_SYNC
GetPixelPosition(pPosition);
#else
pPosition->x = m_x;
pPosition->y = m_y;
pPosition->z = m_z;
#endif
}
}

View File

@@ -5,6 +5,7 @@
#include "EterLib/GrpSubImage.h"
#include "EterGrnLib/Thing.h"
#include "GameType.h"
class CItemData
{

View File

@@ -107,6 +107,32 @@ void CPhysicsObject::IncreaseExternalForce(const D3DXVECTOR3 & c_rvBasePosition,
}
}
#ifdef FIX_POS_SYNC
void CPhysicsObject::SetLastPosition(const TPixelPosition& c_rPosition, const TPixelPosition& c_rDeltaPosition, float fBlendingTime)
{
m_v3FinalPosition.x = float(c_rPosition.x + c_rDeltaPosition.x);
m_v3FinalPosition.y = float(c_rPosition.y + c_rDeltaPosition.y);
m_v3FinalPosition.z = float(c_rPosition.z + c_rDeltaPosition.z);
m_v3DeltaPosition.x = float(c_rDeltaPosition.x);
m_v3DeltaPosition.y = float(c_rDeltaPosition.y);
m_v3DeltaPosition.z = float(c_rDeltaPosition.z);
m_xPushingPosition.Setup(0.0f, c_rDeltaPosition.x, fBlendingTime);
m_yPushingPosition.Setup(0.0f, c_rDeltaPosition.y, fBlendingTime);
}
void CPhysicsObject::GetFinalPosition(TPixelPosition* pPosition)
{
pPosition->x = (m_v3FinalPosition.x);
pPosition->y = (m_v3FinalPosition.y);
pPosition->z = (m_v3FinalPosition.z);
}
void CPhysicsObject::GetDeltaPosition(TPixelPosition* pPosition)
{
pPosition->x = (m_v3DeltaPosition.x);
pPosition->y = (m_v3DeltaPosition.y);
pPosition->z = (m_v3DeltaPosition.z);
}
#else
void CPhysicsObject::SetLastPosition(const TPixelPosition & c_rPosition, float fBlendingTime)
{
m_v3LastPosition.x = float(c_rPosition.x);
@@ -115,6 +141,7 @@ void CPhysicsObject::SetLastPosition(const TPixelPosition & c_rPosition, float f
m_xPushingPosition.Setup(0.0f, c_rPosition.x, fBlendingTime);
m_yPushingPosition.Setup(0.0f, c_rPosition.y, fBlendingTime);
}
#endif
void CPhysicsObject::GetLastPosition(TPixelPosition * pPosition)
{

View File

@@ -71,7 +71,13 @@ class CPhysicsObject
void SetDirection(const D3DXVECTOR3 & c_rv3Direction);
void IncreaseExternalForce(const D3DXVECTOR3 & c_rvBasePosition, float fForce);
void SetLastPosition(const TPixelPosition & c_rPosition, float fBlendingTime);
#ifdef FIX_POS_SYNC
void SetLastPosition(const TPixelPosition& c_rPosition, const TPixelPosition& c_rDeltaPosition, float fBlendingTime);
void GetFinalPosition(TPixelPosition* pPosition);
void GetDeltaPosition(TPixelPosition* pPosition);
#else
void SetLastPosition(const TPixelPosition& c_rPosition, float fBlendingTime);
#endif
void GetLastPosition(TPixelPosition * pPosition);
float GetXMovement();
@@ -92,6 +98,10 @@ class CPhysicsObject
D3DXVECTOR3 m_v3Velocity;
D3DXVECTOR3 m_v3LastPosition;
#ifdef FIX_POS_SYNC
D3DXVECTOR3 m_v3FinalPosition;
D3DXVECTOR3 m_v3DeltaPosition;
#endif
CEaseOutInterpolation m_xPushingPosition;
CEaseOutInterpolation m_yPushingPosition;

View File

@@ -26,6 +26,8 @@
#include "AudioLib/StdAfx.h"
#include "EffectLib/StdAfx.h"
#include "UserInterface/Locale_inc.h"
#include "GameType.h"
#include "GameUtil.h"
#include "MapType.h"

View File

@@ -1,6 +1,7 @@
#pragma once
#include "AbstractSingleton.h"
#include "GameType.h"
class CInstanceBase;

View File

@@ -448,7 +448,11 @@ BOOL CInstanceBase::IsMovieMode()
BOOL CInstanceBase::IsInvisibility()
{
#ifdef __ENABLE_STEALTH_FIX__
if (IsAffect(AFFECT_INVISIBILITY) || IsAffect(AFFECT_EUNHYEONG) || IsAffect(AFFECT_REVIVE_INVISIBILITY))
#else
if (IsAffect(AFFECT_INVISIBILITY))
#endif
return true;
return false;
@@ -1556,7 +1560,11 @@ void CInstanceBase::StateProcess()
SetAdvancingRotation(fRotDst);
SetRotation(fRotDst);
#ifdef FIX_POS_SYNC
NEW_UseSkill(1, eFunc& FUNC_SKILL - 1, uArg & 0x0f, (uArg >> 4) ? true : false);
#else
NEW_UseSkill(0, eFunc & 0x7f, uArg&0x0f, (uArg>>4) ? true : false);
#endif
//Tracen("가깝기 때문에 워프 공격");
}
}
@@ -1734,7 +1742,11 @@ void CInstanceBase::MovementProcess()
{
SetAdvancingRotation(m_fDstRot);
BlendRotation(m_fDstRot);
#ifdef FIX_POS_SYNC
NEW_UseSkill(1, m_kMovAfterFunc.eFunc& FUNC_SKILL - 1, m_kMovAfterFunc.uArg & 0x0f, (m_kMovAfterFunc.uArg >> 4) ? true : false);
#else
NEW_UseSkill(0, m_kMovAfterFunc.eFunc & 0x7f, m_kMovAfterFunc.uArg&0x0f, (m_kMovAfterFunc.uArg>>4) ? true : false);
#endif
}
else
{
@@ -1790,7 +1802,11 @@ void CInstanceBase::MovementProcess()
m_GraphicThingInstance.SetRotation(fRotation);
}
#ifdef __ENABLE_STEALTH_FIX__
if (__IsInDustRange() && !IsAffect(AFFECT_INVISIBILITY) && !IsAffect(AFFECT_EUNHYEONG) && !IsAffect(AFFECT_REVIVE_INVISIBILITY))
#else
if (__IsInDustRange())
#endif
{
float fDustDistance = NEW_GetDistanceFromDestPixelPosition(m_kPPosDust);
if (IsMountingHorse())
@@ -1906,7 +1922,7 @@ void CInstanceBase::Update()
}
__ComboProcess();
ProcessDamage();
}
@@ -1968,7 +1984,30 @@ void CInstanceBase::Render()
++ms_dwRenderCounter;
m_kHorse.Render();
m_GraphicThingInstance.Render();
m_GraphicThingInstance.Render();
#ifdef __ENABLE_STEALTH_FIX__
CPythonCharacterManager& rkChrMgr = CPythonCharacterManager::Instance();
for (auto ptr = rkChrMgr.CharacterInstanceBegin(); ptr != rkChrMgr.CharacterInstanceEnd(); ++ptr)
{
CInstanceBase* pkInstEach = *ptr;
if (pkInstEach)
{
if (pkInstEach->IsAffect(AFFECT_INVISIBILITY) || pkInstEach->IsAffect(AFFECT_EUNHYEONG) || pkInstEach->IsAffect(AFFECT_REVIVE_INVISIBILITY))
{
if (CPythonPlayer::Instance().IsMainCharacterIndex(pkInstEach->GetVirtualID()))
continue;
if (pkInstEach->IsAffect(AFFECT_EUNHYEONG) && !pkInstEach->IsAffect(AFFECT_INVISIBILITY) && !pkInstEach->IsAffect(AFFECT_REVIVE_INVISIBILITY))
pkInstEach->m_GraphicThingInstance.HideAllAttachingEffectForEunhyeong();
else
pkInstEach->m_GraphicThingInstance.HideAllAttachingEffect();
}
}
}
#endif
if (CActorInstance::IsDirLine())
{

View File

@@ -3,6 +3,7 @@
#include "GameLib/RaceData.h"
#include "GameLib/ActorInstance.h"
#include "StdAfx.h"
#include "AffectFlagContainer.h"
class CInstanceBase
@@ -632,6 +633,11 @@ class CInstanceBase
bool NEW_AttackToDestInstanceDirection(CInstanceBase& rkInstDst, IFlyEventHandler* pkFlyHandler);
bool NEW_AttackToDestInstanceDirection(CInstanceBase& rkInstDst);
#ifdef FIX_POS_SYNC
void ServerAttack(DWORD dwVID);
bool ProcessingClientAttack(DWORD dwVID);
#endif
bool NEW_MoveToDestPixelPositionDirection(const TPixelPosition& c_rkPPosDst);
void NEW_MoveToDestInstanceDirection(CInstanceBase& rkInstDst);
void NEW_MoveToDirection(float fDirRot);

View File

@@ -410,6 +410,18 @@ bool CInstanceBase::NEW_AttackToDestInstanceDirection(CInstanceBase& rkInstDst)
return true;
}
#ifdef FIX_POS_SYNC
void CInstanceBase::ServerAttack(DWORD dwVID)
{
m_GraphicThingInstance.ServerAttack(dwVID);
}
bool CInstanceBase::ProcessingClientAttack(DWORD dwVID)
{
return m_GraphicThingInstance.ProcessingClientAttack(dwVID);
}
#endif
void CInstanceBase::AttackProcess()
{
if (!m_GraphicThingInstance.CanCheckAttacking())

View File

@@ -84,7 +84,7 @@ const D3DXCOLOR& CInstanceBase::GetIndexedNameColor(UINT eNameColor)
return g_akD3DXClrName[eNameColor];
}
void CInstanceBase::AddDamageEffect(DWORD damage,BYTE flag,BOOL bSelf,BOOL bTarget)
void CInstanceBase::AddDamageEffect(DWORD damage, BYTE flag, BOOL bSelf, BOOL bTarget)
{
if(CPythonSystem::Instance().IsShowDamage())
{
@@ -149,19 +149,26 @@ void CInstanceBase::ProcessDamage()
else
*/
{
if(bSelf)
if (bSelf)
{
strDamageType = "damage_";
if(m_bDamageEffectType==0)
if (m_bDamageEffectType == 0)
rdwCRCEft = EFFECT_DAMAGE_SELFDAMAGE;
else
rdwCRCEft = EFFECT_DAMAGE_SELFDAMAGE2;
m_bDamageEffectType = !m_bDamageEffectType;
}
else if(bTarget == false)
#ifdef __ENABLE_STEALTH_FIX__ //EXP
else if (!bTarget || ((IsAffect(AFFECT_INVISIBILITY) || IsAffect(AFFECT_EUNHYEONG)) && bTarget))
#else
else if (bTarget == false)
#endif
{
strDamageType = "nontarget_";
rdwCRCEft = EFFECT_DAMAGE_NOT_TARGET;
return;//현재 적용 안됨.
}
else
@@ -174,34 +181,41 @@ void CInstanceBase::ProcessDamage()
DWORD index = 0;
DWORD num = 0;
std::vector<std::string> textures;
while(damage>0)
while (damage > 0)
{
if(index > 7)
if (index > 7)
{
TraceError("ProcessDamage무한루프 가능성");
break;
}
num = damage%10;
damage /= 10;
char numBuf[MAX_PATH];
sprintf(numBuf,"%d.dds",num);
textures.push_back("d:/ymir work/effect/affect/damagevalue/"+strDamageType+numBuf);
sprintf(numBuf, "%d.dds", num);
textures.push_back("d:/ymir work/effect/affect/damagevalue/" +strDamageType + numBuf);
rkEftMgr.SetEffectTextures(ms_adwCRCAffectEffect[rdwCRCEft],textures);
D3DXMATRIX matrix,matTrans;
D3DXMATRIX matrix, matTrans;
D3DXMatrixIdentity(&matrix);
matrix._41 = v3Pos.x;
matrix._42 = v3Pos.y;
matrix._43 = v3Pos.z;
D3DXMatrixTranslation(&matrix,v3Pos.x,v3Pos.y,v3Pos.z);
D3DXMatrixMultiply(&matrix,&pCamera->GetInverseViewMatrix(),&matrix);
D3DXMatrixTranslation(&matTrans,FONT_WIDTH*index,0,0);
D3DXMatrixTranslation(&matrix, v3Pos.x, v3Pos.y, v3Pos.z);
D3DXMatrixMultiply(&matrix, &pCamera->GetInverseViewMatrix(), &matrix);
D3DXMatrixTranslation(&matTrans, FONT_WIDTH * index, 0, 0);
matTrans._41 = -matTrans._41;
matrix = matTrans*matrix;
D3DXMatrixMultiply(&matrix,&pCamera->GetViewMatrix(),&matrix);
D3DXMatrixMultiply(&matrix, &pCamera->GetViewMatrix(), &matrix);
rkEftMgr.CreateEffect(ms_adwCRCAffectEffect[rdwCRCEft],D3DXVECTOR3(matrix._41,matrix._42,matrix._43)
rkEftMgr.CreateEffect(ms_adwCRCAffectEffect[rdwCRCEft], D3DXVECTOR3(matrix._41, matrix._42, matrix._43)
,v3Rot);
textures.clear();
@@ -784,11 +798,31 @@ void CInstanceBase::__SetReviveInvisibilityAffect(bool isVisible)
if (IsWearingDress())
return;
m_GraphicThingInstance.BlendAlphaValue(0.5f, 1.0f);
#ifdef __ENABLE_STEALTH_FIX__
if (__IsMainInstance() || __MainCanSeeHiddenThing())
{
#endif
m_GraphicThingInstance.BlendAlphaValue(0.5f, 1.0f);
#ifdef __ENABLE_STEALTH_FIX__
}
else
{
m_GraphicThingInstance.BlendAlphaValue(0.0f, 1.0f);
m_GraphicThingInstance.HideAllAttachingEffect();
}
#endif
}
else
{
m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f);
#ifdef __ENABLE_STEALTH_FIX__
if (!IsAffect(AFFECT_EUNHYEONG) && !IsAffect(AFFECT_INVISIBILITY))
{
#endif
m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f);
#ifdef __ENABLE_STEALTH_FIX__
m_GraphicThingInstance.ShowAllAttachingEffect();
}
#endif
}
}
@@ -808,13 +842,26 @@ void CInstanceBase::__Assassin_SetEunhyeongAffect(bool isVisible)
{
// 2004.10.16.myevan.은형법 완전 투명
m_GraphicThingInstance.BlendAlphaValue(0.0f, 1.0f);
m_GraphicThingInstance.HideAllAttachingEffect();
#ifdef __ENABLE_STEALTH_FIX__ //EXP
if (!IsAffect(AFFECT_INVISIBILITY) && !IsAffect(AFFECT_REVIVE_INVISIBILITY))
m_GraphicThingInstance.HideAllAttachingEffectForEunhyeong();
else
#endif
m_GraphicThingInstance.HideAllAttachingEffect();
}
}
else
{
m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f);
m_GraphicThingInstance.ShowAllAttachingEffect();
#ifdef __ENABLE_STEALTH_FIX__
if (!IsAffect(AFFECT_REVIVE_INVISIBILITY) && !IsAffect(AFFECT_INVISIBILITY))
{
#endif
m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f);
m_GraphicThingInstance.ShowAllAttachingEffect();
#ifdef __ENABLE_STEALTH_FIX__
ProcessDamage();
}
#endif
}
}
@@ -823,8 +870,6 @@ void CInstanceBase::__Shaman_SetParalysis(bool isParalysis)
m_GraphicThingInstance.SetParalysis(isParalysis);
}
void CInstanceBase::__Warrior_SetGeomgyeongAffect(bool isVisible)
{
if (isVisible)
@@ -895,7 +940,11 @@ void CInstanceBase::__SetAffect(UINT eAffect, bool isVisible)
return;
break;
case AFFECT_REVIVE_INVISIBILITY:
#ifdef __ENABLE_STEALTH_FIX__
__SetReviveInvisibilityAffect(isVisible);
#else
__Assassin_SetEunhyeongAffect(isVisible);
#endif
break;
case AFFECT_EUNHYEONG:
__Assassin_SetEunhyeongAffect(isVisible);
@@ -911,15 +960,28 @@ void CInstanceBase::__SetAffect(UINT eAffect, bool isVisible)
// 2004.07.17.levites.isShow를 ViewFrustumCheck로 변경
if (isVisible)
{
#ifndef __ENABLE_STEALTH_FIX__
m_GraphicThingInstance.ClearAttachingEffect();
__EffectContainer_Destroy();
DetachTextTail();
#else
m_GraphicThingInstance.HideAllAttachingEffect();
#endif
}
else
{
#ifdef __ENABLE_STEALTH_FIX__
if (!IsAffect(AFFECT_EUNHYEONG) && !IsAffect(AFFECT_REVIVE_INVISIBILITY))
{
m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f);
m_GraphicThingInstance.ShowAllAttachingEffect();
ProcessDamage();
}
#else
m_GraphicThingInstance.BlendAlphaValue(1.0f, 1.0f);
AttachTextTail();
RefreshTextTail();
#endif
}
return;
break;

View File

@@ -259,8 +259,8 @@ struct SLOCALEDATA
const char* szSecurityKey;
} gs_stLocaleData[] = {
{ LSS_YMIR, "ymir", 949, "testtesttesttest" }, // Korea
{ LSS_EUROPE, "de", 1252, "1234abcd5678efgh" }, // GameForge (Germany)
{ LSS_EUROPE, "en", 1252, "1234abcd5678efgh" }, // GameForge (United Kingdom)
{ LSS_EUROPE, "de", 1252, "1234abcd5678efgh" }, // GameForge (Germany)
{ LSS_EUROPE, "us", 1252, "1234abcd5678efgh" }, // GameForge (USA)
{ LSS_EUROPE, "es", 1252, "1234abcd5678efgh" }, // GameForge (Spain)
{ LSS_EUROPE, "it", 1252, "1234abcd5678efgh" }, // GameForge (Italy)

View File

@@ -6,3 +6,14 @@
#define ENABLE_DRAGON_SOUL_SYSTEM
#define ENABLE_NEW_EQUIPMENT_SYSTEM
//#define ENABLE_DISCORD_RPC
// Fixes
#define FIX_MESSENGER_ACTION_SYNC
#define FIX_REFRESH_SKILL_COOLDOWN
#define FIX_SEQ_254
#define CHAR_SELECT_STATS_IMPROVEMENT // Improve stats values in character select screen
#define __ENABLE_STEALTH_FIX__
//#define FIX_POS_SYNC
// Python-only
#define FIX_HORSE_SKILLS_TAB

View File

@@ -536,6 +536,41 @@ void CNetworkActorManager::MoveActor(const SNetworkMoveActorData& c_rkNetMoveAct
rkNetActorData.m_fRot=c_rkNetMoveActorData.m_fRot;
}
#ifdef FIX_POS_SYNC
void CNetworkActorManager::AttackActor(DWORD dwVID, DWORD dwAttacakerVID, LONG lDestPosX, LONG lDestPosY, const TPixelPosition& k_pSyncPos, DWORD dwBlendDuration)
{
std::map<DWORD, SNetworkActorData>::iterator f = m_kNetActorDict.find(dwVID);
if (m_kNetActorDict.end() == f)
{
return;
}
SNetworkActorData& rkNetActorData = f->second;
if (k_pSyncPos.x && k_pSyncPos.y) {
CInstanceBase* pkInstFind = __FindActor(rkNetActorData);
if (pkInstFind)
{
const bool bProcessingClientAttack = pkInstFind->ProcessingClientAttack(dwAttacakerVID);
pkInstFind->ServerAttack(dwAttacakerVID);
// if already blending, update
if (bProcessingClientAttack && pkInstFind->IsPushing() && pkInstFind->GetBlendingRemainTime() > 0.15) {
pkInstFind->SetBlendingPosition(k_pSyncPos, pkInstFind->GetBlendingRemainTime());
}
else {
// otherwise sync
//pkInstFind->SCRIPT_SetPixelPosition(k_pSyncPos.x, k_pSyncPos.y);
pkInstFind->NEW_SyncPixelPosition(k_pSyncPos, dwBlendDuration);
}
}
rkNetActorData.SetPosition(long(k_pSyncPos.x), long(k_pSyncPos.y));
}
}
#endif
void CNetworkActorManager::SyncActor(DWORD dwVID, LONG lPosX, LONG lPosY)
{
std::map<DWORD, SNetworkActorData>::iterator f=m_kNetActorDict.find(dwVID);

View File

@@ -127,6 +127,10 @@ class CNetworkActorManager : public CReferenceObject
void UpdateActor(const SNetworkUpdateActorData& c_rkNetUpdateActorData);
void MoveActor(const SNetworkMoveActorData& c_rkNetMoveActorData);
#ifdef FIX_POS_SYNC
void AttackActor(DWORD dwVID, DWORD dwAttacakerVID, LONG lDestPosX, LONG lDestPosY, const TPixelPosition& k_pSyncPos, DWORD dwBlendDuration);
#endif
void SyncActor(DWORD dwVID, LONG lPosX, LONG lPosY);
void SetActorOwner(DWORD dwOwnerVID, DWORD dwVictimVID);

View File

@@ -1,5 +1,10 @@
#pragma once
#include "Gamelib/RaceData.h"
#include "StdAfx.h"
#ifdef FIX_REFRESH_SKILL_COOLDOWN
#include "GameType.h"
#endif
typedef uint8_t TPacketHeader;
@@ -511,6 +516,18 @@ typedef struct command_attack
uint32_t dwVictimVID; // 적 VID
uint8_t bCRCMagicCubeProcPiece;
uint8_t bCRCMagicCubeFilePiece;
#ifdef FIX_POS_SYNC
BOOL bPacket;
LONG lSX;
LONG lSY;
LONG lX;
LONG lY;
float fSyncDestX;
float fSyncDestY;
DWORD dwBlendDuration;
DWORD dwComboMotion;
DWORD dwTime;
#endif
} TPacketCGAttack;
typedef struct command_chat
@@ -730,6 +747,9 @@ enum
MESSENGER_SUBHEADER_GC_LOGOUT,
MESSENGER_SUBHEADER_GC_INVITE,
MESSENGER_SUBHEADER_GC_MOBILE,
#ifdef FIX_MESSENGER_ACTION_SYNC
MESSENGER_SUBHEADER_GC_REMOVE_FRIEND
#endif
};
typedef struct packet_messenger
@@ -1862,6 +1882,16 @@ typedef struct packet_attack
uint32_t dwVID;
uint32_t dwVictimVID; // 적 VID
uint8_t bType; // 공격 유형
#ifdef FIX_POS_SYNC
BOOL bPacket;
LONG lSX;
LONG lSY;
LONG lX;
LONG lY;
float fSyncDestX;
float fSyncDestY;
DWORD dwBlendDuration;
#endif
} TPacketGCAttack;
typedef struct packet_c2c

View File

@@ -1305,7 +1305,6 @@ void initapp()
{ "OnLogoRender", appLogoRender, METH_VARARGS },
{ "OnLogoOpen", appLogoOpen, METH_VARARGS },
{ "OnLogoClose", appLogoClose, METH_VARARGS },
{ NULL, NULL },
};
@@ -1490,4 +1489,22 @@ void initapp()
#else
PyModule_AddIntConstant(poModule, "ENABLE_NEW_EQUIPMENT_SYSTEM", 0);
#endif
#ifdef FIX_MESSENGER_ACTION_SYNC
PyModule_AddIntConstant(poModule, "FIX_MESSENGER_ACTION_SYNC", 1);
#else
PyModule_AddIntConstant(poModule, "FIX_MESSENGER_ACTION_SYNC", 0);
#endif
#ifdef FIX_REFRESH_SKILL_COOLDOWN
PyModule_AddIntConstant(poModule, "FIX_REFRESH_SKILL_COOLDOWN", 1);
#else
PyModule_AddIntConstant(poModule, "FIX_REFRESH_SKILL_COOLDOWN", 0);
#endif
#ifdef FIX_HORSE_SKILLS_TAB
PyModule_AddIntConstant(poModule, "FIX_HORSE_SKILLS_TAB", 1);
#else
PyModule_AddIntConstant(poModule, "FIX_HORSE_SKILLS_TAB", 0);
#endif
}

View File

@@ -4,6 +4,11 @@
void CPythonMessenger::RemoveFriend(const char * c_szKey)
{
m_FriendNameMap.erase(c_szKey);
#ifdef FIX_MESSENGER_ACTION_SYNC
if (m_poMessengerHandler)
PyCallClassMemberFunc(m_poMessengerHandler, "OnRemoveList", Py_BuildValue("(is)", MESSENGER_GRUOP_INDEX_FRIEND, c_szKey));
#endif
}
void CPythonMessenger::OnFriendLogin(const char * c_szKey/*, const char * c_szName*/)
@@ -161,6 +166,7 @@ void initMessenger()
{ "Destroy", messengerDestroy, METH_VARARGS },
{ "RefreshGuildMember", messengerRefreshGuildMember, METH_VARARGS },
{ "SetMessengerHandler", messengerSetMessengerHandler, METH_VARARGS },
{ NULL, NULL, NULL },
};

View File

@@ -1,5 +1,7 @@
#pragma once
#include <set>
class CPythonMessenger : public CSingleton<CPythonMessenger>
{
public:

View File

@@ -662,10 +662,14 @@ bool CPythonNetworkStream::RecvPingPacket()
if (!Send(sizeof(TPacketCGPong), &kPacketPong))
return false;
#ifdef FIX_SEQ_254
return SendSequence();
#else
if (IsSecurityMode())
return SendSequence();
else
return true;
#endif
}
bool CPythonNetworkStream::RecvDefaultPacket(int header)

View File

@@ -8,6 +8,10 @@
#include "packet.h"
#ifdef FIX_POS_SYNC
#include <GameLib/ActorInstance.h>
#endif
class CInstanceBase;
class CNetworkActorManager;
struct SNetworkActorData;
@@ -136,7 +140,11 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
bool SendSyncPositionElementPacket(DWORD dwVictimVID, DWORD dwVictimX, DWORD dwVictimY);
#ifdef FIX_POS_SYNC
bool SendAttackPacket(UINT uMotAttack, DWORD dwVIDVictim, BOOL bPacket, CActorInstance::BlendingPosition& sBlending);
#else
bool SendAttackPacket(UINT uMotAttack, DWORD dwVIDVictim);
#endif
bool SendCharacterStatePacket(const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg);
bool SendUseSkillPacket(DWORD dwSkillIndex, DWORD dwTargetVID=0);
bool SendTargetPacket(DWORD dwVID);
@@ -478,6 +486,9 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
bool RecvTargetPacket();
bool RecvViewEquipPacket();
bool RecvDamageInfoPacket();
#ifdef FIX_POS_SYNC
bool RecvCharacterAttackPacket();
#endif
// Mount
bool RecvMountPacket();

View File

@@ -1495,7 +1495,18 @@ bool CPythonNetworkStream::RecvPointChange()
case POINT_STAT_RESET_COUNT:
__RefreshStatus();
break;
#ifdef CHAR_SELECT_STATS_IMPROVEMENT
case POINT_PLAYTIME:
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].dwPlayMinutes = PointChange.value;
break;
case POINT_LEVEL:
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byLevel = PointChange.value;
__RefreshStatus();
__RefreshSkillWindow();
break;
#else
case POINT_LEVEL:
#endif
case POINT_ST:
case POINT_DX:
case POINT_HT:
@@ -2332,16 +2343,19 @@ bool CPythonNetworkStream::RecvSkillCoolTimeEnd()
bool CPythonNetworkStream::RecvSkillLevel()
{
assert(!"CPythonNetworkStream::RecvSkillLevel - 사용하지 않는 함수");
TPacketGCSkillLevel packet;
if (!Recv(sizeof(TPacketGCSkillLevel), &packet))
{
Tracen("CPythonNetworkStream::RecvSkillLevel - RecvError");
return false;
}
DWORD dwSlotIndex;
CPythonPlayer& rkPlayer = CPythonPlayer::Instance();
CPythonPlayer& rkPlayer=CPythonPlayer::Instance();
for (int i = 0; i < SKILL_MAX_NUM; ++i)
{
if (rkPlayer.GetSkillSlotIndex(i, &dwSlotIndex))
@@ -2350,7 +2364,9 @@ bool CPythonNetworkStream::RecvSkillLevel()
__RefreshSkillWindow();
__RefreshStatus();
Tracef(" >> RecvSkillLevel\n");
return true;
}
@@ -2364,7 +2380,7 @@ bool CPythonNetworkStream::RecvSkillLevelNew()
return false;
}
CPythonPlayer& rkPlayer=CPythonPlayer::Instance();
CPythonPlayer& rkPlayer = CPythonPlayer::Instance();
rkPlayer.SetSkill(7, 0);
rkPlayer.SetSkill(8, 0);
@@ -2412,6 +2428,31 @@ bool CPythonNetworkStream::RecvDamageInfoPacket()
return true;
}
#ifdef FIX_POS_SYNC
bool CPythonNetworkStream::RecvCharacterAttackPacket()
{
TPacketGCAttack kPacket;
if (!Recv(sizeof(TPacketGCAttack), &kPacket))
{
Tracen("CPythonNetworkStream::RecvCharacterAttackPacket - PACKET READ ERROR");
return false;
}
if (kPacket.lX && kPacket.lY) {
__GlobalPositionToLocalPosition(kPacket.lX, kPacket.lY);
}
__GlobalPositionToLocalPosition(kPacket.lSX, kPacket.lSY);
TPixelPosition tSyncPosition = TPixelPosition{ kPacket.fSyncDestX, kPacket.fSyncDestY, 0 };
m_rokNetActorMgr->AttackActor(kPacket.dwVID, kPacket.dwVictimVID, kPacket.lX, kPacket.lY, tSyncPosition, kPacket.dwBlendDuration);
return true;
}
#endif
bool CPythonNetworkStream::RecvTargetPacket()
{
TPacketGCTarget TargetPacket;
@@ -2503,11 +2544,20 @@ bool CPythonNetworkStream::RecvChangeSpeedPacket()
///////////////////////////////////////////////////////////////////////////////////////////////////
// Recv
#ifdef FIX_POS_SYNC
bool CPythonNetworkStream::SendAttackPacket(UINT uMotAttack, DWORD dwVIDVictim, BOOL bPacket, CActorInstance::BlendingPosition& sBlending)
#else
bool CPythonNetworkStream::SendAttackPacket(UINT uMotAttack, DWORD dwVIDVictim)
#endif
{
if (!__CanActMainInstance())
return true;
#ifdef FIX_POS_SYNC
CPythonCharacterManager& rkChrMgr = CPythonCharacterManager::Instance();
CInstanceBase* pkInstMain = rkChrMgr.GetMainInstancePtr();
#endif
#ifdef ATTACK_TIME_LOG
static DWORD prevTime = timeGetTime();
DWORD curTime = timeGetTime();
@@ -2520,6 +2570,25 @@ bool CPythonNetworkStream::SendAttackPacket(UINT uMotAttack, DWORD dwVIDVictim)
kPacketAtk.header = HEADER_CG_ATTACK;
kPacketAtk.bType = uMotAttack;
kPacketAtk.dwVictimVID = dwVIDVictim;
#ifdef FIX_POS_SYNC
kPacketAtk.bPacket = bPacket;
kPacketAtk.lX = (long)sBlending.dest.x;
kPacketAtk.lY = (long)sBlending.dest.y;
kPacketAtk.lSX = (long)sBlending.source.x;
kPacketAtk.lSY = (long)sBlending.source.y;
kPacketAtk.fSyncDestX = sBlending.dest.x;
// sources and dest are normalized with both coordinates positive
// since fSync are ment to be broadcasted to other clients, the Y has to preserve the negative coord
kPacketAtk.fSyncDestY = -sBlending.dest.y;
kPacketAtk.dwBlendDuration = (unsigned int)(sBlending.duration * 1000);
kPacketAtk.dwComboMotion = pkInstMain->GetComboMotion();
kPacketAtk.dwTime = ELTimer_GetServerMSec();
if (kPacketAtk.lX && kPacketAtk.lY)
__LocalPositionToGlobalPosition(kPacketAtk.lX, kPacketAtk.lY);
__LocalPositionToGlobalPosition(kPacketAtk.lSX, kPacketAtk.lSY);
#endif
if (!SendSpecial(sizeof(kPacketAtk), &kPacketAtk))
{
@@ -2814,6 +2883,26 @@ bool CPythonNetworkStream::RecvMessenger()
CPythonMessenger::Instance().SetMobile(char_name, byState);
break;
}
#ifdef FIX_MESSENGER_ACTION_SYNC
case MESSENGER_SUBHEADER_GC_REMOVE_FRIEND:
{
BYTE bLength;
if (!Recv(sizeof(bLength), &bLength))
return false;
if (!Recv(bLength, char_name))
return false;
char_name[bLength] = 0;
CPythonMessenger::Instance().RemoveFriend(char_name);
__RefreshTargetBoardByName(char_name);
break;
}
#endif
}
return true;
}
@@ -3984,6 +4073,7 @@ bool CPythonNetworkStream::RecvWalkModePacket()
bool CPythonNetworkStream::RecvChangeSkillGroupPacket()
{
TPacketGCChangeSkillGroup ChangeSkillGroup;
if (!Recv(sizeof(ChangeSkillGroup), &ChangeSkillGroup))
return false;
@@ -3991,6 +4081,7 @@ bool CPythonNetworkStream::RecvChangeSkillGroupPacket()
CPythonPlayer::Instance().NEW_ClearSkillData();
__RefreshCharacterWindow();
return true;
}

View File

@@ -324,6 +324,10 @@ void CPythonNetworkStream::__RecvCharacterUpdatePacket(SNetworkUpdateActorData *
__RefreshAlignmentWindow();
__RefreshEquipmentWindow();
__RefreshInventoryWindow();
#ifdef CHAR_SELECT_STATS_IMPROVEMENT
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wHairPart = pkNetUpdateActorData->m_dwHair;
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wMainPart = pkNetUpdateActorData->m_dwArmor;
#endif
}
else
{

View File

@@ -326,7 +326,21 @@ bool CPythonNetworkStream::__RecvPlayerPoints()
return false;
for (DWORD i = 0; i < POINT_MAX_NUM; ++i)
{
CPythonPlayer::Instance().SetStatus(i, PointsPacket.points[i]);
#ifdef CHAR_SELECT_STATS_IMPROVEMENT
if (i == POINT_LEVEL)
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byLevel = PointsPacket.points[i];
else if (i == POINT_ST)
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byST = PointsPacket.points[i];
else if (i == POINT_HT)
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byHT = PointsPacket.points[i];
else if (i == POINT_DX)
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byDX = PointsPacket.points[i];
else if (i == POINT_IQ)
m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byIQ = PointsPacket.points[i];
#endif
}
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "RefreshStatus", Py_BuildValue("()"));
return true;

View File

@@ -532,6 +532,74 @@ void CPythonPlayer::NotifyChangePKMode()
PyCallClassMemberFunc(m_ppyGameWindow, "OnChangePKMode", Py_BuildValue("()"));
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void CPythonPlayer::ResetSkillCoolTimes()
{
for (int i = 0; i < SKILL_MAX_NUM; ++i)
ResetSkillCoolTimeForSlot(i);
}
void CPythonPlayer::ResetSkillCoolTimeForSlot(DWORD dwSlotIndex)
{
if (dwSlotIndex >= SKILL_MAX_NUM)
return;
TSkillInstance& rkSkillInst = m_playerStatus.aSkill[dwSlotIndex];
// If this skill is a toggle and currently active, deactivate it so UI/state is consistent.
// __DeactivateSkillSlot is a private/protected helper on this class.
if (IsToggleSkill(dwSlotIndex) && IsSkillActive(dwSlotIndex))
__DeactivateSkillSlot(dwSlotIndex);
// If nothing to clear, skip
if (!rkSkillInst.fLastUsedTime && !rkSkillInst.fCoolTime)
return;
// Clear cooldown timers
rkSkillInst.fLastUsedTime = rkSkillInst.fCoolTime = 0.0f;
// Get the actual skill type to clear cooldowns from the correct storage
DWORD dwSkillType = CPythonSkill::SKILL_TYPE_ACTIVE; // default
DWORD dwSkillIndex = rkSkillInst.dwIndex;
CPythonSkill::TSkillData* pSkillData = NULL;
if (dwSkillIndex != 0 && CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
{
dwSkillType = pSkillData->byType;
}
if (dwSkillType == CPythonSkill::SKILL_TYPE_ACTIVE)
{
for (int iGrade = 0; iGrade < CPythonSkill::SKILL_GRADE_COUNT; ++iGrade)
{
UI::CWindowManager::Instance().ClearStoredSlotCoolTimeInAllSlotWindows(
dwSkillType,
dwSlotIndex + iGrade * CPythonSkill::SKILL_GRADE_STEP_COUNT);
}
}
else
{
UI::CWindowManager::Instance().ClearStoredSlotCoolTimeInAllSlotWindows(dwSkillType, dwSlotIndex);
}
// Inform Python/UI which slot was cleared
PyCallClassMemberFunc(m_ppyGameWindow, "SkillClearCoolTime", Py_BuildValue("(i)", (int)dwSlotIndex));
}
void CPythonPlayer::ResetHorseSkillCoolTime(DWORD dwSkillIndex, DWORD dwVisualSlotIndex)
{
// Clear both the source slot (137-140) and the visual slot (0-3)
// so RestoreSlotCoolTime won't have anything to restore
UI::CWindowManager::Instance().ClearStoredSlotCoolTimeInAllSlotWindows(
CPythonSkill::SKILL_TYPE_HORSE,
dwSkillIndex);
UI::CWindowManager::Instance().ClearStoredSlotCoolTimeInAllSlotWindows(
CPythonSkill::SKILL_TYPE_HORSE,
dwVisualSlotIndex);
}
#endif
void CPythonPlayer::MoveItemData(TItemPos SrcCell, TItemPos DstCell)
{
@@ -993,6 +1061,7 @@ void CPythonPlayer::SetSkillLevel(DWORD dwSlotIndex, DWORD dwSkillLevel)
void CPythonPlayer::SetSkillLevel_(DWORD dwSkillIndex, DWORD dwSkillGrade, DWORD dwSkillLevel)
{
DWORD dwSlotIndex;
if (!GetSkillSlotIndex(dwSkillIndex, &dwSlotIndex))
return;
@@ -1004,39 +1073,46 @@ void CPythonPlayer::SetSkillLevel_(DWORD dwSkillIndex, DWORD dwSkillGrade, DWORD
case 0:
m_playerStatus.aSkill[dwSlotIndex].iGrade = dwSkillGrade;
m_playerStatus.aSkill[dwSlotIndex].iLevel = dwSkillLevel;
break;
case 1:
m_playerStatus.aSkill[dwSlotIndex].iGrade = dwSkillGrade;
m_playerStatus.aSkill[dwSlotIndex].iLevel = dwSkillLevel-20+1;
m_playerStatus.aSkill[dwSlotIndex].iLevel = dwSkillLevel - 20 + 1;
break;
case 2:
m_playerStatus.aSkill[dwSlotIndex].iGrade = dwSkillGrade;
m_playerStatus.aSkill[dwSlotIndex].iLevel = dwSkillLevel-30+1;
m_playerStatus.aSkill[dwSlotIndex].iLevel = dwSkillLevel - 30 + 1;
break;
case 3:
m_playerStatus.aSkill[dwSlotIndex].iGrade = dwSkillGrade;
m_playerStatus.aSkill[dwSlotIndex].iLevel = dwSkillLevel-40+1;
m_playerStatus.aSkill[dwSlotIndex].iLevel = dwSkillLevel - 40 + 1;
break;
}
const DWORD SKILL_MAX_LEVEL = 40;
if (dwSkillLevel>SKILL_MAX_LEVEL)
if (dwSkillLevel > SKILL_MAX_LEVEL)
{
m_playerStatus.aSkill[dwSlotIndex].fcurEfficientPercentage = 0.0f;
m_playerStatus.aSkill[dwSlotIndex].fnextEfficientPercentage = 0.0f;
TraceError("CPythonPlayer::SetSkillLevel(SlotIndex=%d, SkillLevel=%d)", dwSlotIndex, dwSkillLevel);
return;
}
m_playerStatus.aSkill[dwSlotIndex].fcurEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel)/100.0f;
m_playerStatus.aSkill[dwSlotIndex].fnextEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel+1)/100.0f;
#ifdef FIX_REFRESH_SKILL_COOLDOWN
if (m_playerStatus.aSkill[dwSlotIndex].iLevel <= 0)
{
ResetSkillCoolTimeForSlot(dwSlotIndex);
}
#endif
m_playerStatus.aSkill[dwSlotIndex].fcurEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel) / 100.0f;
m_playerStatus.aSkill[dwSlotIndex].fnextEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel + 1) / 100.0f;
}
void CPythonPlayer::SetSkillCoolTime(DWORD dwSkillIndex)
@@ -1568,7 +1644,19 @@ void CPythonPlayer::NEW_ClearSkillData(bool bAll)
for (it = m_skillSlotDict.begin(); it != m_skillSlotDict.end();)
{
#ifdef FIX_REFRESH_SKILL_COOLDOWN
CPythonSkill::TSkillData* data = nullptr;
if (!CPythonSkill::Instance().GetSkillData(it->first, &data))
{
++it;
continue;
}
if (bAll || (data->byType != CPythonSkill::SKILL_TYPE_SUPPORT && data->byType != CPythonSkill::SKILL_TYPE_HORSE && data->byType != CPythonSkill::SKILL_TYPE_GUILD))
#else
if (bAll || __GetSkillType(it->first) == CPythonSkill::SKILL_TYPE_ACTIVE)
#endif
it = m_skillSlotDict.erase(it);
else
++it;
@@ -1576,6 +1664,24 @@ void CPythonPlayer::NEW_ClearSkillData(bool bAll)
for (int i = 0; i < SKILL_MAX_NUM; ++i)
{
#ifdef FIX_REFRESH_SKILL_COOLDOWN
DWORD dwSkillIndex = m_playerStatus.aSkill[i].dwIndex;
CPythonSkill::TSkillData* pSkillData = NULL;
// Skip empty slots
if (dwSkillIndex == 0)
continue;
if (!CPythonSkill::Instance().GetSkillData(dwSkillIndex, &pSkillData))
continue;
// If not clearing all, skip persistent skill types (SUPPORT, HORSE, GUILD)
if (!bAll && (pSkillData->byType == CPythonSkill::SKILL_TYPE_SUPPORT ||
pSkillData->byType == CPythonSkill::SKILL_TYPE_HORSE ||
pSkillData->byType == CPythonSkill::SKILL_TYPE_GUILD))
continue;
#endif
ZeroMemory(&m_playerStatus.aSkill[i], sizeof(TSkillInstance));
}
@@ -1583,8 +1689,22 @@ void CPythonPlayer::NEW_ClearSkillData(bool bAll)
{
// 2004.09.30.myevan.스킬갱신시 스킬 포인트업[+] 버튼이 안나와 처리
m_playerStatus.aSkill[j].iGrade = 0;
m_playerStatus.aSkill[j].fcurEfficientPercentage=0.0f;
m_playerStatus.aSkill[j].fnextEfficientPercentage=0.05f;
m_playerStatus.aSkill[j].fcurEfficientPercentage = 0.0f;
m_playerStatus.aSkill[j].fnextEfficientPercentage = 0.05f;
#ifdef FIX_REFRESH_SKILL_COOLDOWN
m_playerStatus.aSkill[j].isCoolTime = false;
m_playerStatus.aSkill[j].fCoolTime = 0.0f;
m_playerStatus.aSkill[j].fLastUsedTime = 0.0f;
//ResetSkillCoolTimeForSlot(j);
for (int iGrade = 0; iGrade < CPythonSkill::SKILL_GRADE_COUNT; ++iGrade)
{
UI::CWindowManager::Instance().ClearStoredSlotCoolTimeInAllSlotWindows(
CPythonSkill::SKILL_TYPE_ACTIVE,
j + iGrade * CPythonSkill::SKILL_GRADE_STEP_COUNT);
}
#endif
}
if (m_ppyGameWindow)

View File

@@ -262,6 +262,11 @@ class CPythonPlayer : public CSingleton<CPythonPlayer>, public IAbstractPlayer
void NotifyCharacterUpdate(DWORD dwVID);
void NotifyDeadMainCharacter();
void NotifyChangePKMode();
#ifdef FIX_REFRESH_SKILL_COOLDOWN
void ResetSkillCoolTimes();
void ResetSkillCoolTimeForSlot(DWORD dwSlotIndex);
void ResetHorseSkillCoolTime(DWORD dwSkillIndex, DWORD dwVisualSlotIndex);
#endif
// Player Status

View File

@@ -132,10 +132,26 @@ void CPythonPlayerEventHandler::OnChangeShape()
CPythonPlayer::Instance().NEW_Stop();
}
#ifdef FIX_POS_SYNC
void CPythonPlayerEventHandler::OnHit(UINT uSkill, CActorInstance& rkActorVictim, BOOL isSendPacket, CActorInstance::BlendingPosition* sBlending)
#else
void CPythonPlayerEventHandler::OnHit(UINT uSkill, CActorInstance& rkActorVictim, BOOL isSendPacket)
#endif
{
DWORD dwVIDVictim=rkActorVictim.GetVirtualID();
#ifdef FIX_POS_SYNC
CPythonCharacterManager::Instance().AdjustCollisionWithOtherObjects(&rkActorVictim);
CActorInstance::BlendingPosition kBlendingPacket;
memset(&kBlendingPacket, 0, sizeof(kBlendingPacket));
kBlendingPacket.source = rkActorVictim.NEW_GetCurPixelPositionRef();
if (rkActorVictim.IsPushing()) {
kBlendingPacket.dest = rkActorVictim.NEW_GetLastPixelPositionRef();
kBlendingPacket.duration = sBlending->duration;
}
#endif
// Update Target
CPythonPlayer::Instance().SetTarget(dwVIDVictim, FALSE);
// Update Target
@@ -165,7 +181,11 @@ void CPythonPlayerEventHandler::OnHit(UINT uSkill, CActorInstance& rkActorVictim
s_prevTimed[dwVIDVictim] = curTime;
#endif
CPythonNetworkStream& rkStream=CPythonNetworkStream::Instance();
#ifdef FIX_POS_SYNC
rkStream.SendAttackPacket(uSkill, dwVIDVictim, isSendPacket, kBlendingPacket);
#else
rkStream.SendAttackPacket(uSkill, dwVIDVictim);
#endif
}
if (!rkActorVictim.IsPushing())

View File

@@ -27,7 +27,11 @@ class CPythonPlayerEventHandler : public CActorInstance::IEventHandler
virtual void OnUseSkill(const SState& c_rkState, UINT uMotSkill, UINT uArg);
virtual void OnUpdate();
virtual void OnChangeShape();
#ifdef FIX_POS_SYNC
virtual void OnHit(UINT uSkill, CActorInstance& rkActorVictim, BOOL isSendPacket, CActorInstance::BlendingPosition* sBlending);
#else
virtual void OnHit(UINT uSkill, CActorInstance& rkActorVictim, BOOL isSendPacket);
#endif
void FlushVictimList();

View File

@@ -543,6 +543,31 @@ PyObject * playerGetSkillCoolTime(PyObject* poSelf, PyObject* poArgs)
return Py_BuildValue("ff", fCoolTime, fElapsedCoolTime);
}
#ifdef FIX_REFRESH_SKILL_COOLDOWN
PyObject * playerResetSkillCoolTimeForSlot(PyObject* poSelf, PyObject* poArgs)
{
int iSlotIndex;
if (!PyTuple_GetInteger(poArgs, 0, &iSlotIndex))
return Py_BuildException();
CPythonPlayer::Instance().ResetSkillCoolTimeForSlot(iSlotIndex);
return Py_BuildNone();
}
PyObject* playerResetHorseSkillCoolTime(PyObject* poSelf, PyObject* poArgs)
{
DWORD dwSkillIndex;
DWORD dwVisualSlotIndex;
if (!PyArg_ParseTuple(poArgs, "ii", &dwSkillIndex, &dwVisualSlotIndex))
return Py_BuildException();
CPythonPlayer::Instance().ResetHorseSkillCoolTime(dwSkillIndex, dwVisualSlotIndex);
Py_RETURN_NONE;
}
#endif
PyObject * playerIsSkillActive(PyObject* poSelf, PyObject* poArgs)
{
int iSlotIndex;
@@ -2233,6 +2258,10 @@ void initPlayer()
{ "IsSkillCoolTime", playerIsSkillCoolTime, METH_VARARGS },
{ "GetSkillCoolTime", playerGetSkillCoolTime, METH_VARARGS },
#ifdef FIX_REFRESH_SKILL_COOLDOWN
{ "ResetSkillCoolTimeForSlot", playerResetSkillCoolTimeForSlot, METH_VARARGS },
{ "ResetHorseSkillCoolTime", playerResetHorseSkillCoolTime, METH_VARARGS },
#endif
{ "IsSkillActive", playerIsSkillActive, METH_VARARGS },
{ "UseGuildSkill", playerUseGuildSkill, METH_VARARGS },
{ "AffectIndexToSkillIndex", playerAffectIndexToSkillIndex, METH_VARARGS },