diff --git a/audit/history.jsonl b/audit/history.jsonl index 2ea7d041..94a288cb 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -531,3 +531,4 @@ {"time": "2026-09-24T04:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2: verify and mark 28 units copied into port/ in 2V1/2A", "ported": ["28 units, 372 functions: PythonNetworkStream{,PhaseLoading,PhaseLogin,PhaseSelect,PhaseHandShake,PhaseOffline,Event}, AccountConnector, NetStream, NetPacketHeaderMap, NetAddress, NetDevice, TextTag, EterPack, EterPackManager, EterPackCursor, EterPackPolicy_CSHybridCrypt, Timer, cipher, lzo, Random, Stl, tea, Arabic, StringCodec, StringCodec_Vietnamese, InsultChecker, AffectFlagContainer"], "adapted": [], "divergent": [], "needs_live": [], "tests": ["port_copy.py diff: 23 exact mechanical copies, 5 with // PORT: edits only; StringCodec_Vietnamese (not CP949) differs by BOM + include case", "no same-named platform/pending files", "ctest all 19/19 + render test on the same tree", "port_map.py check: 0 errors"], "todo": ["P2 ServerStateChecker (module still stubbed)", "P3 items/minimap/text tail"]} {"time": "2026-09-24T05:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P2: ServerStateChecker + module", "ported": ["UserInterface/ServerStateChecker.cpp", "UserInterface/ServerStateCheckerModule.cpp"], "adapted": [], "divergent": [], "needs_live": [], "tests": ["port.login_flow: fake state port answers CG_STATE_CHECKER, NotifyChannelState(2, 1)", "port.login_live 192.168.21.203: channel states {1: 1, 2: 1}", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3 item chain: ItemData, ItemManager, PythonItem, PythonExchange"]} {"time": "2026-09-24T06:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-a: ItemData, ItemManager, PythonNonPlayer + LoadLocaleData", "ported": ["GameLib/ItemData.cpp", "GameLib/ItemManager.cpp", "UserInterface/PythonNonPlayer.cpp", "UserInterface/PythonNonPlayerModule.cpp"], "adapted": ["UserInterface/PythonApplication.cpp:LoadLocaleData"], "divergent": [], "needs_live": [], "tests": ["port.login_flow 3c: item 19 Sword+9 type 1 refine 9, mob 101 Wild Dog", "port.login_live 192.168.21.203: same", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3-b PythonItem + PythonItemModule", "CPythonSkill (RegisterSkillDesc/Table) still pending"]} +{"time": "2026-09-24T07:00:00Z", "event": "port_round", "unit": "PORT-PLAN batch 2 P3-b: PythonItem + PythonItemModule", "ported": ["UserInterface/PythonItem.cpp", "UserInterface/PythonItemModule.cpp"], "adapted": ["UserInterface/PythonItemModule.cpp:itemGetIconImage", "GameLib/MapManager.cpp:CMapManager::GetNormal"], "divergent": [], "needs_live": [], "tests": ["port.login_flow: fake GC_ITEM_GROUND_ADD vnum 19 + ownership, player.PickCloseItem -> CG_ITEM_PICKUP -> GC_ITEM_GROUND_DEL removes it", "port.login_flow: item.SelectItem(19) name/type/subtype/value", "port.login_live 192.168.21.203: passes (icon pointer truncation segfault fixed)", "ctest all 19/19, python_game_render_test offline PASS", "port_map.py check: 0 errors"], "todo": ["P3-c PythonExchange", "PythonTextTail item tails (Register/Delete/SetOwner/Pick still stubs)", "CEffectManager (dropitem.mse)"]} diff --git a/audit/port-map/GameLib/MapManager.cpp.json b/audit/port-map/GameLib/MapManager.cpp.json index dbdca8b0..1a84d589 100644 --- a/audit/port-map/GameLib/MapManager.cpp.json +++ b/audit/port-map/GameLib/MapManager.cpp.json @@ -179,7 +179,12 @@ "status": "TODO" }, "CMapManager::GetNormal": { - "status": "TODO" + "status": "ADAPTED", + "impl": [ + "extension/src/platform/pending/GameLib/MapManager.cpp:CMapManager::GetNormal" + ], + "test": "extension/tests/port_login_flow_test.cpp (port.login_flow: ground item vnum 19 add/ownership/PickCloseItem/GROUND_DEL; item.SelectItem(19))", + "note": "CMapOutdoor::GetNormal tile clamp + CTerrain::CalculateNormal formula evaluated per call on the native height tile (no m_acNormalMap until CMapOutdoor/CTerrain are ported)." }, "CMapManager::isPhysicalCollision": { "status": "TODO" diff --git a/audit/port-map/UserInterface/PythonItem.cpp.json b/audit/port-map/UserInterface/PythonItem.cpp.json new file mode 100644 index 00000000..ce02afe9 --- /dev/null +++ b/audit/port-map/UserInterface/PythonItem.cpp.json @@ -0,0 +1,194 @@ +{ + "reference": "UserInterface/PythonItem.cpp", + "reference_sha256": "8917e3780091f01c584e180677000fa971c2d8d12a6d2da5a6f9e1588d567937", + "priority": "P3", + "contracts": [], + "functions": { + "CPythonItem::GetInfo": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetInfo" + ] + }, + "CPythonItem::TGroundItemInstance::Clear": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::TGroundItemInstance::Clear" + ] + }, + "CPythonItem::TGroundItemInstance::__PlayDropSound": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::TGroundItemInstance::__PlayDropSound" + ] + }, + "CPythonItem::TGroundItemInstance::Update": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::TGroundItemInstance::Update" + ] + }, + "CPythonItem::Update": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::Update" + ] + }, + "CPythonItem::Render": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::Render" + ] + }, + "CPythonItem::SetUseSoundFileName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::SetUseSoundFileName" + ] + }, + "CPythonItem::SetDropSoundFileName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::SetDropSoundFileName" + ] + }, + "CPythonItem::PlayUseSound": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::PlayUseSound" + ] + }, + "CPythonItem::PlayDropSound": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::PlayDropSound" + ] + }, + "CPythonItem::PlayUsePotionSound": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::PlayUsePotionSound" + ] + }, + "CPythonItem::__GetDropSoundType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::__GetDropSoundType" + ] + }, + "CPythonItem::__GetUseSoundType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::__GetUseSoundType" + ] + }, + "CPythonItem::CreateItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::CreateItem" + ] + }, + "CPythonItem::SetOwnership": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::SetOwnership" + ] + }, + "CPythonItem::GetOwnership": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetOwnership" + ] + }, + "CPythonItem::DeleteAllItems": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::DeleteAllItems" + ] + }, + "CPythonItem::DeleteItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::DeleteItem" + ] + }, + "CPythonItem::GetCloseMoney": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetCloseMoney" + ] + }, + "CPythonItem::GetCloseItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetCloseItem" + ] + }, + "CPythonItem::GetGroundItemPosition": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetGroundItemPosition" + ] + }, + "CPythonItem::__Pick": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::__Pick" + ] + }, + "CPythonItem::GetPickedItemID": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetPickedItemID" + ] + }, + "CPythonItem::GetVirtualNumberOfGroundItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetVirtualNumberOfGroundItem" + ] + }, + "CPythonItem::BuildNoGradeNameData": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::BuildNoGradeNameData" + ] + }, + "CPythonItem::GetNoGradeNameDataCount": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetNoGradeNameDataCount" + ] + }, + "CPythonItem::GetNoGradeNameDataPtr": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::GetNoGradeNameDataPtr" + ] + }, + "CPythonItem::Destroy": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::Destroy" + ] + }, + "CPythonItem::Create": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::Create" + ] + }, + "CPythonItem::CPythonItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::CPythonItem" + ] + }, + "CPythonItem::~CPythonItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItem.cpp:CPythonItem::~CPythonItem" + ] + } + } +} diff --git a/audit/port-map/UserInterface/PythonItemModule.cpp.json b/audit/port-map/UserInterface/PythonItemModule.cpp.json new file mode 100644 index 00000000..d186dfa4 --- /dev/null +++ b/audit/port-map/UserInterface/PythonItemModule.cpp.json @@ -0,0 +1,232 @@ +{ + "reference": "UserInterface/PythonItemModule.cpp", + "reference_sha256": "6eb7357f37a19961a8b3293ce3098321b5a8231b8f09391a5bccbbaf7157bbe7", + "priority": "P3", + "contracts": [], + "functions": { + "itemSetUseSoundFileName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemSetUseSoundFileName" + ] + }, + "itemSetDropSoundFileName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemSetDropSoundFileName" + ] + }, + "itemSelectItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemSelectItem" + ] + }, + "itemGetItemName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetItemName" + ] + }, + "itemGetItemDescription": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetItemDescription" + ] + }, + "itemGetItemSummary": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetItemSummary" + ] + }, + "itemGetIconImage": { + "status": "ADAPTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetIconImage" + ], + "test": "extension/tests/port_login_flow_test.cpp (port.login_live: inventory slots set icons without the truncated-pointer crash)", + "note": "Returns the CGraphicSubImage* through Py_BuildPointer instead of Py_BuildValue(\"i\"): 40250 is ILP32, and wndMgr.SetSlot reads the handle back with PyTuple_GetPointer." + }, + "itemGetIconImageFileName": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetIconImageFileName" + ] + }, + "itemGetItemSize": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetItemSize" + ] + }, + "itemGetItemType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetItemType" + ] + }, + "itemGetItemSubType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetItemSubType" + ] + }, + "itemGetIBuyItemPrice": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetIBuyItemPrice" + ] + }, + "itemGetISellItemPrice": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetISellItemPrice" + ] + }, + "itemIsAntiFlag": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsAntiFlag" + ] + }, + "itemIsFlag": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsFlag" + ] + }, + "itemIsWearableFlag": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsWearableFlag" + ] + }, + "itemIs1GoldItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIs1GoldItem" + ] + }, + "itemGetLimit": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetLimit" + ] + }, + "itemGetAffect": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetAffect" + ] + }, + "itemGetValue": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetValue" + ] + }, + "itemGetSocket": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetSocket" + ] + }, + "itemGetIconInstance": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetIconInstance" + ] + }, + "itemDeleteIconInstance": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemDeleteIconInstance" + ] + }, + "itemIsEquipmentVID": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsEquipmentVID" + ] + }, + "itemGetUseType": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemGetUseType" + ] + }, + "itemIsRefineScroll": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsRefineScroll" + ] + }, + "itemIsDetachScroll": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsDetachScroll" + ] + }, + "itemCanAddToQuickSlotItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemCanAddToQuickSlotItem" + ] + }, + "itemIsKey": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsKey" + ] + }, + "itemIsMetin": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemIsMetin" + ] + }, + "itemRender": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemRender" + ] + }, + "itemUpdate": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemUpdate" + ] + }, + "itemCreateItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemCreateItem" + ] + }, + "itemDeleteItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemDeleteItem" + ] + }, + "itemPick": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemPick" + ] + }, + "itemLoadItemTable": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:itemLoadItemTable" + ] + }, + "initItem": { + "status": "PORTED", + "impl": [ + "extension/src/port/UserInterface/PythonItemModule.cpp:initItem" + ] + } + } +} diff --git a/docs/PORT-PLAN.md b/docs/PORT-PLAN.md index b9bcea06..edb4f3fe 100644 --- a/docs/PORT-PLAN.md +++ b/docs/PORT-PLAN.md @@ -436,6 +436,8 @@ extension/third_party/cpython-2.7.18/ # 静态库(2P 批次 P3-a(2026-09-24):`GameLib/ItemData.cpp`、`GameLib/ItemManager.cpp`、`UserInterface/PythonNonPlayer.cpp` 与 `PythonNonPlayerModule.cpp` 原样移植,删除三个 pending 替身与 nonplayer 模块桩,`initNonPlayer()` 按 40250 顺序插在 `initPlayer()` 之后。`LoadLocaleData` 的函数体原样放进平台 `PythonApplication.cpp`(选角阶段 `localeInfo.LoadLocaleData()` 调它):读 item_list/item_proto/itemdesc 与 mob_proto;`CPythonSkill` 仍是替身,`RegisterSkillDesc` 失败后返回 false(脚本不看返回值),记 ADAPTED。`port.login_flow` 3c 步:物品 19 = Sword+9(武器、refine 9、模型可载),怪 101 = Wild Dog;真服同样通过。下一步 P3-b:`PythonItem` + `PythonItemModule`(地面物品、item 模块)。 + P3-b(2026-09-24):`PythonItem.cpp` 与 `PythonItemModule.cpp` 原样移植,删除 pending 替身与 item 模块桩,`initItem()` 按 40250 顺序在 `initPlayer()` 之后;平台 `CPythonApplication::Create` 按原序调 `m_pyItem.Create()`(dropitem.mse 注册仍落在 CEffectManager 桩)。改动:`itemGetIconImage` 用 `Py_BuildPointer` 返回图标指针(40250 ILP32 用 `"i"`,64 位下被截断,真服背包 `wndMgr.SetSlot` 段错误);`D3DXMath.h` 补 `D3DXQuaternionConjugate`;pending `CMapManager::GetNormal` 以 `CTerrain::CalculateNormal` 公式按需在高度块上算法线;`CPythonTextTail` 的物品名牌四函数暂为桩,`Pick` 按 40250 空表语义返回 -1(返回 0 会把地面物品 VID 0 当作选中,点地移动失效)。假服入场时按 `CItem::EncodeInsertPacket` 发 vnum 19 的 `GC_ITEM_GROUND_ADD`+`GC_ITEM_OWNERSHIP`,收到 `CG_ITEM_PICKUP` 回 `GC_ITEM_GROUND_DEL`;`port.login_flow` 验证地面物品位置/归属/vnum,`player.PickCloseItem()` 发出拾取、物品被删除,以及 `item.SelectItem(19)` 的名称/类型/子类型/数值。下一步 P3-c:`PythonExchange`,之后 `PythonTextTail`(物品名牌)与 `PythonMiniMap`。 + 每个切片都必须同时跑 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 3526fd11..24075aa4 100644 --- a/extension/src/platform/ScriptLib/GameplayModuleConstants.cpp +++ b/extension/src/platform/ScriptLib/GameplayModuleConstants.cpp @@ -105,272 +105,6 @@ void AddStubConstants_ime(PyObject* poModule) (void) poModule; } -// 40250 UserInterface/PythonItemModule.cpp -void AddStubConstants_item(PyObject* poModule) -{ - (void) poModule; - PyModule_AddIntConstant(poModule, "USESOUND_ACCESSORY", CPythonItem::USESOUND_ACCESSORY); - PyModule_AddIntConstant(poModule, "USESOUND_ARMOR", CPythonItem::USESOUND_ARMOR); - PyModule_AddIntConstant(poModule, "USESOUND_BOW", CPythonItem::USESOUND_BOW); - PyModule_AddIntConstant(poModule, "USESOUND_DEFAULT", CPythonItem::USESOUND_DEFAULT); - PyModule_AddIntConstant(poModule, "USESOUND_WEAPON", CPythonItem::USESOUND_WEAPON); - PyModule_AddIntConstant(poModule, "USESOUND_POTION", CPythonItem::USESOUND_POTION); - PyModule_AddIntConstant(poModule, "USESOUND_PORTAL", CPythonItem::USESOUND_PORTAL); - PyModule_AddIntConstant(poModule, "DROPSOUND_ACCESSORY", CPythonItem::DROPSOUND_ACCESSORY); - PyModule_AddIntConstant(poModule, "DROPSOUND_ARMOR", CPythonItem::DROPSOUND_ARMOR); - PyModule_AddIntConstant(poModule, "DROPSOUND_BOW", CPythonItem::DROPSOUND_BOW); - PyModule_AddIntConstant(poModule, "DROPSOUND_DEFAULT", CPythonItem::DROPSOUND_DEFAULT); - PyModule_AddIntConstant(poModule, "DROPSOUND_WEAPON", CPythonItem::DROPSOUND_WEAPON); - PyModule_AddIntConstant(poModule, "EQUIPMENT_COUNT", c_Equipment_Count); - PyModule_AddIntConstant(poModule, "EQUIPMENT_HEAD", c_Equipment_Head); - PyModule_AddIntConstant(poModule, "EQUIPMENT_BODY", c_Equipment_Body); - PyModule_AddIntConstant(poModule, "EQUIPMENT_WEAPON", c_Equipment_Weapon); - PyModule_AddIntConstant(poModule, "EQUIPMENT_WRIST", c_Equipment_Wrist); - PyModule_AddIntConstant(poModule, "EQUIPMENT_SHOES", c_Equipment_Shoes); - PyModule_AddIntConstant(poModule, "EQUIPMENT_NECK", c_Equipment_Neck); - PyModule_AddIntConstant(poModule, "EQUIPMENT_EAR", c_Equipment_Ear); - PyModule_AddIntConstant(poModule, "EQUIPMENT_UNIQUE1", c_Equipment_Unique1); - PyModule_AddIntConstant(poModule, "EQUIPMENT_UNIQUE2", c_Equipment_Unique2); - PyModule_AddIntConstant(poModule, "EQUIPMENT_ARROW", c_Equipment_Arrow); -#ifdef ENABLE_NEW_EQUIPMENT_SYSTEM - PyModule_AddIntConstant(poModule, "EQUIPMENT_RING1", c_Equipment_Ring1); - PyModule_AddIntConstant(poModule, "EQUIPMENT_RING2", c_Equipment_Ring2); - PyModule_AddIntConstant(poModule, "EQUIPMENT_BELT", c_Equipment_Belt); -#endif - PyModule_AddIntConstant(poModule, "ITEM_TYPE_NONE", CItemData::ITEM_TYPE_NONE); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_WEAPON", CItemData::ITEM_TYPE_WEAPON); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_ARMOR", CItemData::ITEM_TYPE_ARMOR); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_USE", CItemData::ITEM_TYPE_USE); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_AUTOUSE", CItemData::ITEM_TYPE_AUTOUSE); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_MATERIAL", CItemData::ITEM_TYPE_MATERIAL); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_SPECIAL", CItemData::ITEM_TYPE_SPECIAL); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_TOOL", CItemData::ITEM_TYPE_TOOL); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_LOTTERY", CItemData::ITEM_TYPE_LOTTERY); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_ELK", CItemData::ITEM_TYPE_ELK); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_METIN", CItemData::ITEM_TYPE_METIN); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_CONTAINER", CItemData::ITEM_TYPE_CONTAINER); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_FISH", CItemData::ITEM_TYPE_FISH); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_ROD", CItemData::ITEM_TYPE_ROD); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_RESOURCE", CItemData::ITEM_TYPE_RESOURCE); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_CAMPFIRE", CItemData::ITEM_TYPE_CAMPFIRE); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_UNIQUE", CItemData::ITEM_TYPE_UNIQUE); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_SKILLBOOK", CItemData::ITEM_TYPE_SKILLBOOK); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_QUEST", CItemData::ITEM_TYPE_QUEST); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_POLYMORPH", CItemData::ITEM_TYPE_POLYMORPH); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_TREASURE_BOX", CItemData::ITEM_TYPE_TREASURE_BOX); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_TREASURE_KEY", CItemData::ITEM_TYPE_TREASURE_KEY); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_PICK", CItemData::ITEM_TYPE_PICK); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_BLEND", CItemData::ITEM_TYPE_BLEND); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_DS", CItemData::ITEM_TYPE_DS); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_SPECIAL_DS", CItemData::ITEM_TYPE_SPECIAL_DS); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_RING", CItemData::ITEM_TYPE_RING); - PyModule_AddIntConstant(poModule, "ITEM_TYPE_BELT", CItemData::ITEM_TYPE_BELT); -#ifdef ENABLE_COSTUME_SYSTEM - PyModule_AddIntConstant(poModule, "ITEM_TYPE_COSTUME", CItemData::ITEM_TYPE_COSTUME); - PyModule_AddIntConstant(poModule, "COSTUME_TYPE_BODY", CItemData::COSTUME_BODY); - PyModule_AddIntConstant(poModule, "COSTUME_TYPE_HAIR", CItemData::COSTUME_HAIR); - PyModule_AddIntConstant(poModule, "COSTUME_SLOT_START", c_Costume_Slot_Start); - PyModule_AddIntConstant(poModule, "COSTUME_SLOT_COUNT", c_Costume_Slot_Count); - PyModule_AddIntConstant(poModule, "COSTUME_SLOT_BODY", c_Costume_Slot_Body); - PyModule_AddIntConstant(poModule, "COSTUME_SLOT_HAIR", c_Costume_Slot_Hair); - PyModule_AddIntConstant(poModule, "COSTUME_SLOT_END", c_Costume_Slot_End); -#endif -#ifdef ENABLE_NEW_EQUIPMENT_SYSTEM - PyModule_AddIntConstant(poModule, "BELT_INVENTORY_SLOT_START", c_Belt_Inventory_Slot_Start); - PyModule_AddIntConstant(poModule, "BELT_INVENTORY_SLOT_COUNT", c_Belt_Inventory_Slot_Count); - PyModule_AddIntConstant(poModule, "BELT_INVENTORY_SLOT_END", c_Belt_Inventory_Slot_End); -#endif - PyModule_AddIntConstant(poModule, "WEAPON_SWORD", CItemData::WEAPON_SWORD); - PyModule_AddIntConstant(poModule, "WEAPON_DAGGER", CItemData::WEAPON_DAGGER); - PyModule_AddIntConstant(poModule, "WEAPON_BOW", CItemData::WEAPON_BOW); - PyModule_AddIntConstant(poModule, "WEAPON_TWO_HANDED", CItemData::WEAPON_TWO_HANDED); - PyModule_AddIntConstant(poModule, "WEAPON_BELL", CItemData::WEAPON_BELL); - PyModule_AddIntConstant(poModule, "WEAPON_FAN", CItemData::WEAPON_FAN); - PyModule_AddIntConstant(poModule, "WEAPON_ARROW", CItemData::WEAPON_ARROW); - PyModule_AddIntConstant(poModule, "WEAPON_NUM_TYPES", CItemData::WEAPON_NUM_TYPES); - PyModule_AddIntConstant(poModule, "USE_POTION", CItemData::USE_POTION); - PyModule_AddIntConstant(poModule, "USE_TALISMAN", CItemData::USE_TALISMAN); - PyModule_AddIntConstant(poModule, "USE_TUNING", CItemData::USE_TUNING); - PyModule_AddIntConstant(poModule, "USE_MOVE", CItemData::USE_MOVE); - PyModule_AddIntConstant(poModule, "USE_TREASURE_BOX", CItemData::USE_TREASURE_BOX); - PyModule_AddIntConstant(poModule, "USE_MONEYBAG", CItemData::USE_MONEYBAG); - PyModule_AddIntConstant(poModule, "USE_BAIT", CItemData::USE_BAIT); - PyModule_AddIntConstant(poModule, "USE_ABILITY_UP", CItemData::USE_ABILITY_UP); - PyModule_AddIntConstant(poModule, "USE_AFFECT", CItemData::USE_AFFECT); - PyModule_AddIntConstant(poModule, "USE_CREATE_STONE", CItemData::USE_CREATE_STONE); - PyModule_AddIntConstant(poModule, "USE_SPECIAL", CItemData::USE_SPECIAL); - PyModule_AddIntConstant(poModule, "USE_POTION_NODELAY", CItemData::USE_POTION_NODELAY); - PyModule_AddIntConstant(poModule, "USE_CLEAR", CItemData::USE_CLEAR); - PyModule_AddIntConstant(poModule, "USE_INVISIBILITY", CItemData::USE_INVISIBILITY); - PyModule_AddIntConstant(poModule, "USE_DETACHMENT", CItemData::USE_DETACHMENT); - PyModule_AddIntConstant(poModule, "USE_TIME_CHARGE_PER", CItemData::USE_TIME_CHARGE_PER); - PyModule_AddIntConstant(poModule, "USE_TIME_CHARGE_FIX", CItemData::USE_TIME_CHARGE_FIX); - PyModule_AddIntConstant(poModule, "MATERIAL_DS_REFINE_NORMAL", CItemData::MATERIAL_DS_REFINE_NORMAL); - PyModule_AddIntConstant(poModule, "MATERIAL_DS_REFINE_BLESSED", CItemData::MATERIAL_DS_REFINE_BLESSED); - PyModule_AddIntConstant(poModule, "MATERIAL_DS_REFINE_HOLLY", CItemData::MATERIAL_DS_REFINE_HOLLY); - PyModule_AddIntConstant(poModule, "METIN_NORMAL", CItemData::METIN_NORMAL); - PyModule_AddIntConstant(poModule, "METIN_GOLD", CItemData::METIN_GOLD); - PyModule_AddIntConstant(poModule, "LIMIT_NONE", CItemData::LIMIT_NONE); - PyModule_AddIntConstant(poModule, "LIMIT_LEVEL", CItemData::LIMIT_LEVEL); - PyModule_AddIntConstant(poModule, "LIMIT_STR", CItemData::LIMIT_STR); - PyModule_AddIntConstant(poModule, "LIMIT_DEX", CItemData::LIMIT_DEX); - PyModule_AddIntConstant(poModule, "LIMIT_INT", CItemData::LIMIT_INT); - PyModule_AddIntConstant(poModule, "LIMIT_CON", CItemData::LIMIT_CON); - PyModule_AddIntConstant(poModule, "LIMIT_PCBANG", CItemData::LIMIT_PCBANG); - PyModule_AddIntConstant(poModule, "LIMIT_REAL_TIME", CItemData::LIMIT_REAL_TIME); - PyModule_AddIntConstant(poModule, "LIMIT_REAL_TIME_START_FIRST_USE", CItemData::LIMIT_REAL_TIME_START_FIRST_USE); - PyModule_AddIntConstant(poModule, "LIMIT_TIMER_BASED_ON_WEAR", CItemData::LIMIT_TIMER_BASED_ON_WEAR); - PyModule_AddIntConstant(poModule, "LIMIT_TYPE_MAX_NUM", CItemData::LIMIT_MAX_NUM); - PyModule_AddIntConstant(poModule, "LIMIT_MAX_NUM", CItemData::ITEM_LIMIT_MAX_NUM); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_FEMALE", CItemData::ITEM_ANTIFLAG_FEMALE); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_MALE", CItemData::ITEM_ANTIFLAG_MALE); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_WARRIOR", CItemData::ITEM_ANTIFLAG_WARRIOR); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_ASSASSIN", CItemData::ITEM_ANTIFLAG_ASSASSIN); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SURA", CItemData::ITEM_ANTIFLAG_SURA); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SHAMAN", CItemData::ITEM_ANTIFLAG_SHAMAN); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_GET", CItemData::ITEM_ANTIFLAG_GET); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_DROP", CItemData::ITEM_ANTIFLAG_DROP); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SELL", CItemData::ITEM_ANTIFLAG_SELL); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_EMPIRE_A", CItemData::ITEM_ANTIFLAG_EMPIRE_A); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_EMPIRE_B", CItemData::ITEM_ANTIFLAG_EMPIRE_B); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_EMPIRE_R", CItemData::ITEM_ANTIFLAG_EMPIRE_R); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SAVE", CItemData::ITEM_ANTIFLAG_SAVE); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_GIVE", CItemData::ITEM_ANTIFLAG_GIVE); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_PKDROP", CItemData::ITEM_ANTIFLAG_PKDROP); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_STACK", CItemData::ITEM_ANTIFLAG_STACK); - PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_MYSHOP", CItemData::ITEM_ANTIFLAG_MYSHOP); - PyModule_AddIntConstant(poModule, "ITEM_FLAG_RARE", CItemData::ITEM_FLAG_RARE); - PyModule_AddIntConstant(poModule, "ITEM_FLAG_UNIQUE", CItemData::ITEM_FLAG_UNIQUE); - PyModule_AddIntConstant(poModule, "ITEM_FLAG_CONFIRM_WHEN_USE", CItemData::ITEM_FLAG_CONFIRM_WHEN_USE); - PyModule_AddIntConstant(poModule, "ANTIFLAG_FEMALE", CItemData::ITEM_ANTIFLAG_FEMALE); - PyModule_AddIntConstant(poModule, "ANTIFLAG_MALE", CItemData::ITEM_ANTIFLAG_MALE); - PyModule_AddIntConstant(poModule, "ANTIFLAG_WARRIOR", CItemData::ITEM_ANTIFLAG_WARRIOR); - PyModule_AddIntConstant(poModule, "ANTIFLAG_ASSASSIN", CItemData::ITEM_ANTIFLAG_ASSASSIN); - PyModule_AddIntConstant(poModule, "ANTIFLAG_SURA", CItemData::ITEM_ANTIFLAG_SURA); - PyModule_AddIntConstant(poModule, "ANTIFLAG_SHAMAN", CItemData::ITEM_ANTIFLAG_SHAMAN); - PyModule_AddIntConstant(poModule, "ANTIFLAG_GET", CItemData::ITEM_ANTIFLAG_GET); - PyModule_AddIntConstant(poModule, "ANTIFLAG_DROP", CItemData::ITEM_ANTIFLAG_DROP); - PyModule_AddIntConstant(poModule, "ANTIFLAG_SELL", CItemData::ITEM_ANTIFLAG_SELL); - PyModule_AddIntConstant(poModule, "ANTIFLAG_EMPIRE_A", CItemData::ITEM_ANTIFLAG_EMPIRE_A); - PyModule_AddIntConstant(poModule, "ANTIFLAG_EMPIRE_B", CItemData::ITEM_ANTIFLAG_EMPIRE_B); - PyModule_AddIntConstant(poModule, "ANTIFLAG_EMPIRE_R", CItemData::ITEM_ANTIFLAG_EMPIRE_R); - PyModule_AddIntConstant(poModule, "ANTIFLAG_SAVE", CItemData::ITEM_ANTIFLAG_SAVE); - PyModule_AddIntConstant(poModule, "ANTIFLAG_GIVE", CItemData::ITEM_ANTIFLAG_GIVE); - PyModule_AddIntConstant(poModule, "ANTIFLAG_PKDROP", CItemData::ITEM_ANTIFLAG_PKDROP); - PyModule_AddIntConstant(poModule, "ANTIFLAG_STACK", CItemData::ITEM_ANTIFLAG_STACK); - PyModule_AddIntConstant(poModule, "ANTIFLAG_MYSHOP", CItemData::ITEM_ANTIFLAG_MYSHOP); - PyModule_AddIntConstant(poModule, "WEARABLE_BODY", CItemData::WEARABLE_BODY); - PyModule_AddIntConstant(poModule, "WEARABLE_HEAD", CItemData::WEARABLE_HEAD); - PyModule_AddIntConstant(poModule, "WEARABLE_FOOTS", CItemData::WEARABLE_FOOTS); - PyModule_AddIntConstant(poModule, "WEARABLE_WRIST", CItemData::WEARABLE_WRIST); - PyModule_AddIntConstant(poModule, "WEARABLE_WEAPON", CItemData::WEARABLE_WEAPON); - PyModule_AddIntConstant(poModule, "WEARABLE_NECK", CItemData::WEARABLE_NECK); - PyModule_AddIntConstant(poModule, "WEARABLE_EAR", CItemData::WEARABLE_EAR); - PyModule_AddIntConstant(poModule, "WEARABLE_UNIQUE", CItemData::WEARABLE_UNIQUE); - PyModule_AddIntConstant(poModule, "WEARABLE_SHIELD", CItemData::WEARABLE_SHIELD); - PyModule_AddIntConstant(poModule, "WEARABLE_ARROW", CItemData::WEARABLE_ARROW); - PyModule_AddIntConstant(poModule, "ARMOR_BODY", CItemData::ARMOR_BODY); - PyModule_AddIntConstant(poModule, "ARMOR_HEAD", CItemData::ARMOR_HEAD); - PyModule_AddIntConstant(poModule, "ARMOR_SHIELD", CItemData::ARMOR_SHIELD); - PyModule_AddIntConstant(poModule, "ARMOR_WRIST", CItemData::ARMOR_WRIST); - PyModule_AddIntConstant(poModule, "ARMOR_FOOTS", CItemData::ARMOR_FOOTS); - PyModule_AddIntConstant(poModule, "ARMOR_NECK", CItemData::ARMOR_NECK); - PyModule_AddIntConstant(poModule, "ARMOR_EAR", CItemData::ARMOR_EAR); - PyModule_AddIntConstant(poModule, "ITEM_APPLY_MAX_NUM", CItemData::ITEM_APPLY_MAX_NUM); - PyModule_AddIntConstant(poModule, "ITEM_SOCKET_MAX_NUM", CItemData::ITEM_SOCKET_MAX_NUM); - PyModule_AddIntConstant(poModule, "APPLY_NONE", CItemData::APPLY_NONE); - PyModule_AddIntConstant(poModule, "APPLY_STR", CItemData::APPLY_STR); - PyModule_AddIntConstant(poModule, "APPLY_DEX", CItemData::APPLY_DEX); - PyModule_AddIntConstant(poModule, "APPLY_CON", CItemData::APPLY_CON); - PyModule_AddIntConstant(poModule, "APPLY_INT", CItemData::APPLY_INT); - PyModule_AddIntConstant(poModule, "APPLY_MAX_HP", CItemData::APPLY_MAX_HP); - PyModule_AddIntConstant(poModule, "APPLY_MAX_SP", CItemData::APPLY_MAX_SP); - PyModule_AddIntConstant(poModule, "APPLY_HP_REGEN", CItemData::APPLY_HP_REGEN); - PyModule_AddIntConstant(poModule, "APPLY_SP_REGEN", CItemData::APPLY_SP_REGEN); - PyModule_AddIntConstant(poModule, "APPLY_DEF_GRADE_BONUS", CItemData::APPLY_DEF_GRADE_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_ATT_GRADE_BONUS", CItemData::APPLY_ATT_GRADE_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_ATT_SPEED", CItemData::APPLY_ATT_SPEED); - PyModule_AddIntConstant(poModule, "APPLY_MOV_SPEED", CItemData::APPLY_MOV_SPEED); - PyModule_AddIntConstant(poModule, "APPLY_CAST_SPEED", CItemData::APPLY_CAST_SPEED); - PyModule_AddIntConstant(poModule, "APPLY_MAGIC_ATT_GRADE", CItemData::APPLY_MAGIC_ATT_GRADE); - PyModule_AddIntConstant(poModule, "APPLY_MAGIC_DEF_GRADE", CItemData::APPLY_MAGIC_DEF_GRADE); - PyModule_AddIntConstant(poModule, "APPLY_SKILL", CItemData::APPLY_SKILL); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_ANIMAL", CItemData::APPLY_ATTBONUS_ANIMAL); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_UNDEAD", CItemData::APPLY_ATTBONUS_UNDEAD); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_DEVIL", CItemData::APPLY_ATTBONUS_DEVIL); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_HUMAN", CItemData::APPLY_ATTBONUS_HUMAN); - PyModule_AddIntConstant(poModule, "APPLY_BOW_DISTANCE", CItemData::APPLY_BOW_DISTANCE); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_BOW", CItemData::APPLY_RESIST_BOW); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_FIRE", CItemData::APPLY_RESIST_FIRE); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_ELEC", CItemData::APPLY_RESIST_ELEC); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_MAGIC", CItemData::APPLY_RESIST_MAGIC); - PyModule_AddIntConstant(poModule, "APPLY_POISON_PCT", CItemData::APPLY_POISON_PCT); - PyModule_AddIntConstant(poModule, "APPLY_SLOW_PCT", CItemData::APPLY_SLOW_PCT); - PyModule_AddIntConstant(poModule, "APPLY_STUN_PCT", CItemData::APPLY_STUN_PCT); - PyModule_AddIntConstant(poModule, "APPLY_CRITICAL_PCT", CItemData::APPLY_CRITICAL_PCT); // n% 확률로 두배 타격 - PyModule_AddIntConstant(poModule, "APPLY_PENETRATE_PCT", CItemData::APPLY_PENETRATE_PCT); // n% 확률로 적의 방어력 무시 - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_ORC", CItemData::APPLY_ATTBONUS_ORC); // 웅귀에게 n% 추가 데미지 - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_MILGYO", CItemData::APPLY_ATTBONUS_MILGYO); // 밀교에게 n% 추가 데미지 - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_UNDEAD", CItemData::APPLY_ATTBONUS_UNDEAD); // 시체에게 n% 추가 데미지 - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_DEVIL", CItemData::APPLY_ATTBONUS_DEVIL); // 악마에게 n% 추가 데미지 - PyModule_AddIntConstant(poModule, "APPLY_STEAL_HP", CItemData::APPLY_STEAL_HP); // n% 확률로 타격의 10% 를 생명력으로 흡수 - PyModule_AddIntConstant(poModule, "APPLY_STEAL_SP", CItemData::APPLY_STEAL_SP); // n% 확률로 타격의 10% 를 정신력으로 흡수 - PyModule_AddIntConstant(poModule, "APPLY_MANA_BURN_PCT", CItemData::APPLY_MANA_BURN_PCT); // n% 확률로 상대의 마나를 깎는다 - PyModule_AddIntConstant(poModule, "APPLY_DAMAGE_SP_RECOVER", CItemData::APPLY_DAMAGE_SP_RECOVER); // n% 확률로 정신력 2 회복 - PyModule_AddIntConstant(poModule, "APPLY_BLOCK", CItemData::APPLY_BLOCK); // n% 확률로 물리공격 완벽 방어 - PyModule_AddIntConstant(poModule, "APPLY_DODGE", CItemData::APPLY_DODGE); // n% 확률로 물리공격 완벽 회피 - PyModule_AddIntConstant(poModule, "APPLY_RESIST_SWORD", CItemData::APPLY_RESIST_SWORD); // 한손검에 의한 피해를 n% 감소 - PyModule_AddIntConstant(poModule, "APPLY_RESIST_TWOHAND", CItemData::APPLY_RESIST_TWOHAND); // 양손검에 의한 피해를 n% 감소 - PyModule_AddIntConstant(poModule, "APPLY_RESIST_DAGGER", CItemData::APPLY_RESIST_DAGGER); // 단도에 의한 피해를 n% 감소 - PyModule_AddIntConstant(poModule, "APPLY_RESIST_BELL", CItemData::APPLY_RESIST_BELL); // 방울에 의한 피해를 n% 감소 - PyModule_AddIntConstant(poModule, "APPLY_RESIST_FAN", CItemData::APPLY_RESIST_FAN); // 부채에 의한 피해를 n% 감소 - PyModule_AddIntConstant(poModule, "APPLY_RESIST_WIND", CItemData::APPLY_RESIST_WIND); // 바람에 의한 피해를 n% 감소 - PyModule_AddIntConstant(poModule, "APPLY_REFLECT_MELEE", CItemData::APPLY_REFLECT_MELEE); // 근접 타격 n% 를 적에게 되돌린다 - PyModule_AddIntConstant(poModule, "APPLY_REFLECT_CURSE", CItemData::APPLY_REFLECT_CURSE); // 적이 나에게 저주 사용시 n% 확률로 되돌린다 - PyModule_AddIntConstant(poModule, "APPLY_POISON_REDUCE", CItemData::APPLY_POISON_REDUCE); // 독에 의한 데미지 감소 - PyModule_AddIntConstant(poModule, "APPLY_KILL_SP_RECOVER", CItemData::APPLY_KILL_SP_RECOVER); // 적을 죽였을때 n% 확률로 정신력 10 회복 - PyModule_AddIntConstant(poModule, "APPLY_EXP_DOUBLE_BONUS", CItemData::APPLY_EXP_DOUBLE_BONUS); // n% 확률로 경험치 획득량 2배 - PyModule_AddIntConstant(poModule, "APPLY_GOLD_DOUBLE_BONUS", CItemData::APPLY_GOLD_DOUBLE_BONUS); // n% 확률로 돈 획득량 2배 - PyModule_AddIntConstant(poModule, "APPLY_ITEM_DROP_BONUS", CItemData::APPLY_ITEM_DROP_BONUS); // n% 확률로 아이템 획득량 2배 - PyModule_AddIntConstant(poModule, "APPLY_POTION_BONUS", CItemData::APPLY_POTION_BONUS); // 물약 복용시 n% 만큼 성능 증대 - PyModule_AddIntConstant(poModule, "APPLY_KILL_HP_RECOVER", CItemData::APPLY_KILL_HP_RECOVER); // 죽일때마다 생명력 회복 - PyModule_AddIntConstant(poModule, "APPLY_IMMUNE_STUN", CItemData::APPLY_IMMUNE_STUN); // 기절 하지 않는다 - PyModule_AddIntConstant(poModule, "APPLY_IMMUNE_SLOW", CItemData::APPLY_IMMUNE_SLOW); // 느려지지 않는다 - PyModule_AddIntConstant(poModule, "APPLY_IMMUNE_FALL", CItemData::APPLY_IMMUNE_FALL); // 넘어지지 않는다 - PyModule_AddIntConstant(poModule, "APPLY_MAX_STAMINA", CItemData::APPLY_MAX_STAMINA); // 최대 스테미너 증가 - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_WARRIOR", CItemData::APPLY_ATT_BONUS_TO_WARRIOR); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_ASSASSIN", CItemData::APPLY_ATT_BONUS_TO_ASSASSIN); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_SURA", CItemData::APPLY_ATT_BONUS_TO_SURA); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_SHAMAN", CItemData::APPLY_ATT_BONUS_TO_SHAMAN); - PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_MONSTER", CItemData::APPLY_ATT_BONUS_TO_MONSTER); - PyModule_AddIntConstant(poModule, "APPLY_MALL_ATTBONUS", CItemData::APPLY_MALL_ATTBONUS); - PyModule_AddIntConstant(poModule, "APPLY_MALL_DEFBONUS", CItemData::APPLY_MALL_DEFBONUS); - PyModule_AddIntConstant(poModule, "APPLY_MALL_EXPBONUS", CItemData::APPLY_MALL_EXPBONUS); - PyModule_AddIntConstant(poModule, "APPLY_MALL_ITEMBONUS", CItemData::APPLY_MALL_ITEMBONUS); - PyModule_AddIntConstant(poModule, "APPLY_MALL_GOLDBONUS", CItemData::APPLY_MALL_GOLDBONUS); - PyModule_AddIntConstant(poModule, "APPLY_MAX_HP_PCT", CItemData::APPLY_MAX_HP_PCT); - PyModule_AddIntConstant(poModule, "APPLY_MAX_SP_PCT", CItemData::APPLY_MAX_SP_PCT); - PyModule_AddIntConstant(poModule, "APPLY_SKILL_DAMAGE_BONUS", CItemData::APPLY_SKILL_DAMAGE_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_NORMAL_HIT_DAMAGE_BONUS", CItemData::APPLY_NORMAL_HIT_DAMAGE_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_SKILL_DEFEND_BONUS", CItemData::APPLY_SKILL_DEFEND_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_NORMAL_HIT_DEFEND_BONUS", CItemData::APPLY_NORMAL_HIT_DEFEND_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_PC_BANG_EXP_BONUS", CItemData::APPLY_PC_BANG_EXP_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_PC_BANG_DROP_BONUS", CItemData::APPLY_PC_BANG_DROP_BONUS); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_WARRIOR", CItemData::APPLY_RESIST_WARRIOR ); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_ASSASSIN", CItemData::APPLY_RESIST_ASSASSIN ); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_SURA", CItemData::APPLY_RESIST_SURA ); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_SHAMAN", CItemData::APPLY_RESIST_SHAMAN ); - PyModule_AddIntConstant(poModule, "APPLY_ENERGY", CItemData::APPLY_ENERGY ); // 기력 - PyModule_AddIntConstant(poModule, "APPLY_COSTUME_ATTR_BONUS", CItemData::APPLY_COSTUME_ATTR_BONUS ); - PyModule_AddIntConstant(poModule, "APPLY_MAGIC_ATTBONUS_PER", CItemData::APPLY_MAGIC_ATTBONUS_PER ); - PyModule_AddIntConstant(poModule, "APPLY_MELEE_MAGIC_ATTBONUS_PER", CItemData::APPLY_MELEE_MAGIC_ATTBONUS_PER ); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_ICE", CItemData::APPLY_RESIST_ICE ); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_EARTH", CItemData::APPLY_RESIST_EARTH ); - PyModule_AddIntConstant(poModule, "APPLY_RESIST_DARK", CItemData::APPLY_RESIST_DARK ); - PyModule_AddIntConstant(poModule, "APPLY_ANTI_CRITICAL_PCT", CItemData::APPLY_ANTI_CRITICAL_PCT ); - PyModule_AddIntConstant(poModule, "APPLY_ANTI_PENETRATE_PCT", CItemData::APPLY_ANTI_PENETRATE_PCT ); -} - // 40250 UserInterface/PythonMessenger.cpp void AddStubConstants_messenger(PyObject* poModule) { diff --git a/extension/src/platform/ScriptLib/GameplayModules.cpp b/extension/src/platform/ScriptLib/GameplayModules.cpp index 4dff03e0..e9518a83 100644 --- a/extension/src/platform/ScriptLib/GameplayModules.cpp +++ b/extension/src/platform/ScriptLib/GameplayModules.cpp @@ -11,7 +11,6 @@ void AddStubConstants_eventMgr(PyObject* poModule); void AddStubConstants_exchange(PyObject* poModule); void AddStubConstants_guild(PyObject* poModule); void AddStubConstants_ime(PyObject* poModule); -void AddStubConstants_item(PyObject* poModule); void AddStubConstants_messenger(PyObject* poModule); void AddStubConstants_miniMap(PyObject* poModule); void AddStubConstants_profiler(PyObject* poModule); @@ -370,82 +369,6 @@ PyMethodDef methods_ime[] = { { "EnablePaste", stub_ime_EnablePaste, METH_VARARGS }, { NULL, NULL } }; -// 40250 UserInterface/PythonItemModule.cpp: item export names. -PyObject* stub_item_SetUseSoundFileName(PyObject*, PyObject*) { return stub_call_named("item.SetUseSoundFileName", Py_BuildNone()); } -PyObject* stub_item_SetDropSoundFileName(PyObject*, PyObject*) { return stub_call_named("item.SetDropSoundFileName", Py_BuildNone()); } -PyObject* stub_item_SelectItem(PyObject*, PyObject*) { return stub_call_named("item.SelectItem", Py_BuildNone()); } -PyObject* stub_item_GetItemName(PyObject*, PyObject*) { return stub_call_named("item.GetItemName", Py_BuildValue("s", "")); } -PyObject* stub_item_GetItemDescription(PyObject*, PyObject*) { return stub_call_named("item.GetItemDescription", Py_BuildValue("s", "")); } -PyObject* stub_item_GetItemSummary(PyObject*, PyObject*) { return stub_call_named("item.GetItemSummary", Py_BuildValue("s", "")); } -PyObject* stub_item_GetIconImage(PyObject*, PyObject*) { return stub_call_named("item.GetIconImage", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetIconImageFileName(PyObject*, PyObject*) { return stub_call_named("item.GetIconImageFileName", Py_BuildValue("s", "")); } -PyObject* stub_item_GetItemSize(PyObject*, PyObject*) { return stub_call_named("item.GetItemSize", Py_BuildValue("(ii)", 0, 0)); } -PyObject* stub_item_GetItemType(PyObject*, PyObject*) { return stub_call_named("item.GetItemType", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetItemSubType(PyObject*, PyObject*) { return stub_call_named("item.GetItemSubType", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetIBuyItemPrice(PyObject*, PyObject*) { return stub_call_named("item.GetIBuyItemPrice", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetISellItemPrice(PyObject*, PyObject*) { return stub_call_named("item.GetISellItemPrice", Py_BuildValue("i", 0)); } -PyObject* stub_item_IsAntiFlag(PyObject*, PyObject*) { return stub_call_named("item.IsAntiFlag", Py_BuildValue("i", 0)); } -PyObject* stub_item_IsFlag(PyObject*, PyObject*) { return stub_call_named("item.IsFlag", Py_BuildValue("i", 0)); } -PyObject* stub_item_IsWearableFlag(PyObject*, PyObject*) { return stub_call_named("item.IsWearableFlag", Py_BuildValue("i", 0)); } -PyObject* stub_item_Is1GoldItem(PyObject*, PyObject*) { return stub_call_named("item.Is1GoldItem", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetLimit(PyObject*, PyObject*) { return stub_call_named("item.GetLimit", Py_BuildValue("ii", 0, 0)); } -PyObject* stub_item_GetAffect(PyObject*, PyObject*) { return stub_call_named("item.GetAffect", Py_BuildValue("ii", 0, 0)); } -PyObject* stub_item_GetValue(PyObject*, PyObject*) { return stub_call_named("item.GetValue", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetSocket(PyObject*, PyObject*) { return stub_call_named("item.GetSocket", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetIconInstance(PyObject*, PyObject*) { return stub_call_named("item.GetIconInstance", Py_BuildValue("i", 0)); } -PyObject* stub_item_GetUseType(PyObject*, PyObject*) { return stub_call_named("item.GetUseType", Py_BuildValue("s", "")); } -PyObject* stub_item_DeleteIconInstance(PyObject*, PyObject*) { return stub_call_named("item.DeleteIconInstance", Py_BuildNone()); } -PyObject* stub_item_IsEquipmentVID(PyObject*, PyObject*) { return stub_call_named("item.IsEquipmentVID", Py_BuildValue("i", 0)); } -PyObject* stub_item_IsRefineScroll(PyObject*, PyObject*) { return stub_call_named("item.IsRefineScroll", Py_BuildValue("i", 0)); } -PyObject* stub_item_IsDetachScroll(PyObject*, PyObject*) { return stub_call_named("item.IsDetachScroll", Py_BuildValue("i", 0)); } -PyObject* stub_item_IsKey(PyObject*, PyObject*) { return stub_call_named("item.IsKey", Py_BuildValue("i", 0)); } -PyObject* stub_item_IsMetin(PyObject*, PyObject*) { return stub_call_named("item.IsMetin", Py_BuildValue("i", 0)); } -PyObject* stub_item_CanAddToQuickSlotItem(PyObject*, PyObject*) { return stub_call_named("item.CanAddToQuickSlotItem", Py_BuildValue("i", 0)); } -PyObject* stub_item_Update(PyObject*, PyObject*) { return stub_call_named("item.Update", Py_BuildNone()); } -PyObject* stub_item_Render(PyObject*, PyObject*) { return stub_call_named("item.Render", Py_BuildNone()); } -PyObject* stub_item_CreateItem(PyObject*, PyObject*) { return stub_call_named("item.CreateItem", Py_BuildNone()); } -PyObject* stub_item_DeleteItem(PyObject*, PyObject*) { return stub_call_named("item.DeleteItem", Py_BuildNone()); } -PyObject* stub_item_Pick(PyObject*, PyObject*) { return stub_call_named("item.Pick", Py_BuildValue("i", 0)); } -PyObject* stub_item_LoadItemTable(PyObject*, PyObject*) { return stub_call_named("item.LoadItemTable", Py_BuildNone()); } -PyMethodDef methods_item[] = { - { "SetUseSoundFileName", stub_item_SetUseSoundFileName, METH_VARARGS }, - { "SetDropSoundFileName", stub_item_SetDropSoundFileName, METH_VARARGS }, - { "SelectItem", stub_item_SelectItem, METH_VARARGS }, - { "GetItemName", stub_item_GetItemName, METH_VARARGS }, - { "GetItemDescription", stub_item_GetItemDescription, METH_VARARGS }, - { "GetItemSummary", stub_item_GetItemSummary, METH_VARARGS }, - { "GetIconImage", stub_item_GetIconImage, METH_VARARGS }, - { "GetIconImageFileName", stub_item_GetIconImageFileName, METH_VARARGS }, - { "GetItemSize", stub_item_GetItemSize, METH_VARARGS }, - { "GetItemType", stub_item_GetItemType, METH_VARARGS }, - { "GetItemSubType", stub_item_GetItemSubType, METH_VARARGS }, - { "GetIBuyItemPrice", stub_item_GetIBuyItemPrice, METH_VARARGS }, - { "GetISellItemPrice", stub_item_GetISellItemPrice, METH_VARARGS }, - { "IsAntiFlag", stub_item_IsAntiFlag, METH_VARARGS }, - { "IsFlag", stub_item_IsFlag, METH_VARARGS }, - { "IsWearableFlag", stub_item_IsWearableFlag, METH_VARARGS }, - { "Is1GoldItem", stub_item_Is1GoldItem, METH_VARARGS }, - { "GetLimit", stub_item_GetLimit, METH_VARARGS }, - { "GetAffect", stub_item_GetAffect, METH_VARARGS }, - { "GetValue", stub_item_GetValue, METH_VARARGS }, - { "GetSocket", stub_item_GetSocket, METH_VARARGS }, - { "GetIconInstance", stub_item_GetIconInstance, METH_VARARGS }, - { "GetUseType", stub_item_GetUseType, METH_VARARGS }, - { "DeleteIconInstance", stub_item_DeleteIconInstance, METH_VARARGS }, - { "IsEquipmentVID", stub_item_IsEquipmentVID, METH_VARARGS }, - { "IsRefineScroll", stub_item_IsRefineScroll, METH_VARARGS }, - { "IsDetachScroll", stub_item_IsDetachScroll, METH_VARARGS }, - { "IsKey", stub_item_IsKey, METH_VARARGS }, - { "IsMetin", stub_item_IsMetin, METH_VARARGS }, - { "CanAddToQuickSlotItem", stub_item_CanAddToQuickSlotItem, METH_VARARGS }, - { "Update", stub_item_Update, METH_VARARGS }, - { "Render", stub_item_Render, METH_VARARGS }, - { "CreateItem", stub_item_CreateItem, METH_VARARGS }, - { "DeleteItem", stub_item_DeleteItem, METH_VARARGS }, - { "Pick", stub_item_Pick, METH_VARARGS }, - { "LoadItemTable", stub_item_LoadItemTable, METH_VARARGS }, - { NULL, NULL } -}; // 40250 UserInterface/PythonMessenger.cpp: messenger export names. PyObject* stub_messenger_RemoveFriend(PyObject*, PyObject*) { return stub_call_named("messenger.RemoveFriend", Py_BuildNone()); } PyObject* stub_messenger_IsFriendByName(PyObject*, PyObject*) { return stub_call_named("messenger.IsFriendByName", Py_BuildValue("i", 0)); } @@ -890,11 +813,6 @@ void init_2v0_gameplay_stubs() { PyModule_AddIntConstant(module, "__port_stub__", 1); AddStubConstants_ime(module); } - { - PyObject* module = Py_InitModule("item", methods_item); - PyModule_AddIntConstant(module, "__port_stub__", 1); - AddStubConstants_item(module); - } { PyObject* module = Py_InitModule("messenger", methods_messenger); PyModule_AddIntConstant(module, "__port_stub__", 1); diff --git a/extension/src/platform/ScriptLib/PythonBoot.cpp b/extension/src/platform/ScriptLib/PythonBoot.cpp index 9c67990e..915d9cc0 100644 --- a/extension/src/platform/ScriptLib/PythonBoot.cpp +++ b/extension/src/platform/ScriptLib/PythonBoot.cpp @@ -347,6 +347,7 @@ bool run_main_script_body(const char* lpCmdLine, std::string* error) initchr(); initchrmgr(); initPlayer(); + initItem(); initNonPlayer(); initChat(); initnet(); diff --git a/extension/src/platform/UserInterface/PythonApplication.cpp b/extension/src/platform/UserInterface/PythonApplication.cpp index 4940e1ef..aa6067b2 100644 --- a/extension/src/platform/UserInterface/PythonApplication.cpp +++ b/extension/src/platform/UserInterface/PythonApplication.cpp @@ -7,6 +7,7 @@ #include "EterLib/ResourceManager.h" #include "UserInterface/PythonNetworkStream.h" #include "UserInterface/AccountConnector.h" +#include "UserInterface/PythonItem.h" #include "UserInterface/PythonSkill.h" #include "UserInterface/PythonNonPlayer.h" #include "GameLib/ItemManager.h" @@ -119,6 +120,10 @@ bool CPythonApplication::Create(PyObject*, const char*, int, int, int) PyErr_SetString(PyExc_RuntimeError, "CREATE_NETWORK"); return false; } + + // 40250 m_pyItem.Create() (PythonApplication.cpp:1253): registers dropitem.mse with CEffectManager, + // still a platform stub. + CPythonItem::Instance().Create(); return true; } // 40250 PythonApplication.cpp:105 diff --git a/extension/src/platform/pending/GameLib/MapManager.cpp b/extension/src/platform/pending/GameLib/MapManager.cpp index b808ab21..78a7c5d6 100644 --- a/extension/src/platform/pending/GameLib/MapManager.cpp +++ b/extension/src/platform/pending/GameLib/MapManager.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -111,6 +112,49 @@ auto CMapManager::GetTerrainHeight(float fx, float fy) -> float return height; } +// CMapOutdoor::GetNormal → CTerrain::GetNormal. 40250 fills CTerrain::m_acNormalMap at LoadHeightMap with +// CTerrain::CalculateNormal and reads the cell's byte triple; the same formula runs here per call on the +// cached height tile (GetHeightMapValue = raw[(y+1)*131 + x+1]). +bool CMapManager::GetNormal(int ix, int iy, D3DXVECTOR3 * pv3Normal) +{ + auto found = s_native_maps.find(this); + if (found == s_native_maps.end() || !found->second.ready) + return false; + NativeMapState &state = found->second; + const int count_x = state.setting.map_size_x, count_y = state.setting.map_size_y; + ix = std::clamp(ix, 0, count_x * CTerrainImpl::TERRAIN_XSIZE); + iy = std::clamp(iy, 0, count_y * CTerrainImpl::TERRAIN_YSIZE); + const int tx = std::min(ix / CTerrainImpl::TERRAIN_XSIZE, count_x - 1); + const int ty = std::min(iy / CTerrainImpl::TERRAIN_YSIZE, count_y - 1); + if (!load_height_tile(state, tx, ty)) + return false; + while (ix >= CTerrainImpl::TERRAIN_XSIZE) + ix -= CTerrainImpl::TERRAIN_XSIZE; + while (iy >= CTerrainImpl::TERRAIN_YSIZE) + iy -= CTerrainImpl::TERRAIN_YSIZE; + const int x = ix / CTerrainImpl::CELLSCALE, y = iy / CTerrainImpl::CELLSCALE; + + const std::vector &raw = state.heights.at({tx, ty}).raw; + auto height = [&](int sx, int sy) { + return float(raw[(sy + 1) * CTerrainImpl::HEIGHTMAP_RAW_XSIZE + sx + 1]); + }; + D3DXVECTOR3 normal; + normal.x = -state.setting.height_scale * (height(x - 1, y) - height(x + 1, y)); + normal.y = -state.setting.height_scale * (height(x, y - 1) - height(x, y + 1)); + normal.z = 2.0f * static_cast(CTerrainImpl::CELLSCALE); + normal *= 127.0f / D3DXVec3Length(&normal); + // PR_FLOAT_TO_INT (fistp, then one down when it rounded up) into the char normal map. + const signed char n[3] = { + static_cast(int(std::floor(normal.x))), + static_cast(int(std::floor(normal.y))), + static_cast(int(std::floor(normal.z))), + }; + pv3Normal->x = -((float)n[0]) * 0.007874016f; + pv3Normal->y = ((float)n[1]) * 0.007874016f; + pv3Normal->z = ((float)n[2]) * 0.007874016f; + return true; +} + CMapManager::CMapManager() : mc_pcurEnvironmentData(NULL) { m_pkMap = NULL; diff --git a/extension/src/platform/pending/UserInterface/PythonItem.cpp b/extension/src/platform/pending/UserInterface/PythonItem.cpp deleted file mode 100644 index e9ec9d60..00000000 --- a/extension/src/platform/pending/UserInterface/PythonItem.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// Stand-in for the 40250 logic unit UserInterface/PythonItem.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/PythonItem.h" - -#include "../../PlatformStub.h" - -CPythonItem::CPythonItem() -{ - MT_PLATFORM_STUB(); -} - -CPythonItem::~CPythonItem() -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::Destroy() -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::PlayUseSound(DWORD) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::PlayDropSound(DWORD) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::PlayUsePotionSound() -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::CreateItem(DWORD, DWORD, float, float, float, bool) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::DeleteItem(DWORD) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::DeleteAllItems() -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::SetOwnership(DWORD, const char *) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::Render() -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::Update(const POINT &) -> void -{ - MT_PLATFORM_STUB(); -} - -auto CPythonItem::GetOwnership(DWORD, const char **) -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonItem::GetGroundItemPosition(DWORD, TPixelPosition *) -> BOOL -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonItem::GetPickedItemID(DWORD *) -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonItem::GetCloseItem(const TPixelPosition &, DWORD *, DWORD) -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonItem::GetCloseMoney(const TPixelPosition &, DWORD *, DWORD) -> bool -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} - -auto CPythonItem::GetVirtualNumberOfGroundItem(DWORD) -> DWORD -{ - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); -} diff --git a/extension/src/platform/pending/UserInterface/PythonTextTail.cpp b/extension/src/platform/pending/UserInterface/PythonTextTail.cpp index b9f664a5..11d5ed45 100644 --- a/extension/src/platform/pending/UserInterface/PythonTextTail.cpp +++ b/extension/src/platform/pending/UserInterface/PythonTextTail.cpp @@ -50,3 +50,26 @@ auto CPythonTextTail::AttachLevel(DWORD, const char *, const D3DXCOLOR &) -> voi { MT_PLATFORM_STUB(); } + +auto CPythonTextTail::RegisterItemTextTail(DWORD, const char *, CGraphicObjectInstance *) -> void +{ + MT_PLATFORM_STUB(); +} + +auto CPythonTextTail::DeleteItemTextTail(DWORD) -> void +{ + MT_PLATFORM_STUB(); +} + +auto CPythonTextTail::SetItemTextTailOwner(DWORD, const char *) -> void +{ + MT_PLATFORM_STUB(); +} + +// 40250 returns -1 when no item text tail is under the mouse; RegisterItemTextTail is still a stub, so +// m_ItemTextTailMap stays empty and that is always the answer (0 would pick ground item VID 0). +auto CPythonTextTail::Pick(int, int) -> int +{ + MT_PLATFORM_STUB(); + return -1; +} diff --git a/extension/src/port/UserInterface/PythonItem.cpp b/extension/src/port/UserInterface/PythonItem.cpp new file mode 100644 index 00000000..6b85b84e --- /dev/null +++ b/extension/src/port/UserInterface/PythonItem.cpp @@ -0,0 +1,763 @@ +#include "StdAfx.h" +#include "../EterLib/GrpMath.h" +#include "../GameLib/ItemManager.h" +#include "../EffectLib/EffectManager.h" +#include "PythonBackground.h" + +#include "PythonItem.h" +#include "PythonTextTail.h" + +const float c_fDropStartHeight = 100.0f; +const float c_fDropTime = 0.5f; + +std::string CPythonItem::TGroundItemInstance::ms_astDropSoundFileName[DROPSOUND_NUM]; + +void CPythonItem::GetInfo(std::string* pstInfo) +{ + char szInfo[256]; + sprintf(szInfo, "Item: Inst %d, Pool %d", m_GroundItemInstanceMap.size(), m_GroundItemInstancePool.GetCapacity()); + + pstInfo->append(szInfo); +} + +void CPythonItem::TGroundItemInstance::Clear() +{ + stOwnership = ""; + ThingInstance.Clear(); + CEffectManager::Instance().DestroyEffectInstance(dwEffectInstanceIndex); +} + +void CPythonItem::TGroundItemInstance::__PlayDropSound(DWORD eItemType, const D3DXVECTOR3& c_rv3Pos) +{ + if (eItemType>=DROPSOUND_NUM) + return; + + CSoundManager::Instance().PlaySound3D(c_rv3Pos.x, c_rv3Pos.y, c_rv3Pos.z, ms_astDropSoundFileName[eItemType].c_str()); +} + +bool CPythonItem::TGroundItemInstance::Update() +{ + if (bAnimEnded) + return false; + if (dwEndTime < CTimer::Instance().GetCurrentMillisecond()) + { + ThingInstance.SetRotationQuaternion(qEnd); + + /*D3DXVECTOR3 v3Adjust = -v3Center; + D3DXMATRIX mat; + D3DXMatrixRotationYawPitchRoll(&mat, + D3DXToRadian(rEnd.y), + D3DXToRadian(rEnd.x), + D3DXToRadian(rEnd.z)); + D3DXVec3TransformCoord(&v3Adjust,&v3Adjust,&mat);*/ + + D3DXQUATERNION qAdjust(-v3Center.x, -v3Center.y, -v3Center.z, 0.0f); + D3DXQUATERNION qc; + D3DXQuaternionConjugate(&qc, &qEnd); + D3DXQuaternionMultiply(&qAdjust,&qAdjust,&qEnd); + D3DXQuaternionMultiply(&qAdjust,&qc,&qAdjust); + + ThingInstance.SetPosition(v3EndPosition.x+qAdjust.x, + v3EndPosition.y+qAdjust.y, + v3EndPosition.z+qAdjust.z); + //ThingInstance.Update(); + bAnimEnded = true; + + __PlayDropSound(eDropSoundType, v3EndPosition); + } + else + { + DWORD time = CTimer::Instance().GetCurrentMillisecond() - dwStartTime; + DWORD etime = dwEndTime - CTimer::Instance().GetCurrentMillisecond(); + float rate = time * 1.0f / (dwEndTime - dwStartTime); + + D3DXVECTOR3 v3NewPosition=v3EndPosition;// = rate*(v3EndPosition - v3StartPosition) + v3StartPosition; + v3NewPosition.z += 100-100*rate*(3*rate-2);//-100*(rate-1)*(3*rate+2); + + D3DXQUATERNION q; + D3DXQuaternionRotationAxis(&q, &v3RotationAxis, etime * 0.03f *(-1+rate*(3*rate-2))); + //ThingInstance.SetRotation(rEnd.y + etime*rStart.y, rEnd.x + etime*rStart.x, rEnd.z + etime*rStart.z); + D3DXQuaternionMultiply(&q,&qEnd,&q); + + ThingInstance.SetRotationQuaternion(q); + D3DXQUATERNION qAdjust(-v3Center.x, -v3Center.y, -v3Center.z, 0.0f); + D3DXQUATERNION qc; + D3DXQuaternionConjugate(&qc, &q); + D3DXQuaternionMultiply(&qAdjust,&qAdjust,&q); + D3DXQuaternionMultiply(&qAdjust,&qc,&qAdjust); + + ThingInstance.SetPosition(v3NewPosition.x+qAdjust.x, + v3NewPosition.y+qAdjust.y, + v3NewPosition.z+qAdjust.z); + + /*D3DXVECTOR3 v3Adjust = -v3Center; + D3DXMATRIX mat; + D3DXMatrixRotationYawPitchRoll(&mat, + D3DXToRadian(rEnd.y + etime*rStart.y), + D3DXToRadian(rEnd.x + etime*rStart.x), + D3DXToRadian(rEnd.z + etime*rStart.z)); + + D3DXVec3TransformCoord(&v3Adjust,&v3Adjust,&mat); + //Tracef("%f %f %f\n",v3Adjust.x,v3Adjust.y,v3Adjust.z); + v3NewPosition += v3Adjust; + ThingInstance.SetPosition(v3NewPosition.x, v3NewPosition.y, v3NewPosition.z);*/ + } + ThingInstance.Transform(); + ThingInstance.Deform(); + return !bAnimEnded; +} + +void CPythonItem::Update(const POINT& c_rkPtMouse) +{ + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.begin(); + for(; itor != m_GroundItemInstanceMap.end(); ++itor) + { + itor->second->Update(); + } + + m_dwPickedItemID=__Pick(c_rkPtMouse); +} + +void CPythonItem::Render() +{ + CPythonGraphic::Instance().SetDiffuseOperation(); + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.begin(); + for (; itor != m_GroundItemInstanceMap.end(); ++itor) + { + CGraphicThingInstance & rInstance = itor->second->ThingInstance; + //rInstance.Update(); + rInstance.Render(); + rInstance.BlendRender(); + } +} + +void CPythonItem::SetUseSoundFileName(DWORD eItemType, const std::string& c_rstFileName) +{ + if (eItemType>=USESOUND_NUM) + return; + + //Tracenf("SetUseSoundFile %d : %s", eItemType, c_rstFileName.c_str()); + + m_astUseSoundFileName[eItemType]=c_rstFileName; +} + +void CPythonItem::SetDropSoundFileName(DWORD eItemType, const std::string& c_rstFileName) +{ + if (eItemType>=DROPSOUND_NUM) + return; + + Tracenf("SetDropSoundFile %d : %s", eItemType, c_rstFileName.c_str()); + + SGroundItemInstance::ms_astDropSoundFileName[eItemType]=c_rstFileName; +} + +void CPythonItem::PlayUseSound(DWORD dwItemID) +{ + //CItemManager& rkItemMgr=CItemManager::Instance(); + + CItemData* pkItemData; + if (!CItemManager::Instance().GetItemDataPointer(dwItemID, &pkItemData)) + return; + + DWORD eItemType=__GetUseSoundType(*pkItemData); + if (eItemType==USESOUND_NONE) + return; + if (eItemType>=USESOUND_NUM) + return; + + CSoundManager::Instance().PlaySound2D(m_astUseSoundFileName[eItemType].c_str()); +} + + +void CPythonItem::PlayDropSound(DWORD dwItemID) +{ + //CItemManager& rkItemMgr=CItemManager::Instance(); + + CItemData* pkItemData; + if (!CItemManager::Instance().GetItemDataPointer(dwItemID, &pkItemData)) + return; + + DWORD eItemType=__GetDropSoundType(*pkItemData); + if (eItemType>=DROPSOUND_NUM) + return; + + CSoundManager::Instance().PlaySound2D(SGroundItemInstance::ms_astDropSoundFileName[eItemType].c_str()); +} + +void CPythonItem::PlayUsePotionSound() +{ + CSoundManager::Instance().PlaySound2D(m_astUseSoundFileName[USESOUND_POTION].c_str()); +} + +DWORD CPythonItem::__GetDropSoundType(const CItemData& c_rkItemData) +{ + switch (c_rkItemData.GetType()) + { + case CItemData::ITEM_TYPE_WEAPON: + switch (c_rkItemData.GetWeaponType()) + { + case CItemData::WEAPON_BOW: + return DROPSOUND_BOW; + break; + case CItemData::WEAPON_ARROW: + return DROPSOUND_DEFAULT; + break; + default: + return DROPSOUND_WEAPON; + break; + } + break; + case CItemData::ITEM_TYPE_ARMOR: + switch (c_rkItemData.GetSubType()) + { + case CItemData::ARMOR_NECK: + case CItemData::ARMOR_EAR: + return DROPSOUND_ACCESSORY; + break; + case CItemData::ARMOR_BODY: + return DROPSOUND_ARMOR; + default: + return DROPSOUND_DEFAULT; + break; + } + break; + default: + return DROPSOUND_DEFAULT; + break; + } + + return DROPSOUND_DEFAULT; +} + + +DWORD CPythonItem::__GetUseSoundType(const CItemData& c_rkItemData) +{ + switch (c_rkItemData.GetType()) + { + case CItemData::ITEM_TYPE_WEAPON: + switch (c_rkItemData.GetWeaponType()) + { + case CItemData::WEAPON_BOW: + return USESOUND_BOW; + break; + case CItemData::WEAPON_ARROW: + return USESOUND_DEFAULT; + break; + default: + return USESOUND_WEAPON; + break; + } + break; + case CItemData::ITEM_TYPE_ARMOR: + switch (c_rkItemData.GetSubType()) + { + case CItemData::ARMOR_NECK: + case CItemData::ARMOR_EAR: + return USESOUND_ACCESSORY; + break; + case CItemData::ARMOR_BODY: + return USESOUND_ARMOR; + default: + return USESOUND_DEFAULT; + break; + } + break; + case CItemData::ITEM_TYPE_USE: + switch (c_rkItemData.GetSubType()) + { + case CItemData::USE_ABILITY_UP: + return USESOUND_POTION; + break; + case CItemData::USE_POTION: + return USESOUND_NONE; + break; + case CItemData::USE_TALISMAN: + return USESOUND_PORTAL; + break; + default: + return USESOUND_DEFAULT; + break; + } + break; + default: + return USESOUND_DEFAULT; + break; + } + + return USESOUND_DEFAULT; +} + +void CPythonItem::CreateItem(DWORD dwVirtualID, DWORD dwVirtualNumber, float x, float y, float z, bool bDrop) +{ + //CItemManager& rkItemMgr=CItemManager::Instance(); + + CItemData * pItemData; + if (!CItemManager::Instance().GetItemDataPointer(dwVirtualNumber, &pItemData)) + return; + + CGraphicThing* pItemModel = pItemData->GetDropModelThing(); + + TGroundItemInstance * pGroundItemInstance = m_GroundItemInstancePool.Alloc(); + pGroundItemInstance->dwVirtualNumber = dwVirtualNumber; + + bool bStabGround = false; + + if (bDrop) + { + z = CPythonBackground::Instance().GetHeight(x, y) + 10.0f; + + if (pItemData->GetType()==CItemData::ITEM_TYPE_WEAPON && + (pItemData->GetWeaponType() == CItemData::WEAPON_SWORD || + pItemData->GetWeaponType() == CItemData::WEAPON_ARROW)) + bStabGround = true; + + bStabGround = false; + pGroundItemInstance->bAnimEnded = false; + } + else + { + pGroundItemInstance->bAnimEnded = true; + } + + { + // attaching effect + CEffectManager & rem =CEffectManager::Instance(); + pGroundItemInstance->dwEffectInstanceIndex = + rem.CreateEffect(m_dwDropItemEffectID, D3DXVECTOR3(x, -y, z), D3DXVECTOR3(0,0,0)); + + pGroundItemInstance->eDropSoundType=__GetDropSoundType(*pItemData); + } + + + D3DXVECTOR3 normal; + if (!CPythonBackground::Instance().GetNormal(int(x),int(y),&normal)) + normal = D3DXVECTOR3(0.0f,0.0f,1.0f); + + pGroundItemInstance->ThingInstance.Clear(); + pGroundItemInstance->ThingInstance.ReserveModelThing(1); + pGroundItemInstance->ThingInstance.ReserveModelInstance(1); + pGroundItemInstance->ThingInstance.RegisterModelThing(0, pItemModel); + pGroundItemInstance->ThingInstance.SetModelInstance(0, 0, 0); + if (bDrop) + { + pGroundItemInstance->v3EndPosition = D3DXVECTOR3(x,-y,z); + pGroundItemInstance->ThingInstance.SetPosition(0,0,0); + } + else + pGroundItemInstance->ThingInstance.SetPosition(x, -y, z); + + pGroundItemInstance->ThingInstance.Update(); + pGroundItemInstance->ThingInstance.Transform(); + pGroundItemInstance->ThingInstance.Deform(); + + if (bDrop) + { + D3DXVECTOR3 vMin, vMax; + pGroundItemInstance->ThingInstance.GetBoundBox(&vMin,&vMax); + pGroundItemInstance->v3Center = (vMin + vMax) * 0.5f; + + std::pair f[3] = + { + std::make_pair(vMax.x - vMin.x,0), + std::make_pair(vMax.y - vMin.y,1), + std::make_pair(vMax.z - vMin.z,2) + }; + + std::sort(f,f+3); + + //int no_rotation_axis=-1; + + D3DXVECTOR3 rEnd; + + if (/*f[1].first-f[0].first < (f[2].first-f[0].first)*0.30f*/ bStabGround) + { + // 뾰족 + if (f[2].second == 0) // axis x + { + rEnd.y = 90.0f + frandom(-15.0f, 15.0f); + rEnd.x = frandom(0.0f, 360.0f); + rEnd.z = frandom(-15.0f, 15.0f); + } + else if (f[2].second == 1) // axis y + { + rEnd.y = frandom(0.0f, 360.0f); + rEnd.x = frandom(-15.0f, 15.0f); + rEnd.z = 180.0f + frandom(-15.0f, 15.0f); + } + else // axis z + { + rEnd.y = 180.0f + frandom(-15.0f, 15.0f); + rEnd.x = 0.0f+frandom(-15.0f, 15.0f); + rEnd.z = frandom(0.0f, 360.0f); + } + } + else + { + // 넓적 + // 땅의 노말의 영향을 받을 것 + if (f[0].second == 0) + { + // y,z = by normal + pGroundItemInstance->qEnd = + RotationArc( + D3DXVECTOR3( + ((float)(random()%2))*2-1+frandom(-0.1f,0.1f), + 0+frandom(-0.1f,0.1f), + 0+frandom(-0.1f,0.1f)), + D3DXVECTOR3(0,0,1)/*normal*/); + } + else if (f[0].second == 1) + { + pGroundItemInstance->qEnd = + RotationArc( + D3DXVECTOR3( + 0+frandom(-0.1f,0.1f), + ((float)(random()%2))*2-1+frandom(-0.1f,0.1f), + 0+frandom(-0.1f,0.1f)), + D3DXVECTOR3(0,0,1)/*normal*/); + } + else + { + pGroundItemInstance->qEnd = + RotationArc( + D3DXVECTOR3( + 0+frandom(-0.1f,0.1f), + 0+frandom(-0.1f,0.1f), + ((float)(random()%2))*2-1+frandom(-0.1f,0.1f)), + D3DXVECTOR3(0,0,1)/*normal*/); + } + } + //D3DXQuaternionRotationYawPitchRoll(&pGroundItemInstance->qEnd, rEnd.y, rEnd.x, rEnd.z ); + float rot = frandom(0, 2*3.1415926535f); + D3DXQUATERNION q(0,0,cosf(rot),sinf(rot)); + D3DXQuaternionMultiply(&pGroundItemInstance->qEnd, &pGroundItemInstance->qEnd, &q); + q = RotationArc(D3DXVECTOR3(0,0,1),normal); + D3DXQuaternionMultiply(&pGroundItemInstance->qEnd, &pGroundItemInstance->qEnd, &q); + + pGroundItemInstance->dwStartTime = CTimer::Instance().GetCurrentMillisecond(); + pGroundItemInstance->dwEndTime = pGroundItemInstance->dwStartTime+300; + pGroundItemInstance->v3RotationAxis.x = sinf(rot+0);//frandom(0.4f,0.7f) * (2*(int)(random()%2) - 1); + pGroundItemInstance->v3RotationAxis.y = cosf(rot+0);//frandom(0.4f,0.7f) * (2*(int)(random()%2) - 1); + pGroundItemInstance->v3RotationAxis.z = 0;//frandom(0.4f,0.7f) * (2*(int)(random()%2) - 1); + + /* + switch (no_rotation_axis) + { + case 0: + pGroundItemInstance->rStart.x = 0; + break; + case 1: + pGroundItemInstance->rStart.y = 0; + break; + case 2: + pGroundItemInstance->rStart.z = 0; + break; + }*/ + + D3DXVECTOR3 v3Adjust = -pGroundItemInstance->v3Center; + D3DXMATRIX mat; + D3DXMatrixRotationQuaternion(&mat, &pGroundItemInstance->qEnd); + /*D3DXMatrixRotationYawPitchRoll(&mat, + D3DXToRadian(pGroundItemInstance->rEnd.y), + D3DXToRadian(pGroundItemInstance->rEnd.x), + D3DXToRadian(pGroundItemInstance->rEnd.z));*/ + + D3DXVec3TransformCoord(&v3Adjust,&v3Adjust,&mat); + //Tracef("%f %f %f\n",v3Adjust.x,v3Adjust.y,v3Adjust.z); + //pGroundItemInstance->v3EndPosition += v3Adjust; + //pGroundItemInstance->rEnd.z += pGroundItemInstance->v3Center.z; + } + + pGroundItemInstance->ThingInstance.Show(); + + m_GroundItemInstanceMap.insert(TGroundItemInstanceMap::value_type(dwVirtualID, pGroundItemInstance)); + + CPythonTextTail& rkTextTail=CPythonTextTail::Instance(); + rkTextTail.RegisterItemTextTail( + dwVirtualID, + pItemData->GetName(), + &pGroundItemInstance->ThingInstance); +} + +void CPythonItem::SetOwnership(DWORD dwVID, const char * c_pszName) +{ + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.find(dwVID); + + if (m_GroundItemInstanceMap.end() == itor) + return; + + TGroundItemInstance * pGroundItemInstance = itor->second; + pGroundItemInstance->stOwnership.assign(c_pszName); + + CPythonTextTail& rkTextTail = CPythonTextTail::Instance(); + rkTextTail.SetItemTextTailOwner(dwVID, c_pszName); +} + +bool CPythonItem::GetOwnership(DWORD dwVID, const char ** c_pszName) +{ + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.find(dwVID); + + if (m_GroundItemInstanceMap.end() == itor) + return false; + + TGroundItemInstance * pGroundItemInstance = itor->second; + *c_pszName = pGroundItemInstance->stOwnership.c_str(); + + return true; +} + +void CPythonItem::DeleteAllItems() +{ + CPythonTextTail& rkTextTail=CPythonTextTail::Instance(); + + TGroundItemInstanceMap::iterator i; + for (i= m_GroundItemInstanceMap.begin(); i!=m_GroundItemInstanceMap.end(); ++i) + { + TGroundItemInstance* pGroundItemInst=i->second; + rkTextTail.DeleteItemTextTail(i->first); + pGroundItemInst->Clear(); + m_GroundItemInstancePool.Free(pGroundItemInst); + } + m_GroundItemInstanceMap.clear(); +} + +void CPythonItem::DeleteItem(DWORD dwVirtualID) +{ + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.find(dwVirtualID); + if (m_GroundItemInstanceMap.end() == itor) + return; + + TGroundItemInstance * pGroundItemInstance = itor->second; + pGroundItemInstance->Clear(); + m_GroundItemInstancePool.Free(pGroundItemInstance); + m_GroundItemInstanceMap.erase(itor); + + // Text Tail + CPythonTextTail::Instance().DeleteItemTextTail(dwVirtualID); +} + + +bool CPythonItem::GetCloseMoney(const TPixelPosition & c_rPixelPosition, DWORD * pdwItemID, DWORD dwDistance) +{ + DWORD dwCloseItemID = 0; + DWORD dwCloseItemDistance = 1000 * 1000; + + TGroundItemInstanceMap::iterator i; + for (i = m_GroundItemInstanceMap.begin(); i != m_GroundItemInstanceMap.end(); ++i) + { + TGroundItemInstance * pInstance = i->second; + + if (pInstance->dwVirtualNumber!=VNUM_MONEY) + continue; + + DWORD dwxDistance = DWORD(c_rPixelPosition.x-pInstance->v3EndPosition.x); + DWORD dwyDistance = DWORD(c_rPixelPosition.y-(-pInstance->v3EndPosition.y)); + DWORD dwDistance = DWORD(dwxDistance*dwxDistance + dwyDistance*dwyDistance); + + if (dwxDistance*dwxDistance + dwyDistance*dwyDistance < dwCloseItemDistance) + { + dwCloseItemID = i->first; + dwCloseItemDistance = dwDistance; + } + } + + if (dwCloseItemDistance>float(dwDistance)*float(dwDistance)) + return false; + + *pdwItemID=dwCloseItemID; + + return true; +} + +// bool CPythonItem::GetCloseItem(const TPixelPosition & c_rPixelPosition, DWORD * pdwItemID, DWORD dwDistance) +// { + // DWORD dwCloseItemID = 0; + // DWORD dwCloseItemDistance = 1000 * 1000; + + // TGroundItemInstanceMap::iterator i; + // for (i = m_GroundItemInstanceMap.begin(); i != m_GroundItemInstanceMap.end(); ++i) + // { + // TGroundItemInstance * pInstance = i->second; + + // DWORD dwxDistance = DWORD(c_rPixelPosition.x-pInstance->v3EndPosition.x); + // DWORD dwyDistance = DWORD(c_rPixelPosition.y-(-pInstance->v3EndPosition.y)); + // DWORD dwDistance = DWORD(dwxDistance*dwxDistance + dwyDistance*dwyDistance); + + // if (dwxDistance*dwxDistance + dwyDistance*dwyDistance < dwCloseItemDistance) + // { + // dwCloseItemID = i->first; + // dwCloseItemDistance = dwDistance; + // } + // } + + // if (dwCloseItemDistance>float(dwDistance)*float(dwDistance)) + // return false; + + // *pdwItemID=dwCloseItemID; + + // return true; +// } + +// Fix for picking up items +// https://metin2.dev/board/topic/24691-fix-pickup-distances-bug/ +int DISTANCE_APPROX(int dx, int dy) +{ + int min, max; + + if (dx < 0) + dx = -dx; + + if (dy < 0) + dy = -dy; + + if (dx < dy) + { + min = dx; + max = dy; + } + else + { + min = dy; + max = dx; + } + + // coefficients equivalent to ( 123/128 * max ) and ( 51/128 * min ) + return (((max << 8) + (max << 3) - (max << 4) - (max << 1) + + (min << 7) - (min << 5) + (min << 3) - (min << 1)) >> 8); +} + +bool CPythonItem::GetCloseItem(const TPixelPosition& c_rPixelPosition, DWORD* pdwItemID, DWORD dwDistance) +{ + DWORD dwCloseItemID = 0; + DWORD dwCloseItemDistance = 0; + int aproMin = 0; + + TGroundItemInstanceMap::iterator i; + for (i = m_GroundItemInstanceMap.begin(); i != m_GroundItemInstanceMap.end(); ++i) + { + TGroundItemInstance* pInstance = i->second; + + int iDist = DISTANCE_APPROX((int)c_rPixelPosition.x - (int)pInstance->v3EndPosition.x, (int)c_rPixelPosition.y - (-(int)pInstance->v3EndPosition.y)); + if (aproMin == 0) + aproMin = iDist; + if (aproMin >= iDist) { + aproMin = iDist; + dwCloseItemID = i->first; + dwCloseItemDistance = iDist; + } + } + + if (dwCloseItemDistance > 300) + return false; + + *pdwItemID = dwCloseItemID; + + return true; +} + +BOOL CPythonItem::GetGroundItemPosition(DWORD dwVirtualID, TPixelPosition * pPosition) +{ + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.find(dwVirtualID); + if (m_GroundItemInstanceMap.end() == itor) + return FALSE; + + TGroundItemInstance * pInstance = itor->second; + + const D3DXVECTOR3& rkD3DVct3=pInstance->ThingInstance.GetPosition(); + + pPosition->x=+rkD3DVct3.x; + pPosition->y=-rkD3DVct3.y; + pPosition->z=+rkD3DVct3.z; + + return TRUE; +} + +DWORD CPythonItem::__Pick(const POINT& c_rkPtMouse) +{ + float fu, fv, ft; + + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.begin(); + for (; itor != m_GroundItemInstanceMap.end(); ++itor) + { + TGroundItemInstance * pInstance = itor->second; + + if (pInstance->ThingInstance.Intersect(&fu, &fv, &ft)) + { + return itor->first; + } + } + + CPythonTextTail& rkTextTailMgr=CPythonTextTail::Instance(); + return rkTextTailMgr.Pick(c_rkPtMouse.x, c_rkPtMouse.y); +} + +bool CPythonItem::GetPickedItemID(DWORD* pdwPickedItemID) +{ + if (INVALID_ID==m_dwPickedItemID) + return false; + + *pdwPickedItemID=m_dwPickedItemID; + return true; +} + +DWORD CPythonItem::GetVirtualNumberOfGroundItem(DWORD dwVID) +{ + TGroundItemInstanceMap::iterator itor = m_GroundItemInstanceMap.find(dwVID); + + if (itor == m_GroundItemInstanceMap.end()) + return 0; + else + return itor->second->dwVirtualNumber; +} + +void CPythonItem::BuildNoGradeNameData(int iType) +{ + /* + CMapIterator itor = CItemManager::Instance().GetItemNameMapIterator(); + + m_NoGradeNameItemData.clear(); + m_NoGradeNameItemData.reserve(1024); + + while (++itor) + { + CItemData * pItemData = *itor; + if (iType == pItemData->GetType()) + m_NoGradeNameItemData.push_back(pItemData); + } + */ +} + +DWORD CPythonItem::GetNoGradeNameDataCount() +{ + return m_NoGradeNameItemData.size(); +} + +CItemData * CPythonItem::GetNoGradeNameDataPtr(DWORD dwIndex) +{ + if (dwIndex >= m_NoGradeNameItemData.size()) + return NULL; + + return m_NoGradeNameItemData[dwIndex]; +} + +void CPythonItem::Destroy() +{ + DeleteAllItems(); + m_GroundItemInstancePool.Clear(); +} + +void CPythonItem::Create() +{ + CEffectManager::Instance().RegisterEffect2("d:/ymir work/effect/etc/dropitem/dropitem.mse", &m_dwDropItemEffectID); +} + +CPythonItem::CPythonItem() +{ + m_GroundItemInstancePool.SetName("CDynamicPool"); + m_dwPickedItemID = INVALID_ID; +} + +CPythonItem::~CPythonItem() +{ + assert(m_GroundItemInstanceMap.empty()); +} \ No newline at end of file diff --git a/extension/src/port/UserInterface/PythonItemModule.cpp b/extension/src/port/UserInterface/PythonItemModule.cpp new file mode 100644 index 00000000..aab220f9 --- /dev/null +++ b/extension/src/port/UserInterface/PythonItemModule.cpp @@ -0,0 +1,841 @@ +#include "StdAfx.h" +#include "../common/PortPythonPointer.h" // PORT: preserve Win32 pointer handles on 64-bit hosts +#include "PythonItem.h" + +#include "../GameLib/ItemManager.h" +#include "InstanceBase.h" +#include "AbstractApplication.h" + +extern int TWOHANDED_WEWAPON_ATT_SPEED_DECREASE_VALUE; + +PyObject * itemSetUseSoundFileName(PyObject * poSelf, PyObject * poArgs) +{ + int iUseSound; + if (!PyTuple_GetInteger(poArgs, 0, &iUseSound)) + return Py_BadArgument(); + + char* szFileName; + if (!PyTuple_GetString(poArgs, 1, &szFileName)) + return Py_BadArgument(); + + CPythonItem& rkItem=CPythonItem::Instance(); + rkItem.SetUseSoundFileName(iUseSound, szFileName); + return Py_BuildNone(); +} + +PyObject * itemSetDropSoundFileName(PyObject * poSelf, PyObject * poArgs) +{ + int iDropSound; + if (!PyTuple_GetInteger(poArgs, 0, &iDropSound)) + return Py_BadArgument(); + + char* szFileName; + if (!PyTuple_GetString(poArgs, 1, &szFileName)) + return Py_BadArgument(); + + CPythonItem& rkItem=CPythonItem::Instance(); + rkItem.SetDropSoundFileName(iDropSound, szFileName); + return Py_BuildNone(); +} + +PyObject * itemSelectItem(PyObject * poSelf, PyObject * poArgs) +{ + int iIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iIndex)) + return Py_BadArgument(); + + if (!CItemManager::Instance().SelectItemData(iIndex)) + { + TraceError("Cannot find item by %d", iIndex); + CItemManager::Instance().SelectItemData(60001); + } + + return Py_BuildNone(); +} + +PyObject * itemGetItemName(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("s", pItemData->GetName()); +} + +PyObject * itemGetItemDescription(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("s", pItemData->GetDescription()); +} + +PyObject * itemGetItemSummary(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("s", pItemData->GetSummary()); +} + +PyObject * itemGetIconImage(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + +// if (CItemData::ITEM_TYPE_SKILLBOOK == pItemData->GetType()) +// { +// char szItemName[64+1]; +// _snprintf(szItemName, "d:/ymir work/ui/items/etc/book_%02d.sub", ); +// CGraphicImage * pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(szItemName); +// } + + return Py_BuildPointer(pItemData->GetIconImage()); // PORT: was Py_BuildValue("i", ...) (ILP32 handle) +} + +PyObject * itemGetIconImageFileName(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + CGraphicSubImage * pImage = pItemData->GetIconImage(); + if (!pImage) + return Py_BuildValue("s", "Noname"); + + return Py_BuildValue("s", pImage->GetFileName()); +} + +PyObject * itemGetItemSize(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("(ii)", 1, pItemData->GetSize()); +} + +PyObject * itemGetItemType(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->GetType()); +} + +PyObject * itemGetItemSubType(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->GetSubType()); +} + +PyObject * itemGetIBuyItemPrice(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->GetIBuyItemPrice()); +} + +PyObject * itemGetISellItemPrice(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->GetISellItemPrice()); +} + + +PyObject * itemIsAntiFlag(PyObject * poSelf, PyObject * poArgs) +{ + int iFlag; + if (!PyTuple_GetInteger(poArgs, 0, &iFlag)) + return Py_BadArgument(); + + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->IsAntiFlag(iFlag)); +} + +PyObject * itemIsFlag(PyObject * poSelf, PyObject * poArgs) +{ + int iFlag; + if (!PyTuple_GetInteger(poArgs, 0, &iFlag)) + return Py_BadArgument(); + + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->IsFlag(iFlag)); +} + +PyObject * itemIsWearableFlag(PyObject * poSelf, PyObject * poArgs) +{ + int iFlag; + if (!PyTuple_GetInteger(poArgs, 0, &iFlag)) + return Py_BadArgument(); + + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->IsWearableFlag(iFlag)); +} + +PyObject * itemIs1GoldItem(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("no selected item data"); + + return Py_BuildValue("i", pItemData->IsFlag(CItemData::ITEM_FLAG_COUNT_PER_1GOLD)); +} + +PyObject * itemGetLimit(PyObject * poSelf, PyObject * poArgs) +{ + int iValueIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iValueIndex)) + return Py_BadArgument(); + + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Not yet select item data"); + + CItemData::TItemLimit ItemLimit; + if (!pItemData->GetLimit(iValueIndex, &ItemLimit)) + return Py_BuildException(); + + return Py_BuildValue("ii", ItemLimit.bType, ItemLimit.lValue); +} + +PyObject * itemGetAffect(PyObject * poSelf, PyObject * poArgs) +{ + int iValueIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iValueIndex)) + return Py_BadArgument(); + + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Not yet select item data"); + + CItemData::TItemApply ItemApply; + if (!pItemData->GetApply(iValueIndex, &ItemApply)) + return Py_BuildException(); + + if ((CItemData::APPLY_ATT_SPEED == ItemApply.bType) && (CItemData::ITEM_TYPE_WEAPON == pItemData->GetType()) && (CItemData::WEAPON_TWO_HANDED == pItemData->GetSubType())) + { + ItemApply.lValue -= TWOHANDED_WEWAPON_ATT_SPEED_DECREASE_VALUE; + } + + return Py_BuildValue("ii", ItemApply.bType, ItemApply.lValue); +} + +PyObject * itemGetValue(PyObject * poSelf, PyObject * poArgs) +{ + int iValueIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iValueIndex)) + return Py_BadArgument(); + + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Not yet select item data"); + + return Py_BuildValue("i", pItemData->GetValue(iValueIndex)); +} + +PyObject * itemGetSocket(PyObject * poSelf, PyObject * poArgs) +{ + int iValueIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iValueIndex)) + return Py_BadArgument(); + + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Not yet select item data"); + + return Py_BuildValue("i", pItemData->GetSocket(iValueIndex)); +} + +PyObject * itemGetIconInstance(PyObject * poSelf, PyObject * poArgs) +{ + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Not yet select item data"); + + CGraphicSubImage * pImage = pItemData->GetIconImage(); + if (!pImage) + return Py_BuildException("Cannot get icon image by %d", pItemData->GetIndex()); + + CGraphicImageInstance * pImageInstance = CGraphicImageInstance::New(); + pImageInstance->SetImagePointer(pImage); + + return Py_BuildValue("i", pImageInstance); +} + +PyObject * itemDeleteIconInstance(PyObject * poSelf, PyObject * poArgs) +{ + int iHandle; + if (!PyTuple_GetInteger(poArgs, 0, &iHandle)) + return Py_BadArgument(); + + CGraphicImageInstance::Delete((CGraphicImageInstance *) iHandle); + + return Py_BuildNone(); +} + +PyObject * itemIsEquipmentVID(PyObject * poSelf, PyObject * poArgs) +{ + int iItemVID; + if (!PyTuple_GetInteger(poArgs, 0, &iItemVID)) + return Py_BadArgument(); + + CItemManager::Instance().SelectItemData(iItemVID); + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Not yet select item data"); + + return Py_BuildValue("i", pItemData->IsEquipment()); +} + +// 2005.05.20.myevan.통합 USE_TYPE 체크 +PyObject* itemGetUseType(PyObject * poSelf, PyObject * poArgs) +{ + int iItemVID; + if (!PyTuple_GetInteger(poArgs, 0, &iItemVID)) + return Py_BadArgument(); + + CItemManager::Instance().SelectItemData(iItemVID); + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Can't find select item data"); + + return Py_BuildValue("s", pItemData->GetUseTypeString()); +} + +PyObject * itemIsRefineScroll(PyObject * poSelf, PyObject * poArgs) +{ + int iItemIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iItemIndex)) + return Py_BadArgument(); + + CItemManager::Instance().SelectItemData(iItemIndex); + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Can't find select item data"); + + if (pItemData->GetType() != CItemData::ITEM_TYPE_USE) + return Py_BuildValue("i", FALSE); + + switch (pItemData->GetSubType()) + { + case CItemData::USE_TUNING: + return Py_BuildValue("i", TRUE); + break; + } + + return Py_BuildValue("i", FALSE); +} + +PyObject * itemIsDetachScroll(PyObject * poSelf, PyObject * poArgs) +{ + int iItemIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iItemIndex)) + return Py_BadArgument(); + + CItemManager::Instance().SelectItemData(iItemIndex); + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Can't find select item data"); + + int iType = pItemData->GetType(); + int iSubType = pItemData->GetSubType(); + if (iType == CItemData::ITEM_TYPE_USE) + if (iSubType == CItemData::USE_DETACHMENT) + { + return Py_BuildValue("i", TRUE); + } + + return Py_BuildValue("i", FALSE); +} + +PyObject * itemCanAddToQuickSlotItem(PyObject * poSelf, PyObject * poArgs) +{ + int iItemIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iItemIndex)) + return Py_BadArgument(); + + CItemManager::Instance().SelectItemData(iItemIndex); + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Can't find select item data"); + + if (CItemData::ITEM_TYPE_USE == pItemData->GetType() || CItemData::ITEM_TYPE_QUEST == pItemData->GetType()) + { + return Py_BuildValue("i", TRUE); + } + + return Py_BuildValue("i", FALSE); +} + +PyObject * itemIsKey(PyObject * poSelf, PyObject * poArgs) +{ + int iItemIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iItemIndex)) + return Py_BadArgument(); + + CItemManager::Instance().SelectItemData(iItemIndex); + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Can't find select item data"); + + if (CItemData::ITEM_TYPE_TREASURE_KEY == pItemData->GetType()) + { + return Py_BuildValue("i", TRUE); + } + + return Py_BuildValue("i", FALSE); +} + +PyObject * itemIsMetin(PyObject * poSelf, PyObject * poArgs) +{ + int iItemIndex; + if (!PyTuple_GetInteger(poArgs, 0, &iItemIndex)) + return Py_BadArgument(); + + CItemManager::Instance().SelectItemData(iItemIndex); + CItemData * pItemData = CItemManager::Instance().GetSelectedItemDataPointer(); + if (!pItemData) + return Py_BuildException("Can't find select item data"); + + if (CItemData::ITEM_TYPE_METIN == pItemData->GetType()) + { + return Py_BuildValue("i", TRUE); + } + + return Py_BuildValue("i", FALSE); +} + +PyObject * itemRender(PyObject * poSelf, PyObject * poArgs) +{ + CPythonItem::Instance().Render(); + return Py_BuildNone(); +} + +PyObject * itemUpdate(PyObject * poSelf, PyObject * poArgs) +{ + IAbstractApplication& rkApp=IAbstractApplication::GetSingleton(); + + POINT ptMouse; + rkApp.GetMousePosition(&ptMouse); + + CPythonItem::Instance().Update(ptMouse); + return Py_BuildNone(); +} + +PyObject * itemCreateItem(PyObject * poSelf, PyObject * poArgs) +{ + int iVirtualID; + if (!PyTuple_GetInteger(poArgs, 0, &iVirtualID)) + return Py_BadArgument(); + int iVirtualNumber; + if (!PyTuple_GetInteger(poArgs, 1, &iVirtualNumber)) + return Py_BadArgument(); + + float x; + if (!PyTuple_GetFloat(poArgs, 2, &x)) + return Py_BadArgument(); + float y; + if (!PyTuple_GetFloat(poArgs, 3, &y)) + return Py_BadArgument(); + float z; + if (!PyTuple_GetFloat(poArgs, 4, &z)) + return Py_BadArgument(); + + bool bDrop = true; + PyTuple_GetBoolean(poArgs, 5, &bDrop); + + CPythonItem::Instance().CreateItem(iVirtualID, iVirtualNumber, x, y, z, bDrop); + + return Py_BuildNone(); +} + +PyObject * itemDeleteItem(PyObject * poSelf, PyObject * poArgs) +{ + int iVirtualID; + if (!PyTuple_GetInteger(poArgs, 0, &iVirtualID)) + return Py_BadArgument(); + + CPythonItem::Instance().DeleteItem(iVirtualID); + return Py_BuildNone(); +} + +PyObject * itemPick(PyObject * poSelf, PyObject * poArgs) +{ + DWORD dwItemID; + if (CPythonItem::Instance().GetPickedItemID(&dwItemID)) + return Py_BuildValue("i", dwItemID); + else + return Py_BuildValue("i", -1); +} + +PyObject* itemLoadItemTable(PyObject* poSelf, PyObject* poArgs) +{ + char * szFileName; + if (!PyTuple_GetString(poArgs, 0, &szFileName)) + return Py_BadArgument(); + + CItemManager::Instance().LoadItemTable(szFileName); + return Py_BuildNone(); +} + +void initItem() +{ + static PyMethodDef s_methods[] = + { + { "SetUseSoundFileName", itemSetUseSoundFileName, METH_VARARGS }, + { "SetDropSoundFileName", itemSetDropSoundFileName, METH_VARARGS }, + { "SelectItem", itemSelectItem, METH_VARARGS }, + + { "GetItemName", itemGetItemName, METH_VARARGS }, + { "GetItemDescription", itemGetItemDescription, METH_VARARGS }, + { "GetItemSummary", itemGetItemSummary, METH_VARARGS }, + { "GetIconImage", itemGetIconImage, METH_VARARGS }, + { "GetIconImageFileName", itemGetIconImageFileName, METH_VARARGS }, + { "GetItemSize", itemGetItemSize, METH_VARARGS }, + { "GetItemType", itemGetItemType, METH_VARARGS }, + { "GetItemSubType", itemGetItemSubType, METH_VARARGS }, + { "GetIBuyItemPrice", itemGetIBuyItemPrice, METH_VARARGS }, + { "GetISellItemPrice", itemGetISellItemPrice, METH_VARARGS }, + { "IsAntiFlag", itemIsAntiFlag, METH_VARARGS }, + { "IsFlag", itemIsFlag, METH_VARARGS }, + { "IsWearableFlag", itemIsWearableFlag, METH_VARARGS }, + { "Is1GoldItem", itemIs1GoldItem, METH_VARARGS }, + { "GetLimit", itemGetLimit, METH_VARARGS }, + { "GetAffect", itemGetAffect, METH_VARARGS }, + { "GetValue", itemGetValue, METH_VARARGS }, + { "GetSocket", itemGetSocket, METH_VARARGS }, + { "GetIconInstance", itemGetIconInstance, METH_VARARGS }, + { "GetUseType", itemGetUseType, METH_VARARGS }, + { "DeleteIconInstance", itemDeleteIconInstance, METH_VARARGS }, + { "IsEquipmentVID", itemIsEquipmentVID, METH_VARARGS }, + { "IsRefineScroll", itemIsRefineScroll, METH_VARARGS }, + { "IsDetachScroll", itemIsDetachScroll, METH_VARARGS }, + { "IsKey", itemIsKey, METH_VARARGS }, + { "IsMetin", itemIsMetin, METH_VARARGS }, + { "CanAddToQuickSlotItem", itemCanAddToQuickSlotItem, METH_VARARGS }, + + { "Update", itemUpdate, METH_VARARGS }, + { "Render", itemRender, METH_VARARGS }, + { "CreateItem", itemCreateItem, METH_VARARGS }, + { "DeleteItem", itemDeleteItem, METH_VARARGS }, + { "Pick", itemPick, METH_VARARGS }, + + { "LoadItemTable", itemLoadItemTable, METH_VARARGS }, + + { NULL, NULL, NULL }, + }; + + PyObject * poModule = Py_InitModule("item", s_methods); + + PyModule_AddIntConstant(poModule, "USESOUND_ACCESSORY", CPythonItem::USESOUND_ACCESSORY); + PyModule_AddIntConstant(poModule, "USESOUND_ARMOR", CPythonItem::USESOUND_ARMOR); + PyModule_AddIntConstant(poModule, "USESOUND_BOW", CPythonItem::USESOUND_BOW); + PyModule_AddIntConstant(poModule, "USESOUND_DEFAULT", CPythonItem::USESOUND_DEFAULT); + PyModule_AddIntConstant(poModule, "USESOUND_WEAPON", CPythonItem::USESOUND_WEAPON); + PyModule_AddIntConstant(poModule, "USESOUND_POTION", CPythonItem::USESOUND_POTION); + PyModule_AddIntConstant(poModule, "USESOUND_PORTAL", CPythonItem::USESOUND_PORTAL); + + PyModule_AddIntConstant(poModule, "DROPSOUND_ACCESSORY", CPythonItem::DROPSOUND_ACCESSORY); + PyModule_AddIntConstant(poModule, "DROPSOUND_ARMOR", CPythonItem::DROPSOUND_ARMOR); + PyModule_AddIntConstant(poModule, "DROPSOUND_BOW", CPythonItem::DROPSOUND_BOW); + PyModule_AddIntConstant(poModule, "DROPSOUND_DEFAULT", CPythonItem::DROPSOUND_DEFAULT); + PyModule_AddIntConstant(poModule, "DROPSOUND_WEAPON", CPythonItem::DROPSOUND_WEAPON); + + PyModule_AddIntConstant(poModule, "EQUIPMENT_COUNT", c_Equipment_Count); + PyModule_AddIntConstant(poModule, "EQUIPMENT_HEAD", c_Equipment_Head); + PyModule_AddIntConstant(poModule, "EQUIPMENT_BODY", c_Equipment_Body); + PyModule_AddIntConstant(poModule, "EQUIPMENT_WEAPON", c_Equipment_Weapon); + PyModule_AddIntConstant(poModule, "EQUIPMENT_WRIST", c_Equipment_Wrist); + PyModule_AddIntConstant(poModule, "EQUIPMENT_SHOES", c_Equipment_Shoes); + PyModule_AddIntConstant(poModule, "EQUIPMENT_NECK", c_Equipment_Neck); + PyModule_AddIntConstant(poModule, "EQUIPMENT_EAR", c_Equipment_Ear); + PyModule_AddIntConstant(poModule, "EQUIPMENT_UNIQUE1", c_Equipment_Unique1); + PyModule_AddIntConstant(poModule, "EQUIPMENT_UNIQUE2", c_Equipment_Unique2); + PyModule_AddIntConstant(poModule, "EQUIPMENT_ARROW", c_Equipment_Arrow); + +#ifdef ENABLE_NEW_EQUIPMENT_SYSTEM + PyModule_AddIntConstant(poModule, "EQUIPMENT_RING1", c_Equipment_Ring1); + PyModule_AddIntConstant(poModule, "EQUIPMENT_RING2", c_Equipment_Ring2); + PyModule_AddIntConstant(poModule, "EQUIPMENT_BELT", c_Equipment_Belt); +#endif + + PyModule_AddIntConstant(poModule, "ITEM_TYPE_NONE", CItemData::ITEM_TYPE_NONE); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_WEAPON", CItemData::ITEM_TYPE_WEAPON); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_ARMOR", CItemData::ITEM_TYPE_ARMOR); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_USE", CItemData::ITEM_TYPE_USE); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_AUTOUSE", CItemData::ITEM_TYPE_AUTOUSE); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_MATERIAL", CItemData::ITEM_TYPE_MATERIAL); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_SPECIAL", CItemData::ITEM_TYPE_SPECIAL); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_TOOL", CItemData::ITEM_TYPE_TOOL); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_LOTTERY", CItemData::ITEM_TYPE_LOTTERY); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_ELK", CItemData::ITEM_TYPE_ELK); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_METIN", CItemData::ITEM_TYPE_METIN); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_CONTAINER", CItemData::ITEM_TYPE_CONTAINER); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_FISH", CItemData::ITEM_TYPE_FISH); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_ROD", CItemData::ITEM_TYPE_ROD); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_RESOURCE", CItemData::ITEM_TYPE_RESOURCE); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_CAMPFIRE", CItemData::ITEM_TYPE_CAMPFIRE); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_UNIQUE", CItemData::ITEM_TYPE_UNIQUE); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_SKILLBOOK", CItemData::ITEM_TYPE_SKILLBOOK); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_QUEST", CItemData::ITEM_TYPE_QUEST); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_POLYMORPH", CItemData::ITEM_TYPE_POLYMORPH); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_TREASURE_BOX", CItemData::ITEM_TYPE_TREASURE_BOX); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_TREASURE_KEY", CItemData::ITEM_TYPE_TREASURE_KEY); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_PICK", CItemData::ITEM_TYPE_PICK); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_BLEND", CItemData::ITEM_TYPE_BLEND); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_DS", CItemData::ITEM_TYPE_DS); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_SPECIAL_DS", CItemData::ITEM_TYPE_SPECIAL_DS); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_RING", CItemData::ITEM_TYPE_RING); + PyModule_AddIntConstant(poModule, "ITEM_TYPE_BELT", CItemData::ITEM_TYPE_BELT); + + +#ifdef ENABLE_COSTUME_SYSTEM + PyModule_AddIntConstant(poModule, "ITEM_TYPE_COSTUME", CItemData::ITEM_TYPE_COSTUME); + + // Item Sub Type + PyModule_AddIntConstant(poModule, "COSTUME_TYPE_BODY", CItemData::COSTUME_BODY); + PyModule_AddIntConstant(poModule, "COSTUME_TYPE_HAIR", CItemData::COSTUME_HAIR); + + // 인벤토리 및 장비창에서의 슬롯 번호 + PyModule_AddIntConstant(poModule, "COSTUME_SLOT_START", c_Costume_Slot_Start); + PyModule_AddIntConstant(poModule, "COSTUME_SLOT_COUNT", c_Costume_Slot_Count); + PyModule_AddIntConstant(poModule, "COSTUME_SLOT_BODY", c_Costume_Slot_Body); + PyModule_AddIntConstant(poModule, "COSTUME_SLOT_HAIR", c_Costume_Slot_Hair); + PyModule_AddIntConstant(poModule, "COSTUME_SLOT_END", c_Costume_Slot_End); +#endif + +#ifdef ENABLE_NEW_EQUIPMENT_SYSTEM + PyModule_AddIntConstant(poModule, "BELT_INVENTORY_SLOT_START", c_Belt_Inventory_Slot_Start); + PyModule_AddIntConstant(poModule, "BELT_INVENTORY_SLOT_COUNT", c_Belt_Inventory_Slot_Count); + PyModule_AddIntConstant(poModule, "BELT_INVENTORY_SLOT_END", c_Belt_Inventory_Slot_End); + +#endif + + PyModule_AddIntConstant(poModule, "WEAPON_SWORD", CItemData::WEAPON_SWORD); + PyModule_AddIntConstant(poModule, "WEAPON_DAGGER", CItemData::WEAPON_DAGGER); + PyModule_AddIntConstant(poModule, "WEAPON_BOW", CItemData::WEAPON_BOW); + PyModule_AddIntConstant(poModule, "WEAPON_TWO_HANDED", CItemData::WEAPON_TWO_HANDED); + PyModule_AddIntConstant(poModule, "WEAPON_BELL", CItemData::WEAPON_BELL); + PyModule_AddIntConstant(poModule, "WEAPON_FAN", CItemData::WEAPON_FAN); + PyModule_AddIntConstant(poModule, "WEAPON_ARROW", CItemData::WEAPON_ARROW); + PyModule_AddIntConstant(poModule, "WEAPON_NUM_TYPES", CItemData::WEAPON_NUM_TYPES); + + PyModule_AddIntConstant(poModule, "USE_POTION", CItemData::USE_POTION); + PyModule_AddIntConstant(poModule, "USE_TALISMAN", CItemData::USE_TALISMAN); + PyModule_AddIntConstant(poModule, "USE_TUNING", CItemData::USE_TUNING); + PyModule_AddIntConstant(poModule, "USE_MOVE", CItemData::USE_MOVE); + PyModule_AddIntConstant(poModule, "USE_TREASURE_BOX", CItemData::USE_TREASURE_BOX); + PyModule_AddIntConstant(poModule, "USE_MONEYBAG", CItemData::USE_MONEYBAG); + PyModule_AddIntConstant(poModule, "USE_BAIT", CItemData::USE_BAIT); + PyModule_AddIntConstant(poModule, "USE_ABILITY_UP", CItemData::USE_ABILITY_UP); + PyModule_AddIntConstant(poModule, "USE_AFFECT", CItemData::USE_AFFECT); + PyModule_AddIntConstant(poModule, "USE_CREATE_STONE", CItemData::USE_CREATE_STONE); + PyModule_AddIntConstant(poModule, "USE_SPECIAL", CItemData::USE_SPECIAL); + PyModule_AddIntConstant(poModule, "USE_POTION_NODELAY", CItemData::USE_POTION_NODELAY); + PyModule_AddIntConstant(poModule, "USE_CLEAR", CItemData::USE_CLEAR); + PyModule_AddIntConstant(poModule, "USE_INVISIBILITY", CItemData::USE_INVISIBILITY); + PyModule_AddIntConstant(poModule, "USE_DETACHMENT", CItemData::USE_DETACHMENT); + PyModule_AddIntConstant(poModule, "USE_TIME_CHARGE_PER", CItemData::USE_TIME_CHARGE_PER); + PyModule_AddIntConstant(poModule, "USE_TIME_CHARGE_FIX", CItemData::USE_TIME_CHARGE_FIX); + + PyModule_AddIntConstant(poModule, "MATERIAL_DS_REFINE_NORMAL", CItemData::MATERIAL_DS_REFINE_NORMAL); + PyModule_AddIntConstant(poModule, "MATERIAL_DS_REFINE_BLESSED", CItemData::MATERIAL_DS_REFINE_BLESSED); + PyModule_AddIntConstant(poModule, "MATERIAL_DS_REFINE_HOLLY", CItemData::MATERIAL_DS_REFINE_HOLLY); + + PyModule_AddIntConstant(poModule, "METIN_NORMAL", CItemData::METIN_NORMAL); + PyModule_AddIntConstant(poModule, "METIN_GOLD", CItemData::METIN_GOLD); + + PyModule_AddIntConstant(poModule, "LIMIT_NONE", CItemData::LIMIT_NONE); + PyModule_AddIntConstant(poModule, "LIMIT_LEVEL", CItemData::LIMIT_LEVEL); + PyModule_AddIntConstant(poModule, "LIMIT_STR", CItemData::LIMIT_STR); + PyModule_AddIntConstant(poModule, "LIMIT_DEX", CItemData::LIMIT_DEX); + PyModule_AddIntConstant(poModule, "LIMIT_INT", CItemData::LIMIT_INT); + PyModule_AddIntConstant(poModule, "LIMIT_CON", CItemData::LIMIT_CON); + PyModule_AddIntConstant(poModule, "LIMIT_PCBANG", CItemData::LIMIT_PCBANG); + PyModule_AddIntConstant(poModule, "LIMIT_REAL_TIME", CItemData::LIMIT_REAL_TIME); + PyModule_AddIntConstant(poModule, "LIMIT_REAL_TIME_START_FIRST_USE", CItemData::LIMIT_REAL_TIME_START_FIRST_USE); + PyModule_AddIntConstant(poModule, "LIMIT_TIMER_BASED_ON_WEAR", CItemData::LIMIT_TIMER_BASED_ON_WEAR); + PyModule_AddIntConstant(poModule, "LIMIT_TYPE_MAX_NUM", CItemData::LIMIT_MAX_NUM); + PyModule_AddIntConstant(poModule, "LIMIT_MAX_NUM", CItemData::ITEM_LIMIT_MAX_NUM); + + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_FEMALE", CItemData::ITEM_ANTIFLAG_FEMALE); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_MALE", CItemData::ITEM_ANTIFLAG_MALE); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_WARRIOR", CItemData::ITEM_ANTIFLAG_WARRIOR); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_ASSASSIN", CItemData::ITEM_ANTIFLAG_ASSASSIN); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SURA", CItemData::ITEM_ANTIFLAG_SURA); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SHAMAN", CItemData::ITEM_ANTIFLAG_SHAMAN); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_GET", CItemData::ITEM_ANTIFLAG_GET); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_DROP", CItemData::ITEM_ANTIFLAG_DROP); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SELL", CItemData::ITEM_ANTIFLAG_SELL); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_EMPIRE_A", CItemData::ITEM_ANTIFLAG_EMPIRE_A); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_EMPIRE_B", CItemData::ITEM_ANTIFLAG_EMPIRE_B); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_EMPIRE_R", CItemData::ITEM_ANTIFLAG_EMPIRE_R); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_SAVE", CItemData::ITEM_ANTIFLAG_SAVE); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_GIVE", CItemData::ITEM_ANTIFLAG_GIVE); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_PKDROP", CItemData::ITEM_ANTIFLAG_PKDROP); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_STACK", CItemData::ITEM_ANTIFLAG_STACK); + PyModule_AddIntConstant(poModule, "ITEM_ANTIFLAG_MYSHOP", CItemData::ITEM_ANTIFLAG_MYSHOP); + + PyModule_AddIntConstant(poModule, "ITEM_FLAG_RARE", CItemData::ITEM_FLAG_RARE); + PyModule_AddIntConstant(poModule, "ITEM_FLAG_UNIQUE", CItemData::ITEM_FLAG_UNIQUE); + PyModule_AddIntConstant(poModule, "ITEM_FLAG_CONFIRM_WHEN_USE", CItemData::ITEM_FLAG_CONFIRM_WHEN_USE); + + PyModule_AddIntConstant(poModule, "ANTIFLAG_FEMALE", CItemData::ITEM_ANTIFLAG_FEMALE); + PyModule_AddIntConstant(poModule, "ANTIFLAG_MALE", CItemData::ITEM_ANTIFLAG_MALE); + PyModule_AddIntConstant(poModule, "ANTIFLAG_WARRIOR", CItemData::ITEM_ANTIFLAG_WARRIOR); + PyModule_AddIntConstant(poModule, "ANTIFLAG_ASSASSIN", CItemData::ITEM_ANTIFLAG_ASSASSIN); + PyModule_AddIntConstant(poModule, "ANTIFLAG_SURA", CItemData::ITEM_ANTIFLAG_SURA); + PyModule_AddIntConstant(poModule, "ANTIFLAG_SHAMAN", CItemData::ITEM_ANTIFLAG_SHAMAN); + PyModule_AddIntConstant(poModule, "ANTIFLAG_GET", CItemData::ITEM_ANTIFLAG_GET); + PyModule_AddIntConstant(poModule, "ANTIFLAG_DROP", CItemData::ITEM_ANTIFLAG_DROP); + PyModule_AddIntConstant(poModule, "ANTIFLAG_SELL", CItemData::ITEM_ANTIFLAG_SELL); + PyModule_AddIntConstant(poModule, "ANTIFLAG_EMPIRE_A", CItemData::ITEM_ANTIFLAG_EMPIRE_A); + PyModule_AddIntConstant(poModule, "ANTIFLAG_EMPIRE_B", CItemData::ITEM_ANTIFLAG_EMPIRE_B); + PyModule_AddIntConstant(poModule, "ANTIFLAG_EMPIRE_R", CItemData::ITEM_ANTIFLAG_EMPIRE_R); + PyModule_AddIntConstant(poModule, "ANTIFLAG_SAVE", CItemData::ITEM_ANTIFLAG_SAVE); + PyModule_AddIntConstant(poModule, "ANTIFLAG_GIVE", CItemData::ITEM_ANTIFLAG_GIVE); + PyModule_AddIntConstant(poModule, "ANTIFLAG_PKDROP", CItemData::ITEM_ANTIFLAG_PKDROP); + PyModule_AddIntConstant(poModule, "ANTIFLAG_STACK", CItemData::ITEM_ANTIFLAG_STACK); + PyModule_AddIntConstant(poModule, "ANTIFLAG_MYSHOP", CItemData::ITEM_ANTIFLAG_MYSHOP); + + PyModule_AddIntConstant(poModule, "WEARABLE_BODY", CItemData::WEARABLE_BODY); + PyModule_AddIntConstant(poModule, "WEARABLE_HEAD", CItemData::WEARABLE_HEAD); + PyModule_AddIntConstant(poModule, "WEARABLE_FOOTS", CItemData::WEARABLE_FOOTS); + PyModule_AddIntConstant(poModule, "WEARABLE_WRIST", CItemData::WEARABLE_WRIST); + PyModule_AddIntConstant(poModule, "WEARABLE_WEAPON", CItemData::WEARABLE_WEAPON); + PyModule_AddIntConstant(poModule, "WEARABLE_NECK", CItemData::WEARABLE_NECK); + PyModule_AddIntConstant(poModule, "WEARABLE_EAR", CItemData::WEARABLE_EAR); + PyModule_AddIntConstant(poModule, "WEARABLE_UNIQUE", CItemData::WEARABLE_UNIQUE); + PyModule_AddIntConstant(poModule, "WEARABLE_SHIELD", CItemData::WEARABLE_SHIELD); + PyModule_AddIntConstant(poModule, "WEARABLE_ARROW", CItemData::WEARABLE_ARROW); + + PyModule_AddIntConstant(poModule, "ARMOR_BODY", CItemData::ARMOR_BODY); + PyModule_AddIntConstant(poModule, "ARMOR_HEAD", CItemData::ARMOR_HEAD); + PyModule_AddIntConstant(poModule, "ARMOR_SHIELD", CItemData::ARMOR_SHIELD); + PyModule_AddIntConstant(poModule, "ARMOR_WRIST", CItemData::ARMOR_WRIST); + PyModule_AddIntConstant(poModule, "ARMOR_FOOTS", CItemData::ARMOR_FOOTS); + PyModule_AddIntConstant(poModule, "ARMOR_NECK", CItemData::ARMOR_NECK); + PyModule_AddIntConstant(poModule, "ARMOR_EAR", CItemData::ARMOR_EAR); + + PyModule_AddIntConstant(poModule, "ITEM_APPLY_MAX_NUM", CItemData::ITEM_APPLY_MAX_NUM); + PyModule_AddIntConstant(poModule, "ITEM_SOCKET_MAX_NUM", CItemData::ITEM_SOCKET_MAX_NUM); + + PyModule_AddIntConstant(poModule, "APPLY_NONE", CItemData::APPLY_NONE); + PyModule_AddIntConstant(poModule, "APPLY_STR", CItemData::APPLY_STR); + PyModule_AddIntConstant(poModule, "APPLY_DEX", CItemData::APPLY_DEX); + PyModule_AddIntConstant(poModule, "APPLY_CON", CItemData::APPLY_CON); + PyModule_AddIntConstant(poModule, "APPLY_INT", CItemData::APPLY_INT); + PyModule_AddIntConstant(poModule, "APPLY_MAX_HP", CItemData::APPLY_MAX_HP); + PyModule_AddIntConstant(poModule, "APPLY_MAX_SP", CItemData::APPLY_MAX_SP); + PyModule_AddIntConstant(poModule, "APPLY_HP_REGEN", CItemData::APPLY_HP_REGEN); + PyModule_AddIntConstant(poModule, "APPLY_SP_REGEN", CItemData::APPLY_SP_REGEN); + PyModule_AddIntConstant(poModule, "APPLY_DEF_GRADE_BONUS", CItemData::APPLY_DEF_GRADE_BONUS); + PyModule_AddIntConstant(poModule, "APPLY_ATT_GRADE_BONUS", CItemData::APPLY_ATT_GRADE_BONUS); + PyModule_AddIntConstant(poModule, "APPLY_ATT_SPEED", CItemData::APPLY_ATT_SPEED); + PyModule_AddIntConstant(poModule, "APPLY_MOV_SPEED", CItemData::APPLY_MOV_SPEED); + PyModule_AddIntConstant(poModule, "APPLY_CAST_SPEED", CItemData::APPLY_CAST_SPEED); + PyModule_AddIntConstant(poModule, "APPLY_MAGIC_ATT_GRADE", CItemData::APPLY_MAGIC_ATT_GRADE); + PyModule_AddIntConstant(poModule, "APPLY_MAGIC_DEF_GRADE", CItemData::APPLY_MAGIC_DEF_GRADE); + PyModule_AddIntConstant(poModule, "APPLY_SKILL", CItemData::APPLY_SKILL); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_ANIMAL", CItemData::APPLY_ATTBONUS_ANIMAL); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_UNDEAD", CItemData::APPLY_ATTBONUS_UNDEAD); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_DEVIL", CItemData::APPLY_ATTBONUS_DEVIL); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_HUMAN", CItemData::APPLY_ATTBONUS_HUMAN); + PyModule_AddIntConstant(poModule, "APPLY_BOW_DISTANCE", CItemData::APPLY_BOW_DISTANCE); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_BOW", CItemData::APPLY_RESIST_BOW); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_FIRE", CItemData::APPLY_RESIST_FIRE); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_ELEC", CItemData::APPLY_RESIST_ELEC); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_MAGIC", CItemData::APPLY_RESIST_MAGIC); + PyModule_AddIntConstant(poModule, "APPLY_POISON_PCT", CItemData::APPLY_POISON_PCT); + PyModule_AddIntConstant(poModule, "APPLY_SLOW_PCT", CItemData::APPLY_SLOW_PCT); + PyModule_AddIntConstant(poModule, "APPLY_STUN_PCT", CItemData::APPLY_STUN_PCT); + PyModule_AddIntConstant(poModule, "APPLY_CRITICAL_PCT", CItemData::APPLY_CRITICAL_PCT); // n% 확률로 두배 타격 + PyModule_AddIntConstant(poModule, "APPLY_PENETRATE_PCT", CItemData::APPLY_PENETRATE_PCT); // n% 확률로 적의 방어력 무시 + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_ORC", CItemData::APPLY_ATTBONUS_ORC); // 웅귀에게 n% 추가 데미지 + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_MILGYO", CItemData::APPLY_ATTBONUS_MILGYO); // 밀교에게 n% 추가 데미지 + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_UNDEAD", CItemData::APPLY_ATTBONUS_UNDEAD); // 시체에게 n% 추가 데미지 + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_DEVIL", CItemData::APPLY_ATTBONUS_DEVIL); // 악마에게 n% 추가 데미지 + PyModule_AddIntConstant(poModule, "APPLY_STEAL_HP", CItemData::APPLY_STEAL_HP); // n% 확률로 타격의 10% 를 생명력으로 흡수 + PyModule_AddIntConstant(poModule, "APPLY_STEAL_SP", CItemData::APPLY_STEAL_SP); // n% 확률로 타격의 10% 를 정신력으로 흡수 + PyModule_AddIntConstant(poModule, "APPLY_MANA_BURN_PCT", CItemData::APPLY_MANA_BURN_PCT); // n% 확률로 상대의 마나를 깎는다 + PyModule_AddIntConstant(poModule, "APPLY_DAMAGE_SP_RECOVER", CItemData::APPLY_DAMAGE_SP_RECOVER); // n% 확률로 정신력 2 회복 + PyModule_AddIntConstant(poModule, "APPLY_BLOCK", CItemData::APPLY_BLOCK); // n% 확률로 물리공격 완벽 방어 + PyModule_AddIntConstant(poModule, "APPLY_DODGE", CItemData::APPLY_DODGE); // n% 확률로 물리공격 완벽 회피 + PyModule_AddIntConstant(poModule, "APPLY_RESIST_SWORD", CItemData::APPLY_RESIST_SWORD); // 한손검에 의한 피해를 n% 감소 + PyModule_AddIntConstant(poModule, "APPLY_RESIST_TWOHAND", CItemData::APPLY_RESIST_TWOHAND); // 양손검에 의한 피해를 n% 감소 + PyModule_AddIntConstant(poModule, "APPLY_RESIST_DAGGER", CItemData::APPLY_RESIST_DAGGER); // 단도에 의한 피해를 n% 감소 + PyModule_AddIntConstant(poModule, "APPLY_RESIST_BELL", CItemData::APPLY_RESIST_BELL); // 방울에 의한 피해를 n% 감소 + PyModule_AddIntConstant(poModule, "APPLY_RESIST_FAN", CItemData::APPLY_RESIST_FAN); // 부채에 의한 피해를 n% 감소 + PyModule_AddIntConstant(poModule, "APPLY_RESIST_WIND", CItemData::APPLY_RESIST_WIND); // 바람에 의한 피해를 n% 감소 + PyModule_AddIntConstant(poModule, "APPLY_REFLECT_MELEE", CItemData::APPLY_REFLECT_MELEE); // 근접 타격 n% 를 적에게 되돌린다 + PyModule_AddIntConstant(poModule, "APPLY_REFLECT_CURSE", CItemData::APPLY_REFLECT_CURSE); // 적이 나에게 저주 사용시 n% 확률로 되돌린다 + PyModule_AddIntConstant(poModule, "APPLY_POISON_REDUCE", CItemData::APPLY_POISON_REDUCE); // 독에 의한 데미지 감소 + PyModule_AddIntConstant(poModule, "APPLY_KILL_SP_RECOVER", CItemData::APPLY_KILL_SP_RECOVER); // 적을 죽였을때 n% 확률로 정신력 10 회복 + PyModule_AddIntConstant(poModule, "APPLY_EXP_DOUBLE_BONUS", CItemData::APPLY_EXP_DOUBLE_BONUS); // n% 확률로 경험치 획득량 2배 + PyModule_AddIntConstant(poModule, "APPLY_GOLD_DOUBLE_BONUS", CItemData::APPLY_GOLD_DOUBLE_BONUS); // n% 확률로 돈 획득량 2배 + PyModule_AddIntConstant(poModule, "APPLY_ITEM_DROP_BONUS", CItemData::APPLY_ITEM_DROP_BONUS); // n% 확률로 아이템 획득량 2배 + PyModule_AddIntConstant(poModule, "APPLY_POTION_BONUS", CItemData::APPLY_POTION_BONUS); // 물약 복용시 n% 만큼 성능 증대 + PyModule_AddIntConstant(poModule, "APPLY_KILL_HP_RECOVER", CItemData::APPLY_KILL_HP_RECOVER); // 죽일때마다 생명력 회복 + PyModule_AddIntConstant(poModule, "APPLY_IMMUNE_STUN", CItemData::APPLY_IMMUNE_STUN); // 기절 하지 않는다 + PyModule_AddIntConstant(poModule, "APPLY_IMMUNE_SLOW", CItemData::APPLY_IMMUNE_SLOW); // 느려지지 않는다 + PyModule_AddIntConstant(poModule, "APPLY_IMMUNE_FALL", CItemData::APPLY_IMMUNE_FALL); // 넘어지지 않는다 + PyModule_AddIntConstant(poModule, "APPLY_MAX_STAMINA", CItemData::APPLY_MAX_STAMINA); // 최대 스테미너 증가 + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_WARRIOR", CItemData::APPLY_ATT_BONUS_TO_WARRIOR); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_ASSASSIN", CItemData::APPLY_ATT_BONUS_TO_ASSASSIN); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_SURA", CItemData::APPLY_ATT_BONUS_TO_SURA); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_SHAMAN", CItemData::APPLY_ATT_BONUS_TO_SHAMAN); + PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_MONSTER", CItemData::APPLY_ATT_BONUS_TO_MONSTER); + PyModule_AddIntConstant(poModule, "APPLY_MALL_ATTBONUS", CItemData::APPLY_MALL_ATTBONUS); + PyModule_AddIntConstant(poModule, "APPLY_MALL_DEFBONUS", CItemData::APPLY_MALL_DEFBONUS); + PyModule_AddIntConstant(poModule, "APPLY_MALL_EXPBONUS", CItemData::APPLY_MALL_EXPBONUS); + PyModule_AddIntConstant(poModule, "APPLY_MALL_ITEMBONUS", CItemData::APPLY_MALL_ITEMBONUS); + PyModule_AddIntConstant(poModule, "APPLY_MALL_GOLDBONUS", CItemData::APPLY_MALL_GOLDBONUS); + PyModule_AddIntConstant(poModule, "APPLY_MAX_HP_PCT", CItemData::APPLY_MAX_HP_PCT); + PyModule_AddIntConstant(poModule, "APPLY_MAX_SP_PCT", CItemData::APPLY_MAX_SP_PCT); + PyModule_AddIntConstant(poModule, "APPLY_SKILL_DAMAGE_BONUS", CItemData::APPLY_SKILL_DAMAGE_BONUS); + PyModule_AddIntConstant(poModule, "APPLY_NORMAL_HIT_DAMAGE_BONUS", CItemData::APPLY_NORMAL_HIT_DAMAGE_BONUS); + PyModule_AddIntConstant(poModule, "APPLY_SKILL_DEFEND_BONUS", CItemData::APPLY_SKILL_DEFEND_BONUS); + PyModule_AddIntConstant(poModule, "APPLY_NORMAL_HIT_DEFEND_BONUS", CItemData::APPLY_NORMAL_HIT_DEFEND_BONUS); + + PyModule_AddIntConstant(poModule, "APPLY_PC_BANG_EXP_BONUS", CItemData::APPLY_PC_BANG_EXP_BONUS); + PyModule_AddIntConstant(poModule, "APPLY_PC_BANG_DROP_BONUS", CItemData::APPLY_PC_BANG_DROP_BONUS); + + PyModule_AddIntConstant(poModule, "APPLY_RESIST_WARRIOR", CItemData::APPLY_RESIST_WARRIOR ); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_ASSASSIN", CItemData::APPLY_RESIST_ASSASSIN ); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_SURA", CItemData::APPLY_RESIST_SURA ); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_SHAMAN", CItemData::APPLY_RESIST_SHAMAN ); + PyModule_AddIntConstant(poModule, "APPLY_ENERGY", CItemData::APPLY_ENERGY ); // 기력 + PyModule_AddIntConstant(poModule, "APPLY_COSTUME_ATTR_BONUS", CItemData::APPLY_COSTUME_ATTR_BONUS ); + + PyModule_AddIntConstant(poModule, "APPLY_MAGIC_ATTBONUS_PER", CItemData::APPLY_MAGIC_ATTBONUS_PER ); + PyModule_AddIntConstant(poModule, "APPLY_MELEE_MAGIC_ATTBONUS_PER", CItemData::APPLY_MELEE_MAGIC_ATTBONUS_PER ); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_ICE", CItemData::APPLY_RESIST_ICE ); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_EARTH", CItemData::APPLY_RESIST_EARTH ); + PyModule_AddIntConstant(poModule, "APPLY_RESIST_DARK", CItemData::APPLY_RESIST_DARK ); + PyModule_AddIntConstant(poModule, "APPLY_ANTI_CRITICAL_PCT", CItemData::APPLY_ANTI_CRITICAL_PCT ); + PyModule_AddIntConstant(poModule, "APPLY_ANTI_PENETRATE_PCT", CItemData::APPLY_ANTI_PENETRATE_PCT ); +} diff --git a/extension/src/port/UserInterface/StdAfx.h b/extension/src/port/UserInterface/StdAfx.h index c8c1a909..cfd66ae5 100644 --- a/extension/src/port/UserInterface/StdAfx.h +++ b/extension/src/port/UserInterface/StdAfx.h @@ -47,6 +47,7 @@ void initapp(); void initchr(); void initchrmgr(); void initPlayer(); +void initItem(); void initNonPlayer(); void initChat(); void initnet(); diff --git a/extension/src/port/common/D3DXMath.h b/extension/src/port/common/D3DXMath.h index d1f8a3d4..c4141912 100644 --- a/extension/src/port/common/D3DXMath.h +++ b/extension/src/port/common/D3DXMath.h @@ -380,6 +380,14 @@ inline D3DXQUATERNION* D3DXQuaternionIdentity(D3DXQUATERNION* pOut) pOut->w = 1.0f; return pOut; } +inline D3DXQUATERNION* D3DXQuaternionConjugate(D3DXQUATERNION* pOut, const D3DXQUATERNION* pQ) +{ + pOut->x = -pQ->x; + pOut->y = -pQ->y; + pOut->z = -pQ->z; + pOut->w = pQ->w; + return pOut; +} D3DXQUATERNION* D3DXQuaternionMultiply(D3DXQUATERNION* pOut, const D3DXQUATERNION* pQ1, const D3DXQUATERNION* pQ2); D3DXQUATERNION* D3DXQuaternionNormalize(D3DXQUATERNION* pOut, const D3DXQUATERNION* pQ); D3DXQUATERNION* D3DXQuaternionRotationAxis(D3DXQUATERNION* pOut, const D3DXVECTOR3* pV, FLOAT angle); diff --git a/extension/tests/port_login_flow_server.cpp b/extension/tests/port_login_flow_server.cpp index eb75344e..7a6baa8a 100644 --- a/extension/tests/port_login_flow_server.cpp +++ b/extension/tests/port_login_flow_server.cpp @@ -550,6 +550,19 @@ bool FakeLoginServer::ServeGame(Connection& c, int index) GCChatHead chat = {HDR_GC_CHAT, static_cast(sizeof(GCChatHead) + sizeof(greet)), 2 /* CHAT_TYPE_NOTICE */, 0, 1}; if (!c.Send(chat) || !c.Send(greet, sizeof(greet))) return Fail(name + ": send greet notice"); + // CItem::EncodeInsertPacket for an owned item in view: GC_ITEM_GROUND_ADD, then GC_ITEM_OWNERSHIP. + GCItemGroundAdd ground = zeroed(); + ground.header = HDR_GC_ITEM_GROUND_ADD; + ground.x = kGroundItemX; + ground.y = kGroundItemY; + ground.vid = kGroundItemVID; + ground.vnum = kGroundItemVnum; + GCItemOwnership ownership = zeroed(); + ownership.header = HDR_GC_ITEM_OWNERSHIP; + ownership.vid = kGroundItemVID; + std::strncpy(ownership.owner, kCharacterName, sizeof(ownership.owner) - 1); + if (!c.Send(ground) || !c.Send(ownership)) + return Fail(name + ": send ground item"); Event(name + ":burst_sent"); // A ping after the burst proves that GamePhase consumed every packet above and can reply. @@ -593,6 +606,16 @@ bool FakeLoginServer::ServeGame(Connection& c, int index) return Fail(name + ": SEQUENCE mismatch on CG header " + std::to_string(header)); c.sequence = (c.sequence + 1) % SEQUENCE_TABLE_SIZE; } + // CInputMain::ItemPickup → CHARACTER::PickupItem → CItem::RemoveFromGround → EncodeRemovePacket. + if (header == HDR_CG_ITEM_PICKUP) + { + CGItemPickup pickup; + std::memcpy(&pickup, packet, sizeof(pickup)); + Event(name + ":pickup " + std::to_string(pickup.vid)); + GCItemGroundDel del = {HDR_GC_ITEM_GROUND_DEL, pickup.vid}; + if (pickup.vid == kGroundItemVID && !c.Send(del)) + return Fail(name + ": send GC_ITEM_GROUND_DEL"); + } if (header == HDR_CG_MOVE) { CGMove move; diff --git a/extension/tests/port_login_flow_server.h b/extension/tests/port_login_flow_server.h index f3ca3e45..6ad6e0c7 100644 --- a/extension/tests/port_login_flow_server.h +++ b/extension/tests/port_login_flow_server.h @@ -21,6 +21,10 @@ public: static constexpr std::uint32_t kLoginKey = 0x13572468; static constexpr std::uint32_t kMainVID = 0x00012345; static constexpr std::int32_t kX = 469300, kY = 964200; + // A ground item in view at entergame (CItem::EncodeInsertPacket): vnum 19, owned by the character. + static constexpr std::uint32_t kGroundItemVID = 0x00054321; + static constexpr std::uint32_t kGroundItemVnum = 19; + static constexpr std::int32_t kGroundItemX = kX + 150, kGroundItemY = kY; ~FakeLoginServer(); diff --git a/extension/tests/port_login_flow_test.cpp b/extension/tests/port_login_flow_test.cpp index 12e6a1c8..4a9b7c03 100644 --- a/extension/tests/port_login_flow_test.cpp +++ b/extension/tests/port_login_flow_test.cpp @@ -48,6 +48,7 @@ #include "GameLib/FlyingData.h" #include "GameLib/FlyingObjectManager.h" #include "GameLib/ItemManager.h" +#include "UserInterface/PythonItem.h" #include "UserInterface/StdAfx.h" #include "UserInterface/PythonCharacterManager.h" #include "UserInterface/InstanceBase.h" @@ -491,7 +492,33 @@ int main(int argc, char** argv) CHECK(!CFlyingManager::Instance().RegisterFlyingData(msf)); } - // 8. (批次 2V3) Click-to-move: a left click on the ground below the actor reaches game.GameWindow's + // item module (PythonItemModule.cpp) over the loaded item_proto: SelectItem + the selected item's fields. + CHECK(py("import item\n" + "item.SelectItem(19)\n" + "assert item.GetItemName() == 'Sword+9', item.GetItemName()\n" + "assert item.GetItemType() == item.ITEM_TYPE_WEAPON and item.GetItemSubType() == item.WEAPON_SWORD\n" + "assert item.GetValue(3) > 0, 'min attack'")); + + // Ground items (CPythonItem): the fake server put vnum 19 next to the actor at entergame (GC_ITEM_GROUND_ADD + // + GC_ITEM_OWNERSHIP). player.PickCloseItem finds it within __GetPickableDistance, sends CG_ITEM_PICKUP, + // and the server's GC_ITEM_GROUND_DEL removes it. + if (server) + { + CPythonItem& ground = CPythonItem::Instance(); + TPixelPosition item_pos = {}; + const char* owner = nullptr; + CHECK(ground.GetGroundItemPosition(FakeLoginServer::kGroundItemVID, &item_pos)); + CHECK(ground.GetOwnership(FakeLoginServer::kGroundItemVID, &owner) && owner && + std::string(owner) == FakeLoginServer::kCharacterName); + CHECK(ground.GetVirtualNumberOfGroundItem(FakeLoginServer::kGroundItemVID) == FakeLoginServer::kGroundItemVnum); + std::printf("port_login_flow_test: ground item at %.0f %.0f\n", item_pos.x, item_pos.y); + CHECK(py("import player\nplayer.PickCloseItem()")); + const std::string pickup = "game2:pickup " + std::to_string(FakeLoginServer::kGroundItemVID); + CHECK(pump_until(2, [&] { return server->Has(pickup); })); + CHECK(pump_until(2, [&] { return !ground.GetGroundItemPosition(FakeLoginServer::kGroundItemVID, &item_pos); })); + } + + // 8. (批次 2V3) Click-to-move: a left click on the ground below the actor reaches game.GameWindow's // OnMouseLeftButtonDown → player.SetMouseState(MBT_LEFT, MBS_PRESS); CPythonPlayer picks the ground // through the cursor ray (CScreen::SetCursorPosition → CPythonBackground::GetPickingPoint) and the // actor walks to it, sending CG_MOVE FUNC_MOVE, then FUNC_WAIT on arrival. @@ -537,7 +564,8 @@ int main(int argc, char** argv) if (e.rfind(prefix, 0) == 0) want.push_back(e); for (const auto& e : events) - if (e.rfind(prefix, 0) == 0 && e.find(":move ") == std::string::npos) + if (e.rfind(prefix, 0) == 0 && e.find(":move ") == std::string::npos && + e.find(":pickup ") == std::string::npos) got.push_back(e); CHECK(want == got); }