Merge pull request #40 from MindRapist/mr-3

MR-3: Bunch of fixes
This commit is contained in:
rtw1x1
2025-12-25 16:00:54 +00:00
committed by GitHub
9 changed files with 60 additions and 10 deletions

View File

@@ -10,7 +10,10 @@ This repository contains the source code necessary to compile the game client ex
---
## Changelog 📋
## 📋 Changelog
### 🐛 Bug Fixes
* **Realtime Character Level Updates:** Implemented the reversed fix (credits to Mali) for updating character level in real-time across game view and all windows (such as Guild window) for all viewing players.
* **Shaman Mounted Combat:** Fixed a bug that wrongly calculated Shaman characters mounted hits that didn't collide with the target to cause damage when attack speed was had an extremely high value.
* **Invisibility VFX Logic:** Fixed an issue where skill visual effects remained visible to the character while under the `AFFECT_INVISIBLE` state.
* **Buff Effects Visibility Recovery:** Fixed an issue where buff skill visual effects remained invisible if the skill was cast while the character was under the `AFFECT_INVISIBLE` state.
* **Casting Speed Cooldowns:** Fixed an issue where Casting Speed was not properly calculated in skill cooldowns. The system now supports real-time calculation updates whenever the bonus value changes.

View File

@@ -270,6 +270,7 @@ void CEffectInstance::Clear()
void CEffectInstance::__Initialize()
{
ReleaseAlwaysHidden();
m_isAlive = FALSE;
m_dwFrame = 0;
m_pSoundInstanceVector = NULL;

View File

@@ -484,15 +484,18 @@ DWORD CEffectManager::GetSelectedEffectDataCRC() const
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());
}

View File

@@ -285,9 +285,7 @@ void CGraphicObjectInstance::Initialize()
m_isVisible = TRUE;
m_BlockCamera = false;
m_isAlwaysHidden = false;
m_v3Position.x = m_v3Position.y = m_v3Position.z = 0.0f;
m_v3Scale.x = m_v3Scale.y = m_v3Scale.z = 1.0f;

View File

@@ -60,7 +60,6 @@ class CGraphicObjectInstance : public CGraphicCollisionObject
void ApplyAlwaysHidden();
void ReleaseAlwaysHidden();
// Camera Block
void BlockCamera(bool bBlock) {m_BlockCamera = bBlock;}
bool BlockCamera() { return m_BlockCamera; }

View File

@@ -362,6 +362,7 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
BOOL IsActEmotion();
DWORD GetComboIndex();
float GetAttackingElapsedTime();
void SetBlendingPosition(const TPixelPosition & c_rPosition, float fBlendingTime = 1.0f);
void ResetBlendingPosition();
void GetBlendingPosition(TPixelPosition * pPosition);
@@ -607,6 +608,9 @@ class CActorInstance : public IActorInstance, public IFlyTargetableObject
void __ProcessMotionEventAttackSuccess(DWORD dwMotionKey, BYTE byEventIndex, CActorInstance & rVictim);
void __ProcessMotionAttackSuccess(DWORD dwMotionKey, CActorInstance & rVictim);
// MR-3: Shaman on-mount hitting fix
float __GetInvisibleTimeAdjust(const UINT uiSkill, const NRaceData::TAttackData& c_rAttackData);
// MR-3: -- END OF -- Shaman on-mount hitting fix
void __HitStone(CActorInstance& rVictim);
void __HitGood(CActorInstance& rVictim);

View File

