feat: complete native client rendering parity updates

This commit is contained in:
shen
2026-09-27 19:44:41 -07:00
parent 9a9dc6d224
commit 25dd65f2ce
99 changed files with 21121 additions and 921 deletions
@@ -2775,6 +2775,9 @@ void CInstanceBase::ChangeWeapon(DWORD eWeapon)
if (SetWeapon(eWeapon))
RefreshState(CRaceMotionData::NAME_WAIT, true);
if (IsAffect(AFFECT_GEOMGYEONG))
__Warrior_SetGeomgyeongAffect(true);
}
bool CInstanceBase::ChangeArmor(DWORD dwArmor)
@@ -3028,6 +3031,7 @@ void CInstanceBase::__Warrior_Initialize()
void CInstanceBase::__Initialize()
{
__Warrior_Initialize();
memset(m_byAffectGrade, 0, sizeof(m_byAffectGrade));
__StoneSmoke_Inialize();
__EffectContainer_Initialize();
__InitializeRotationSpeed();
@@ -436,6 +436,7 @@ class CInstanceBase
// 스크립트용 테스트 함수. 나중에 없에자
void SCRIPT_SetAffect(UINT eAffect, bool isVisible);
void __Warrior_SetGeomgyeongAffect(bool isVisible);
float CalculateDistanceSq3d(const TPixelPosition& c_rkPPosDst);
@@ -803,7 +804,7 @@ class CInstanceBase
void __ClearMainInstance();
void __Shaman_SetParalysis(bool isParalysis);
void __Warrior_SetGeomgyeongAffect(bool isVisible);
BYTE __GetAffectGrade(UINT eAffect);
void __Assassin_SetEunhyeongAffect(bool isVisible);
void __SetReviveInvisibilityAffect(bool isVisible);
@@ -1045,6 +1046,7 @@ class CInstanceBase
};
SWarrior m_kWarrior;
BYTE m_byAffectGrade[AFFECT_NUM];
void __Warrior_Initialize();
@@ -340,6 +340,66 @@ bool CInstanceBase::NEW_UseSkill(UINT uSkill, UINT uMot, UINT uMotLoopCount, boo
m_GraphicThingInstance.__OnUseSkill(uMot, uMotLoopCount, isMovingSkill);
BYTE bGrade = (uMot >= 25) ? (uMot / 25) : 0;
if (bGrade > 3)
bGrade = 3;
if (uSkill != 0)
{
switch (uSkill)
{
case 3: m_byAffectGrade[AFFECT_JEONGWI] = bGrade; break;
case 4: m_byAffectGrade[AFFECT_GEOMGYEONG] = bGrade; break;
case 19: m_byAffectGrade[AFFECT_CHEONGEUN] = bGrade; break;
case 34: m_byAffectGrade[AFFECT_EUNHYEONG] = bGrade; break;
case 49: m_byAffectGrade[AFFECT_GYEONGGONG] = bGrade; break;
case 63: m_byAffectGrade[AFFECT_GWIGEOM] = bGrade; break;
case 64: m_byAffectGrade[AFFECT_GONGPO] = bGrade; break;
case 65: m_byAffectGrade[AFFECT_JUMAGAP] = bGrade; break;
case 78: m_byAffectGrade[AFFECT_MUYEONG] = bGrade; break;
case 79: m_byAffectGrade[AFFECT_HEUKSIN] = bGrade; break;
case 94: m_byAffectGrade[AFFECT_HOSIN] = bGrade; break;
case 95: m_byAffectGrade[AFFECT_BOHO] = bGrade; break;
case 96: m_byAffectGrade[AFFECT_GICHEON] = bGrade; break;
case 110: m_byAffectGrade[AFFECT_KWAESOK] = bGrade; break;
case 111: m_byAffectGrade[AFFECT_JEUNGRYEOK] = bGrade; break;
}
}
else
{
UINT uMotSub = uMot % 25;
int iJob = RaceToJob(GetRace());
switch (iJob)
{
case NRaceData::JOB_WARRIOR:
if (uMotSub == 3) m_byAffectGrade[AFFECT_JEONGWI] = bGrade;
else if (uMotSub == 4) m_byAffectGrade[AFFECT_GEOMGYEONG] = bGrade;
else if (uMotSub == 19) m_byAffectGrade[AFFECT_CHEONGEUN] = bGrade;
break;
case NRaceData::JOB_ASSASSIN:
if (uMotSub == 4) m_byAffectGrade[AFFECT_EUNHYEONG] = bGrade;
else if (uMotSub == 19) m_byAffectGrade[AFFECT_GYEONGGONG] = bGrade;
break;
case NRaceData::JOB_SURA:
if (uMotSub == 3) m_byAffectGrade[AFFECT_GWIGEOM] = bGrade;
else if (uMotSub == 4) m_byAffectGrade[AFFECT_GONGPO] = bGrade;
else if (uMotSub == 5) m_byAffectGrade[AFFECT_JUMAGAP] = bGrade;
else if (uMotSub == 18) m_byAffectGrade[AFFECT_MUYEONG] = bGrade;
else if (uMotSub == 19) m_byAffectGrade[AFFECT_HEUKSIN] = bGrade;
break;
case NRaceData::JOB_SHAMAN:
if (uMotSub == 4) m_byAffectGrade[AFFECT_HOSIN] = bGrade;
else if (uMotSub == 5) m_byAffectGrade[AFFECT_BOHO] = bGrade;
else if (uMotSub == 6) m_byAffectGrade[AFFECT_GICHEON] = bGrade;
else if (uMotSub == 20) m_byAffectGrade[AFFECT_KWAESOK] = bGrade;
else if (uMotSub == 21) m_byAffectGrade[AFFECT_JEUNGRYEOK] = bGrade;
break;
}
}
if (IsAffect(AFFECT_GEOMGYEONG))
__Warrior_SetGeomgyeongAffect(true);
if (uMotLoopCount > 0)
m_GraphicThingInstance.SetMotionLoopCount(uMotLoopCount);
@@ -825,6 +825,29 @@ void CInstanceBase::__Shaman_SetParalysis(bool isParalysis)
BYTE CInstanceBase::__GetAffectGrade(UINT eAffect)
{
if (__IsMainInstance())
{
DWORD dwSkillIndex = 0;
if (CPythonPlayer::Instance().AffectIndexToSkillIndex(eAffect, &dwSkillIndex))
{
DWORD dwSkillSlotIndex = 0;
if (CPythonPlayer::Instance().GetSkillSlotIndex(dwSkillIndex, &dwSkillSlotIndex))
{
int iGrade = CPythonPlayer::Instance().GetSkillGrade(dwSkillSlotIndex);
if (iGrade >= 0 && iGrade < 4)
return (BYTE)iGrade;
}
}
}
if (eAffect < AFFECT_NUM)
return m_byAffectGrade[eAffect];
return 0;
}
void CInstanceBase::__Warrior_SetGeomgyeongAffect(bool isVisible)
{
if (isVisible)
@@ -836,10 +859,38 @@ void CInstanceBase::__Warrior_SetGeomgyeongAffect(bool isVisible)
__DetachEffect(m_kWarrior.m_dwGeomgyeongEffect);
m_GraphicThingInstance.SetReachScale(1.5f);
if (m_GraphicThingInstance.IsTwoHandMode())
m_kWarrior.m_dwGeomgyeongEffect=__AttachEffect(EFFECT_WEAPON+WEAPON_TWOHAND);
BYTE bGrade = __GetAffectGrade(AFFECT_GEOMGYEONG);
if (bGrade >= 4)
bGrade = 3;
static const char * c_szGeomSpearFiles[4] = {
"d:/ymir work/pc/warrior/effect/geom_spear_loop.mse",
"d:/ymir work/pc/warrior/effect/geom_2_spear_loop.mse",
"d:/ymir work/pc/warrior/effect/geom_3_spear_loop.mse",
"d:/ymir work/pc/warrior/effect/geom_4_spear_loop.mse"
};
static const char * c_szGeomSwordFiles[4] = {
"d:/ymir work/pc/warrior/effect/geom_sword_loop.mse",
"d:/ymir work/pc/warrior/effect/geom_2_sword_loop.mse",
"d:/ymir work/pc/warrior/effect/geom_3_sword_loop.mse",
"d:/ymir work/pc/warrior/effect/geom_4_sword_loop.mse"
};
const char * c_szFileName = m_GraphicThingInstance.IsTwoHandMode() ? c_szGeomSpearFiles[bGrade] : c_szGeomSwordFiles[bGrade];
DWORD dwEffectCRC = 0;
if (CEffectManager::Instance().RegisterEffect2(c_szFileName, &dwEffectCRC, true))
{
m_kWarrior.m_dwGeomgyeongEffect = m_GraphicThingInstance.AttachEffectByID(0, "equip_right_hand", dwEffectCRC);
}
else
m_kWarrior.m_dwGeomgyeongEffect=__AttachEffect(EFFECT_WEAPON+WEAPON_ONEHAND);
{
if (m_GraphicThingInstance.IsTwoHandMode())
m_kWarrior.m_dwGeomgyeongEffect = __AttachEffect(EFFECT_WEAPON + WEAPON_TWOHAND);
else
m_kWarrior.m_dwGeomgyeongEffect = __AttachEffect(EFFECT_WEAPON + WEAPON_ONEHAND);
}
}
else
{
@@ -1033,6 +1084,129 @@ DWORD CInstanceBase::__AttachEffect(UINT eEftType)
if (eEftType>=EFFECT_NUM)
return 0;
if (eEftType >= EFFECT_AFFECT && eEftType < EFFECT_AFFECT_END)
{
UINT eAffect = eEftType - EFFECT_AFFECT;
BYTE bGrade = __GetAffectGrade(eAffect);
if (bGrade >= 4)
bGrade = 3;
const char * c_szFileName = NULL;
const char * c_szBoneName = NULL;
switch (eAffect)
{
case AFFECT_GWIGEOM:
{
static const char * c_szGwigeomFiles[4] = {
"d:/ymir work/pc/sura/effect/gwigeom_loop.mse",
"d:/ymir work/pc/sura/effect/gwigeom_2_loop.mse",
"d:/ymir work/pc/sura/effect/gwigeom_3_loop.mse",
"d:/ymir work/pc/sura/effect/gwigeom_4_loop.mse"
};
c_szFileName = c_szGwigeomFiles[bGrade];
c_szBoneName = "Bip01 R Finger2";
break;
}
case AFFECT_GONGPO:
{
static const char * c_szFearFiles[4] = {
"d:/ymir work/pc/sura/effect/fear_loop.mse",
"d:/ymir work/pc/sura/effect/fear_2_loop.mse",
"d:/ymir work/pc/sura/effect/fear_3_loop.mse",
"d:/ymir work/pc/sura/effect/fear_3_loop.mse"
};
c_szFileName = c_szFearFiles[bGrade];
c_szBoneName = "";
break;
}
case AFFECT_JUMAGAP:
{
static const char * c_szJumagapFiles[4] = {
"d:/ymir work/pc/sura/effect/jumagap_loop.mse",
"d:/ymir work/pc/sura/effect/jumagap_2_loop.mse",
"d:/ymir work/pc/sura/effect/jumagap_3_loop.mse",
"d:/ymir work/pc/sura/effect/jumagap_4_loop.mse"
};
c_szFileName = c_szJumagapFiles[bGrade];
c_szBoneName = "";
break;
}
case AFFECT_HEUKSIN:
{
static const char * c_szHeuksinFiles[4] = {
"d:/ymir work/pc/sura/effect/heuksin_loop.mse",
"d:/ymir work/pc/sura/effect/heuksin_2_loop.mse",
"d:/ymir work/pc/sura/effect/heuksin_3_loop.mse",
"d:/ymir work/pc/sura/effect/heuksin_4_loop.mse"
};
c_szFileName = c_szHeuksinFiles[bGrade];
c_szBoneName = "";
break;
}
case AFFECT_HOSIN:
{
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/3hosin_loop_4.mse" : "d:/ymir work/pc/shaman/effect/3hosin_loop.mse";
c_szBoneName = "";
break;
}
case AFFECT_BOHO:
{
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/boho_loop_4.mse" : "d:/ymir work/pc/shaman/effect/boho_loop.mse";
c_szBoneName = "";
break;
}
case AFFECT_GYEONGGONG:
{
static const char * c_szGyeonggongFiles[4] = {
"d:/ymir work/pc/assassin/effect/gyeonggong_loop.mse",
"d:/ymir work/pc/assassin/effect/gyeonggong_2_loop.mse",
"d:/ymir work/pc/assassin/effect/gyeonggong_3_loop.mse",
"d:/ymir work/pc/assassin/effect/gyeonggong_4_loop.mse"
};
c_szFileName = c_szGyeonggongFiles[bGrade];
c_szBoneName = "";
break;
}
case AFFECT_CHEONGEUN:
{
static const char * c_szCheongeunFiles[4] = {
"d:/ymir work/pc/warrior/effect/gyeokgongjang_loop.mse",
"d:/ymir work/pc/warrior/effect/gyeokgongjang_2_loop.mse",
"d:/ymir work/pc/warrior/effect/gyeokgongjang_3_loop.mse",
"d:/ymir work/pc/warrior/effect/gyeokgongjang_3_loop.mse"
};
c_szFileName = c_szCheongeunFiles[bGrade];
c_szBoneName = "";
break;
}
case AFFECT_GICHEON:
{
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/6gicheon_hand_4.mse" : "d:/ymir work/pc/shaman/effect/6gicheon_hand.mse";
c_szBoneName = "Bip01 R Hand";
break;
}
case AFFECT_JEUNGRYEOK:
{
c_szFileName = (bGrade >= 3) ? "d:/ymir work/pc/shaman/effect/jeungryeok_hand_4.mse" : "d:/ymir work/pc/shaman/effect/jeungryeok_hand.mse";
c_szBoneName = "Bip01 L Hand";
break;
}
default:
break;
}
if (c_szFileName)
{
DWORD dwEffectCRC = 0;
if (CEffectManager::Instance().RegisterEffect2(c_szFileName, &dwEffectCRC, true))
{
const char * bone = (c_szBoneName && c_szBoneName[0]) ? c_szBoneName : NULL;
return m_GraphicThingInstance.AttachEffectByID(0, bone, dwEffectCRC);
}
}
}
if (ms_astAffectEffectAttachBone[eEftType].empty())
{
return m_GraphicThingInstance.AttachEffectByID(0, NULL, ms_adwCRCAffectEffect[eEftType]);
@@ -274,17 +274,7 @@ class CPythonApplication final : public CMSApplication, public CInputKeyboard, p
int m_nLeft, m_nRight, m_nTop, m_nBottom;
protected:
LRESULT WindowProcedure(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
void OnCameraUpdate();
void OnUIUpdate();
void OnUIRender();
void OnMouseUpdate();
void OnMouseRender();
public:
void OnMouseWheel(int nLen);
void OnMouseMove(int x, int y);
void OnMouseMiddleButtonDown(int x, int y);
@@ -299,6 +289,17 @@ class CPythonApplication final : public CMSApplication, public CInputKeyboard, p
void OnKeyUp(int iIndex);
void OnIMEKeyDown(int iIndex);
protected:
LRESULT WindowProcedure(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
void OnCameraUpdate();
void OnUIUpdate();
void OnUIRender();
void OnMouseUpdate();
void OnMouseRender();
int CheckDeviceState();
BOOL __IsContinuousChangeTypeCursor(int iCursorNum);
@@ -254,10 +254,34 @@ void CPythonBackground::__CreateProperty()
{
// The exported client runs with player settings as CWD; its read-only property pack
// lives beside the other bundled 40250 packs. Use the same root registered by PackBackend.
std::string property_pack = "pack/property";
std::vector<std::string> candidates;
if (const char* client = getenv("MT_40250_CLIENT"))
property_pack = std::string(client) + "/pack/Property";
m_PropertyManager.Initialize(property_pack.c_str());
{
candidates.push_back(std::string(client) + "/pack/Property");
candidates.push_back(std::string(client) + "/pack/property");
}
candidates.push_back("pack/Property");
candidates.push_back("pack/property");
candidates.push_back("Client/pack/Property");
candidates.push_back("Client/pack/property");
bool initialized = false;
for (const auto& path : candidates)
{
std::string eix = path + ".eix";
if (_access(eix.c_str(), 0) == 0)
{
if (m_PropertyManager.Initialize(path.c_str()))
{
initialized = true;
break;
}
}
}
if (!initialized && !candidates.empty())
{
m_PropertyManager.Initialize(candidates.front().c_str());
}
}
}
@@ -735,6 +735,11 @@ void CPythonCharacterManager::__SortPickedActorList()
std::sort(m_kVct_pkInstPicked.begin(), m_kVct_pkInstPicked.end(), kLess);
}
void CPythonCharacterManager::Pick()
{
__NEW_Pick();
}
void CPythonCharacterManager::__NEW_Pick()
{
__UpdateSortPickedActorList();
@@ -773,31 +778,10 @@ void CPythonCharacterManager::__NEW_Pick()
}
}
// 못찾겠으면 걍 순서대로
{
std::vector<CInstanceBase*>::iterator f;
for (f=m_kVct_pkInstPicked.begin(); f!=m_kVct_pkInstPicked.end(); ++f)
{
CInstanceBase* pkInstEach=*f;
if (pkInstEach!=pkInstMain)
{
if (m_pkInstPick)
if (m_pkInstPick!=pkInstEach)
m_pkInstPick->OnUnselected();
if (pkInstEach->CanPickInstance())
{
m_pkInstPick = pkInstEach;
m_pkInstPick->OnSelected();
return;
}
}
}
}
if (pkInstMain)
if (pkInstMain->CanPickInstance())
if (m_kVct_pkInstPicked.end() != std::find(m_kVct_pkInstPicked.begin(), m_kVct_pkInstPicked.end(), pkInstMain))
if (pkInstMain->IntersectBoundingBox())
{
if (m_pkInstPick)
if (m_pkInstPick!=pkInstMain)
@@ -85,6 +85,7 @@ class CPythonCharacterManager : public CSingleton<CPythonCharacterManager>, publ
CInstanceBase * GetInstancePtrByName(const char *name);
// Pick
void Pick();
int PickAll();
CInstanceBase * GetCloseInstance(CInstanceBase * pInstance);
@@ -1037,6 +1037,25 @@ void CPythonPlayer::SetSkillLevel_(DWORD dwSkillIndex, DWORD dwSkillGrade, DWORD
m_playerStatus.aSkill[dwSlotIndex].fcurEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel)/100.0f;
m_playerStatus.aSkill[dwSlotIndex].fnextEfficientPercentage = LocaleService_GetSkillPower(dwSkillLevel+1)/100.0f;
CInstanceBase * pkInstMain = NEW_GetMainActorPtr();
if (pkInstMain)
{
if (dwSkillIndex == 4 && pkInstMain->IsAffect(CInstanceBase::AFFECT_GEOMGYEONG))
{
pkInstMain->__Warrior_SetGeomgyeongAffect(true);
}
else
{
for (std::map<DWORD, DWORD>::const_iterator it = m_kMap_dwAffectIndexToSkillIndex.begin(); it != m_kMap_dwAffectIndexToSkillIndex.end(); ++it)
{
if (it->second == dwSkillIndex && pkInstMain->IsAffect(it->first))
{
pkInstMain->SCRIPT_SetAffect(it->first, false);
pkInstMain->SCRIPT_SetAffect(it->first, true);
}
}
}
}
}
void CPythonPlayer::SetSkillCoolTime(DWORD dwSkillIndex)
@@ -12,7 +12,7 @@ std::map<std::string, DWORD> CPythonSkill::SSkillData::ms_NewMinStatusNameMap;
std::map<std::string, DWORD> CPythonSkill::SSkillData::ms_NewMaxStatusNameMap;
DWORD CPythonSkill::SSkillData::ms_dwTimeIncreaseSkillNumber = 0;
BOOL SKILL_EFFECT_UPGRADE_ENABLE = FALSE;
BOOL SKILL_EFFECT_UPGRADE_ENABLE = TRUE;
int SplitLine(const char * c_szText, CTokenVector* pstTokenVector, const char * c_szDelimeter)
{