From 03de3f314a499d69f956470f2ff60e5e73dd2147 Mon Sep 17 00:00:00 2001 From: shenlei Date: Thu, 24 Sep 2026 03:07:15 +0900 Subject: [PATCH] port: CPythonSkill + skill module + EterBase/Poly (1:1 40250) Copy PythonSkill.cpp and the EterBase/Poly formula parser verbatim, drop the pending stand-in and the skill module stub, register initskill() after initfly() and build CPythonSkill in m_pySkill's place. LoadLocaleData now loads skilldesc/skilltable. Skill and item icon handles go through Py_BuildPointer/PyTuple_GetPointer (ILP32 ints truncate 64-bit pointers). Co-Authored-By: Claude Opus 5.5 --- audit/history.jsonl | 1 + audit/port-map/EterBase/Poly/Base.cpp.json | 38 + audit/port-map/EterBase/Poly/Poly.cpp.json | 152 ++ .../port-map/EterBase/Poly/SymTable.cpp.json | 20 + audit/port-map/EterBase/Poly/Symbol.cpp.json | 50 + .../UserInterface/PythonApplication.cpp.json | 4 +- .../UserInterface/PythonItemModule.cpp.json | 12 +- .../UserInterface/PythonSkill.cpp.json | 608 +++++ docs/PORT-PLAN.md | 2 + .../ScriptLib/GameplayModuleConstants.cpp | 15 - .../platform/ScriptLib/GameplayModules.cpp | 90 - .../src/platform/ScriptLib/PythonBoot.cpp | 3 + .../UserInterface/PythonApplication.cpp | 4 +- .../pending/UserInterface/PythonSkill.cpp | 210 -- extension/src/port/EterBase/Poly/Base.cpp | 27 + extension/src/port/EterBase/Poly/Base.h | 25 + extension/src/port/EterBase/Poly/Poly.cpp | 622 +++++ extension/src/port/EterBase/Poly/StdAfx.h | 2 + extension/src/port/EterBase/Poly/SymTable.cpp | 11 + extension/src/port/EterBase/Poly/Symbol.cpp | 50 + extension/src/port/EterBase/Poly/Symbol.h | 39 + .../port/UserInterface/PythonItemModule.cpp | 6 +- .../src/port/UserInterface/PythonSkill.cpp | 2259 +++++++++++++++++ extension/src/port/UserInterface/StdAfx.h | 1 + extension/tests/port_login_flow_test.cpp | 21 +- 25 files changed, 3944 insertions(+), 328 deletions(-) create mode 100644 audit/port-map/EterBase/Poly/Base.cpp.json create mode 100644 audit/port-map/EterBase/Poly/Poly.cpp.json create mode 100644 audit/port-map/EterBase/Poly/SymTable.cpp.json create mode 100644 audit/port-map/EterBase/Poly/Symbol.cpp.json create mode 100644 audit/port-map/UserInterface/PythonSkill.cpp.json delete mode 100644 extension/src/platform/pending/UserInterface/PythonSkill.cpp create mode 100644 extension/src/port/EterBase/Poly/Base.cpp create mode 100644 extension/src/port/EterBase/Poly/Base.h create mode 100644 extension/src/port/EterBase/Poly/Poly.cpp create mode 100644 extension/src/port/EterBase/Poly/StdAfx.h create mode 100644 extension/src/port/EterBase/Poly/SymTable.cpp create mode 100644 extension/src/port/EterBase/Poly/Symbol.cpp create mode 100644 extension/src/port/EterBase/Poly/Symbol.h create mode 100644 extension/src/port/UserInterface/PythonSkill.cpp diff --git a/audit/history.jsonl b/audit/history.jsonl index 627d4774..cebccfe1 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -535,3 +535,4 @@ {"time": "2026-09-24T08:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-c: PythonExchange + PythonExchangeModule", "ported": ["UserInterface/PythonExchange.cpp", "UserInterface/PythonExchangeModule.cpp"], "adapted": [], "divergent": [], "needs_live": ["exchange with a real second player"], "tests": ["port.login_flow: net.SendExchangeStartPacket -> fake GC_EXCHANGE START/ITEM_ADD/GOLD_ADD fills target side, uiexchange opens; SendExchangeExitPacket -> END closes", "port.login_live 192.168.21.203: passes", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["PythonTextTail item tails", "PythonMiniMap", "CEffectManager", "CPythonSkill"]} {"time": "2026-09-24T09:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-d: PythonTextTail + textTail module", "ported": ["UserInterface/PythonTextTail.cpp", "UserInterface/PythonTextTailModule.cpp"], "adapted": ["EterLib/GrpScreen.cpp:CScreen::ProjectPosition", "EterLib/GrpScreen.cpp:CScreen::UnprojectPosition", "UserInterface/UserInterface.cpp:ApplicationStringTable_GetString", "UserInterface/UserInterface.cpp:ApplicationStringTable_GetStringz"], "divergent": [], "needs_live": [], "tests": ["port.login_flow: ground item name tail registered, ALT frame projects it, CPythonTextTail::Pick returns the item VID, deleted on pickup", "port.login_live 192.168.21.203: passes", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["PythonMiniMap", "CEffectManager", "CPythonSkill"]} {"time": "2026-09-24T10:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-e: PythonMiniMap + miniMap module", "ported": ["UserInterface/PythonMiniMap.cpp", "UserInterface/PythonMiniMapModule.cpp", "PRTerrainLib/StdAfx.cpp"], "adapted": [], "divergent": ["GameLib/MapManager.cpp:CMapManager::IsMapOutdoor (false until CMapOutdoor is ported)"], "needs_live": [], "tests": ["port.login_flow: miniMap.isShow() after uiminimap, GetAtlasSize() not loaded", "port.login_live 192.168.21.203: passes", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["CMapOutdoor (minimap terrain textures, atlas)", "CEffectManager", "CPythonSkill"]} +{"time": "2026-09-24T12:00:00Z", "event": "port_round", "unit": "batch 3-a: CPythonSkill + skill module + EterBase/Poly", "ported": ["UserInterface/PythonSkill.cpp", "EterBase/Poly/Base.cpp", "EterBase/Poly/Poly.cpp", "EterBase/Poly/SymTable.cpp", "EterBase/Poly/Symbol.cpp"], "adapted": ["PythonSkill.cpp: icon handle functions (Py_BuildPointer), skillGetGradeData (varargs struct)", "PythonItemModule.cpp: itemGetIconInstance/itemDeleteIconInstance (Py_BuildPointer)"], "divergent": [], "needs_live": [], "tests": ["port.login_flow: skill 1 name/type/cooltime after LoadLocaleData; grade icon + icon instance in game", "port.login_live 192.168.21.203 passes", "ctest 19/19, python_game_render_test PASS", "port_map check 0 errors"], "todo": ["EffectLib", "CMapOutdoor", "default route switch"]} diff --git a/audit/port-map/EterBase/Poly/Base.cpp.json b/audit/port-map/EterBase/Poly/Base.cpp.json new file mode 100644 index 00000000..da3217e9 --- /dev/null +++ b/audit/port-map/EterBase/Poly/Base.cpp.json @@ -0,0 +1,38 @@ +{ + "reference": "EterBase/Poly/Base.cpp", + "reference_sha256": "44777e6173df4d43f20730d2a241ecb5a2576561cb5c49d89645ab83f119aa6d", + "priority": "P4", + "contracts": [], + "functions": { + "CBase::CBase": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Base.cpp:CBase::CBase" + ] + }, + "CBase::~CBase": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Base.cpp:CBase::~CBase" + ] + }, + "CBase::isNumber": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Base.cpp:CBase::isNumber" + ] + }, + "CBase::isVar": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Base.cpp:CBase::isVar" + ] + }, + "CBase::isSymbol": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Base.cpp:CBase::isSymbol" + ] + } + } +} diff --git a/audit/port-map/EterBase/Poly/Poly.cpp.json b/audit/port-map/EterBase/Poly/Poly.cpp.json new file mode 100644 index 00000000..48a44db2 --- /dev/null +++ b/audit/port-map/EterBase/Poly/Poly.cpp.json @@ -0,0 +1,152 @@ +{ + "reference": "EterBase/Poly/Poly.cpp", + "reference_sha256": "1ca53bed299366c916408e02c9e23b4a799134b63174bab9246d2d79e75b7a3c", + "priority": "P4", + "contracts": [], + "functions": { + "_random": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:_random" + ] + }, + "CPoly::SetRandom": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::SetRandom" + ] + }, + "CPoly::my_irandom": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::my_irandom" + ] + }, + "CPoly::my_frandom": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::my_frandom" + ] + }, + "CPoly::CPoly": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::CPoly" + ] + }, + "CPoly::~CPoly": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::~CPoly" + ] + }, + "CPoly::SetStr": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::SetStr" + ] + }, + "CPoly::Eval": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::Eval" + ] + }, + "CPoly::Analyze": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::Analyze" + ] + }, + "CPoly::Clear": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::Clear" + ] + }, + "CPoly::expr": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::expr" + ] + }, + "CPoly::error": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::error" + ] + }, + "CPoly::lexan": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::lexan" + ] + }, + "CPoly::term": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::term" + ] + }, + "CPoly::factor": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::factor" + ] + }, + "CPoly::expo": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::expo" + ] + }, + "CPoly::match": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::match" + ] + }, + "CPoly::emit": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::emit" + ] + }, + "CPoly::find": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::find" + ] + }, + "CPoly::insert": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::insert" + ] + }, + "CPoly::SetVar": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::SetVar" + ] + }, + "CPoly::GetVarCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::GetVarCount" + ] + }, + "CPoly::GetVarName": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::GetVarName" + ] + }, + "CPoly::init": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Poly.cpp:CPoly::init" + ] + } + } +} diff --git a/audit/port-map/EterBase/Poly/SymTable.cpp.json b/audit/port-map/EterBase/Poly/SymTable.cpp.json new file mode 100644 index 00000000..7f2cab5d --- /dev/null +++ b/audit/port-map/EterBase/Poly/SymTable.cpp.json @@ -0,0 +1,20 @@ +{ + "reference": "EterBase/Poly/SymTable.cpp", + "reference_sha256": "055323b1fbc4360c9f751089eb537afabb42343d19b65439dbe7d2a2a47d2fb4", + "priority": "P4", + "contracts": [], + "functions": { + "CSymTable::CSymTable": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/SymTable.cpp:CSymTable::CSymTable" + ] + }, + "CSymTable::~CSymTable": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/SymTable.cpp:CSymTable::~CSymTable" + ] + } + } +} diff --git a/audit/port-map/EterBase/Poly/Symbol.cpp.json b/audit/port-map/EterBase/Poly/Symbol.cpp.json new file mode 100644 index 00000000..d6d74d5d --- /dev/null +++ b/audit/port-map/EterBase/Poly/Symbol.cpp.json @@ -0,0 +1,50 @@ +{ + "reference": "EterBase/Poly/Symbol.cpp", + "reference_sha256": "018d4ee2824ccf9b10c859650ff22e47d815c03d958caa7490acc4c90479a032", + "priority": "P4", + "contracts": [], + "functions": { + "CSymbol::CSymbol": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Symbol.cpp:CSymbol::CSymbol" + ] + }, + "CSymbol::~CSymbol": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Symbol.cpp:CSymbol::~CSymbol" + ] + }, + "CSymbol::Equal": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Symbol.cpp:CSymbol::Equal" + ] + }, + "CSymbol::Less": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Symbol.cpp:CSymbol::Less" + ] + }, + "CSymbol::GetType": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Symbol.cpp:CSymbol::GetType" + ] + }, + "CSymbol::SetType": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Symbol.cpp:CSymbol::SetType" + ] + }, + "CSymbol::issymbol": { + "status": "PORTED", + "impl": [ + "extension/src/port/EterBase/Poly/Symbol.cpp:CSymbol::issymbol" + ] + } + } +} diff --git a/audit/port-map/UserInterface/PythonApplication.cpp.json b/audit/port-map/UserInterface/PythonApplication.cpp.json index 5fceb77b..8d18c6ca 100644 --- a/audit/port-map/UserInterface/PythonApplication.cpp.json +++ b/audit/port-map/UserInterface/PythonApplication.cpp.json @@ -63,8 +63,8 @@ "impl": [ "extension/src/platform/UserInterface/PythonApplication.cpp:LoadLocaleData" ], - "note": "Body verbatim in the platform CPythonApplication stand-in; CPythonSkill is still pending, so RegisterSkillDesc fails and it returns false after the item and mob tables load (localeinfo.py ignores the result).", - "test": "extension/tests/port_login_flow_test.cpp step 3c (port.login_flow / port.login_live: item 19 Sword+9, mob 101 Wild Dog)" + "note": "Body verbatim in the platform CPythonApplication stand-in (the class itself is not ported); it reads item/mob tables and CPythonSkill's skilldesc/skilltable.", + "test": "extension/tests/port_login_flow_test.cpp step 3c (port.login_flow / port.login_live: item 19 Sword+9, mob 101 Wild Dog, skill 1 Three-Way Cut cool time 12)" }, "__GetWindowMode": { "status": "TODO" diff --git a/audit/port-map/UserInterface/PythonItemModule.cpp.json b/audit/port-map/UserInterface/PythonItemModule.cpp.json index d186dfa4..d0886aee 100644 --- a/audit/port-map/UserInterface/PythonItemModule.cpp.json +++ b/audit/port-map/UserInterface/PythonItemModule.cpp.json @@ -133,16 +133,20 @@ ] }, "itemGetIconInstance": { - "status": "PORTED", + "status": "ADAPTED", "impl": [ "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetIconInstance" - ] + ], + "note": "Returns/reads the pointer through Py_BuildPointer/PyTuple_GetPointer instead of Py_BuildValue(\"i\")/PyTuple_GetInteger: 40250 is ILP32, a 64-bit pointer truncated in \"i\" crashed wndMgr.SetSlot.", + "test": "extension/tests/port_login_flow_test.cpp (compiles with the same handle helpers as skill icon instances)" }, "itemDeleteIconInstance": { - "status": "PORTED", + "status": "ADAPTED", "impl": [ "extension/src/port/UserInterface/PythonItemModule.cpp:itemDeleteIconInstance" - ] + ], + "note": "Returns/reads the pointer through Py_BuildPointer/PyTuple_GetPointer instead of Py_BuildValue(\"i\")/PyTuple_GetInteger: 40250 is ILP32, a 64-bit pointer truncated in \"i\" crashed wndMgr.SetSlot.", + "test": "extension/tests/port_login_flow_test.cpp (compiles with the same handle helpers as skill icon instances)" }, "itemIsEquipmentVID": { "status": "PORTED", diff --git a/audit/port-map/UserInterface/PythonSkill.cpp.json b/audit/port-map/UserInterface/PythonSkill.cpp.json new file mode 100644 index 00000000..af0c594b --- /dev/null +++ b/audit/port-map/UserInterface/PythonSkill.cpp.json @@ -0,0 +1,608 @@ +{ + "reference": "UserInterface/PythonSkill.cpp", + "reference_sha256": "c3c5d946aa801cbcc2a42c32e1c77ae59113a263f5618faaa8e15fc77b903fac", + "priority": "P1", + "contracts": [], + "functions": { + "SplitLine": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:SplitLine" + ] + }, + "string_replace_word": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:string_replace_word" + ] + }, + "CPythonSkill::RegisterSkillTable": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::RegisterSkillTable" + ] + }, + "CPythonSkill::__RegisterGradeIconImage": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::__RegisterGradeIconImage" + ] + }, + "CPythonSkill::__RegisterNormalIconImage": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::__RegisterNormalIconImage" + ] + }, + "CPythonSkill::RegisterSkillDesc": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::RegisterSkillDesc" + ] + }, + "CPythonSkill::Destroy": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::Destroy" + ] + }, + "CPythonSkill::RegisterSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::RegisterSkill" + ] + }, + "CPythonSkill::GetSkillData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::GetSkillData" + ] + }, + "CPythonSkill::GetSkillDataByName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::GetSkillDataByName" + ] + }, + "CPythonSkill::SetPathName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SetPathName" + ] + }, + "CPythonSkill::GetPathName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::GetPathName" + ] + }, + "CPythonSkill::TEST": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::TEST" + ] + }, + "CPythonSkill::CPythonSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::CPythonSkill" + ] + }, + "CPythonSkill::~CPythonSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::~CPythonSkill" + ] + }, + "CPythonSkill::SSkillData::GetName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetName" + ] + }, + "CPythonSkill::SSkillData::GetType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetType" + ] + }, + "CPythonSkill::SSkillData::IsMeleeSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsMeleeSkill" + ] + }, + "CPythonSkill::SSkillData::IsChargeSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsChargeSkill" + ] + }, + "CPythonSkill::SSkillData::IsOnlyForGuildWar": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsOnlyForGuildWar" + ] + }, + "CPythonSkill::SSkillData::GetTargetRange": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetTargetRange" + ] + }, + "CPythonSkill::SSkillData::CanChangeDirection": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::CanChangeDirection" + ] + }, + "CPythonSkill::SSkillData::IsFanRange": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsFanRange" + ] + }, + "CPythonSkill::SSkillData::IsCircleRange": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsCircleRange" + ] + }, + "CPythonSkill::SSkillData::IsAutoSearchTarget": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsAutoSearchTarget" + ] + }, + "CPythonSkill::SSkillData::IsNeedCorpse": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsNeedCorpse" + ] + }, + "CPythonSkill::SSkillData::IsNeedTarget": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsNeedTarget" + ] + }, + "CPythonSkill::SSkillData::IsToggleSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsToggleSkill" + ] + }, + "CPythonSkill::SSkillData::IsUseHPSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsUseHPSkill" + ] + }, + "CPythonSkill::SSkillData::IsStandingSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsStandingSkill" + ] + }, + "CPythonSkill::SSkillData::CanUseWeaponType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::CanUseWeaponType" + ] + }, + "CPythonSkill::SSkillData::IsOnlyForAlliance": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsOnlyForAlliance" + ] + }, + "CPythonSkill::SSkillData::CanUseForMe": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::CanUseForMe" + ] + }, + "CPythonSkill::SSkillData::CanUseIfNotEnough": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::CanUseIfNotEnough" + ] + }, + "CPythonSkill::SSkillData::IsNeedEmptyBottle": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsNeedEmptyBottle" + ] + }, + "CPythonSkill::SSkillData::IsNeedPoisonBottle": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsNeedPoisonBottle" + ] + }, + "CPythonSkill::SSkillData::IsNeedBow": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsNeedBow" + ] + }, + "CPythonSkill::SSkillData::IsHorseSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsHorseSkill" + ] + }, + "CPythonSkill::SSkillData::IsMovingSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsMovingSkill" + ] + }, + "CPythonSkill::SSkillData::IsAttackSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsAttackSkill" + ] + }, + "CPythonSkill::SSkillData::IsTimeIncreaseSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsTimeIncreaseSkill" + ] + }, + "CPythonSkill::SSkillData::GetState": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetState" + ] + }, + "CPythonSkill::SSkillData::ProcessFormula": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::ProcessFormula" + ] + }, + "CPythonSkill::SSkillData::GetAffectDescription": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetAffectDescription" + ] + }, + "CPythonSkill::SSkillData::GetSkillCoolTime": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetSkillCoolTime" + ] + }, + "CPythonSkill::SSkillData::GetTargetCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetTargetCount" + ] + }, + "CPythonSkill::SSkillData::GetSkillMotionIndex": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetSkillMotionIndex" + ] + }, + "CPythonSkill::SSkillData::GetMaxLevel": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetMaxLevel" + ] + }, + "CPythonSkill::SSkillData::GetLevelUpPoint": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetLevelUpPoint" + ] + }, + "CPythonSkill::SSkillData::IsNoMotion": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsNoMotion" + ] + }, + "CPythonSkill::SSkillData::IsCanUseSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::IsCanUseSkill" + ] + }, + "CPythonSkill::SSkillData::GetMotionLoopCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetMotionLoopCount" + ] + }, + "CPythonSkill::SSkillData::GetNeedSP": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetNeedSP" + ] + }, + "CPythonSkill::SSkillData::GetContinuationSP": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetContinuationSP" + ] + }, + "CPythonSkill::SSkillData::GetDuration": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::GetDuration" + ] + }, + "CPythonSkill::SSkillData::SSkillData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:CPythonSkill::SSkillData::SSkillData" + ] + }, + "skillSetPathName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillSetPathName" + ] + }, + "skillRegisterSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillRegisterSkill" + ] + }, + "skillLoadSkillData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillLoadSkillData" + ] + }, + "skillRegisterSkillDesc": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillRegisterSkillDesc" + ] + }, + "skillClearSkillData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillClearSkillData" + ] + }, + "skillGetSkillName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillName" + ] + }, + "skillGetSkillDescription": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillDescription" + ] + }, + "skillGetSkillType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillType" + ] + }, + "skillGetSkillConditionDescriptionCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillConditionDescriptionCount" + ] + }, + "skillGetSkillConditionDescription": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillConditionDescription" + ] + }, + "skillGetSkillAffectDescriptionCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillAffectDescriptionCount" + ] + }, + "skillGetSkillAffectDescription": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillAffectDescription" + ] + }, + "skillGetSkillCoolTime": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillCoolTime" + ] + }, + "skillGetSkillNeedSP": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillNeedSP" + ] + }, + "skillGetSkillContinuationSP": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillContinuationSP" + ] + }, + "skillGetSkillMaxLevel": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillMaxLevel" + ] + }, + "skillGetSkillLevelUpPoint": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillLevelUpPoint" + ] + }, + "skillGetSkillLevelLimit": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillLevelLimit" + ] + }, + "skillIsSkillRequirement": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillIsSkillRequirement" + ] + }, + "skillGetSkillRequirementData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillRequirementData" + ] + }, + "skillGetSkillRequireStatCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillRequireStatCount" + ] + }, + "skillGetSkillRequireStatData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetSkillRequireStatData" + ] + }, + "skillCanLevelUpSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillCanLevelUpSkill" + ] + }, + "skillCheckRequirementSueccess": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillCheckRequirementSueccess" + ] + }, + "skillGetNeedCharacterLevel": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetNeedCharacterLevel" + ] + }, + "skillIsToggleSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillIsToggleSkill" + ] + }, + "skillIsUseHPSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillIsUseHPSkill" + ] + }, + "skillIsStandingSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillIsStandingSkill" + ] + }, + "skillCanUseSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillCanUseSkill" + ] + }, + "skillIsLevelUpSkill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillIsLevelUpSkill" + ] + }, + "skillGetIconName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetIconName" + ] + }, + "skillGetIconImage": { + "status": "ADAPTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetIconImage" + ], + "note": "Returns/reads the pointer through Py_BuildPointer/PyTuple_GetPointer instead of Py_BuildValue(\"i\")/PyTuple_GetInteger: 40250 is ILP32, a 64-bit pointer truncated in \"i\" crashed wndMgr.SetSlot.", + "test": "extension/tests/port_login_flow_test.cpp (port.login_flow in-game step: grade icon image + icon instance round trip)" + }, + "skillGetIconInstance": { + "status": "ADAPTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetIconInstance" + ], + "note": "Returns/reads the pointer through Py_BuildPointer/PyTuple_GetPointer instead of Py_BuildValue(\"i\")/PyTuple_GetInteger: 40250 is ILP32, a 64-bit pointer truncated in \"i\" crashed wndMgr.SetSlot.", + "test": "extension/tests/port_login_flow_test.cpp (port.login_flow in-game step: grade icon image + icon instance round trip)" + }, + "skillGetIconImageNew": { + "status": "ADAPTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetIconImageNew" + ], + "note": "Returns/reads the pointer through Py_BuildPointer/PyTuple_GetPointer instead of Py_BuildValue(\"i\")/PyTuple_GetInteger: 40250 is ILP32, a 64-bit pointer truncated in \"i\" crashed wndMgr.SetSlot.", + "test": "extension/tests/port_login_flow_test.cpp (port.login_flow in-game step: grade icon image + icon instance round trip)" + }, + "skillGetIconInstanceNew": { + "status": "ADAPTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetIconInstanceNew" + ], + "note": "Returns/reads the pointer through Py_BuildPointer/PyTuple_GetPointer instead of Py_BuildValue(\"i\")/PyTuple_GetInteger: 40250 is ILP32, a 64-bit pointer truncated in \"i\" crashed wndMgr.SetSlot.", + "test": "extension/tests/port_login_flow_test.cpp (port.login_flow in-game step: grade icon image + icon instance round trip)" + }, + "skillDeleteIconInstance": { + "status": "ADAPTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillDeleteIconInstance" + ], + "note": "Returns/reads the pointer through Py_BuildPointer/PyTuple_GetPointer instead of Py_BuildValue(\"i\")/PyTuple_GetInteger: 40250 is ILP32, a 64-bit pointer truncated in \"i\" crashed wndMgr.SetSlot.", + "test": "extension/tests/port_login_flow_test.cpp (port.login_flow in-game step: grade icon image + icon instance round trip)" + }, + "skillGetGradeData": { + "status": "ADAPTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetGradeData" + ], + "note": "40250 passes the non-trivial TGradeData through varargs (\"i\" reads its first 4 bytes); clang rejects that, so the same first 4 bytes are read explicitly. No root script calls skill.GetGradeData.", + "test": "extension/tests/port_login_flow_test.cpp (module imports; function unused by root scripts)" + }, + "skillGetNewAffectDataCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetNewAffectDataCount" + ] + }, + "skillGetNewAffectData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetNewAffectData" + ] + }, + "skillGetDuration": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillGetDuration" + ] + }, + "skillTEST": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:skillTEST" + ] + }, + "initskill": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonSkill.cpp:initskill" + ] + } + } +} diff --git a/docs/PORT-PLAN.md b/docs/PORT-PLAN.md index 8649d289..a833c9ed 100644 --- a/docs/PORT-PLAN.md +++ b/docs/PORT-PLAN.md @@ -444,6 +444,8 @@ extension/third_party/cpython-2.7.18/ # 静态库(2P 批次 P3-e(2026-09-24):`PythonMiniMap.cpp` 与 `PythonMiniMapModule.cpp` 原样移植(无手改),删除 pending 替身与 miniMap 模块桩,`initMiniMap()` 按 40250 顺序在 `initnet()` 之后;`PRTerrainLib/StdAfx.cpp`(`PR_FCNV/PR_ICNV`)原样复制,UserInterface PCH 按 40250 补 `PRTerrainLib/StdAfx.h`,`TerrainType.h` 的 `PR_FLOAT_TO_INTASM` 在非 MSVC 下用 `lrintf`(x87 fistp 默认舍入)代替内联汇编;`D3DXMath.h` 补 `D3DXColorModulate`。缺口:`CMapOutdoor` 未移植(地形由 Godot 适配层绘制),pending `CMapManager::IsMapOutdoor()` 返回 false(记 DIVERGENT),`GetMapOutdoorRef` 与 pending `CMapOutdoor::GetTerrainPointer/GetBaseXY` 只为链接存在、不可达——小地图地形贴图、标记与大地图(atlas)因此走 40250「非室外地图」路径不显示,待 `CMapOutdoor` 移植后自然恢复。`port.login_flow` 验证 uiminimap 创建并显示 miniMap、`GetAtlasSize()` 报未载入。P3 物品链与三个 UI 单元至此完成;下一步候选:`CMapOutdoor`(解锁小地图/大地图)、`CEffectManager`/EffectLib、`CPythonSkill`。 + 批次 3-a CPythonSkill(2026-09-24):`UserInterface/PythonSkill.cpp`(含 skill 模块)与 `EterBase/Poly/`(技能公式解析器)原样移植,删除 pending 替身与 skill 模块桩,`initskill()` 按 40250 顺序在 `initfly()` 之后,实例按 `m_pySkill` 位置进 PythonBoot 的 `GameSingletons`;平台 `PythonApplication.cpp` 里重复的 `SKILL_EFFECT_UPGRADE_ENABLE` 删掉(40250 定义在 PythonSkill.cpp),`LoadLocaleData` 的 skilldesc/skilltable 现在真正载入。改动:技能图标/图标实例句柄用 `Py_BuildPointer`/`PyTuple_GetPointer`(item 模块的 `GetIconInstance/DeleteIconInstance` 同改),`skillGetGradeData` 把非平凡结构传进 varargs(clang 拒绝),改为显式读同样的前 4 字节(脚本不调用)。`port.login_flow`:选角阶段 skill 1 = Three-Way Cut、ACTIVE、冷却 12;进游戏后主动技能只有分等级图标(`GetIconImage` 为 0,与 40250 相同),`GetIconImageNew/GetIconInstanceNew` 可用;真服同样通过。 + 每个切片都必须同时跑 legacy/port 双路回归;只有 2V3 稳定并把默认路由切到 `port` 后,才能删除总开关和剩余 legacy 宿主。 ## 5. 数据源切换:m2dev assets → 40250 diff --git a/extension/src/platform/ScriptLib/GameplayModuleConstants.cpp b/extension/src/platform/ScriptLib/GameplayModuleConstants.cpp index c3f35326..4b58012a 100644 --- a/extension/src/platform/ScriptLib/GameplayModuleConstants.cpp +++ b/extension/src/platform/ScriptLib/GameplayModuleConstants.cpp @@ -136,21 +136,6 @@ void AddStubConstants_shop(PyObject* poModule) } // 40250 UserInterface/PythonSkill.cpp -void AddStubConstants_skill(PyObject* poModule) -{ - (void) poModule; - PyModule_AddIntConstant(poModule, "SKILL_TYPE_NONE", CPythonSkill::SKILL_TYPE_NONE); - PyModule_AddIntConstant(poModule, "SKILL_TYPE_ACTIVE", CPythonSkill::SKILL_TYPE_ACTIVE); - PyModule_AddIntConstant(poModule, "SKILL_TYPE_SUPPORT", CPythonSkill::SKILL_TYPE_SUPPORT); - PyModule_AddIntConstant(poModule, "SKILL_TYPE_GUILD", CPythonSkill::SKILL_TYPE_GUILD); - PyModule_AddIntConstant(poModule, "SKILL_TYPE_HORSE", CPythonSkill::SKILL_TYPE_HORSE); - PyModule_AddIntConstant(poModule, "SKILL_TYPE_MAX_NUM", CPythonSkill::SKILL_TYPE_MAX_NUM); - PyModule_AddIntConstant(poModule, "SKILL_GRADE_COUNT", CPythonSkill::SKILL_GRADE_COUNT); - PyModule_AddIntConstant(poModule, "SKILL_GRADE_STEP_COUNT", CPythonSkill::SKILL_GRADE_STEP_COUNT); - PyModule_AddIntConstant(poModule, "SKILL_GRADEGAP", CPythonSkill::SKILL_GRADEGAP); - PyModule_AddIntConstant(poModule, "SKILL_EFFECT_COUNT", CPythonSkill::SKILL_EFFECT_COUNT); -} - // 40250 UserInterface/PythonSoundManagerModule.cpp void AddStubConstants_snd(PyObject* poModule) { diff --git a/extension/src/platform/ScriptLib/GameplayModules.cpp b/extension/src/platform/ScriptLib/GameplayModules.cpp index 037a5711..63b48b6e 100644 --- a/extension/src/platform/ScriptLib/GameplayModules.cpp +++ b/extension/src/platform/ScriptLib/GameplayModules.cpp @@ -15,7 +15,6 @@ void AddStubConstants_profiler(PyObject* poModule); void AddStubConstants_quest(PyObject* poModule); void AddStubConstants_safebox(PyObject* poModule); void AddStubConstants_shop(PyObject* poModule); -void AddStubConstants_skill(PyObject* poModule); void AddStubConstants_snd(PyObject* poModule); void AddStubConstants_systemSetting(PyObject* poModule); void AddStubConstants_udp(PyObject* poModule); @@ -430,90 +429,6 @@ PyMethodDef methods_shop[] = { { "BuildPrivateShop", stub_shop_BuildPrivateShop, METH_VARARGS }, { NULL, NULL } }; -// 40250 UserInterface/PythonSkill.cpp: skill export names. -PyObject* stub_skill_SetPathName(PyObject*, PyObject*) { return stub_call_named("skill.SetPathName", Py_BuildNone()); } -PyObject* stub_skill_RegisterSkill(PyObject*, PyObject*) { return stub_call_named("skill.RegisterSkill", Py_BuildNone()); } -PyObject* stub_skill_LoadSkillData(PyObject*, PyObject*) { return stub_call_named("skill.LoadSkillData", Py_BuildNone()); } -PyObject* stub_skill_ClearSkillData(PyObject*, PyObject*) { return stub_call_named("skill.ClearSkillData", Py_BuildNone()); } -PyObject* stub_skill_GetSkillName(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillName", Py_BuildValue("s", "")); } -PyObject* stub_skill_GetSkillDescription(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillDescription", Py_BuildValue("s", "")); } -PyObject* stub_skill_GetSkillType(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillType", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillConditionDescriptionCount(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillConditionDescriptionCount", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillConditionDescription(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillConditionDescription", Py_BuildValue("s", "")); } -PyObject* stub_skill_GetSkillAffectDescriptionCount(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillAffectDescriptionCount", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillAffectDescription(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillAffectDescription", Py_BuildValue("s", "")); } -PyObject* stub_skill_GetSkillCoolTime(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillCoolTime", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillNeedSP(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillNeedSP", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillContinuationSP(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillContinuationSP", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillMaxLevel(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillMaxLevel", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillLevelUpPoint(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillLevelUpPoint", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillLevelLimit(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillLevelLimit", Py_BuildValue("i", 0)); } -PyObject* stub_skill_IsSkillRequirement(PyObject*, PyObject*) { return stub_call_named("skill.IsSkillRequirement", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillRequirementData(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillRequirementData", Py_BuildValue("si", "", 0)); } -PyObject* stub_skill_GetSkillRequireStatCount(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillRequireStatCount", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetSkillRequireStatData(PyObject*, PyObject*) { return stub_call_named("skill.GetSkillRequireStatData", Py_BuildValue("ii", 0, 0)); } -PyObject* stub_skill_CanLevelUpSkill(PyObject*, PyObject*) { return stub_call_named("skill.CanLevelUpSkill", Py_BuildValue("i", 0)); } -PyObject* stub_skill_IsLevelUpSkill(PyObject*, PyObject*) { return stub_call_named("skill.IsLevelUpSkill", Py_BuildValue("i", 0)); } -PyObject* stub_skill_CheckRequirementSueccess(PyObject*, PyObject*) { return stub_call_named("skill.CheckRequirementSueccess", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetNeedCharacterLevel(PyObject*, PyObject*) { return stub_call_named("skill.GetNeedCharacterLevel", Py_BuildValue("i", 0)); } -PyObject* stub_skill_IsToggleSkill(PyObject*, PyObject*) { return stub_call_named("skill.IsToggleSkill", Py_BuildValue("i", 0)); } -PyObject* stub_skill_IsUseHPSkill(PyObject*, PyObject*) { return stub_call_named("skill.IsUseHPSkill", Py_BuildValue("i", 0)); } -PyObject* stub_skill_IsStandingSkill(PyObject*, PyObject*) { return stub_call_named("skill.IsStandingSkill", Py_BuildValue("i", 0)); } -PyObject* stub_skill_CanUseSkill(PyObject*, PyObject*) { return stub_call_named("skill.CanUseSkill", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetIconName(PyObject*, PyObject*) { return stub_call_named("skill.GetIconName", Py_BuildValue("s", "")); } -PyObject* stub_skill_GetIconImage(PyObject*, PyObject*) { return stub_call_named("skill.GetIconImage", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetIconImageNew(PyObject*, PyObject*) { return stub_call_named("skill.GetIconImageNew", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetIconInstance(PyObject*, PyObject*) { return stub_call_named("skill.GetIconInstance", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetIconInstanceNew(PyObject*, PyObject*) { return stub_call_named("skill.GetIconInstanceNew", Py_BuildValue("i", 0)); } -PyObject* stub_skill_DeleteIconInstance(PyObject*, PyObject*) { return stub_call_named("skill.DeleteIconInstance", Py_BuildNone()); } -PyObject* stub_skill_GetGradeData(PyObject*, PyObject*) { return stub_call_named("skill.GetGradeData", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetNewAffectDataCount(PyObject*, PyObject*) { return stub_call_named("skill.GetNewAffectDataCount", Py_BuildValue("i", 0)); } -PyObject* stub_skill_GetNewAffectData(PyObject*, PyObject*) { return stub_call_named("skill.GetNewAffectData", Py_BuildValue("sff", "", 0.0, 0.0)); } -PyObject* stub_skill_GetDuration(PyObject*, PyObject*) { return stub_call_named("skill.GetDuration", Py_BuildValue("i", 0)); } -PyObject* stub_skill_TEST(PyObject*, PyObject*) { return stub_call_named("skill.TEST", Py_BuildNone()); } -PyMethodDef methods_skill[] = { - { "SetPathName", stub_skill_SetPathName, METH_VARARGS }, - { "RegisterSkill", stub_skill_RegisterSkill, METH_VARARGS }, - { "LoadSkillData", stub_skill_LoadSkillData, METH_VARARGS }, - { "ClearSkillData", stub_skill_ClearSkillData, METH_VARARGS }, - { "GetSkillName", stub_skill_GetSkillName, METH_VARARGS }, - { "GetSkillDescription", stub_skill_GetSkillDescription, METH_VARARGS }, - { "GetSkillType", stub_skill_GetSkillType, METH_VARARGS }, - { "GetSkillConditionDescriptionCount", stub_skill_GetSkillConditionDescriptionCount, METH_VARARGS }, - { "GetSkillConditionDescription", stub_skill_GetSkillConditionDescription, METH_VARARGS }, - { "GetSkillAffectDescriptionCount", stub_skill_GetSkillAffectDescriptionCount, METH_VARARGS }, - { "GetSkillAffectDescription", stub_skill_GetSkillAffectDescription, METH_VARARGS }, - { "GetSkillCoolTime", stub_skill_GetSkillCoolTime, METH_VARARGS }, - { "GetSkillNeedSP", stub_skill_GetSkillNeedSP, METH_VARARGS }, - { "GetSkillContinuationSP", stub_skill_GetSkillContinuationSP, METH_VARARGS }, - { "GetSkillMaxLevel", stub_skill_GetSkillMaxLevel, METH_VARARGS }, - { "GetSkillLevelUpPoint", stub_skill_GetSkillLevelUpPoint, METH_VARARGS }, - { "GetSkillLevelLimit", stub_skill_GetSkillLevelLimit, METH_VARARGS }, - { "IsSkillRequirement", stub_skill_IsSkillRequirement, METH_VARARGS }, - { "GetSkillRequirementData", stub_skill_GetSkillRequirementData, METH_VARARGS }, - { "GetSkillRequireStatCount", stub_skill_GetSkillRequireStatCount, METH_VARARGS }, - { "GetSkillRequireStatData", stub_skill_GetSkillRequireStatData, METH_VARARGS }, - { "CanLevelUpSkill", stub_skill_CanLevelUpSkill, METH_VARARGS }, - { "IsLevelUpSkill", stub_skill_IsLevelUpSkill, METH_VARARGS }, - { "CheckRequirementSueccess", stub_skill_CheckRequirementSueccess, METH_VARARGS }, - { "GetNeedCharacterLevel", stub_skill_GetNeedCharacterLevel, METH_VARARGS }, - { "IsToggleSkill", stub_skill_IsToggleSkill, METH_VARARGS }, - { "IsUseHPSkill", stub_skill_IsUseHPSkill, METH_VARARGS }, - { "IsStandingSkill", stub_skill_IsStandingSkill, METH_VARARGS }, - { "CanUseSkill", stub_skill_CanUseSkill, METH_VARARGS }, - { "GetIconName", stub_skill_GetIconName, METH_VARARGS }, - { "GetIconImage", stub_skill_GetIconImage, METH_VARARGS }, - { "GetIconImageNew", stub_skill_GetIconImageNew, METH_VARARGS }, - { "GetIconInstance", stub_skill_GetIconInstance, METH_VARARGS }, - { "GetIconInstanceNew", stub_skill_GetIconInstanceNew, METH_VARARGS }, - { "DeleteIconInstance", stub_skill_DeleteIconInstance, METH_VARARGS }, - { "GetGradeData", stub_skill_GetGradeData, METH_VARARGS }, - { "GetNewAffectDataCount", stub_skill_GetNewAffectDataCount, METH_VARARGS }, - { "GetNewAffectData", stub_skill_GetNewAffectData, METH_VARARGS }, - { "GetDuration", stub_skill_GetDuration, METH_VARARGS }, - { "TEST", stub_skill_TEST, METH_VARARGS }, - { NULL, NULL } -}; // 40250 UserInterface/PythonSoundManagerModule.cpp: snd export names. PyObject* stub_snd_PlaySound(PyObject*, PyObject*) { return stub_call_named("snd.PlaySound", Py_BuildNone()); } PyObject* stub_snd_PlaySound3D(PyObject*, PyObject*) { return stub_call_named("snd.PlaySound3D", Py_BuildNone()); } @@ -692,11 +607,6 @@ void init_2v0_gameplay_stubs() { PyModule_AddIntConstant(module, "__port_stub__", 1); AddStubConstants_shop(module); } - { - PyObject* module = Py_InitModule("skill", methods_skill); - PyModule_AddIntConstant(module, "__port_stub__", 1); - AddStubConstants_skill(module); - } { PyObject* module = Py_InitModule("snd", methods_snd); PyModule_AddIntConstant(module, "__port_stub__", 1); diff --git a/extension/src/platform/ScriptLib/PythonBoot.cpp b/extension/src/platform/ScriptLib/PythonBoot.cpp index 4d524285..0294e945 100644 --- a/extension/src/platform/ScriptLib/PythonBoot.cpp +++ b/extension/src/platform/ScriptLib/PythonBoot.cpp @@ -27,6 +27,7 @@ #include "UserInterface/PythonMiniMap.h" #include "UserInterface/PythonEventManager.h" #include "UserInterface/PythonBackground.h" +#include "UserInterface/PythonSkill.h" #include "UserInterface/PythonQuest.h" #include "UserInterface/PythonMessenger.h" #include "UserInterface/PythonSafeBox.h" @@ -117,6 +118,7 @@ struct GameSingletons CPythonMiniMap pyMiniMap; CPythonEventManager pyEventManager; CPythonBackground pyBackground; + CPythonSkill pySkill; CPythonQuest pyQuest; CPythonMessenger pyManager; CPythonSafeBox pySafeBox; @@ -356,6 +358,7 @@ bool run_main_script_body(const char* lpCmdLine, std::string* error) initMiniMap(); initeffect(); initfly(); + initskill(); initServerStateChecker(); init_2v0_gameplay_stubs(); diff --git a/extension/src/platform/UserInterface/PythonApplication.cpp b/extension/src/platform/UserInterface/PythonApplication.cpp index b18667a5..3094c725 100644 --- a/extension/src/platform/UserInterface/PythonApplication.cpp +++ b/extension/src/platform/UserInterface/PythonApplication.cpp @@ -320,11 +320,9 @@ void CPythonApplication::SetForceSightRange(int) { MT_PLATFORM_STUB(); } void CMovieMan::PlayLogo(const char*) { MT_PLATFORM_STUB(); } BOOL PERF_CHECKER_RENDER_GAME = FALSE; -BOOL SKILL_EFFECT_UPGRADE_ENABLE = FALSE; double g_specularSpd = 0; -// 40250 UserInterface/PythonApplication.cpp, verbatim. PORT: CPythonSkill is still a stand-in, so -// RegisterSkillDesc fails and the function returns false after the item and mob tables load. +// 40250 UserInterface/PythonApplication.cpp, verbatim. // SUPPORT_NEW_KOREA_SERVER bool LoadLocaleData(const char* localePath) { diff --git a/extension/src/platform/pending/UserInterface/PythonSkill.cpp b/extension/src/platform/pending/UserInterface/PythonSkill.cpp deleted file mode 100644 index 9f7edd30..00000000 --- a/extension/src/platform/pending/UserInterface/PythonSkill.cpp +++ /dev/null @@ -1,210 +0,0 @@ -// Stand-in for the 40250 logic unit UserInterface/PythonSkill.cpp, not ported yet: the members the ported units -// reference, as platform_stub.py stubs. Delete this file in the commit that ports the unit into port/ -// (docs/PORT-PLAN.md). -#include "UserInterface/StdAfx.h" -#include "UserInterface/PythonSkill.h" - -#include "../../PlatformStub.h" - -auto CPythonSkill::SSkillData::IsNeedCorpse() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsToggleSkill() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsChargeSkill() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::GetSkillData(DWORD, TSkillData **) -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::GetTargetRange() const -> DWORD -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::CanChangeDirection() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsFanRange() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsCircleRange() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsAutoSearchTarget() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsNeedTarget() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsUseHPSkill() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsStandingSkill() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::CanUseWeaponType(DWORD) -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsOnlyForAlliance() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::CanUseForMe() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::CanUseIfNotEnough() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsNeedEmptyBottle() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsNeedPoisonBottle() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsNeedBow() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsAttackSkill() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsHorseSkill() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsMovingSkill() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsOnlyForGuildWar() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::GetSkillCoolTime(float) -> DWORD -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::GetNeedSP(float) -> int -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::GetMotionLoopCount(float) -> DWORD -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::GetTargetCount(float) -> DWORD -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::GetSkillMotionIndex(int) -> DWORD -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsCanUseSkill() -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::IsNoMotion() -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::SSkillData::GetType() const -> BYTE -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::Destroy() -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonSkill::RegisterSkillTable(const char *) -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonSkill::RegisterSkillDesc(const char *) -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} diff --git a/extension/src/port/EterBase/Poly/Base.cpp b/extension/src/port/EterBase/Poly/Base.cpp new file mode 100644 index 00000000..b084b794 --- /dev/null +++ b/extension/src/port/EterBase/Poly/Base.cpp @@ -0,0 +1,27 @@ +#include "StdAfx.h" +#include "Base.h" + +CBase::CBase() +{ + id = 0; +} + +CBase::~CBase() +{ +} + +bool CBase::isNumber() +{ + return (id & MID_NUMBER) != 0 ? true : false; +} + +bool CBase::isVar() +{ + return (id & MID_VARIABLE) != 0 ? true : false; +} + +bool CBase::isSymbol() +{ + return (id & MID_SYMBOL) != 0 ? true : false; +} + diff --git a/extension/src/port/EterBase/Poly/Base.h b/extension/src/port/EterBase/Poly/Base.h new file mode 100644 index 00000000..a7b01877 --- /dev/null +++ b/extension/src/port/EterBase/Poly/Base.h @@ -0,0 +1,25 @@ +#ifndef __POLY_BASE_H__ +#define __POLY_BASE_H__ + +#define MID_UNKNOWN 0 +#define MID_NUMBER 256 +#define MID_VARIABLE 512 +#define MID_SYMBOL 1024 + +#define MID_LONG MID_NUMBER + 1 +#define MID_SQRT MID_NUMBER + 2 +#define MID_FRACTION MID_NUMBER + 3 + +class CBase +{ + public: + bool isSymbol(); + bool isVar(); + bool isNumber(); + int id; + CBase(); + virtual ~CBase(); + +}; + +#endif diff --git a/extension/src/port/EterBase/Poly/Poly.cpp b/extension/src/port/EterBase/Poly/Poly.cpp new file mode 100644 index 00000000..d10f7dda --- /dev/null +++ b/extension/src/port/EterBase/Poly/Poly.cpp @@ -0,0 +1,622 @@ +#include "StdAfx.h" +#include +#include + +#include "Poly.h" +#include +#include +#include + +using namespace std; + +double _random() +{ + return rand() / (RAND_MAX + 1.0); +} + +void CPoly::SetRandom(int iRandomType) +{ + m_iRandomType = iRandomType; +} + +int CPoly::my_irandom(double start, double end) +{ + switch (m_iRandomType) + { + case RANDOM_TYPE_FORCE_MIN: + return int(start); + break; + case RANDOM_TYPE_FORCE_MAX: + return int(end); + break; + } + + // Make range as inclusive-exclusive + int is = int(start + 0.5); + int ie = int(end - start + 0.5) + 1; + + return int(_random() * ie + is); +} + +double CPoly::my_frandom(double start, double end) +{ + return _random() * (end - start) + start; +} + +CPoly::CPoly() +{ + m_iRandomType = RANDOM_TYPE_FREELY; + uiLookPos = 0; + ErrorOccur = true; + lSymbol.clear(); + STSize = 0; + MathSymbolCount = 0; + lSymbol.reserve(50); + init(); +} + +CPoly::~CPoly() +{ + Clear(); +} + +void CPoly::SetStr(const string & str) +{ + strData = str; +} + +float CPoly::Eval() +{ + int stNow; + double save[POLY_MAXSTACK],t; + int iSp=0; + if (ErrorOccur) + { + /*THROW(new CEvalException("Evaluate Error"));*/ + return 0; + } + + //TEST + //list::iterator pos = tokenBase.begin(); + //list::iterator posn = numBase.begin(); + vector::iterator pos = tokenBase.begin(); + vector::iterator posn = numBase.begin(); + while (pos != tokenBase.end()) + { + + stNow=*pos; + ++pos; + switch (stNow) + { + case POLY_NUM: + save[iSp++]=*posn++; break; + case POLY_ID: + save[iSp++]= + lSymbol[ *pos ]->dVal; + pos++; + break; + //case '+': + case POLY_PLU: + iSp--; + save[iSp-1]+=save[iSp]; break; + //case '-': + case POLY_MIN: + iSp--; + save[iSp-1]-=save[iSp]; break; + //case '*': + case POLY_MUL: + iSp--; + save[iSp-1]*=save[iSp]; break; + //case '%': + case POLY_MOD: + iSp--; + if (save[iSp]==0) + { + //THROW(new CEvalException("Divide by 0")); + return 0; + } + save[iSp-1]=fmod(save[iSp-1],save[iSp]); break; + //case '/': + case POLY_DIV: + iSp--; + if (save[iSp]==0) + { + //THROW(new CEvalException("Divide by 0")); + return 0; + } + save[iSp-1]/=save[iSp]; break; + //case '^': + case POLY_POW: + iSp--; + save[iSp-1]=pow(save[iSp-1],save[iSp]); break; + case POLY_ROOT: + if (save[iSp-1]<0) + { + //THROW(new CEvalException("Negative in root")); + return 0; + } + save[iSp-1]=sqrt(save[iSp-1]); break; + case POLY_COS: + save[iSp-1]=cos(save[iSp-1]); break; + case POLY_SIN: + save[iSp-1]=sin(save[iSp-1]); break; + case POLY_TAN: + if (!(t=cos(save[iSp-1]))) + { + //THROW (new CEvalException("Divide by 0")); + return 0; + } + save[iSp-1]=tan(save[iSp-1]); break; + case POLY_CSC: + if (!(t=sin(save[iSp-1]))) + { + //THROW(new CEvalException("Divide by 0")); + return 0; + } + save[iSp-1]=1/t; break; + case POLY_SEC: + if (!(t=cos(save[iSp-1]))) + { + //THROW(new CEvalException("Divide by 0")); + return 0; + } + save[iSp-1]=1/t; break; + case POLY_COT: + if (!(t=sin(save[iSp-1]))) + { + //THROW(new CEvalException("Divide by 0")); + return 0; + } + save[iSp-1]=cos(save[iSp-1])/t; break; + case POLY_LN: + if (save[iSp-1]<=0) + { + //THROW( new CEvalException("Call Log with minus number")); + return 0; + } + save[iSp-1]=log(save[iSp-1]); break; + case POLY_LOG10: + if (save[iSp-1]<=0) + { + //THROW( new CEvalException("Call Log with minus number")); + return 0; + } + save[iSp-1]=log10(save[iSp-1]); break; + case POLY_LOG: + if (save[iSp-1]<=0) + { + //THROW( new CEvalException("Call Log with minus number")); + return 0; + } + if (save[iSp-2]<=0 || save[iSp-2]==1) + { + //THROW( new CEvalException("Call Log with minus number")); + return 0; + } + + save[iSp-2]=log(save[iSp-1])/log(save[iSp-2]); + iSp--; + break; + case POLY_ABS: + save[iSp-1]=fabs(save[iSp-1]); + break; + case POLY_FLOOR: + save[iSp-1]=floor(save[iSp-1]); + break; + case POLY_IRAND: + save[iSp-2]=my_irandom(save[iSp-2],save[iSp-1]); + iSp--; + break; + case POLY_FRAND: + save[iSp-2]=my_frandom(save[iSp-2],save[iSp-1]); + iSp--; + break; + case POLY_MINF: + save[iSp-2]=(save[iSp-2]save[iSp-1])?save[iSp-2]:save[iSp-1]; + iSp--; + break; + /*case POLY_MOD: + save[iSp-2]=fmod(save[iSp-2],save[iSp-1]); + iSp--; + break;*/ + default: + return 0; + //THROW(new CEvalException("Token Error")); + } + } + return float(save[iSp-1]); +} + +int CPoly::Analyze(const char * pszStr) +{ + if (pszStr) + SetStr(pszStr); + + if (0 == strData.length()) + return true; + + //DisposeList(); + ErrorOccur = false; + uiLookPos = 0; + iLookAhead = lexan(); + + expr(); + + if (tokenBase.empty()) + { + //THROW(new CParseException("No Data")); + return false; + } + + return !ErrorOccur; +} + +void CPoly::Clear() +{ + int i; + //while (!tokenBase.IsEmpty()) listBase.RemoveTail(); + //while (!numBase.IsEmpty()) numBase.RemoveTail(); + tokenBase.clear(); + numBase.clear(); + + for (i = 0;i < STSize; ++i) + { + if (lSymbol[i]) delete lSymbol[i]; + lSymbol[i]=NULL; + } + //lSymbol.FreeExtra(); + lSymbol.clear(); + SymbolIndex.clear(); + STSize=0; + MathSymbolCount=0; +} + +void CPoly::expr() +{ + int t; + + switch (iLookAhead) + { + case '+': + case '-': + uiLookPos--; + iLookAhead = POLY_NUM; + iNumToken = iToken = 0; + + } + + term(); + + while (!ErrorOccur) + { + switch (iLookAhead) + { + case '+': + case '-': + t=iLookAhead; + match(t); + term(); + emit(t,POLY_NONE); + continue; + case POLY_EOS: case ')': case ',': return; + default: + error(); + //THROW( new CParseException("Error Parsing")); + return; + } + } +} + +void CPoly::error() +{ + iErrorPos=uiLookPos; + ErrorOccur=true; +} + +int CPoly::lexan() +{ + int t; + double tt; + + while (uiLookPos < strData.size()) + { + if (strData[uiLookPos] == ' ' || strData[uiLookPos] == '\t') + ; + else if (isdigit(strData[uiLookPos])) + { + t = 0; + for (;uiLookPostoken; + } + else + { + iToken=0; + return strData[uiLookPos++]; + } + uiLookPos++; + } + return POLY_EOS; +} + +void CPoly::term() +{ + int t; + factor(); + while (!ErrorOccur) + { + switch (iLookAhead) + { + case '*': + case '/': + case '%': + t=iLookAhead; + match(t); + factor(); + emit(t,POLY_NONE); + continue; + default: + return; + } + } +} + +void CPoly::factor() +{ + int t; + expo(); + while (!ErrorOccur) + { + switch (iLookAhead) + { + case '^': + t=iLookAhead; + match(t); + expo(); + emit(t,POLY_NONE); + continue; + default: + return; + } + } +} + +void CPoly::expo() +{ + int t; + switch (iLookAhead) + { + case '(': + match('('); expr(); match(')'); break; + case POLY_NUM: + emit(POLY_NUM, iToken); match(POLY_NUM); break; + case POLY_ID: + emit(POLY_ID,(int)/*FindIndex*/(iToken)); match(POLY_ID); break; + case POLY_ROOT: + case POLY_SIN: + case POLY_COT: + case POLY_TAN: + case POLY_CSC: + case POLY_SEC: + case POLY_LN: + case POLY_LOG10: + case POLY_COS: + case POLY_ABS: + case POLY_FLOOR: + t=iLookAhead; + match(iLookAhead); match('('); expr(); match(')'); emit(t,iToken); + break; + case POLY_LOG: + case POLY_MINF: + case POLY_MAXF: + case POLY_IRAND: + case POLY_FRAND: + case POLY_MOD: + t=iLookAhead; + match(iLookAhead); match('('); expr(); match(','); expr(); match(')'); emit(t,iToken); + break; + case POLY_EOS: + break; + default: + error(); + //THROW( new CParseException("Error Parsing")); + } +} + +void CPoly::match(int t) +{ + if (iLookAhead==t) iLookAhead=lexan(); else error(); +} + +void CPoly::emit(int t, int tval) +{ + switch (t) + { + case '+': + tokenBase.push_back(POLY_PLU); + break; + case '-': + tokenBase.push_back(POLY_MIN); + break; + case '*': + tokenBase.push_back(POLY_MUL); + break; + case '/': + tokenBase.push_back(POLY_DIV); + break; + case '%': + tokenBase.push_back(POLY_MOD); + break; + case '^': + tokenBase.push_back(POLY_POW); + break; + case POLY_ROOT: + case POLY_SIN: + case POLY_TAN: + case POLY_COT: + case POLY_COS: + case POLY_CSC: + case POLY_SEC: + case POLY_LOG: + case POLY_LN: + case POLY_LOG10: + case POLY_ABS: + case POLY_MINF: + case POLY_MAXF: + case POLY_IRAND: + case POLY_FRAND: + case POLY_MOD: + case POLY_FLOOR: + tokenBase.push_back(t); + break; + case POLY_NUM: + tokenBase.push_back(t); + numBase.push_back(iNumToken); + break; + case POLY_ID: + tokenBase.push_back(t); + tokenBase.push_back(tval); break; + default: + error(); + Clear(); + //THROW( new CParseException("Error Parsing")); + return; + } +} + +int CPoly::find(const string & s) +{ + int l, m, r; + + l = 0; + r = STSize - 1; + + while (l <= r) + { + m = (l + r) >> 1; + + if (lSymbol[SymbolIndex[m]]->strlex == s) + return SymbolIndex[m]; + else if (lSymbol[SymbolIndex[m]]->strlex < s) + l = m + 1; + else + r = m - 1; + } + return -1; +} + +int CPoly::insert(const string & s, int tok) +{ + int i; + bool bAdded=false; + + lSymbol.push_back(new CSymTable(tok,s)); + for (i=0;istrlex) + { + SymbolIndex.insert(SymbolIndex.begin()+i,STSize); + bAdded=true; + break; + } + } + if (!bAdded) + { + //SymbolIndex.SetAtGrow(STSize,STSize); + SymbolIndex.push_back(STSize); + } + STSize++; + return STSize-1; +} + +int CPoly::SetVar(const string & strName, double dVar) +{ + + if (ErrorOccur) return false; + int index=find(strName); + if (index==-1) return false; + CSymTable* stVar = lSymbol[(/*FindIndex*/(index))]; + stVar->dVal=dVar; + return true; +} + +int CPoly::GetVarCount() +{ + return lSymbol.size() - MathSymbolCount; +} + +const char * CPoly::GetVarName(unsigned int dwIndex) +{ + assert(dwIndex + MathSymbolCount < lSymbol.size()); + return lSymbol[dwIndex + MathSymbolCount]->strlex.c_str(); +} + +void CPoly::init() +{ + insert("min",POLY_MINF); + insert("max",POLY_MAXF); + insert("number", POLY_IRAND); + insert("irandom", POLY_IRAND); + insert("irand", POLY_IRAND); + insert("frandom",POLY_FRAND); + insert("frand",POLY_FRAND); + insert("rt",POLY_ROOT); + insert("sqrt",POLY_ROOT); + insert("cos",POLY_COS); + insert("sin",POLY_SIN); + insert("tan",POLY_TAN); + insert("cot",POLY_COT); + insert("csc",POLY_CSC); + insert("cosec",POLY_COSEC); + insert("sec",POLY_SEC); + insert("pi",POLY_PI); + SetVar("pi",3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068); + insert("e",POLY_EXP); + SetVar("e",2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427); + insert("log",POLY_LOG); + insert("ln",POLY_LN); + insert("log10",POLY_LOG10); + insert("abs",POLY_ABS); + insert("mod",POLY_MOD); + insert("floor",POLY_FLOOR); + MathSymbolCount = STSize; +} diff --git a/extension/src/port/EterBase/Poly/StdAfx.h b/extension/src/port/EterBase/Poly/StdAfx.h new file mode 100644 index 00000000..d5df4dfd --- /dev/null +++ b/extension/src/port/EterBase/Poly/StdAfx.h @@ -0,0 +1,2 @@ +#pragma once +#include "../StdAfx.h" diff --git a/extension/src/port/EterBase/Poly/SymTable.cpp b/extension/src/port/EterBase/Poly/SymTable.cpp new file mode 100644 index 00000000..935587f3 --- /dev/null +++ b/extension/src/port/EterBase/Poly/SymTable.cpp @@ -0,0 +1,11 @@ +#include "StdAfx.h" +#include "SymTable.h" + +CSymTable::CSymTable(int aTok, std::string aStr) : dVal(0), token(aTok), strlex(aStr) +{ +} + +CSymTable::~CSymTable() +{ +} + diff --git a/extension/src/port/EterBase/Poly/Symbol.cpp b/extension/src/port/EterBase/Poly/Symbol.cpp new file mode 100644 index 00000000..dff6b5d6 --- /dev/null +++ b/extension/src/port/EterBase/Poly/Symbol.cpp @@ -0,0 +1,50 @@ +#include "StdAfx.h" +#include "Symbol.h" + +CSymbol::CSymbol() +{ + id = MID_SYMBOL; + iType = ST_UNKNOWN; +} + +CSymbol::~CSymbol() +{ + +} + +bool CSymbol::Equal(CSymbol dif) +{ + if (dif.iType/10 == iType/10) return true; + return false; +} + +bool CSymbol::Less(CSymbol dif) +{ + if (dif.iType/10 > iType/10) return true; + return false; +} + +int CSymbol::GetType() +{ + return iType; +} + +void CSymbol::SetType(int Type) +{ + iType=Type; +} + +int CSymbol::issymbol(int ch) +{ + switch(ch) + { + case SY_PLUS : return ST_PLUS; + case SY_MINUS : return ST_MINUS; + case SY_MULTIPLY: return ST_MULTIPLY; + case SY_DIVIDE : return SY_DIVIDE; + case SY_CARET : return SY_CARET; + case SY_OPEN : return SY_OPEN; + case SY_CLOSE : return ST_CLOSE; + } + return 0; +} diff --git a/extension/src/port/EterBase/Poly/Symbol.h b/extension/src/port/EterBase/Poly/Symbol.h new file mode 100644 index 00000000..427cfe52 --- /dev/null +++ b/extension/src/port/EterBase/Poly/Symbol.h @@ -0,0 +1,39 @@ +#ifndef __POLY_SYMBOL_H__ +#define __POLY_SYMBOL_H__ + +#include "Base.h" + +#define ST_UNKNOWN 0 +#define ST_PLUS 11 +#define ST_MINUS 12 +#define ST_MULTIPLY 23 +#define ST_DIVIDE 24 +#define ST_CARET 35 +#define ST_OPEN 06 +#define ST_CLOSE 07 + +#define SY_PLUS '+' +#define SY_MINUS '-' +#define SY_MULTIPLY '*' +#define SY_DIVIDE '/' +#define SY_CARET '^' +#define SY_OPEN '(' +#define SY_CLOSE ')' + +class CSymbol : public CBase +{ + private: + int iType; + + public: + CSymbol(); + virtual ~CSymbol(); + + static int issymbol(int ch); + void SetType(int Type); + int GetType(); + bool Equal(CSymbol dif); + bool Less(CSymbol dif); +}; + +#endif diff --git a/extension/src/port/UserInterface/PythonItemModule.cpp b/extension/src/port/UserInterface/PythonItemModule.cpp index aab220f9..a7f8bdb0 100644 --- a/extension/src/port/UserInterface/PythonItemModule.cpp +++ b/extension/src/port/UserInterface/PythonItemModule.cpp @@ -283,13 +283,13 @@ PyObject * itemGetIconInstance(PyObject * poSelf, PyObject * poArgs) CGraphicImageInstance * pImageInstance = CGraphicImageInstance::New(); pImageInstance->SetImagePointer(pImage); - return Py_BuildValue("i", pImageInstance); + return Py_BuildPointer(pImageInstance); // PORT: was Py_BuildValue("i", ...) (ILP32 handle) } PyObject * itemDeleteIconInstance(PyObject * poSelf, PyObject * poArgs) { - int iHandle; - if (!PyTuple_GetInteger(poArgs, 0, &iHandle)) + CGraphicImageInstance * iHandle; // PORT: was int (ILP32 handle) + if (!PyTuple_GetPointer(poArgs, 0, &iHandle)) return Py_BadArgument(); CGraphicImageInstance::Delete((CGraphicImageInstance *) iHandle); diff --git a/extension/src/port/UserInterface/PythonSkill.cpp b/extension/src/port/UserInterface/PythonSkill.cpp new file mode 100644 index 00000000..d52977f7 --- /dev/null +++ b/extension/src/port/UserInterface/PythonSkill.cpp @@ -0,0 +1,2259 @@ +#include "StdAfx.h" +#include "../common/PortPythonPointer.h" // PORT: preserve Win32 pointer handles on 64-bit hosts +#include "PythonSkill.h" + +#include "../EterBase/Poly/Poly.h" +#include "../EterPack/EterPackManager.h" +#include "InstanceBase.h" +#include "PythonPlayer.h" + +std::map CPythonSkill::SSkillData::ms_StatusNameMap; +std::map CPythonSkill::SSkillData::ms_NewMinStatusNameMap; +std::map CPythonSkill::SSkillData::ms_NewMaxStatusNameMap; +DWORD CPythonSkill::SSkillData::ms_dwTimeIncreaseSkillNumber = 0; + +BOOL SKILL_EFFECT_UPGRADE_ENABLE = FALSE; + +int SplitLine(const char * c_szText, CTokenVector* pstTokenVector, const char * c_szDelimeter) +{ + pstTokenVector->reserve(10); + pstTokenVector->clear(); + + std::string stToken; + std::string stLine = c_szText; + + DWORD basePos = 0; + + do + { + int beginPos = stLine.find_first_not_of(c_szDelimeter, basePos); + + if (beginPos < 0) + return -1; + + int endPos; + + if (stLine[beginPos] == '"') + { + ++beginPos; + endPos = stLine.find_first_of("\"", beginPos); + + if (endPos < 0) + return -2; + + basePos = endPos + 1; + } + else + { + endPos = stLine.find_first_of(c_szDelimeter, beginPos); + basePos = endPos; + } + + pstTokenVector->push_back(stLine.substr(beginPos, endPos - beginPos)); + + // 추가 코드. 맨뒤에 탭이 있는 경우를 체크한다. - [levites] + if (int(stLine.find_first_not_of(c_szDelimeter, basePos)) < 0) + break; + } while (basePos < stLine.length()); + + return 0; +} + +// OVERWRITE_SKILLPROTO_POLY +void string_replace_word(const char* base, int base_len, const char* src, int src_len, const char* dst, int dst_len, std::string& result) +{ + result.resize(0); + if (base_len > 0 && dst_len > src_len) + result.reserve(base_len + (dst_len-src_len) * (base_len/src_len)); + else + result.reserve(base_len); + + int prev = 0; + int cur = 0; + while (cur < base_len) + { + if (memcmp(base + cur, src, src_len) == 0) + { + result.append(base + prev, cur - prev); + result.append(dst, dst_len); + cur += src_len; + prev = cur; + } + else + { + ++cur; + } + } + result.append(base + prev, cur - prev); +} +// END_OF_OVERWRITE_SKILLPROTO_POLY + +bool CPythonSkill::RegisterSkillTable(const char * c_szFileName) +{ + const VOID* pvData; + CMappedFile kFile; + if (!CEterPackManager::Instance().Get(kFile, c_szFileName, &pvData)) + return false; + + CMemoryTextFileLoader textFileLoader; + textFileLoader.Bind(kFile.Size(), pvData); + + // OVERWRITE_SKILLPROTO_POLY + std::string src_poly_rand; + std::string src_poly_atk; + std::string src_poly_mwep; + // END_OF_OVERWRITE_SKILLPROTO_POLY + + CTokenVector TokenVector; + for (DWORD i = 0; i < textFileLoader.GetLineCount(); ++i) + { + if (!textFileLoader.SplitLineByTab(i, &TokenVector)) + continue; + + std::string strLine = textFileLoader.GetLineString(i); + + if (TABLE_TOKEN_TYPE_MAX_NUM != TokenVector.size()) + { + Tracef("CPythonSkill::RegisterSkillTable(%s) - Strange Token Count [Line:%d / TokenCount:%d]\n", c_szFileName, i, TokenVector.size()); + continue; + } + + int iVnum = atoi(TokenVector[TABLE_TOKEN_TYPE_VNUM].c_str()); + + TSkillDataMap::iterator itor = m_SkillDataMap.find(iVnum); + if (m_SkillDataMap.end() == itor) + { + Tracef("CPythonSkill::RegisterSkillTable(%s) - NOT EXIST SkillDesc [Vnum:%d Line:%d]\n", c_szFileName, iVnum, i); + continue; + } + + TSkillData & rSkillData = itor->second; + + const std::string & c_strSPCostPoly = TokenVector[TABLE_TOKEN_TYPE_SP_COST_POLY]; + if (!c_strSPCostPoly.empty()) + { + rSkillData.strNeedSPFormula = c_strSPCostPoly; + } + + const std::string & c_strCooldownPoly = TokenVector[TABLE_TOKEN_TYPE_COOLDOWN_POLY]; + if (!c_strCooldownPoly.empty()) + { + rSkillData.strCoolTimeFormula = c_strCooldownPoly; + } + + const std::string & c_strDurationSPCostPoly = TokenVector[TABLE_TOKEN_TYPE_DURATION_SP_COST_POLY]; + if (!c_strDurationSPCostPoly.empty()) + { + rSkillData.strContinuationSPFormula = c_strDurationSPCostPoly; + } + + const std::string & c_strTargetRange = TokenVector[TABLE_TOKEN_TYPE_TARGET_RANGE]; + if (!c_strTargetRange.empty()) + { + rSkillData.dwTargetRange = atoi(c_strTargetRange.c_str()); + } + + rSkillData.strDuration = TokenVector[TABLE_TOKEN_TYPE_DURATION_POLY]; + + + const DWORD LevelEmpty = 1; + + const std::string & c_strMaxLevel = TokenVector[TABLE_TOKEN_TYPE_MAX_LEVEL]; + if (!c_strMaxLevel.empty()) + { + int maxLevel = atoi(c_strMaxLevel.c_str()); + if(maxLevel > LevelEmpty) + rSkillData.byMaxLevel = maxLevel; + } + + const std::string & c_strLevelLimit = TokenVector[TABLE_TOKEN_TYPE_LEVEL_LIMIT]; + if (!c_strLevelLimit.empty()) + { + int levelLimit = atoi(c_strLevelLimit.c_str()); + if(rSkillData.byLevelLimit > LevelEmpty) + rSkillData.byLevelLimit = levelLimit; + } + const std::string & c_strPointPoly = TokenVector[TABLE_TOKEN_TYPE_POINT_POLY]; + + // OVERWRITE_SKILLPROTO_POLY + bool USE_SKILL_PROTO = LocaleService_IsCHEONMA() ? false : true; + + switch (iVnum) + { + case 34: + + // GUILD_SKILL_DISPLAY_BUG_FIX + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + case 157: + // END_OF_GUILD_SKILL_DISPLAY_BUG_FIX + USE_SKILL_PROTO = false; + break; + } + + if (!rSkillData.AffectDataVector.empty() && USE_SKILL_PROTO) + { + TAffectData& affect = rSkillData.AffectDataVector[0]; + + if (strstr(c_strPointPoly.c_str(), "atk") != NULL || + strstr(c_strPointPoly.c_str(), "mwep") != NULL || + strstr(c_strPointPoly.c_str(), "number") != NULL) + { + src_poly_rand = ""; + src_poly_atk = ""; + src_poly_mwep = ""; + + // MIN + string_replace_word(c_strPointPoly.c_str(), c_strPointPoly.length(), + "number", 6, "min", 3, src_poly_rand); + string_replace_word(src_poly_rand.c_str(), src_poly_rand.length(), + "atk", 3, "minatk", 6, src_poly_atk); + string_replace_word(src_poly_atk.c_str(), src_poly_atk.length(), + "mwep", 4, "minmwep", 7, affect.strAffectMinFormula); + // END_OF_MIN + + // MAX + string_replace_word(c_strPointPoly.c_str(), c_strPointPoly.length(), + "number", 6, "max", 3, src_poly_rand); + string_replace_word(src_poly_rand.c_str(), src_poly_rand.length(), + "atk", 3, "maxatk", 6, src_poly_atk); + string_replace_word(src_poly_atk.c_str(), src_poly_atk.length(), + "mwep", 4, "maxmwep", 7, affect.strAffectMaxFormula); + // END_OF_MAX + + switch (iVnum) + { + case 1: // 삼연참 + affect.strAffectMinFormula += "* 3"; + affect.strAffectMaxFormula += "* 3"; + break; + } + + } + else + { + affect.strAffectMinFormula = c_strPointPoly; + affect.strAffectMaxFormula = ""; + } + } + // END_OF_OVERWRITE_SKILLPROTO_POLY + } + + return true; +} + +void CPythonSkill::__RegisterGradeIconImage(TSkillData & rData, const char * c_szHeader, const char * c_szImageName) +{ + for (int j = 0; j < SKILL_GRADE_COUNT; ++j) + { + TGradeData & rGradeData = rData.GradeData[j]; + + char szCount[8+1]; + _snprintf(szCount, sizeof(szCount), "_%02d", j+1); + + std::string strFileName = ""; + strFileName += c_szHeader; + strFileName += c_szImageName; + strFileName += szCount; + strFileName += ".sub"; + rGradeData.pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(strFileName.c_str()); + } +} + +void CPythonSkill::__RegisterNormalIconImage(TSkillData & rData, const char * c_szHeader, const char * c_szImageName) +{ + std::string strFileName = ""; + strFileName += c_szHeader; + strFileName += c_szImageName; + strFileName += ".sub"; + rData.pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(strFileName.c_str()); + for (int j = 0; j < SKILL_GRADE_COUNT; ++j) + { + TGradeData & rGradeData = rData.GradeData[j]; + rGradeData.pImage = rData.pImage; + } +} +extern const DWORD c_iSkillIndex_Riding; +bool CPythonSkill::RegisterSkillDesc(const char * c_szFileName) +{ + const VOID* pvData; + CMappedFile kFile; + if (!CEterPackManager::Instance().Get(kFile, c_szFileName, &pvData)) + return false; + + CMemoryTextFileLoader textFileLoader; + textFileLoader.Bind(kFile.Size(), pvData); + + CTokenVector TokenVector; + for (DWORD i = 0; i < textFileLoader.GetLineCount(); ++i) + { + if (!textFileLoader.SplitLineByTab(i, &TokenVector)) + continue; + + if (DESC_TOKEN_TYPE_VNUM >= TokenVector.size()) + { + TraceError("SkillDesc.line(%d).NO_VNUM_ERROR\n", i + 1); + continue; + } + + DWORD iSkillIndex = atoi(TokenVector[DESC_TOKEN_TYPE_VNUM].c_str()); + if (iSkillIndex == 0) + { + TraceError("SkillDesc.line(%d).NO_INDEX_ERROR\n", i + 1); + continue; + } + + if (DESC_TOKEN_TYPE_JOB >= TokenVector.size()) + { + TraceError("SkillDesc.line(%d).NO_JOB_ERROR\n", i + 1); + continue; + } + + m_SkillDataMap.insert(std::make_pair(iSkillIndex, TSkillData())); + TSkillData & rSkillData = m_SkillDataMap[iSkillIndex]; + + // Vnum + rSkillData.dwSkillIndex = iSkillIndex; + + // Type + { + std::string strJob = TokenVector[DESC_TOKEN_TYPE_JOB]; + stl_lowers(strJob); + + std::map::iterator it = m_SkillTypeIndexMap.find(strJob.c_str()); + if (m_SkillTypeIndexMap.end() == it) + { + TraceError("CPythonSkill::RegisterSkillDesc(dwSkillIndex=%d, strType=%s).STRANGE_SKILL_TYPE", iSkillIndex, strJob.c_str()); + continue; + } + + rSkillData.byType = BYTE(it->second); + } + + // Name + { + rSkillData.strName = TokenVector[DESC_TOKEN_TYPE_NAME1]; + rSkillData.GradeData[0].strName = TokenVector[DESC_TOKEN_TYPE_NAME1]; + rSkillData.GradeData[1].strName = TokenVector[DESC_TOKEN_TYPE_NAME2]; + rSkillData.GradeData[2].strName = TokenVector[DESC_TOKEN_TYPE_NAME3]; + + if (rSkillData.GradeData[1].strName.empty()) + rSkillData.GradeData[1].strName = TokenVector[DESC_TOKEN_TYPE_NAME1]; + if (rSkillData.GradeData[2].strName.empty()) + rSkillData.GradeData[2].strName = TokenVector[DESC_TOKEN_TYPE_NAME1]; + } + + // Description + { + rSkillData.strDescription = TokenVector[DESC_TOKEN_TYPE_DESCRIPTION]; + } + + // Condition + { + rSkillData.ConditionDataVector.clear(); + for (int j = 0; j < CONDITION_COLUMN_COUNT; ++j) + { + const std::string & c_rstrCondition = TokenVector[DESC_TOKEN_TYPE_CONDITION1+j]; + if (!c_rstrCondition.empty()) + rSkillData.ConditionDataVector.push_back(c_rstrCondition); + } + } + + // Attribute + { + const std::string & c_rstrAttribute = TokenVector[DESC_TOKEN_TYPE_ATTRIBUTE]; + CTokenVector AttributeTokenVector; + SplitLine(c_rstrAttribute.c_str(), &AttributeTokenVector, "|"); + + for (CTokenVector::iterator it = AttributeTokenVector.begin(); it != AttributeTokenVector.end(); ++it) + { + std::string & rstrToken = *it; + std::map::iterator it2 = m_SkillAttributeIndexMap.find(rstrToken); + if (m_SkillAttributeIndexMap.end() == it2) + { + TraceError("CPythonSkill::RegisterSkillDesc(dwSkillIndex=%d) - Strange Skill Attribute(%s)", iSkillIndex, rstrToken.c_str()); + continue; + } + rSkillData.dwSkillAttribute |= it2->second; + } + } + + // Weapon + { + const std::string & c_rstrWeapon = TokenVector[DESC_TOKEN_TYPE_WEAPON]; + CTokenVector WeaponTokenVector; + SplitLine(c_rstrWeapon.c_str(), &WeaponTokenVector, "|"); + + for (CTokenVector::iterator it = WeaponTokenVector.begin(); it != WeaponTokenVector.end(); ++it) + { + std::string & rstrToken = *it; + std::map::iterator it2 = m_SkillNeedWeaponIndexMap.find(rstrToken); + if (m_SkillNeedWeaponIndexMap.end() == it2) + { + TraceError("CPythonSkill::RegisterSkillDesc(dwSkillIndex=%d) - Strange Skill Need Weapon(%s)", iSkillIndex, rstrToken.c_str()); + continue; + } + rSkillData.dwNeedWeapon |= it2->second; + } + } + + // Icon Name + { + const std::string & c_rstrJob = TokenVector[DESC_TOKEN_TYPE_JOB]; + const std::string & c_rstrIconName = TokenVector[DESC_TOKEN_TYPE_ICON_NAME]; + + // NOTE : Support 스킬임에도 3단계를 지원해야 해서 예외 처리 - [levites] + if (c_iSkillIndex_Riding == iSkillIndex) + { + char szIconFileNameHeader[64+1]; + _snprintf(szIconFileNameHeader, sizeof(szIconFileNameHeader), "%sskill/common/support/", g_strImagePath.c_str()); + + __RegisterGradeIconImage(rSkillData, szIconFileNameHeader, c_rstrIconName.c_str()); + } + else if (m_PathNameMap.end() != m_PathNameMap.find(c_rstrJob)) + { + char szIconFileNameHeader[64+1]; + _snprintf(szIconFileNameHeader, sizeof(szIconFileNameHeader), "%sskill/%s/", g_strImagePath.c_str(), m_PathNameMap[c_rstrJob].c_str()); + + switch (rSkillData.byType) + { + case SKILL_TYPE_ACTIVE: + { + __RegisterGradeIconImage(rSkillData, szIconFileNameHeader, c_rstrIconName.c_str()); + break; + } + case SKILL_TYPE_SUPPORT: + case SKILL_TYPE_GUILD: + case SKILL_TYPE_HORSE: + { + __RegisterNormalIconImage(rSkillData, szIconFileNameHeader, c_rstrIconName.c_str()); + break; + } + } + } + } + + // Motion Index + if (TokenVector.size() > DESC_TOKEN_TYPE_MOTION_INDEX) + { + const std::string & c_rstrMotionIndex = TokenVector[DESC_TOKEN_TYPE_MOTION_INDEX]; + if (c_rstrMotionIndex.empty()) + { + rSkillData.bNoMotion = TRUE; + rSkillData.wMotionIndex = 0; + } + else + { + rSkillData.bNoMotion = FALSE; + rSkillData.wMotionIndex = (WORD)atoi(c_rstrMotionIndex.c_str()); + } + } + else + { + rSkillData.wMotionIndex = 0; + } + + if (TokenVector.size() > DESC_TOKEN_TYPE_TARGET_COUNT_FORMULA) + rSkillData.strTargetCountFormula = TokenVector[DESC_TOKEN_TYPE_TARGET_COUNT_FORMULA].c_str(); + if (TokenVector.size() > DESC_TOKEN_TYPE_MOTION_LOOP_COUNT_FORMULA) + rSkillData.strMotionLoopCountFormula = TokenVector[DESC_TOKEN_TYPE_MOTION_LOOP_COUNT_FORMULA].c_str(); + + rSkillData.AffectDataNewVector.clear(); + rSkillData.AffectDataNewVector.reserve(3); + + // Affect + for (int j = 0; j < AFFECT_COLUMN_COUNT; ++j) + { + int iDescriptionSlotIndex = DESC_TOKEN_TYPE_AFFECT_DESCRIPTION_1 + j*AFFECT_STEP_COUNT; + int iMinSlotIndex = DESC_TOKEN_TYPE_AFFECT_MIN_1 + j*AFFECT_STEP_COUNT; + int iMaxSlotIndex = DESC_TOKEN_TYPE_AFFECT_MAX_1 + j*AFFECT_STEP_COUNT; + + if (TokenVector.size() > iDescriptionSlotIndex) + if (!TokenVector[iDescriptionSlotIndex].empty()) + { + rSkillData.AffectDataVector.push_back(TAffectData()); + + TAffectData & rAffectData = *rSkillData.AffectDataVector.rbegin(); + rAffectData.strAffectDescription = ""; + rAffectData.strAffectMinFormula = ""; + rAffectData.strAffectMaxFormula = ""; + + rAffectData.strAffectDescription = TokenVector[iDescriptionSlotIndex]; + if (TokenVector.size() > iMinSlotIndex) + if (!TokenVector[iMinSlotIndex].empty()) + rAffectData.strAffectMinFormula = TokenVector[iMinSlotIndex]; + if (TokenVector.size() > iMaxSlotIndex) + if (!TokenVector[iMaxSlotIndex].empty()) + rAffectData.strAffectMaxFormula = TokenVector[iMaxSlotIndex]; + } + } + + if (TokenVector.size() > DESC_TOKEN_TYPE_MOTION_INDEX_GRADE_NUM) + { + int numGrade = atoi(TokenVector[DESC_TOKEN_TYPE_MOTION_INDEX_GRADE_NUM].c_str()); + if (SKILL_EFFECT_COUNT < numGrade) + { + TraceError("%s[%s] \260\241 \265\356\261\336 \301\246\307\321[%d]\300\273 \263\321\276\356\260\254\275\300\264\317\264\331.",rSkillData.strName.c_str(), TokenVector[DESC_TOKEN_TYPE_MOTION_INDEX_GRADE_NUM].c_str(), SKILL_EFFECT_COUNT); + return false; + } + for (int iGrade = 0; iGrade < numGrade; iGrade++) + { + //if (iGrade == SKILL_GRADE_COUNT) + // rSkillData.GradeData[iGrade] = rSkillData.GradeData[iGrade-1]; + rSkillData.GradeData[iGrade].wMotionIndex = rSkillData.wMotionIndex+iGrade*SKILL_GRADEGAP; + } + for(int iSpace = numGrade; iSpace < SKILL_EFFECT_COUNT; iSpace++) + { + rSkillData.GradeData[iSpace].wMotionIndex = rSkillData.wMotionIndex; + } + } + + if (TokenVector.size() > DESC_TOKEN_TYPE_LEVEL_LIMIT) + { + const std::string & c_rstrLevelLimit = TokenVector[DESC_TOKEN_TYPE_LEVEL_LIMIT]; + if (c_rstrLevelLimit.empty()) + rSkillData.byLevelLimit = 0; + else + rSkillData.byLevelLimit = (WORD)atoi(c_rstrLevelLimit.c_str()); + } + + if (TokenVector.size() > DESC_TOKEN_TYPE_MAX_LEVEL) + { + const std::string & c_rstrMaxLevel = TokenVector[DESC_TOKEN_TYPE_MAX_LEVEL]; + const DWORD LevelLimitEmpty = 1; + if (c_rstrMaxLevel.empty()) + { + if(rSkillData.byLevelLimit > LevelLimitEmpty) + rSkillData.byMaxLevel = rSkillData.byLevelLimit; + else + rSkillData.byMaxLevel = 20; + } + else + rSkillData.byMaxLevel = (BYTE)atoi(c_rstrMaxLevel.c_str()); + } + } + + return true; +} + +void CPythonSkill::Destroy() +{ + m_SkillDataMap.clear(); +} + +bool CPythonSkill::RegisterSkill(DWORD dwSkillIndex, const char * c_szFileName) +{ + CTextFileLoader TextFileLoader; + if (!TextFileLoader.Load(c_szFileName)) + { + TraceError("CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s) - Failed to find file", dwSkillIndex, c_szFileName); + return false; + } + + TextFileLoader.SetTop(); + + TSkillData SkillData; + SkillData.dwSkillIndex = dwSkillIndex; + + std::string strTypeName; + if (TextFileLoader.GetTokenString("type", &strTypeName)) + { + stl_lowers(strTypeName); + std::map::iterator it = m_SkillTypeIndexMap.find(strTypeName.c_str()); + if (m_SkillTypeIndexMap.end() == it) + { + TraceError("Strange Skill Type - CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s)", dwSkillIndex, c_szFileName); + return false; + } + + SkillData.byType = (BYTE)it->second; + } + else + { + TraceError("CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s) - Failed to find key [type]", dwSkillIndex, c_szFileName); + return false; + } + + CTokenVector * pAttributeTokenVector; + if (TextFileLoader.GetTokenVector("attribute", &pAttributeTokenVector)) + { + for (CTokenVector::iterator it = pAttributeTokenVector->begin(); it != pAttributeTokenVector->end(); ++it) + { + std::string & rstrToken = *it; + std::map::iterator it2 = m_SkillAttributeIndexMap.find(rstrToken.c_str()); + if (m_SkillAttributeIndexMap.end() == it2) + { + TraceError("Strange Skill Attribute - CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s)", dwSkillIndex, c_szFileName); + continue; + } + SkillData.dwSkillAttribute |= it2->second; + } + } + + CTokenVector * pNeedWeaponVector; + if (TextFileLoader.GetTokenVector("needweapon", &pNeedWeaponVector)) + { + for (CTokenVector::iterator it = pNeedWeaponVector->begin(); it != pNeedWeaponVector->end(); ++it) + { + std::string & rstrToken = *it; + std::map::iterator it2 = m_SkillNeedWeaponIndexMap.find(rstrToken.c_str()); + if (m_SkillNeedWeaponIndexMap.end() == it2) + { + TraceError("Strange Skill Need Weapon - CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s)", dwSkillIndex, c_szFileName); + continue; + } + SkillData.dwNeedWeapon |= it2->second; + } + } + + { + char szName[256]; + sprintf(szName, "%dname", LocaleService_GetCodePage()); + if (!TextFileLoader.GetTokenString(szName, &SkillData.strName)) + if (!TextFileLoader.GetTokenString("name", &SkillData.strName)) + { + TraceError("CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s) - Failed to find [%s]", dwSkillIndex, c_szFileName, szName); + return false; + } + } + + { + char szName[256]; + sprintf(szName, "%ddescription", LocaleService_GetCodePage()); + if (!TextFileLoader.GetTokenString(szName, &SkillData.strDescription)) + TextFileLoader.GetTokenString("description", &SkillData.strDescription); + } + + if (!TextFileLoader.GetTokenString("iconfilename", &SkillData.strIconFileName)) + { + TraceError("CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s) - Failed to find [iconfilename]", dwSkillIndex, c_szFileName); + return false; + } + + { + CTokenVector * pConditionDataVector; + + char szConditionData[256]; + sprintf(szConditionData, "%dconditiondata", LocaleService_GetCodePage()); + + bool isConditionData=true; + if (!TextFileLoader.GetTokenVector(szConditionData, &pConditionDataVector)) + if (!TextFileLoader.GetTokenVector("conditiondata", &pConditionDataVector)) + isConditionData=false; + + if (isConditionData) + { + DWORD dwSize = pConditionDataVector->size(); + SkillData.ConditionDataVector.clear(); + SkillData.ConditionDataVector.resize(dwSize); + for (DWORD i = 0; i < dwSize; ++i) + { + SkillData.ConditionDataVector[i] = pConditionDataVector->at(i); + } + } + } + + { + CTokenVector * pAffectDataVector; + + char szAffectData[256]; + sprintf(szAffectData, "%daffectdata", LocaleService_GetCodePage()); + + bool isAffectData=true; + if (!TextFileLoader.GetTokenVector(szAffectData, &pAffectDataVector)) + if (!TextFileLoader.GetTokenVector("affectdata", &pAffectDataVector)) + isAffectData=false; + + if (isAffectData) + { + DWORD dwSize = pAffectDataVector->size()/3; + SkillData.AffectDataVector.clear(); + SkillData.AffectDataVector.resize(dwSize); + for (DWORD i = 0; i < dwSize; ++i) + { + SkillData.AffectDataVector[i].strAffectDescription = pAffectDataVector->at(i*3+0); + SkillData.AffectDataVector[i].strAffectMinFormula = pAffectDataVector->at(i*3+1); + SkillData.AffectDataVector[i].strAffectMaxFormula = pAffectDataVector->at(i*3+2); + } + } + } + + { + CTokenVector * pGradeDataVector; + + char szGradeData[256]; + sprintf(szGradeData, "%dgradedata", LocaleService_GetCodePage()); + + if (TextFileLoader.GetTokenVector(szGradeData, &pGradeDataVector)) + { + if (SKILL_GRADE_COUNT*2 != pGradeDataVector->size()) + TraceError("CPythonSkill::RegisterSkill(dwSkillIndex=%d, c_szFileName=%s) - Strange Grade Data Count", dwSkillIndex, c_szFileName); + + for (DWORD i = 0; i < min(SKILL_GRADE_COUNT, pGradeDataVector->size()/2); ++i) + { + SkillData.GradeData[i].strName = pGradeDataVector->at(i*2+0); + std::string strIconFileName = g_strImagePath + pGradeDataVector->at(i*2+1); + SkillData.GradeData[i].pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(strIconFileName.c_str()); + } + } + } + + TextFileLoader.GetTokenString("cooltimeformula", &SkillData.strCoolTimeFormula); + TextFileLoader.GetTokenString("targetcountformula", &SkillData.strTargetCountFormula); + TextFileLoader.GetTokenString("motionloopcountformula", &SkillData.strMotionLoopCountFormula); + TextFileLoader.GetTokenString("needspformula", &SkillData.strNeedSPFormula); + TextFileLoader.GetTokenString("continuationspformula", &SkillData.strContinuationSPFormula); + TextFileLoader.GetTokenDoubleWord("range", &SkillData.dwTargetRange); + TextFileLoader.GetTokenByte("maxlevel", &SkillData.byMaxLevel); + TextFileLoader.GetTokenByte("leveluppoint", &SkillData.byLevelUpPoint); + + WORD wMotionIndex; + if (TextFileLoader.GetTokenWord("motionindex", &wMotionIndex)) + { + SkillData.wMotionIndex = wMotionIndex; + } + else + { + SkillData.wMotionIndex = 0; + } + + WORD wMotionIndexForMe; + if (TextFileLoader.GetTokenWord("motionindexforme", &wMotionIndexForMe)) + { + SkillData.wMotionIndexForMe = wMotionIndexForMe; + } + else + { + SkillData.wMotionIndexForMe = 0; + } + + SkillData.strIconFileName = g_strImagePath + SkillData.strIconFileName; + SkillData.pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(SkillData.strIconFileName.c_str()); + + m_SkillDataMap.insert(TSkillDataMap::value_type(dwSkillIndex, SkillData)); + + ///// + + if (SkillData.IsTimeIncreaseSkill()) + { + CPythonSkill::SSkillData::ms_dwTimeIncreaseSkillNumber = SkillData.dwSkillIndex; + } + + return true; +} + +BOOL CPythonSkill::GetSkillData(DWORD dwSkillIndex, TSkillData ** ppSkillData) +{ + TSkillDataMap::iterator it = m_SkillDataMap.find(dwSkillIndex); + + if (m_SkillDataMap.end() == it) + return FALSE; + + *ppSkillData = &(it->second); + return TRUE; +} + +bool CPythonSkill::GetSkillDataByName(const char * c_szName, TSkillData ** ppSkillData) +{ + TSkillDataMap::iterator itor = m_SkillDataMap.begin(); + for (; itor != m_SkillDataMap.end(); ++itor) + { + TSkillData * pData = &(itor->second); + if (0 == pData->strName.compare(c_szName)) + { + *ppSkillData = &(itor->second); + return true; + } + } + return false; +} + +void CPythonSkill::SetPathName(const char * c_szFileName) +{ + m_strPathName = c_szFileName; +} + +const char * CPythonSkill::GetPathName() +{ + return m_strPathName.c_str(); +} + +void CPythonSkill::TEST() +{ + BOOL isFirst; + std::map::iterator itorSub; + + FILE * File = fopen("test.txt", "w"); + + for (TSkillDataMap::iterator itor = m_SkillDataMap.begin(); itor != m_SkillDataMap.end(); ++itor) + { + TSkillData & rSkillData = itor->second; + + std::string strLine = ""; + strLine += rSkillData.strName.c_str(); + strLine += "\t"; + // Name2 + strLine += "\t"; + // Name3 + strLine += "\t"; + strLine += rSkillData.strDescription; + strLine += "\t"; + if (rSkillData.ConditionDataVector.size() > 0) + strLine += rSkillData.ConditionDataVector[0]; + strLine += "\t"; + if (rSkillData.ConditionDataVector.size() > 1) + strLine += rSkillData.ConditionDataVector[1]; + strLine += "\t"; + if (rSkillData.ConditionDataVector.size() > 2) + strLine += rSkillData.ConditionDataVector[2]; + strLine += "\t"; + if (rSkillData.ConditionDataVector.size() > 3) + strLine += rSkillData.ConditionDataVector[3]; + + strLine += "\t"; + isFirst = TRUE; + for (itorSub = m_SkillAttributeIndexMap.begin(); itorSub != m_SkillAttributeIndexMap.end(); ++itorSub) + { + if (itorSub->second & rSkillData.dwSkillAttribute) + { + if (isFirst) + { + isFirst = FALSE; + } + else + { + strLine += "|"; + } + strLine += itorSub->first.c_str(); + } + } + + strLine += "\t"; + isFirst = TRUE; + for (itorSub = m_SkillNeedWeaponIndexMap.begin(); itorSub != m_SkillNeedWeaponIndexMap.end(); ++itorSub) + { + if (itorSub->second & rSkillData.dwNeedWeapon) + { + if (isFirst) + { + isFirst = FALSE; + } + else + { + strLine += "|"; + } + strLine += itorSub->first.c_str(); + } + } + + strLine += "\t"; + std::string strFileName = rSkillData.strIconFileName; + int iPos = strFileName.find_last_of("/", rSkillData.strIconFileName.length()); + if (iPos > 0) + strFileName = strFileName.substr(iPos+1, strFileName.length() - iPos - 4 - 1); + strLine += strFileName; + + strLine += "\t"; + char szMotionIndex[32+1]; + _snprintf(szMotionIndex, sizeof(szMotionIndex), "%d", rSkillData.wMotionIndex); + strLine += szMotionIndex; + + strLine += "\t"; + if (rSkillData.wMotionIndexForMe > 1) + { + char szMotionIndexForMe[32+1]; + _snprintf(szMotionIndexForMe, sizeof(szMotionIndexForMe), "%d", rSkillData.wMotionIndexForMe); + strLine += szMotionIndexForMe; + } + + assert(rSkillData.AffectDataVector.size() <= 3); + strLine += "\t"; + if (rSkillData.AffectDataVector.size() > 0) + { + strLine += rSkillData.AffectDataVector[0].strAffectDescription; + strLine += "\t"; + strLine += rSkillData.AffectDataVector[0].strAffectMinFormula; + strLine += "\t"; + strLine += rSkillData.AffectDataVector[0].strAffectMaxFormula; + } + strLine += "\t"; + if (rSkillData.AffectDataVector.size() > 1) + { + strLine += rSkillData.AffectDataVector[1].strAffectDescription; + strLine += "\t"; + strLine += rSkillData.AffectDataVector[1].strAffectMinFormula; + strLine += "\t"; + strLine += rSkillData.AffectDataVector[1].strAffectMaxFormula; + } + strLine += "\t"; + if (rSkillData.AffectDataVector.size() > 2) + { + strLine += rSkillData.AffectDataVector[2].strAffectDescription; + strLine += "\t"; + strLine += rSkillData.AffectDataVector[2].strAffectMinFormula; + strLine += "\t"; + strLine += rSkillData.AffectDataVector[2].strAffectMaxFormula; + } + + fprintf(File, "%s\n", strLine.c_str()); + } + + fclose(File); +} + +CPythonSkill::CPythonSkill() +{ + m_SkillTypeIndexMap.insert(std::map::value_type("none", SKILL_TYPE_NONE)); + m_SkillTypeIndexMap.insert(std::map::value_type("active", SKILL_TYPE_ACTIVE)); + m_SkillTypeIndexMap.insert(std::map::value_type("support", SKILL_TYPE_SUPPORT)); + m_SkillTypeIndexMap.insert(std::map::value_type("guild", SKILL_TYPE_GUILD)); + m_SkillTypeIndexMap.insert(std::map::value_type("horse", SKILL_TYPE_HORSE)); + m_SkillTypeIndexMap.insert(std::map::value_type("warrior", SKILL_TYPE_ACTIVE)); + m_SkillTypeIndexMap.insert(std::map::value_type("assassin", SKILL_TYPE_ACTIVE)); + m_SkillTypeIndexMap.insert(std::map::value_type("sura", SKILL_TYPE_ACTIVE)); + m_SkillTypeIndexMap.insert(std::map::value_type("shaman", SKILL_TYPE_ACTIVE)); + m_SkillTypeIndexMap.insert(std::map::value_type("passive", SKILL_TYPE_ACTIVE)); + + m_SkillAttributeIndexMap.insert(std::map::value_type("NEED_POISON_BOTTLE", SKILL_ATTRIBUTE_NEED_POISON_BOTTLE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("NEED_EMPTY_BOTTLE", SKILL_ATTRIBUTE_NEED_EMPTY_BOTTLE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("CAN_USE_IF_NOT_ENOUGH", SKILL_ATTRIBUTE_CAN_USE_IF_NOT_ENOUGH)); + m_SkillAttributeIndexMap.insert(std::map::value_type("FAN_RANGE", SKILL_ATTRIBUTE_FAN_RANGE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("NEED_CORPSE", SKILL_ATTRIBUTE_NEED_CORPSE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("NEED_TARGET", SKILL_ATTRIBUTE_NEED_TARGET)); + m_SkillAttributeIndexMap.insert(std::map::value_type("TOGGLE", SKILL_ATTRIBUTE_TOGGLE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("WEAPON_LIMITATION", SKILL_ATTRIBUTE_WEAPON_LIMITATION)); + m_SkillAttributeIndexMap.insert(std::map::value_type("MELEE_ATTACK", SKILL_ATTRIBUTE_MELEE_ATTACK)); + m_SkillAttributeIndexMap.insert(std::map::value_type("CHARGE_ATTACK", SKILL_ATTRIBUTE_CHARGE_ATTACK)); + m_SkillAttributeIndexMap.insert(std::map::value_type("USE_HP", SKILL_ATTRIBUTE_USE_HP)); + m_SkillAttributeIndexMap.insert(std::map::value_type("CAN_CHANGE_DIRECTION", SKILL_ATTRIBUTE_CAN_CHANGE_DIRECTION)); + m_SkillAttributeIndexMap.insert(std::map::value_type("STANDING_SKILL", SKILL_ATTRIBUTE_STANDING_SKILL)); + m_SkillAttributeIndexMap.insert(std::map::value_type("ONLY_FOR_ALLIANCE", SKILL_ATTRIBUTE_ONLY_FOR_ALLIANCE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("CAN_USE_FOR_ME", SKILL_ATTRIBUTE_CAN_USE_FOR_ME)); + m_SkillAttributeIndexMap.insert(std::map::value_type("ATTACK_SKILL", SKILL_ATTRIBUTE_ATTACK_SKILL)); + m_SkillAttributeIndexMap.insert(std::map::value_type("MOVING_SKILL", SKILL_ATTRIBUTE_MOVING_SKILL)); + m_SkillAttributeIndexMap.insert(std::map::value_type("HORSE_SKILL", SKILL_ATTRIBUTE_HORSE_SKILL)); + m_SkillAttributeIndexMap.insert(std::map::value_type("TIME_INCREASE_SKILL", SKILL_ATTRIBUTE_TIME_INCREASE_SKILL)); + m_SkillAttributeIndexMap.insert(std::map::value_type("PASSIVE", SKILL_ATTRIBUTE_PASSIVE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("CANNOT_LEVEL_UP", SKILL_ATTRIBUTE_CANNOT_LEVEL_UP)); + m_SkillAttributeIndexMap.insert(std::map::value_type("ONLY_FOR_GUILD_WAR", SKILL_ATTRIBUTE_ONLY_FOR_GUILD_WAR)); + m_SkillAttributeIndexMap.insert(std::map::value_type("CIRCLE_RANGE", SKILL_ATTRIBUTE_CIRCLE_RANGE)); + m_SkillAttributeIndexMap.insert(std::map::value_type("SEARCH_TARGET", SKILL_ATTRIBUTE_SEARCH_TARGET)); + + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("SWORD", SKILL_NEED_WEAPON_SWORD)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("DAGGER", SKILL_NEED_WEAPON_DAGGER)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("BOW", SKILL_NEED_WEAPON_BOW)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("TWO_HANDED", SKILL_NEED_WEAPON_TWO_HANDED)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("DOUBLE_SWORD", SKILL_NEED_WEAPON_DOUBLE_SWORD)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("BELL", SKILL_NEED_WEAPON_BELL)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("FAN", SKILL_NEED_WEAPON_FAN)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("ARROW", SKILL_NEED_WEAPON_ARROW)); + m_SkillNeedWeaponIndexMap.insert(std::map::value_type("EMPTY_HAND", SKILL_NEED_WEAPON_EMPTY_HAND)); + + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("SWORD"), CItemData::WEAPON_SWORD)); + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("DAGGER"), CItemData::WEAPON_DAGGER)); + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("BOW"), CItemData::WEAPON_BOW)); + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("TWO_HANDED"), CItemData::WEAPON_TWO_HANDED)); + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("DOUBLE_SWORD"), CItemData::WEAPON_DAGGER)); + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("BELL"), CItemData::WEAPON_BELL)); + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("FAN"), CItemData::WEAPON_FAN)); + m_SkillWeaponTypeIndexMap.insert(std::make_pair(std::string("ARROW"), CItemData::WEAPON_ARROW)); + + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("chain"), POINT_NONE)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("HR"), POINT_HIT_RATE)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("LV"), POINT_LEVEL)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("Level"), POINT_LEVEL)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MaxHP"), POINT_MAX_HP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MaxSP"), POINT_MAX_SP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MinMWEP"), POINT_MIN_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MaxMWEP"), POINT_MAX_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MinWEP"), POINT_MIN_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MaxWEP"), POINT_MAX_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MinATK"), POINT_MIN_ATK)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MaxATK"), POINT_MAX_ATK)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("ATKSPD"), POINT_ATT_SPEED)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("AttackPower"), POINT_MIN_ATK)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("AtkMin"), POINT_MIN_ATK)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("AtkMax"), POINT_MAX_ATK)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("DefencePower"), POINT_DEF_GRADE)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("DEF"), POINT_DEF_GRADE)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MWEP"), POINT_MAGIC_ATT_GRADE)); + + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("MagicAttackPower"), POINT_MAGIC_ATT_GRADE)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("INT"), POINT_IQ)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("STR"), POINT_ST)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("DEX"), POINT_DX)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("CON"), POINT_HT)); + + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("minatk"), POINT_MIN_ATK)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("maxatk"), POINT_MAX_ATK)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("minmtk"), POINT_MIN_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("maxmtk"), POINT_MAX_WEP)); + + // GUILD_SKILL_DISPLAY_BUG_FIX + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("maxhp"), POINT_MAX_HP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("maxsp"), POINT_MAX_SP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("odef"), POINT_DEF_GRADE)); + // END_OF_GUILD_SKILL_DISPLAY_BUG_FIX + + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("minwep"), POINT_MIN_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("maxwep"), POINT_MAX_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("minmwep"), POINT_MIN_MAGIC_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("maxmwep"), POINT_MAX_MAGIC_WEP)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("lv"), POINT_LEVEL)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("ar"), POINT_HIT_RATE)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("iq"), POINT_IQ)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("str"), POINT_ST)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("dex"), POINT_DX)); + SSkillData::ms_StatusNameMap.insert(std::make_pair(std::string("con"), POINT_HT)); + + ///// + + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("atk"), POINT_MIN_ATK)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("mtk"), POINT_MIN_WEP)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("wep"), POINT_MIN_WEP)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("lv"), POINT_LEVEL)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("ar"), POINT_HIT_RATE)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("iq"), POINT_IQ)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("str"), POINT_ST)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("dex"), POINT_DX)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("con"), POINT_HT)); + + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("atk"), POINT_MAX_ATK)); + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("mtk"), POINT_MAX_WEP)); + SSkillData::ms_NewMinStatusNameMap.insert(std::make_pair(std::string("wep"), POINT_MAX_WEP)); + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("lv"), POINT_LEVEL)); + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("ar"), POINT_HIT_RATE)); + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("iq"), POINT_IQ)); + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("str"), POINT_ST)); + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("dex"), POINT_DX)); + SSkillData::ms_NewMaxStatusNameMap.insert(std::make_pair(std::string("con"), POINT_HT)); + + m_PathNameMap.insert(std::make_pair(std::string("WARRIOR"), std::string("warrior"))); + m_PathNameMap.insert(std::make_pair(std::string("ASSASSIN"), std::string("assassin"))); + m_PathNameMap.insert(std::make_pair(std::string("SURA"), std::string("sura"))); + m_PathNameMap.insert(std::make_pair(std::string("SHAMAN"), std::string("shaman"))); + m_PathNameMap.insert(std::make_pair(std::string("PASSIVE"), std::string("passive"))); + m_PathNameMap.insert(std::make_pair(std::string("SUPPORT"), std::string("common/support"))); + m_PathNameMap.insert(std::make_pair(std::string("GUILD"), std::string("common/guild"))); + m_PathNameMap.insert(std::make_pair(std::string("HORSE"), std::string("common/horse"))); +} +CPythonSkill::~CPythonSkill() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +DWORD CPythonSkill::SSkillData::MELEE_SKILL_TARGET_RANGE=170; + +const std::string CPythonSkill::SSkillData::GetName() const +{ + return strName; +} + +BYTE CPythonSkill::SSkillData::GetType() const +{ + return byType; +} + +BOOL CPythonSkill::SSkillData::IsMeleeSkill() +{ + if (dwSkillAttribute & SKILL_ATTRIBUTE_MELEE_ATTACK) + return TRUE; + + return FALSE; +} + +BOOL CPythonSkill::SSkillData::IsChargeSkill() +{ + if (dwSkillAttribute & SKILL_ATTRIBUTE_CHARGE_ATTACK) + return TRUE; + + return FALSE; +} + +BOOL CPythonSkill::SSkillData::IsOnlyForGuildWar() +{ + if (dwSkillAttribute & SKILL_ATTRIBUTE_ONLY_FOR_GUILD_WAR) + return TRUE; + + return FALSE; +} + +DWORD CPythonSkill::SSkillData::GetTargetRange() const +{ + if (dwSkillAttribute & SKILL_ATTRIBUTE_MELEE_ATTACK) + return MELEE_SKILL_TARGET_RANGE; + + if (dwSkillAttribute & SKILL_ATTRIBUTE_CHARGE_ATTACK) + return MELEE_SKILL_TARGET_RANGE; + + return dwTargetRange; +} + +BOOL CPythonSkill::SSkillData::CanChangeDirection() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_CAN_CHANGE_DIRECTION); +} + +BOOL CPythonSkill::SSkillData::IsFanRange() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_FAN_RANGE); +} + +BOOL CPythonSkill::SSkillData::IsCircleRange() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_CIRCLE_RANGE); +} + +BOOL CPythonSkill::SSkillData::IsAutoSearchTarget() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_SEARCH_TARGET); +} + +BOOL CPythonSkill::SSkillData::IsNeedCorpse() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_NEED_CORPSE); +} + +BOOL CPythonSkill::SSkillData::IsNeedTarget() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_NEED_TARGET); +} + +BOOL CPythonSkill::SSkillData::IsToggleSkill() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_TOGGLE); +} + +BOOL CPythonSkill::SSkillData::IsUseHPSkill() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_USE_HP); +} + +BOOL CPythonSkill::SSkillData::IsStandingSkill() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_STANDING_SKILL); +} + +BOOL CPythonSkill::SSkillData::CanUseWeaponType(DWORD dwWeaponType) +{ + if (!(dwSkillAttribute & SKILL_ATTRIBUTE_WEAPON_LIMITATION)) + return TRUE; + + return 0 != (dwNeedWeapon & (1 << dwWeaponType)); +} + +BOOL CPythonSkill::SSkillData::IsOnlyForAlliance() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_ONLY_FOR_ALLIANCE); +} + +BOOL CPythonSkill::SSkillData::CanUseForMe() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_CAN_USE_FOR_ME); +} + +BOOL CPythonSkill::SSkillData::CanUseIfNotEnough() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_CAN_USE_IF_NOT_ENOUGH); +} + +BOOL CPythonSkill::SSkillData::IsNeedEmptyBottle() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_NEED_EMPTY_BOTTLE); +} + +BOOL CPythonSkill::SSkillData::IsNeedPoisonBottle() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_NEED_POISON_BOTTLE); +} + +BOOL CPythonSkill::SSkillData::IsNeedBow() +{ + if (!(dwSkillAttribute & SKILL_ATTRIBUTE_WEAPON_LIMITATION)) + return FALSE; + + return 0 != (dwNeedWeapon & SKILL_NEED_WEAPON_BOW); +} + +BOOL CPythonSkill::SSkillData::IsHorseSkill() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_HORSE_SKILL); +} + +BOOL CPythonSkill::SSkillData::IsMovingSkill() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_MOVING_SKILL); +} + +BOOL CPythonSkill::SSkillData::IsAttackSkill() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_ATTACK_SKILL); +} + +BOOL CPythonSkill::SSkillData::IsTimeIncreaseSkill() +{ + return 0 != (dwSkillAttribute & SKILL_ATTRIBUTE_TIME_INCREASE_SKILL); +} + +bool CPythonSkill::SSkillData::GetState(const char * c_szStateName, int * piState, int iMinMaxType) +{ + std::map * pStatusNameMap = NULL; + + switch (iMinMaxType) + { + case VALUE_TYPE_FREE: + pStatusNameMap = &ms_StatusNameMap; + break; + case VALUE_TYPE_MIN: + pStatusNameMap = &ms_NewMinStatusNameMap; + break; + case VALUE_TYPE_MAX: + pStatusNameMap = &ms_NewMaxStatusNameMap; + break; + default: + return false; + break; + } + + std::map::iterator it = pStatusNameMap->find(c_szStateName); + + if (it != pStatusNameMap->end()) + { + *piState = CPythonPlayer::Instance().GetStatus(it->second); + } + else if (0 == strncmp(c_szStateName, "JeungJi", 7)) + { + *piState = 0; + + // 증지술 임시 제외 +/* + if (0 != ms_dwTimeIncreaseSkillNumber) + { + DWORD dwSkillSlotIndex; + if (!CPythonPlayer::Instance().FindSkillSlotIndexBySkillIndex(ms_dwTimeIncreaseSkillNumber, &dwSkillSlotIndex)) + return false; + + *piState = CPythonPlayer::Instance().GetSkillLevel(dwSkillSlotIndex); + } +*/ + } + + return true; +} + +float CPythonSkill::SSkillData::ProcessFormula(CPoly * pPoly, float fSkillLevel, int iMinMaxType) +{ + if (pPoly->Analyze()) + { + for (DWORD i = 0; i < pPoly->GetVarCount(); ++i) + { + const char * c_szVarName = pPoly->GetVarName(i); + float fState; + if (!strcmp("SkillPoint", c_szVarName) || !strcmp("k", c_szVarName)) + { + fState = fSkillLevel; + } + else + { + int iState; + if (!GetState(c_szVarName, &iState, iMinMaxType)) + return 0.0f; + + fState = float(iState); + + if (!strcmp("ar", c_szVarName)) + fState /= 100.0f; + } + pPoly->SetVar(c_szVarName, fState); + } + } + else + { + TraceError("skillGetAffect - Strange Formula [%s]", strName.c_str()); + return 0.0f; + } + + return pPoly->Eval(); +} + +const char * CPythonSkill::SSkillData::GetAffectDescription(DWORD dwIndex, float fSkillLevel) +{ + if (dwIndex >= AffectDataVector.size()) + return NULL; + + const std::string & c_rstrAffectDescription = AffectDataVector[dwIndex].strAffectDescription; + const std::string & c_rstrAffectMinFormula = AffectDataVector[dwIndex].strAffectMinFormula; + const std::string & c_rstrAffectMaxFormula = AffectDataVector[dwIndex].strAffectMaxFormula; + + CPoly minPoly; + CPoly maxPoly; + minPoly.SetStr(c_rstrAffectMinFormula.c_str()); + maxPoly.SetStr(c_rstrAffectMaxFormula.c_str()); + + // OVERWRITE_SKILLPROTO_POLY + float fMinValue = ProcessFormula(&minPoly, fSkillLevel); + float fMaxValue = ProcessFormula(&maxPoly, fSkillLevel); + + if (fMinValue < 0.0) + fMinValue = - fMinValue; + if (fMaxValue < 0.0) + fMaxValue = - fMaxValue; + + if (CP_ARABIC == ::GetDefaultCodePage()) + { + // #0000870: [M2AE] 한국어 모드일때 특정 아랍어 문장에서 크래쉬 발생 + static std::string strDescription; + strDescription = c_rstrAffectDescription; + int first = strDescription.find("%.0f"); + if (first >= 0) + { + fMinValue = floorf(fMinValue); + + char szMinValue[256]; + _snprintf(szMinValue, sizeof(szMinValue), "%.0f", fMinValue); + strDescription.replace(first, 4, szMinValue); + + int second = strDescription.find("%.0f", first); + if (second >= 0) + { + fMaxValue = floorf(fMaxValue); + + char szMaxValue[256]; + _snprintf(szMaxValue, sizeof(szMaxValue), "%.0f", fMaxValue); + strDescription.replace(second, 4, szMaxValue); + } + } + return strDescription.c_str(); + } + else + { + if (strstr(c_rstrAffectDescription.c_str(), "%.0f")) + { + fMinValue = floorf(fMinValue); + fMaxValue = floorf(fMaxValue); + } + + static char szDescription[64+1]; + _snprintf(szDescription, sizeof(szDescription), c_rstrAffectDescription.c_str(), fMinValue, fMaxValue); + + return szDescription; + } +} + +DWORD CPythonSkill::SSkillData::GetSkillCoolTime(float fSkillPoint) +{ + if (strCoolTimeFormula.empty()) + return 0; + + CPoly poly; + poly.SetStr(strCoolTimeFormula.c_str()); + + return DWORD(ProcessFormula(&poly, fSkillPoint)); +} + + +DWORD CPythonSkill::SSkillData::GetTargetCount(float fSkillPoint) +{ + if (strTargetCountFormula.empty()) + return 0; + + CPoly poly; + poly.SetStr(strTargetCountFormula.c_str()); + + return DWORD(ProcessFormula(&poly, fSkillPoint)); +} + +DWORD CPythonSkill::SSkillData::GetSkillMotionIndex(int iGrade) +{ + if (-1 != iGrade && SKILL_EFFECT_UPGRADE_ENABLE) + { + assert(iGrade >= 0 && iGrade < SKILL_EFFECT_COUNT); + /* + if (SKILL_GRADE_COUNT == iGrade) + { + return GradeData[SKILL_GRADE_COUNT-1].wMotionIndex; + } + else */ + if (iGrade >= 0 && iGrade < SKILL_EFFECT_COUNT) + { + return GradeData[iGrade].wMotionIndex; + } + } + + return wMotionIndex; +} + +BYTE CPythonSkill::SSkillData::GetMaxLevel() +{ + return byMaxLevel; +} + +BYTE CPythonSkill::SSkillData::GetLevelUpPoint() +{ + return byLevelUpPoint; +} + +BOOL CPythonSkill::SSkillData::IsNoMotion() +{ + return bNoMotion; +} + +bool CPythonSkill::SSkillData::IsCanUseSkill() +{ + if (0 != (dwSkillAttribute & SKILL_ATTRIBUTE_PASSIVE)) + return false; + + return true; +} + +DWORD CPythonSkill::SSkillData::GetMotionLoopCount(float fSkillPoint) +{ + if (strMotionLoopCountFormula.empty()) + return 0; + + CPoly poly; + poly.SetStr(strMotionLoopCountFormula.c_str()); + + return DWORD(ProcessFormula(&poly, fSkillPoint)); +} + +int CPythonSkill::SSkillData::GetNeedSP(float fSkillPoint) +{ + if (strNeedSPFormula.empty()) + return 0; + + CPoly poly; + poly.SetStr(strNeedSPFormula.c_str()); + + return int(ProcessFormula(&poly, fSkillPoint)); +} + +DWORD CPythonSkill::SSkillData::GetContinuationSP(float fSkillPoint) +{ + if (strContinuationSPFormula.empty()) + return 0; + + CPoly poly; + poly.SetStr(strContinuationSPFormula.c_str()); + + return DWORD(ProcessFormula(&poly, fSkillPoint)); +} + +DWORD CPythonSkill::SSkillData::GetDuration(float fSkillPoint) +{ + if (strDuration.empty()) + return 0; + + CPoly poly; + poly.SetStr(strDuration.c_str()); + + return DWORD(ProcessFormula(&poly, fSkillPoint)); +} + +CPythonSkill::SSkillData::SSkillData() +{ + byType = SKILL_TYPE_ACTIVE; + byMaxLevel = 20; + byLevelUpPoint = 1; + dwSkillAttribute = 0; + dwNeedWeapon = 0; + dwTargetRange = 0; + strCoolTimeFormula = ""; + strMotionLoopCountFormula = ""; + strNeedSPFormula = ""; + strContinuationSPFormula = ""; + isRequirement = FALSE; + strRequireSkillName = ""; + byRequireSkillLevel = 0; + strDuration = ""; + byLevelLimit = 0; + bNoMotion = FALSE; + + strName = ""; + pImage = NULL; + + for (int j = 0; j < SKILL_GRADE_COUNT; ++j) + { + TGradeData & rGradeData = GradeData[j]; + rGradeData.strName = ""; + rGradeData.pImage = NULL; + rGradeData.wMotionIndex = 0; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +PyObject * skillSetPathName(PyObject * poSelf, PyObject * poArgs) +{ + char * szPathName; + if (!PyTuple_GetString(poArgs, 0, &szPathName)) + return Py_BadArgument(); + + CPythonSkill::Instance().SetPathName(szPathName); + return Py_BuildNone(); +} + +PyObject * skillRegisterSkill(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + char * szFileName; + if (!PyTuple_GetString(poArgs, 1, &szFileName)) + return Py_BadArgument(); + + std::string strFullFileName; + strFullFileName = CPythonSkill::Instance().GetPathName(); + strFullFileName += szFileName; + + if (!CPythonSkill::Instance().RegisterSkill(iSkillIndex, strFullFileName.c_str())) + return Py_BuildException("skill.RegisterSkill - Failed to find skill data file : %d, %s", iSkillIndex, strFullFileName.c_str()); + + return Py_BuildNone(); +} + +PyObject * skillLoadSkillData(PyObject * poSelf, PyObject * poArgs) +{ + + + + return Py_BuildNone(); +} + +PyObject * skillRegisterSkillDesc(PyObject * poSelf, PyObject * poArgs) +{ + char * szFileName; + if (!PyTuple_GetString(poArgs, 0, &szFileName)) + return Py_BadArgument(); + + if (!CPythonSkill::Instance().RegisterSkillDesc(szFileName)) + return Py_BuildException("Failed to load Skill Desc"); + + return Py_BuildNone(); +} + +PyObject * skillClearSkillData(PyObject * poSelf, PyObject * poArgs) +{ + CPythonSkill::SSkillData::ms_dwTimeIncreaseSkillNumber = 0; + return Py_BuildNone(); +} + +PyObject * skillGetSkillName(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + int iSkillGrade = -1; + PyTuple_GetInteger(poArgs, 1, &iSkillGrade); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillName - Failed to find skill by %d", iSkillIndex); + + if (-1 != iSkillGrade) + if (iSkillGrade >= 0 && iSkillGrade < CPythonSkill::SKILL_GRADE_COUNT) + { + return Py_BuildValue("s", c_pSkillData->GradeData[iSkillGrade].strName.c_str()); + } + + return Py_BuildValue("s", c_pSkillData->strName.c_str()); +} + +PyObject * skillGetSkillDescription(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillDescription - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("s", c_pSkillData->strDescription.c_str()); +} + +PyObject * skillGetSkillType(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillType - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->byType); +} + +PyObject * skillGetSkillConditionDescriptionCount(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillConditionDescriptionCount - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->ConditionDataVector.size()); +} + +PyObject * skillGetSkillConditionDescription(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + int iConditionIndex; + if (!PyTuple_GetInteger(poArgs, 1, &iConditionIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillConditionDescription() - Failed to find skill by %d", iSkillIndex); + + if (iConditionIndex >= c_pSkillData->ConditionDataVector.size()) + return Py_BuildValue("None"); + + return Py_BuildValue("s", c_pSkillData->ConditionDataVector[iConditionIndex].c_str()); +} + +PyObject * skillGetSkillAffectDescriptionCount(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillAffectDescriptionCount - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->AffectDataVector.size()); +} + +PyObject * skillGetSkillAffectDescription(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + int iAffectIndex; + if (!PyTuple_GetInteger(poArgs, 1, &iAffectIndex)) + return Py_BadArgument(); + + float fSkillPoint; + if (!PyTuple_GetFloat(poArgs, 2, &fSkillPoint)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillAffectDescription - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("s", c_pSkillData->GetAffectDescription(iAffectIndex, fSkillPoint)); +} + +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)); +} + +PyObject * skillGetSkillNeedSP(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.GetSkillNeedSP Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->GetNeedSP(fSkillPoint)); +} + +PyObject * skillGetSkillContinuationSP(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.GetSkillContinuationSP - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->GetContinuationSP(fSkillPoint)); +} + +PyObject * skillGetSkillMaxLevel(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillMaxLevel - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->GetMaxLevel()); +} + +PyObject * skillGetSkillLevelUpPoint(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillLevelUpPoint - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->GetLevelUpPoint()); +} + +PyObject * skillGetSkillLevelLimit(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillLevelLimit - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->byLevelLimit); +} + +PyObject * skillIsSkillRequirement(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.IsSkillRequirement - Failed to find skill by %d", iSkillIndex); + + if (c_pSkillData->isRequirement) + { + CPythonSkill::SSkillData * pRequireSkillData; + if (!CPythonSkill::Instance().GetSkillDataByName(c_pSkillData->strRequireSkillName.c_str(), &pRequireSkillData)) + { + TraceError("skill.IsSkillRequirement - Failed to find skill : [%d/%s] can't find [%s]\n", c_pSkillData->dwSkillIndex, c_pSkillData->strName.c_str(), c_pSkillData->strRequireSkillName.c_str()); + return Py_BuildValue("i", FALSE); + } + + DWORD dwRequireSkillSlotIndex; + if (!CPythonPlayer::Instance().FindSkillSlotIndexBySkillIndex(pRequireSkillData->dwSkillIndex, &dwRequireSkillSlotIndex)) + return Py_BuildValue("i", FALSE); + } + + return Py_BuildValue("i", c_pSkillData->isRequirement); +} + +PyObject * skillGetSkillRequirementData(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillRequirementData - Failed to find skill by %d", iSkillIndex); + + CPythonSkill::SSkillData * pRequireSkillData; + if (!CPythonSkill::Instance().GetSkillDataByName(c_pSkillData->strRequireSkillName.c_str(), &pRequireSkillData)) + return Py_BuildValue("si", 0, "None", 0); + + int ireqLevel = (int)ceil(float(c_pSkillData->byRequireSkillLevel)/float(max(1, pRequireSkillData->byLevelUpPoint))); + return Py_BuildValue("si", c_pSkillData->strRequireSkillName.c_str(), ireqLevel); +} + +PyObject * skillGetSkillRequireStatCount(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillRequireStatCount - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->RequireStatDataVector.size()); +} + +PyObject * skillGetSkillRequireStatData(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + int iStatIndex; + if (!PyTuple_GetInteger(poArgs, 1, &iStatIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetSkillRequireStatData - Failed to find skill by %d", iSkillIndex); + + if (iStatIndex >= c_pSkillData->RequireStatDataVector.size()) + return Py_BuildValue("ii", 0, 0); + + const CPythonSkill::TRequireStatData & c_rRequireStatData = c_pSkillData->RequireStatDataVector[iStatIndex]; + + return Py_BuildValue("ii", c_rRequireStatData.byPoint, c_rRequireStatData.byLevel); +} + +PyObject * skillCanLevelUpSkill(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + int iSkillLevel; + if (!PyTuple_GetInteger(poArgs, 1, &iSkillLevel)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.CanLevelUpSkill - Failed to find skill by %d", iSkillIndex); + + if (iSkillLevel >= c_pSkillData->GetMaxLevel()) + return Py_BuildValue("i", FALSE); + + if (c_pSkillData->isRequirement) + { + CPythonSkill::SSkillData * pRequireSkillData; + if (CPythonSkill::Instance().GetSkillDataByName(c_pSkillData->strRequireSkillName.c_str(), &pRequireSkillData)) + { + DWORD dwRequireSkillSlotIndex; + if (CPythonPlayer::Instance().FindSkillSlotIndexBySkillIndex(pRequireSkillData->dwSkillIndex, &dwRequireSkillSlotIndex)) + { + int iSkillGrade = CPythonPlayer::Instance().GetSkillGrade(dwRequireSkillSlotIndex); + int iSkillLevel = CPythonPlayer::Instance().GetSkillLevel(dwRequireSkillSlotIndex); + if (iSkillGrade <= 0) + if (iSkillLevel < c_pSkillData->byRequireSkillLevel) + return Py_BuildValue("i", FALSE); + } + } + } + + for (DWORD i = 0; i < c_pSkillData->RequireStatDataVector.size(); ++i) + { + const CPythonSkill::TRequireStatData & c_rRequireStatData = c_pSkillData->RequireStatDataVector[i]; + if (CPythonPlayer::Instance().GetStatus(c_rRequireStatData.byPoint) < c_rRequireStatData.byLevel) + return Py_BuildValue("i", FALSE); + } + + if (0 != (c_pSkillData->dwSkillAttribute & CPythonSkill::SKILL_ATTRIBUTE_CANNOT_LEVEL_UP)) + return Py_BuildValue("i", FALSE); + + return Py_BuildValue("i", TRUE); +} + +PyObject * skillCheckRequirementSueccess(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.CheckRequirementSueccess - Failed to find skill by %d", iSkillIndex); + + if (c_pSkillData->isRequirement) + { + CPythonSkill::SSkillData * pRequireSkillData; + if (CPythonSkill::Instance().GetSkillDataByName(c_pSkillData->strRequireSkillName.c_str(), &pRequireSkillData)) + { + DWORD dwRequireSkillSlotIndex; + if (CPythonPlayer::Instance().FindSkillSlotIndexBySkillIndex(pRequireSkillData->dwSkillIndex, &dwRequireSkillSlotIndex)) + { + int iSkillGrade = CPythonPlayer::Instance().GetSkillGrade(dwRequireSkillSlotIndex); + int iSkillLevel = CPythonPlayer::Instance().GetSkillLevel(dwRequireSkillSlotIndex); + if (iSkillGrade <= 0) + if (iSkillLevel < c_pSkillData->byRequireSkillLevel) + return Py_BuildValue("i", FALSE); + } + } + } + + return Py_BuildValue("i", TRUE); +} + +PyObject * skillGetNeedCharacterLevel(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetNeedCharacterLevel - Failed to find skill by %d", iSkillIndex); + + std::vector::iterator itor = c_pSkillData->RequireStatDataVector.begin(); + for (; itor != c_pSkillData->RequireStatDataVector.end(); ++itor) + { + const CPythonSkill::TRequireStatData & c_rRequireStatData = *itor; + + if (POINT_LEVEL == c_rRequireStatData.byPoint) + return Py_BuildValue("i", c_rRequireStatData.byLevel); + } + + return Py_BuildValue("i", 0); +} + +PyObject * skillIsToggleSkill(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.IsToggleSkill - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->IsToggleSkill()); +} + +PyObject * skillIsUseHPSkill(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.IsUseHPSkill - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->IsUseHPSkill()); +} + +PyObject * skillIsStandingSkill(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.IsStandingSkill - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->IsStandingSkill()); +} + +PyObject * skillCanUseSkill(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.CanUseSkill - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->IsCanUseSkill()); +} + +PyObject * skillIsLevelUpSkill(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.IsLevelUpSkill - Failed to find skill by %d", iSkillIndex); + + // 모두 레벨업 가능 + + return Py_BuildValue("i", TRUE); +} + +PyObject * skillGetIconName(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildValue("s", ""); + + return Py_BuildValue("s", c_pSkillData->strIconFileName.c_str()); +} + +PyObject * skillGetIconImage(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildValue("i", 0); // 익셉션을 내는 대신 0을 리턴한다. + + return Py_BuildPointer(c_pSkillData->pImage); // PORT: was Py_BuildValue("i", ...) (ILP32 handle) +} + + + +PyObject * skillGetIconInstance(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetIconInstance - Failed to find skill by %d", iSkillIndex); + + CGraphicImageInstance * pImageInstance = CGraphicImageInstance::New(); + pImageInstance->SetImagePointer(c_pSkillData->pImage); + + return Py_BuildPointer(pImageInstance); // PORT: was Py_BuildValue("i", ...) (ILP32 handle) +} + +PyObject * skillGetIconImageNew(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + int iGradeIndex; + if (!PyTuple_GetInteger(poArgs, 1, &iGradeIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildValue("i", 0); // 익셉션을 내는 대신 0을 리턴한다. + + if (iGradeIndex < 0) + iGradeIndex = 0; + + if (iGradeIndex >= CPythonSkill::SKILL_GRADE_COUNT) + iGradeIndex = CPythonSkill::SKILL_GRADE_COUNT-1; + + return Py_BuildPointer(c_pSkillData->GradeData[iGradeIndex].pImage); // PORT: was Py_BuildValue("i", ...) (ILP32 handle) +} + +PyObject * skillGetIconInstanceNew(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + int iGradeIndex; + if (!PyTuple_GetInteger(poArgs, 1, &iGradeIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetIconInstanceNew - Failed to find skill by %d", iSkillIndex); + + //CGraphicImage * pImage = c_pSkillData->pImage; + + if (iGradeIndex < 0) + iGradeIndex = 0; + + if (iGradeIndex >= CPythonSkill::SKILL_GRADE_COUNT) + iGradeIndex = CPythonSkill::SKILL_GRADE_COUNT-1; + + CGraphicImageInstance * pImageInstance = CGraphicImageInstance::New(); + pImageInstance->SetImagePointer(c_pSkillData->GradeData[iGradeIndex].pImage); + + return Py_BuildPointer(pImageInstance); // PORT: was Py_BuildValue("i", ...) (ILP32 handle) +} + +PyObject * skillDeleteIconInstance(PyObject * poSelf, PyObject * poArgs) +{ + CGraphicImageInstance * iHandle; // PORT: was int (ILP32 handle) + if (!PyTuple_GetPointer(poArgs, 0, &iHandle)) + return Py_BadArgument(); + + CGraphicImageInstance::Delete((CGraphicImageInstance *) iHandle); + return Py_BuildNone(); +} + +PyObject * skillGetGradeData(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + int iGradeIndex; + if (!PyTuple_GetInteger(poArgs, 1, &iGradeIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetGradeData - Failed to find skill by %d", iSkillIndex); + + if (iGradeIndex < 0 || iGradeIndex >= CPythonSkill::SKILL_GRADE_COUNT) + return Py_BuildException("Strange grade index [%d]", iSkillIndex, iGradeIndex); + + // PORT: 40250 passes the TGradeData struct through "...", so "i" reads its first 4 bytes; clang rejects a + // non-trivial struct in varargs. Read the same bytes explicitly (no root script calls skill.GetGradeData). + return Py_BuildValue("i", *reinterpret_cast(&c_pSkillData->GradeData[iGradeIndex])); +} + +PyObject * skillGetNewAffectDataCount(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetNewAffectDataCount - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->AffectDataNewVector.size()); +} + +PyObject * skillGetNewAffectData(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + int iAffectIndex; + if (!PyTuple_GetInteger(poArgs, 1, &iAffectIndex)) + return Py_BadArgument(); + float fSkillLevel; + if (!PyTuple_GetFloat(poArgs, 2, &fSkillLevel)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &pSkillData)) + return Py_BuildException("skill.GetNewAffectData - Failed to find skill by %d", iSkillIndex); + + if (iAffectIndex < 0 || iAffectIndex >= pSkillData->AffectDataNewVector.size()) + return Py_BuildException(" skill.GetNewAffectData - Strange AffectIndex %d", iAffectIndex); + + CPythonSkill::TAffectDataNew & rAffectData = pSkillData->AffectDataNewVector[iAffectIndex]; + + CPoly minPoly; + CPoly maxPoly; + minPoly.SetRandom(CPoly::RANDOM_TYPE_FORCE_MIN); + maxPoly.SetRandom(CPoly::RANDOM_TYPE_FORCE_MAX); + minPoly.SetStr(rAffectData.strPointPoly.c_str()); + maxPoly.SetStr(rAffectData.strPointPoly.c_str()); + float fMinValue = pSkillData->ProcessFormula(&minPoly, fSkillLevel, CPythonSkill::VALUE_TYPE_MIN); + float fMaxValue = pSkillData->ProcessFormula(&maxPoly, fSkillLevel, CPythonSkill::VALUE_TYPE_MAX); + + return Py_BuildValue("sff", rAffectData.strPointType.c_str(), fMinValue, fMaxValue); +} + +PyObject * skillGetDuration(PyObject * poSelf, PyObject * poArgs) +{ + int iSkillIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iSkillIndex)) + return Py_BadArgument(); + float fSkillLevel; + if (!PyTuple_GetFloat(poArgs, 1, &fSkillLevel)) + return Py_BadArgument(); + + CPythonSkill::SSkillData * c_pSkillData; + if (!CPythonSkill::Instance().GetSkillData(iSkillIndex, &c_pSkillData)) + return Py_BuildException("skill.GetDuration - Failed to find skill by %d", iSkillIndex); + + return Py_BuildValue("i", c_pSkillData->GetDuration(fSkillLevel)); +} + +PyObject * skillTEST(PyObject * poSelf, PyObject * poArgs) +{ + CPythonSkill::Instance().TEST(); + return Py_BuildNone(); +} + +void initskill() +{ + static PyMethodDef s_methods[] = + { + { "SetPathName", skillSetPathName, METH_VARARGS }, + { "RegisterSkill", skillRegisterSkill, METH_VARARGS }, + { "LoadSkillData", skillLoadSkillData, METH_VARARGS }, + { "ClearSkillData", skillClearSkillData, METH_VARARGS }, + + ///// + + { "GetSkillName", skillGetSkillName, METH_VARARGS }, + { "GetSkillDescription", skillGetSkillDescription, METH_VARARGS }, + { "GetSkillType", skillGetSkillType, METH_VARARGS }, + { "GetSkillConditionDescriptionCount", skillGetSkillConditionDescriptionCount, METH_VARARGS }, + { "GetSkillConditionDescription", skillGetSkillConditionDescription, METH_VARARGS }, + { "GetSkillAffectDescriptionCount", skillGetSkillAffectDescriptionCount, METH_VARARGS }, + { "GetSkillAffectDescription", skillGetSkillAffectDescription, METH_VARARGS }, + { "GetSkillCoolTime", skillGetSkillCoolTime, METH_VARARGS }, + { "GetSkillNeedSP", skillGetSkillNeedSP, METH_VARARGS }, + { "GetSkillContinuationSP", skillGetSkillContinuationSP, METH_VARARGS }, + { "GetSkillMaxLevel", skillGetSkillMaxLevel, METH_VARARGS }, + { "GetSkillLevelUpPoint", skillGetSkillLevelUpPoint, METH_VARARGS }, + { "GetSkillLevelLimit", skillGetSkillLevelLimit, METH_VARARGS }, + { "IsSkillRequirement", skillIsSkillRequirement, METH_VARARGS }, + { "GetSkillRequirementData", skillGetSkillRequirementData, METH_VARARGS }, + { "GetSkillRequireStatCount", skillGetSkillRequireStatCount, METH_VARARGS }, + { "GetSkillRequireStatData", skillGetSkillRequireStatData, METH_VARARGS }, + { "CanLevelUpSkill", skillCanLevelUpSkill, METH_VARARGS }, + { "IsLevelUpSkill", skillIsLevelUpSkill, METH_VARARGS }, + { "CheckRequirementSueccess", skillCheckRequirementSueccess, METH_VARARGS }, + { "GetNeedCharacterLevel", skillGetNeedCharacterLevel, METH_VARARGS }, + { "IsToggleSkill", skillIsToggleSkill, METH_VARARGS }, + { "IsUseHPSkill", skillIsUseHPSkill, METH_VARARGS }, + { "IsStandingSkill", skillIsStandingSkill, METH_VARARGS }, + { "CanUseSkill", skillCanUseSkill, METH_VARARGS }, + { "GetIconName", skillGetIconName, METH_VARARGS }, + { "GetIconImage", skillGetIconImage, METH_VARARGS }, + { "GetIconImageNew", skillGetIconImageNew, METH_VARARGS }, + { "GetIconInstance", skillGetIconInstance, METH_VARARGS }, + { "GetIconInstanceNew", skillGetIconInstanceNew, METH_VARARGS }, + { "DeleteIconInstance", skillDeleteIconInstance, METH_VARARGS }, + { "GetGradeData", skillGetGradeData, METH_VARARGS }, + + { "GetNewAffectDataCount", skillGetNewAffectDataCount, METH_VARARGS }, + { "GetNewAffectData", skillGetNewAffectData, METH_VARARGS }, + { "GetDuration", skillGetDuration, METH_VARARGS }, + + { "TEST", skillTEST, METH_VARARGS }, + + { NULL, NULL, NULL }, + }; + + PyObject * poModule = Py_InitModule("skill", s_methods); + PyModule_AddIntConstant(poModule, "SKILL_TYPE_NONE", CPythonSkill::SKILL_TYPE_NONE); + PyModule_AddIntConstant(poModule, "SKILL_TYPE_ACTIVE", CPythonSkill::SKILL_TYPE_ACTIVE); + PyModule_AddIntConstant(poModule, "SKILL_TYPE_SUPPORT", CPythonSkill::SKILL_TYPE_SUPPORT); + PyModule_AddIntConstant(poModule, "SKILL_TYPE_GUILD", CPythonSkill::SKILL_TYPE_GUILD); + PyModule_AddIntConstant(poModule, "SKILL_TYPE_HORSE", CPythonSkill::SKILL_TYPE_HORSE); + PyModule_AddIntConstant(poModule, "SKILL_TYPE_MAX_NUM", CPythonSkill::SKILL_TYPE_MAX_NUM); + + PyModule_AddIntConstant(poModule, "SKILL_GRADE_COUNT", CPythonSkill::SKILL_GRADE_COUNT); + PyModule_AddIntConstant(poModule, "SKILL_GRADE_STEP_COUNT", CPythonSkill::SKILL_GRADE_STEP_COUNT); + PyModule_AddIntConstant(poModule, "SKILL_GRADEGAP", CPythonSkill::SKILL_GRADEGAP); + PyModule_AddIntConstant(poModule, "SKILL_EFFECT_COUNT", CPythonSkill::SKILL_EFFECT_COUNT); +} diff --git a/extension/src/port/UserInterface/StdAfx.h b/extension/src/port/UserInterface/StdAfx.h index e9848b31..f2d3096a 100644 --- a/extension/src/port/UserInterface/StdAfx.h +++ b/extension/src/port/UserInterface/StdAfx.h @@ -57,6 +57,7 @@ void initChat(); void initnet(); void initeffect(); void initfly(); +void initskill(); void initServerStateChecker(); extern const std::string& ApplicationStringTable_GetString(DWORD dwID); diff --git a/extension/tests/port_login_flow_test.cpp b/extension/tests/port_login_flow_test.cpp index 13d9b0ed..646aee07 100644 --- a/extension/tests/port_login_flow_test.cpp +++ b/extension/tests/port_login_flow_test.cpp @@ -222,7 +222,10 @@ int main(int argc, char** argv) CHECK(PackInitialize("pack")); std::string error; - CHECK(PythonBoot::Start(stdlib.c_str(), &error)); + const bool started = PythonBoot::Start(stdlib.c_str(), &error); + if (!started) + std::fprintf(stderr, "PythonBoot::Start: %s\n", error.c_str()); + CHECK(started); PythonBoot::SetUISize(800, 600); const bool ran = PythonBoot::RunMainScript("", &error); if (!ran) @@ -316,6 +319,12 @@ int main(int argc, char** argv) "_mob = nonplayer.GetMonsterName(101)\n" "assert _mob, 'mob 101 has no name'\n" "import sys\nsys.stderr.write('port_login_flow_test: mob 101 %s\\n' % _mob)")); + // CPythonSkill read skilldesc.txt and skilltable.txt (RegisterSkillDesc/RegisterSkillTable); skill 1's + // cool time is skilltable's constant "12". + CHECK(py("import skill\n" + "assert skill.GetSkillName(1, 0) == 'Three-Way Cut', skill.GetSkillName(1, 0)\n" + "assert skill.GetSkillType(1) == skill.SKILL_TYPE_ACTIVE, skill.GetSkillType(1)\n" + "assert skill.GetSkillCoolTime(1, 1.0) == 12, skill.GetSkillCoolTime(1, 1.0)")); } // 4-5. Start the game on the slot: DirectEnter, the second game login and the loading phase. @@ -501,6 +510,16 @@ int main(int argc, char** argv) "assert item.GetItemType() == item.ITEM_TYPE_WEAPON and item.GetItemSubType() == item.WEAPON_SWORD\n" "assert item.GetValue(3) > 0, 'min attack'")); + // skill icons: RegisterSkillDesc loaded each skill's .sub icons; an active skill has one per grade + // (__RegisterGradeIconImage) and no plain icon, as in 40250. The icon instance handle survives the 64-bit + // round trip (Py_BuildPointer). + CHECK(py("import skill\n" + "assert skill.GetIconImage(1) == 0\n" + "assert skill.GetIconImageNew(1, 0) != 0, 'skill 1 has no grade icon'\n" + "_icon = skill.GetIconInstanceNew(1, 0)\n" + "assert _icon != 0\n" + "skill.DeleteIconInstance(_icon)")); + // miniMap module (PythonMiniMapModule.cpp): uiminimap.MiniMap created and showed it. CMapOutdoor is not // ported, so CMapManager::IsMapOutdoor() is false and the atlas reports "not loaded" as 40250 does off an // outdoor map.