@@ -620,19 +620,21 @@ void CActorInstance::__ProcessDataAttackSuccess(const NRaceData::TAttackData & c
// VICTIM_COLLISION_TEST_END
}
// MR-3: Shaman on-mount hitting fix
// Invisible Time
if (IS_PARTY_HUNTING_RACE(rVictim.GetRace()))
{
if (uiSkill) // 파티 사냥 몬스터라도 스킬이면 무적시간 적용
rVictim.m_fInvisibleTime = CTimer::Instance().GetCurrentSecond() + c_rAttackData.fInvisibleTime;
rVictim.m_fInvisibleTime = CTimer::Instance().GetCurrentSecond() + (c_rAttackData.fInvisibleTime - __GetInvisibleTimeAdjust(uiSkill, c_rAttackData));
if (m_isMain) // #0000794: [M2KR] 폴리모프 - 밸런싱 문제 타인 공격에 의한 무적 타임은 고려하지 않고 자신 공격에 의한것만 체크한다
rVictim.m_fInvisibleTime = CTimer::Instance().GetCurrentSecond() + c_rAttackData.fInvisibleTime;
rVictim.m_fInvisibleTime = CTimer::Instance().GetCurrentSecond() + (c_rAttackData.fInvisibleTime - __GetInvisibleTimeAdjust(uiSkill, c_rAttackData));
}
else // 파티 사냥 몬스터가 아닐 경우만 적용
{
rVictim.m_fInvisibleTime = CTimer::Instance().GetCurrentSecond() + c_rAttackData.fInvisibleTime;
rVictim.m_fInvisibleTime = CTimer::Instance().GetCurrentSecond() + (c_rAttackData.fInvisibleTime - __GetInvisibleTimeAdjust(uiSkill, c_rAttackData));
}
// MR-3: -- END OF -- Shaman on-mount hitting fix
// Stiffen Time
rVictim.InsertDelay(c_rAttackData.fStiffenTime);
@@ -964,3 +966,19 @@ void CActorInstance::__SetFallingDirection(float fx, float fy)
{
m_PhysicsObject.SetDirection(D3DXVECTOR3(fx, fy, 0.0f));
}
// MR-3: Shaman on-mount hitting fix
float CActorInstance::__GetInvisibleTimeAdjust(const UINT uiSkill, const NRaceData::TAttackData& c_rAttackData) {
static const int shamanw = 3, shamanm = 7;
if ((GetRace() != shamanw && GetRace() != shamanm) ||
uiSkill != 0 ||
m_fAtkSpd < 1.3)
return 0.0f;
const auto scale = (m_fAtkSpd - 1.3) / 1.3;
const auto inv = c_rAttackData.fInvisibleTime * 0.5;
return inv * scale;
}
// MR-3: -- END OF -- Shaman on-mount hitting fix

View File

@@ -1978,9 +1978,10 @@ void CInstanceBase::Render()
if (pkInstEach)
{
// MR-3: Invisibility fix
if (pkInstEach->IsAffect(AFFECT_INVISIBILITY) || pkInstEach->IsAffect(AFFECT_EUNHYEONG) || pkInstEach->IsAffect(AFFECT_REVIVE_INVISIBILITY))
{
if (CPythonPlayer::Instance().IsMainCharacterIndex(pkInstEach->GetVirtualID()))
if (CPythonPlayer::Instance().IsMainCharacterIndex(pkInstEach->GetVirtualID()) && !pkInstEach->IsAffect(AFFECT_INVISIBILITY))
continue;
if (pkInstEach->IsAffect(AFFECT_EUNHYEONG) && !pkInstEach->IsAffect(AFFECT_INVISIBILITY) && !pkInstEach->IsAffect(AFFECT_REVIVE_INVISIBILITY))
@@ -1988,6 +1989,11 @@ void CInstanceBase::Render()
else
pkInstEach->m_GraphicThingInstance.HideAllAttachingEffect();
}
else
{
pkInstEach->m_GraphicThingInstance.ShowAllAttachingEffect();
}
// MR-3: -- END OF -- Invisibility fix
}
}

View File

@@ -1662,18 +1662,36 @@ PyObject * skillGetSkillAffectDescription(PyObject * poSelf, PyObject * poArgs)
PyObject * skillGetSkillCoolTime(PyObject * poSelf, PyObject * poArgs)
{
int iSkillIndex;
if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex))
return Py_BadArgument();
float fSkillPoint;
if (!PyTuple_GetFloat(poArgs, 1, &fSkillPoint))
return Py_BadArgument();
CPythonSkill::SSkillData * c_pSkillData;
if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData))
return Py_BuildException("skill.GetSkillCoolTime - Failed to find skill by %d", iSkillIndex);
return Py_BuildValue("i", c_pSkillData->GetSkillCoolTime(fSkillPoint));
// MR-3: Calculate casting speed bonus on skill cool time
DWORD dwSkillCoolTime = c_pSkillData->GetSkillCoolTime(fSkillPoint);
int iCastingSpeed = CPythonPlayer::Instance().GetStatus(POINT_CASTING_SPEED);
int iSpd = 100 - iCastingSpeed;
if (iSpd > 0)
iSpd = 100 + iSpd;
else if (iSpd < 0)
iSpd = 10000 / (100 - iSpd);
else
iSpd = 100;
dwSkillCoolTime = dwSkillCoolTime * iSpd / 100;
return Py_BuildValue("i", dwSkillCoolTime);
// MR-3: -- END OF -- Calculate casting speed bonus on skill cool time
}
PyObject * skillGetSkillNeedSP(PyObject * poSelf, PyObject * poArgs)