WIP port 4-d quest dialogue modules
This commit is contained in:
@@ -543,3 +543,4 @@
|
|||||||
{"time": "2026-09-24T19:00:00Z", "event": "port", "unit": "batch 4-a text input: EterLib/IME.cpp (ADAPTED), UserInterface/PythonIME.cpp, PythonIMEModule.cpp", "detail": "ime module ported; IMM/TSF-free CIME in platform/; Godot key events -> ui_ime_key/ui_char -> CWindowManager RunIME*; login typed through the IME; in-game chat CG_CHAT round-trip", "tests": ["port.login_flow (typed id/password with edits, chat send/echo/close)", "port.login_live", "python_game_render_test (Godot key events)"]}
|
{"time": "2026-09-24T19:00:00Z", "event": "port", "unit": "batch 4-a text input: EterLib/IME.cpp (ADAPTED), UserInterface/PythonIME.cpp, PythonIMEModule.cpp", "detail": "ime module ported; IMM/TSF-free CIME in platform/; Godot key events -> ui_ime_key/ui_char -> CWindowManager RunIME*; login typed through the IME; in-game chat CG_CHAT round-trip", "tests": ["port.login_flow (typed id/password with edits, chat send/echo/close)", "port.login_live", "python_game_render_test (Godot key events)"]}
|
||||||
{"time": "2026-09-24T20:00:00Z", "event": "verify", "unit": "batch 4-b combat: InstanceBaseBattle / ActorInstanceCollisionDetection / PythonPlayerInput (already ported)", "detail": "fake server spawns a stray dog outside the BANPK safe disc, answers CG_TARGET/CG_ATTACK with GC_TARGET/GC_DAMAGE_INFO/GC_DEAD; held left button walks up and combo-attacks until death; damage numbers wait on CPythonSystem (4-g)", "tests": ["port.login_flow (step 9 held-button kill)", "port.login_live", "python_game_render_test (Godot mouse events, target HP 100/66/33/0)"]}
|
{"time": "2026-09-24T20:00:00Z", "event": "verify", "unit": "batch 4-b combat: InstanceBaseBattle / ActorInstanceCollisionDetection / PythonPlayerInput (already ported)", "detail": "fake server spawns a stray dog outside the BANPK safe disc, answers CG_TARGET/CG_ATTACK with GC_TARGET/GC_DAMAGE_INFO/GC_DEAD; held left button walks up and combo-attacks until death; damage numbers wait on CPythonSystem (4-g)", "tests": ["port.login_flow (step 9 held-button kill)", "port.login_live", "python_game_render_test (Godot mouse events, target HP 100/66/33/0)"]}
|
||||||
{"time": "2026-09-24T21:00:00Z", "event": "port", "unit": "batch 4-c shop: UserInterface/PythonShop.cpp (+ PythonApplicationCursor.cpp, SetMouseHandler adapted)", "detail": "shop module ported verbatim; app cursor state moved into the platform CPythonApplication (uishop reads app.GetCursor, which dereferenced the missing application object); fake server general store answers CG_ON_CLICK/CG_SHOP BUY/SELL2/END like CShop::AddGuest/Buy and CShopManager::Sell", "tests": ["port.login_flow (step 10 buy/sell/ESC)", "port.login_live", "python_game_render_test"]}
|
{"time": "2026-09-24T21:00:00Z", "event": "port", "unit": "batch 4-c shop: UserInterface/PythonShop.cpp (+ PythonApplicationCursor.cpp, SetMouseHandler adapted)", "detail": "shop module ported verbatim; app cursor state moved into the platform CPythonApplication (uishop reads app.GetCursor, which dereferenced the missing application object); fake server general store answers CG_ON_CLICK/CG_SHOP BUY/SELL2/END like CShop::AddGuest/Buy and CShopManager::Sell", "tests": ["port.login_flow (step 10 buy/sell/ESC)", "port.login_live", "python_game_render_test"]}
|
||||||
|
{"time": "2026-09-24T22:00:00Z", "event": "wip", "unit": "batch 4-d NPC quest dialogue", "detail": "Added event manager, quest state/module, event manager module, parser and DBCS helpers; fake server now has an Oldster NPC and preliminary GC_SCRIPT / CG_SCRIPT_ANSWER exchange. This is explicitly unfinished: login-flow UI round trip and rendering interaction are not wired/verified; all five source-unit port-map entries remain TODO.", "tests": []}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"reference": "EterLib/parser.cpp",
|
||||||
|
"reference_sha256": "1b81a802b14e1a5958aaf981ca81248e389ad5c6f572858fd31e4afb7674ba86",
|
||||||
|
"priority": "P4",
|
||||||
|
"contracts": [],
|
||||||
|
"functions": {
|
||||||
|
"LocaleString_FindChar": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"LocaleString_RightTrim": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"OLD_rtrim": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"LocaleString_Skip": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::GetArg": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::Create": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::GetCmd": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::ReadCmd": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::GetError": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::SetError": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::Group": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"Group::~Group": {
|
||||||
|
"status": "TODO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"reference": "UserInterface/PythonEventManager.cpp",
|
||||||
|
"reference_sha256": "db306daefe5948ad7b3d533266bea7ef04826b22311c72d421c4f23c647de8e2",
|
||||||
|
"priority": "P4",
|
||||||
|
"contracts": [],
|
||||||
|
"functions": {
|
||||||
|
"ShowArgument": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"GetArgumentString": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"GetArgument": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"GetCameraSettingFromArgList": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::__InitEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::RegisterEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::RegisterEventSetFromString": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::ClearEventSeti": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::__ClearEventSetp": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::GetEmptyEventSetSlot": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SetRestrictedCount": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SetEventHandler": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::GetEventSetLocalYPosition": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::AddEventSetLocalYPosition": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::InsertText": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::UpdateEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SetEventSetWidth": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::ProcessEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::RenderEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::Skip": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::IsWait": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::EndEventProcess": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::MakeNextButton": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::MakeQuestion": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SelectAnswer": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SetVisibleStartLine": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SetVisibleLineCount": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::GetVisibleStartLine": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::GetLineCount": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::ClearLine": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::__InsertLine": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::RefreshLinePosition": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::__AddSpace": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::GetScriptEventIndex": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::CheckEventSetIndex": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::Destroy": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SetInterfaceWindow": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::SetLeftTimeString": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::CPythonEventManager": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonEventManager::~CPythonEventManager": {
|
||||||
|
"status": "TODO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
{
|
||||||
|
"reference": "UserInterface/PythonEventManagerMoudle.cpp",
|
||||||
|
"reference_sha256": "104c2b16cef91b4d41844caa10851ff82e8e2766c264aaaeca3b7f246a17e4ae",
|
||||||
|
"priority": "P4",
|
||||||
|
"contracts": [],
|
||||||
|
"functions": {
|
||||||
|
"eventRegisterEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventRegisterEventSetFromString": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventClearEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSetRestrictedCount": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventGetEventSetLocalYPosition": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventAddEventSetLocalYPosition": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventInsertText": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventInsertTextInline": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventUpdateEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventRenderEventSet": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSetEventSetWidth": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSkip": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventIsWait": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventEndEventProcess": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSetEventHandler": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSelectAnswer": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventGetLineCount": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSetVisibleStartLine": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventGetVisibleStartLine": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventQuestButtonClick": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSetInterfaceWindow": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventSetLeftTimeString": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"eventDestroy": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"initEvent": {
|
||||||
|
"status": "TODO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"reference": "UserInterface/PythonGameEventManagerModule.cpp",
|
||||||
|
"reference_sha256": "233eb8e6439422e3262240f8e22e8df6a4049122fe110a218b5c952207414e2e",
|
||||||
|
"priority": "P4",
|
||||||
|
"contracts": [],
|
||||||
|
"functions": {
|
||||||
|
"eventMgrUpdate": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"initeventmgr": {
|
||||||
|
"status": "TODO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"reference": "UserInterface/PythonQuest.cpp",
|
||||||
|
"reference_sha256": "2e48148f3da65c4e286843d1b225aaa2021f2731f9f024fe989d1489c6e5f546",
|
||||||
|
"priority": "P3",
|
||||||
|
"contracts": [],
|
||||||
|
"functions": {
|
||||||
|
"CPythonQuest::RegisterQuestInstance": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::DeleteQuestInstance": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::IsQuest": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::MakeQuest": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::SetQuestTitle": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::SetQuestClockName": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::SetQuestCounterName": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::SetQuestClockValue": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::SetQuestCounterValue": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::SetQuestIconFileName": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::GetQuestCount": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::GetQuestInstancePtr": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::__GetQuestInstancePtr": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::__Initialize": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::Clear": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::CPythonQuest": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"CPythonQuest::~CPythonQuest": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"questGetQuestCount": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"questGetQuestData": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"questGetQuestIndex": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"questGetQuestLastTime": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"questClear": {
|
||||||
|
"status": "TODO"
|
||||||
|
},
|
||||||
|
"initquest": {
|
||||||
|
"status": "TODO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -450,11 +450,12 @@ extension/third_party/cpython-2.7.18/ # 静态库(2P 批次
|
|||||||
批次 3-b EffectLib(2026-09-24):`EffectLib/` 18 个 .cpp 原样移植(EffectManager、EffectData/Instance、EffectMesh、粒子系统、SimpleLight 等),删除 `platform/EffectLib` 生成的桩骨架;唯一改动是 `Type.h` 里 `BILLBOARD_TYPE_2FACE` 行尾注释的 `\` 被 clang 当作续行吞掉下一行,去掉反斜杠。`platform/EterBase/Utils.cpp` 剩下的 21 个桩按 §3 照抄 40250 函数体(`GetOnlyPathName`/`IsGlobalFileName` 缺失会让 .msf 以相对名挂的 .mse 丢目录,106 个 RegisterEffect 报错),Win32 调用换成 POSIX 的记 ADAPTED;平台 `CPythonResource` 补上 40250 的 `mde`(CEffectMesh)和 `mdatr`(CAttributeData)资源类型。`port.utils` 覆盖路径/分词/命令行辅助函数;`port.login_flow`:在主角脚下 `CreateEffect(level_up.mse)`,RenderGame 的 `CEffectManager::Render` 录出 levelup_1 贴图的 alpha 混合粒子绘制(dust、dropitem 同样出现)。40250 声明但未定义 `GetRenderingEffectCount`,测试不用。
|
批次 3-b EffectLib(2026-09-24):`EffectLib/` 18 个 .cpp 原样移植(EffectManager、EffectData/Instance、EffectMesh、粒子系统、SimpleLight 等),删除 `platform/EffectLib` 生成的桩骨架;唯一改动是 `Type.h` 里 `BILLBOARD_TYPE_2FACE` 行尾注释的 `\` 被 clang 当作续行吞掉下一行,去掉反斜杠。`platform/EterBase/Utils.cpp` 剩下的 21 个桩按 §3 照抄 40250 函数体(`GetOnlyPathName`/`IsGlobalFileName` 缺失会让 .msf 以相对名挂的 .mse 丢目录,106 个 RegisterEffect 报错),Win32 调用换成 POSIX 的记 ADAPTED;平台 `CPythonResource` 补上 40250 的 `mde`(CEffectMesh)和 `mdatr`(CAttributeData)资源类型。`port.utils` 覆盖路径/分词/命令行辅助函数;`port.login_flow`:在主角脚下 `CreateEffect(level_up.mse)`,RenderGame 的 `CEffectManager::Render` 录出 levelup_1 贴图的 alpha 混合粒子绘制(dust、dropitem 同样出现)。40250 声明但未定义 `GetRenderingEffectCount`,测试不用。
|
||||||
批次 3-c CMapOutdoor(2026-09-24):`GameLib/` 的 Area、AreaTerrain、DungeonBlock、MapBase、MapManager、MapOutdoor(含 IndexBuffer/Load/Quadtree/Render/Update)、MapType、MonsterAreaInfo、Property/PropertyLoader/PropertyManager、SnowEnvironment/SnowParticle、TerrainDecal/Patch/Quadtree,`PRTerrainLib/` Terrain、TextureSet,`UserInterface/PythonBackground(+Module)`,`EterLib/ColorTransitionHelper` 原样移植,删除 pending 替身与 background 模块桩(含 GameplayModuleConstants 里的常量桩);`EterBase/FileDir`、`TempFile` 在 platform 下照抄 40250 函数体(Win32 查找/临时文件走 common 垫片,记 ADAPTED)。`TEMP_CAreaLoaderThread` 在 40250 已全部注释掉,.cpp 不编(N_A)。手改两处:`CMapManager::BeginEnvironment` 的 `ApplyLight` 标签指针经 `uintptr_t` 转 DWORD;`CTerrainImpl::LoadWaterMap` 按 32 位读 water.wtr 的 `long` 再逐个扩宽(LP64 下 `long` 是 8 字节,否则报 FILE DATA SIZE 16392 != 16400)。平台文件:HTP/STP 地形绘制与 `RenderWater` 为空(地形仍由 Godot 适配层画,§3),STP 的 Initialize/Create/Destroy、水面贴图载入、角色阴影贴图创建照抄;`BeginRenderCharacterShadowToTexture` 返回 false(记 DIVERGENT)。录制设备补齐 `CreateTexture/VertexBuffer/IndexBuffer/DepthStencilSurface`、`Get/SetRenderTarget`、`LightEnable`、`Clear`(CPU 表面/贴图),离屏渲染目标的绘制丢弃,light0 只在启用且为方向光时记录。小地图:`CPythonMiniMap` 在正交投影下画 minimap.dds 瓦片并以 stage 1 相机空间坐标 × `D3DTS_TEXTURE1` 采样 `minimap_image_filter.dds` 做圆形遮罩——录制设备把「正交投影 + 未变换顶点」的绘制按四边形转成 UI 命令(带 mask 贴图与四角 mask uv),`UIRenderAddImage` 按 D3DTS_WORLD 平移、按 TFACTOR 调色(标记点),`python_ui_surface.gd` 用按序的子 canvas item 画 UI 流,带遮罩的图各用一个 shader 材质。`port.login_flow`:Warp 后 `IsMapOutdoor()`、`miniMap.GetAtlasSize()` 已载入、`background.GetCurrentMapName()` 非空;`python_game_render_test` 新增「minimap tiles drawn through the filter mask」(9 块)。截图里主角旁地上的剑是假服 entergame 时按 `GC_ITEM_GROUND_ADD` 放的地面物品(vnum 19,P3-b 拾取测试用),不是武器挂点问题;假服角色没装备武器。
|
批次 3-c CMapOutdoor(2026-09-24):`GameLib/` 的 Area、AreaTerrain、DungeonBlock、MapBase、MapManager、MapOutdoor(含 IndexBuffer/Load/Quadtree/Render/Update)、MapType、MonsterAreaInfo、Property/PropertyLoader/PropertyManager、SnowEnvironment/SnowParticle、TerrainDecal/Patch/Quadtree,`PRTerrainLib/` Terrain、TextureSet,`UserInterface/PythonBackground(+Module)`,`EterLib/ColorTransitionHelper` 原样移植,删除 pending 替身与 background 模块桩(含 GameplayModuleConstants 里的常量桩);`EterBase/FileDir`、`TempFile` 在 platform 下照抄 40250 函数体(Win32 查找/临时文件走 common 垫片,记 ADAPTED)。`TEMP_CAreaLoaderThread` 在 40250 已全部注释掉,.cpp 不编(N_A)。手改两处:`CMapManager::BeginEnvironment` 的 `ApplyLight` 标签指针经 `uintptr_t` 转 DWORD;`CTerrainImpl::LoadWaterMap` 按 32 位读 water.wtr 的 `long` 再逐个扩宽(LP64 下 `long` 是 8 字节,否则报 FILE DATA SIZE 16392 != 16400)。平台文件:HTP/STP 地形绘制与 `RenderWater` 为空(地形仍由 Godot 适配层画,§3),STP 的 Initialize/Create/Destroy、水面贴图载入、角色阴影贴图创建照抄;`BeginRenderCharacterShadowToTexture` 返回 false(记 DIVERGENT)。录制设备补齐 `CreateTexture/VertexBuffer/IndexBuffer/DepthStencilSurface`、`Get/SetRenderTarget`、`LightEnable`、`Clear`(CPU 表面/贴图),离屏渲染目标的绘制丢弃,light0 只在启用且为方向光时记录。小地图:`CPythonMiniMap` 在正交投影下画 minimap.dds 瓦片并以 stage 1 相机空间坐标 × `D3DTS_TEXTURE1` 采样 `minimap_image_filter.dds` 做圆形遮罩——录制设备把「正交投影 + 未变换顶点」的绘制按四边形转成 UI 命令(带 mask 贴图与四角 mask uv),`UIRenderAddImage` 按 D3DTS_WORLD 平移、按 TFACTOR 调色(标记点),`python_ui_surface.gd` 用按序的子 canvas item 画 UI 流,带遮罩的图各用一个 shader 材质。`port.login_flow`:Warp 后 `IsMapOutdoor()`、`miniMap.GetAtlasSize()` 已载入、`background.GetCurrentMapName()` 非空;`python_game_render_test` 新增「minimap tiles drawn through the filter mask」(9 块)。截图里主角旁地上的剑是假服 entergame 时按 `GC_ITEM_GROUND_ADD` 放的地面物品(vnum 19,P3-b 拾取测试用),不是武器挂点问题;假服角色没装备武器。
|
||||||
默认路由切换(2026-09-24):`client_main` 不设 `MT_PORT_PATH` 时走 port 路由(`python_ui_surface.gd` + `python_3d_surface.gd` 跑 40250 system.py),`MT_PORT_PATH=legacy` 回到 GDScript `AppFlow`,规则见 §2「迁移方式」。已验证:实例化 `client_main.tscn`,默认/`port` 起 PythonUISurface + Python3DSurface 并产出 UI 命令,`legacy` 起 AppFlow + NetTrace。下一步:port 路由稳定后删除 legacy 宿主与开关。
|
默认路由切换(2026-09-24):`client_main` 不设 `MT_PORT_PATH` 时走 port 路由(`python_ui_surface.gd` + `python_3d_surface.gd` 跑 40250 system.py),`MT_PORT_PATH=legacy` 回到 GDScript `AppFlow`,规则见 §2「迁移方式」。已验证:实例化 `client_main.tscn`,默认/`port` 起 PythonUISurface + Python3DSurface 并产出 UI 命令,`legacy` 起 AppFlow + NetTrace。下一步:port 路由稳定后删除 legacy 宿主与开关。
|
||||||
批次 4(2026-09-24 起):补齐 port 路由的玩法,以便删除 legacy。顺序:4-a 文字输入 → 4-b 战斗 → 4-c 商店 → 4-d 任务/NPC 对话 → 4-e 仓库 → 4-f 好友/公会/公会标记 → 4-g systemSetting → 4-h 声音。
|
批次 4(2026-09-24 起):补齐 port 路由的玩法,以便删除 legacy。顺序:4-a 文字输入(完成) → 4-b 战斗(完成) → 4-c 商店(完成) → 4-d 任务/NPC 对话(进行中,未完成) → 4-e 仓库(未开始) → 4-f 好友/公会/公会标记(未开始) → 4-g systemSetting(未开始) → 4-h 声音(未开始)。
|
||||||
批次 4-a 文字输入(2026-09-24):`UserInterface/PythonIME.cpp` 与 `PythonIMEModule.cpp` 原样移植(仅把 MSVC 专有的 `unsigned char(x)` 函数式转换改成 C 式转换),删除 ime 模块桩,`initime()` 按 40250 顺序在 `initdbg()` 之后,`CPythonApplication::Create` 按原序 `CPythonIME::Create` + `SetText("", 0)`。`EterLib/IME.cpp` 在 platform 下:缓冲区、光标、`WMChar`(退格、`|` 转义、按输入代码页 `MultiByteToWideChar`)、候选/读音状态、数字/字符串模式等函数体照抄;IMM/TSF 在 Godot 下没有对应物,组字相关处理器为空、`EnableIME` 恒关,已提交的非单字节文本由 `PythonBoot::UIChar` 模拟 `GCS_RESULTSTR`(`InsertString` + `OnUpdate`),`DelCurPos` 用 memmove 替代重叠的 wcscpy(全部记 ADAPTED)。`GameApplicationAdapter` 的 `RunIME*` 转发到 `CWindowManager`;注意 `RunIMEUpdate/RunIMEKeyDown` 只送达正在渲染的活动窗口(登录框未打开时输入被丢弃)。Godot 侧 `python_ui_surface.gd` 把按键送 `ui_ime_key`(VK)再送 `ui_char`(unicode)。`port.login_flow` 与 `port.login_live` 打开登录框后逐字键入账号(含 LEFT/DELETE/BACK 编辑)、TAB 切到密码、RETURN 登录(凭据只来自环境变量,测试随后删除 Python 局部变量);进游戏后 RETURN 打开聊天、键入 hello、RETURN 发出 `CG_CHAT`(假服回显 `GC_CHAT`),空行 RETURN 关闭聊天(40250 发完后只清空、不关闭)。`python_game_render_test` 用 Godot 按键事件走同一路径登录。
|
批次 4-a 文字输入(2026-09-24):`UserInterface/PythonIME.cpp` 与 `PythonIMEModule.cpp` 原样移植(仅把 MSVC 专有的 `unsigned char(x)` 函数式转换改成 C 式转换),删除 ime 模块桩,`initime()` 按 40250 顺序在 `initdbg()` 之后,`CPythonApplication::Create` 按原序 `CPythonIME::Create` + `SetText("", 0)`。`EterLib/IME.cpp` 在 platform 下:缓冲区、光标、`WMChar`(退格、`|` 转义、按输入代码页 `MultiByteToWideChar`)、候选/读音状态、数字/字符串模式等函数体照抄;IMM/TSF 在 Godot 下没有对应物,组字相关处理器为空、`EnableIME` 恒关,已提交的非单字节文本由 `PythonBoot::UIChar` 模拟 `GCS_RESULTSTR`(`InsertString` + `OnUpdate`),`DelCurPos` 用 memmove 替代重叠的 wcscpy(全部记 ADAPTED)。`GameApplicationAdapter` 的 `RunIME*` 转发到 `CWindowManager`;注意 `RunIMEUpdate/RunIMEKeyDown` 只送达正在渲染的活动窗口(登录框未打开时输入被丢弃)。Godot 侧 `python_ui_surface.gd` 把按键送 `ui_ime_key`(VK)再送 `ui_char`(unicode)。`port.login_flow` 与 `port.login_live` 打开登录框后逐字键入账号(含 LEFT/DELETE/BACK 编辑)、TAB 切到密码、RETURN 登录(凭据只来自环境变量,测试随后删除 Python 局部变量);进游戏后 RETURN 打开聊天、键入 hello、RETURN 发出 `CG_CHAT`(假服回显 `GC_CHAT`),空行 RETURN 关闭聊天(40250 发完后只清空、不关闭)。`python_game_render_test` 用 Godot 按键事件走同一路径登录。
|
||||||
批次 4-b 战斗(2026-09-24):战斗代码此前已原样移植(`InstanceBaseBattle`、`ActorInstanceCollisionDetection`、`PythonPlayerInput*`、`uiTarget`),本批只补验证。假服在出生点北 18 m 放一只野狗(npclist 101,怪物不发 `GC_CHAR_ADDITIONAL_INFO`,名字取自 mob_proto;发了会 syserr),出生点在村庄 `ATTRIBUTE_BANPK` 圈内,`CInstanceBase::IsInSafe()` 会挡掉所有命中。`CG_TARGET` 回 `GC_TARGET`,`CG_ATTACK` 回 `GC_DAMAGE_INFO` + `GC_TARGET`,第三下回 `GC_DEAD`。与 40250 相同:单击怪物(`__OnClickActor`)只走过去,按住左键(MBF_SMART → `__OnPressActor`)才走近并连击。`port.login_flow` 第 9 步用显式透视矩阵投影野狗、按住左键直到死亡,检查 target 面板和至少 3 次 `CG_ATTACK`;`python_game_render_test` 用 Godot 鼠标事件走同一路径,截图 combat_mid/combat.png(野狗位于镜头与战士的连线上,被战士挡住,属正常)。新增宿主/测试辅助 `PythonBoot::Evaluate` / `Metin2PythonHost.evaluate`(40250 无对应物)。`python_3d_surface.gd` 修正:D3D 固定管线中材质 emissive 先加进顶点色,再被纹理 MODULATE,Godot 的 emission 却加在纹理之后,导致黑底加色的点击光圈(click_glow_select copy.jpg)显示成灰色方块,角色也被 0.32 的 emissive 洗灰;现在 emission 乘以同一张纹理(`EMISSION_OP_MULTIPLY`)。战斗步骤先等镜头稳定(上一步的走路可能尚未结束),野狗投影落在小地图或任务栏下时先点地面走近一段。已知缺口:伤害数字依赖 `CPythonSystem::IsShowDamage()`,该单元仍在 pending 桩(4-g),故暂不显示。
|
批次 4-b 战斗(2026-09-24):战斗代码此前已原样移植(`InstanceBaseBattle`、`ActorInstanceCollisionDetection`、`PythonPlayerInput*`、`uiTarget`),本批只补验证。假服在出生点北 18 m 放一只野狗(npclist 101,怪物不发 `GC_CHAR_ADDITIONAL_INFO`,名字取自 mob_proto;发了会 syserr),出生点在村庄 `ATTRIBUTE_BANPK` 圈内,`CInstanceBase::IsInSafe()` 会挡掉所有命中。`CG_TARGET` 回 `GC_TARGET`,`CG_ATTACK` 回 `GC_DAMAGE_INFO` + `GC_TARGET`,第三下回 `GC_DEAD`。与 40250 相同:单击怪物(`__OnClickActor`)只走过去,按住左键(MBF_SMART → `__OnPressActor`)才走近并连击。`port.login_flow` 第 9 步用显式透视矩阵投影野狗、按住左键直到死亡,检查 target 面板和至少 3 次 `CG_ATTACK`;`python_game_render_test` 用 Godot 鼠标事件走同一路径,截图 combat_mid/combat.png(野狗位于镜头与战士的连线上,被战士挡住,属正常)。新增宿主/测试辅助 `PythonBoot::Evaluate` / `Metin2PythonHost.evaluate`(40250 无对应物)。`python_3d_surface.gd` 修正:D3D 固定管线中材质 emissive 先加进顶点色,再被纹理 MODULATE,Godot 的 emission 却加在纹理之后,导致黑底加色的点击光圈(click_glow_select copy.jpg)显示成灰色方块,角色也被 0.32 的 emissive 洗灰;现在 emission 乘以同一张纹理(`EMISSION_OP_MULTIPLY`)。战斗步骤先等镜头稳定(上一步的走路可能尚未结束),野狗投影落在小地图或任务栏下时先点地面走近一段。已知缺口:伤害数字依赖 `CPythonSystem::IsShowDamage()`,该单元仍在 pending 桩(4-g),故暂不显示。
|
||||||
|
|
||||||
批次 4-c 商店(2026-09-24):`PythonShop.cpp` 原样移植(`shop` 模块 + `SHOP_SLOT_COUNT`/金币常量,`initshop()` 按 40250 次序接在 `initfly()` 之后;40250 中间的 `initsnd`/`initeventmgr` 尚未移植),删去 pending 桩与模块桩。uishop 在 `OnUpdate` 里读 `app.GetCursor()`,而 `GetCursorNum()` 是头文件内联、读的是不存在的 CPythonApplication 对象的成员,导致空指针崩溃;现把 40250 `PythonApplicationCursor.cpp`(SetCursorNum/Visible/Mode 等)和 `SetMouseHandler` 原样搬进 platform CPythonApplication,成员改为文件静态量,`GetCursorNum` 改为非内联(头文件 PORT 注释);宿主不画硬件光标,`[0, CURSOR_COUNT)` 内的形状都视为已加载。假服在野狗东 4 m 放杂货商(npclist 9003),`CG_ON_CLICK` 回 `GC_SHOP START`(货架 0 为 27001 红药,50 金),`CG_SHOP BUY` 先扣金(`GC_POINT_CHANGE`)再 `GC_ITEM_SET`,`SELL2` 回 `GC_ITEM_DEL` + 加 9 金,`END` 回 `GC_SHOP END`(与 40250 `CShop::Buy`/`CShopManager::Sell` 次序相同;包的附加长度按 `CInputMain::Shop` 读)。`port.login_flow` 第 10 步:左键点商人走过去打开商店窗口和背包,右键货架 0 购买,背包格 0 拾起后放到货架空格出售,ESC 关闭,逐步检查 `CG_SHOP` 字节、背包格和金币。
|
批次 4-c 商店(2026-09-24):`PythonShop.cpp` 原样移植(`shop` 模块 + `SHOP_SLOT_COUNT`/金币常量,`initshop()` 按 40250 次序接在 `initfly()` 之后;40250 中间的 `initsnd`/`initeventmgr` 尚未移植),删去 pending 桩与模块桩。uishop 在 `OnUpdate` 里读 `app.GetCursor()`,而 `GetCursorNum()` 是头文件内联、读的是不存在的 CPythonApplication 对象的成员,导致空指针崩溃;现把 40250 `PythonApplicationCursor.cpp`(SetCursorNum/Visible/Mode 等)和 `SetMouseHandler` 原样搬进 platform CPythonApplication,成员改为文件静态量,`GetCursorNum` 改为非内联(头文件 PORT 注释);宿主不画硬件光标,`[0, CURSOR_COUNT)` 内的形状都视为已加载。假服在野狗东 4 m 放杂货商(npclist 9003),`CG_ON_CLICK` 回 `GC_SHOP START`(货架 0 为 27001 红药,50 金),`CG_SHOP BUY` 先扣金(`GC_POINT_CHANGE`)再 `GC_ITEM_SET`,`SELL2` 回 `GC_ITEM_DEL` + 加 9 金,`END` 回 `GC_SHOP END`(与 40250 `CShop::Buy`/`CShopManager::Sell` 次序相同;包的附加长度按 `CInputMain::Shop` 读)。`port.login_flow` 第 10 步:左键点商人走过去打开商店窗口和背包,右键货架 0 购买,背包格 0 拾起后放到货架空格出售,ESC 关闭,逐步检查 `CG_SHOP` 字节、背包格和金币。
|
||||||
|
批次 4-d 任务/NPC 对话(进行中,未完成,2026-09-24):已加入 `PythonEventManager`、`PythonQuest`、`GameEventManager` 逻辑及 Python 模块,并开始扩展假服对话 NPC 和 `GC_SCRIPT` / `CG_SCRIPT_ANSWER` 应答;`parser.cpp` 和 DBCS 字符串步进也作为事件脚本解析依赖加入。当前还没有在 `port_login_flow` 中接通并验证完整的点击 NPC → 显示对话 → 选择答案 → NEXT/DONE 往返流程,也未做门禁/回归确认。相关逐函数审计仍为 `TODO`;本批不能记为完成。
|
||||||
|
|
||||||
每个切片都必须同时跑 legacy/port 双路回归;默认路由已切到 `port`(2026-09-24);port 路由稳定后删除总开关和剩余 legacy 宿主。
|
每个切片都必须同时跑 legacy/port 双路回归;默认路由已切到 `port`(2026-09-24);port 路由稳定后删除总开关和剩余 legacy 宿主。
|
||||||
|
|
||||||
|
|||||||
@@ -36,21 +36,7 @@
|
|||||||
|
|
||||||
// 40250 UserInterface/PythonBackgroundModule.cpp
|
// 40250 UserInterface/PythonBackgroundModule.cpp
|
||||||
// 40250 UserInterface/PythonEventManagerMoudle.cpp
|
// 40250 UserInterface/PythonEventManagerMoudle.cpp
|
||||||
void AddStubConstants_event(PyObject* poModule)
|
|
||||||
{
|
|
||||||
(void) poModule;
|
|
||||||
PyModule_AddIntConstant(poModule, "BOX_VISIBLE_LINE_COUNT", CPythonEventManager::BOX_VISIBLE_LINE_COUNT);
|
|
||||||
PyModule_AddIntConstant(poModule, "BUTTON_TYPE_NEXT", CPythonEventManager::BUTTON_TYPE_NEXT);
|
|
||||||
PyModule_AddIntConstant(poModule, "BUTTON_TYPE_DONE", CPythonEventManager::BUTTON_TYPE_DONE);
|
|
||||||
PyModule_AddIntConstant(poModule, "BUTTON_TYPE_CANCEL", CPythonEventManager::BUTTON_TYPE_CANCEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 40250 UserInterface/PythonGameEventManagerModule.cpp
|
// 40250 UserInterface/PythonGameEventManagerModule.cpp
|
||||||
void AddStubConstants_eventMgr(PyObject* poModule)
|
|
||||||
{
|
|
||||||
(void) poModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 40250 UserInterface/PythonGuild.cpp
|
// 40250 UserInterface/PythonGuild.cpp
|
||||||
void AddStubConstants_guild(PyObject* poModule)
|
void AddStubConstants_guild(PyObject* poModule)
|
||||||
{
|
{
|
||||||
@@ -76,12 +62,6 @@ void AddStubConstants_profiler(PyObject* poModule)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 40250 UserInterface/PythonQuest.cpp
|
// 40250 UserInterface/PythonQuest.cpp
|
||||||
void AddStubConstants_quest(PyObject* poModule)
|
|
||||||
{
|
|
||||||
(void) poModule;
|
|
||||||
PyModule_AddIntConstant(poModule, "QUEST_MAX_NUM", 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 40250 UserInterface/PythonSafeBox.cpp
|
// 40250 UserInterface/PythonSafeBox.cpp
|
||||||
void AddStubConstants_safebox(PyObject* poModule)
|
void AddStubConstants_safebox(PyObject* poModule)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,12 +5,9 @@
|
|||||||
#include "../EterLib/UIRenderCommands.h"
|
#include "../EterLib/UIRenderCommands.h"
|
||||||
|
|
||||||
// GameplayModuleConstants.cpp: each module's 40250 constants.
|
// GameplayModuleConstants.cpp: each module's 40250 constants.
|
||||||
void AddStubConstants_event(PyObject* poModule);
|
|
||||||
void AddStubConstants_eventMgr(PyObject* poModule);
|
|
||||||
void AddStubConstants_guild(PyObject* poModule);
|
void AddStubConstants_guild(PyObject* poModule);
|
||||||
void AddStubConstants_messenger(PyObject* poModule);
|
void AddStubConstants_messenger(PyObject* poModule);
|
||||||
void AddStubConstants_profiler(PyObject* poModule);
|
void AddStubConstants_profiler(PyObject* poModule);
|
||||||
void AddStubConstants_quest(PyObject* poModule);
|
|
||||||
void AddStubConstants_safebox(PyObject* poModule);
|
void AddStubConstants_safebox(PyObject* poModule);
|
||||||
void AddStubConstants_snd(PyObject* poModule);
|
void AddStubConstants_snd(PyObject* poModule);
|
||||||
void AddStubConstants_systemSetting(PyObject* poModule);
|
void AddStubConstants_systemSetting(PyObject* poModule);
|
||||||
@@ -24,62 +21,6 @@ PyObject* stub_call_named(const char* name, PyObject* result = nullptr) {
|
|||||||
return result ? result : Py_BuildValue("i", 0);
|
return result ? result : Py_BuildValue("i", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 40250 UserInterface/PythonEventManagerMoudle.cpp: event export names.
|
|
||||||
PyObject* stub_event_RegisterEventSet(PyObject*, PyObject*) { return stub_call_named("event.RegisterEventSet", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_event_RegisterEventSetFromString(PyObject*, PyObject*) { return stub_call_named("event.RegisterEventSetFromString", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_event_ClearEventSet(PyObject*, PyObject*) { return stub_call_named("event.ClearEventSet", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_SetRestrictedCount(PyObject*, PyObject*) { return stub_call_named("event.SetRestrictedCount", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_GetEventSetLocalYPosition(PyObject*, PyObject*) { return stub_call_named("event.GetEventSetLocalYPosition", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_event_AddEventSetLocalYPosition(PyObject*, PyObject*) { return stub_call_named("event.AddEventSetLocalYPosition", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_InsertText(PyObject*, PyObject*) { return stub_call_named("event.InsertText", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_InsertTextInline(PyObject*, PyObject*) { return stub_call_named("event.InsertTextInline", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_UpdateEventSet(PyObject*, PyObject*) { return stub_call_named("event.UpdateEventSet", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_RenderEventSet(PyObject*, PyObject*) { return stub_call_named("event.RenderEventSet", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_SetEventSetWidth(PyObject*, PyObject*) { return stub_call_named("event.SetEventSetWidth", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_Skip(PyObject*, PyObject*) { return stub_call_named("event.Skip", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_IsWait(PyObject*, PyObject*) { return stub_call_named("event.IsWait", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_event_EndEventProcess(PyObject*, PyObject*) { return stub_call_named("event.EndEventProcess", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_SelectAnswer(PyObject*, PyObject*) { return stub_call_named("event.SelectAnswer", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_GetLineCount(PyObject*, PyObject*) { return stub_call_named("event.GetLineCount", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_event_SetVisibleStartLine(PyObject*, PyObject*) { return stub_call_named("event.SetVisibleStartLine", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_GetVisibleStartLine(PyObject*, PyObject*) { return stub_call_named("event.GetVisibleStartLine", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_event_SetEventHandler(PyObject*, PyObject*) { return stub_call_named("event.SetEventHandler", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_SetInterfaceWindow(PyObject*, PyObject*) { return stub_call_named("event.SetInterfaceWindow", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_SetLeftTimeString(PyObject*, PyObject*) { return stub_call_named("event.SetLeftTimeString", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_QuestButtonClick(PyObject*, PyObject*) { return stub_call_named("event.QuestButtonClick", Py_BuildNone()); }
|
|
||||||
PyObject* stub_event_Destroy(PyObject*, PyObject*) { return stub_call_named("event.Destroy", Py_BuildNone()); }
|
|
||||||
PyMethodDef methods_event[] = {
|
|
||||||
{ "RegisterEventSet", stub_event_RegisterEventSet, METH_VARARGS },
|
|
||||||
{ "RegisterEventSetFromString", stub_event_RegisterEventSetFromString, METH_VARARGS },
|
|
||||||
{ "ClearEventSet", stub_event_ClearEventSet, METH_VARARGS },
|
|
||||||
{ "SetRestrictedCount", stub_event_SetRestrictedCount, METH_VARARGS },
|
|
||||||
{ "GetEventSetLocalYPosition", stub_event_GetEventSetLocalYPosition, METH_VARARGS },
|
|
||||||
{ "AddEventSetLocalYPosition", stub_event_AddEventSetLocalYPosition, METH_VARARGS },
|
|
||||||
{ "InsertText", stub_event_InsertText, METH_VARARGS },
|
|
||||||
{ "InsertTextInline", stub_event_InsertTextInline, METH_VARARGS },
|
|
||||||
{ "UpdateEventSet", stub_event_UpdateEventSet, METH_VARARGS },
|
|
||||||
{ "RenderEventSet", stub_event_RenderEventSet, METH_VARARGS },
|
|
||||||
{ "SetEventSetWidth", stub_event_SetEventSetWidth, METH_VARARGS },
|
|
||||||
{ "Skip", stub_event_Skip, METH_VARARGS },
|
|
||||||
{ "IsWait", stub_event_IsWait, METH_VARARGS },
|
|
||||||
{ "EndEventProcess", stub_event_EndEventProcess, METH_VARARGS },
|
|
||||||
{ "SelectAnswer", stub_event_SelectAnswer, METH_VARARGS },
|
|
||||||
{ "GetLineCount", stub_event_GetLineCount, METH_VARARGS },
|
|
||||||
{ "SetVisibleStartLine", stub_event_SetVisibleStartLine, METH_VARARGS },
|
|
||||||
{ "GetVisibleStartLine", stub_event_GetVisibleStartLine, METH_VARARGS },
|
|
||||||
{ "SetEventHandler", stub_event_SetEventHandler, METH_VARARGS },
|
|
||||||
{ "SetInterfaceWindow", stub_event_SetInterfaceWindow, METH_VARARGS },
|
|
||||||
{ "SetLeftTimeString", stub_event_SetLeftTimeString, METH_VARARGS },
|
|
||||||
{ "QuestButtonClick", stub_event_QuestButtonClick, METH_VARARGS },
|
|
||||||
{ "Destroy", stub_event_Destroy, METH_VARARGS },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
// 40250 UserInterface/PythonGameEventManagerModule.cpp: eventMgr export names.
|
|
||||||
PyObject* stub_eventMgr_Update(PyObject*, PyObject*) { return stub_call_named("eventMgr.Update", Py_BuildNone()); }
|
|
||||||
PyMethodDef methods_eventMgr[] = {
|
|
||||||
{ "Update", stub_eventMgr_Update, METH_VARARGS },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
// 40250 UserInterface/PythonGuild.cpp: guild export names.
|
// 40250 UserInterface/PythonGuild.cpp: guild export names.
|
||||||
PyObject* stub_guild_IsGuildEnable(PyObject*, PyObject*) { return stub_call_named("guild.IsGuildEnable", Py_BuildValue("i", 0)); }
|
PyObject* stub_guild_IsGuildEnable(PyObject*, PyObject*) { return stub_call_named("guild.IsGuildEnable", Py_BuildValue("i", 0)); }
|
||||||
PyObject* stub_guild_GuildIDToMarkID(PyObject*, PyObject*) { return stub_call_named("guild.GuildIDToMarkID", Py_BuildValue("i", 0)); }
|
PyObject* stub_guild_GuildIDToMarkID(PyObject*, PyObject*) { return stub_call_named("guild.GuildIDToMarkID", Py_BuildValue("i", 0)); }
|
||||||
@@ -174,20 +115,6 @@ PyMethodDef methods_profiler[] = {
|
|||||||
{ "Pop", stub_profiler_Pop, METH_VARARGS },
|
{ "Pop", stub_profiler_Pop, METH_VARARGS },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
// 40250 UserInterface/PythonQuest.cpp: quest export names.
|
|
||||||
PyObject* stub_quest_GetQuestCount(PyObject*, PyObject*) { return stub_call_named("quest.GetQuestCount", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_quest_GetQuestData(PyObject*, PyObject*) { return stub_call_named("quest.GetQuestData", Py_BuildValue("sisi", "", 0, "", 0)); }
|
|
||||||
PyObject* stub_quest_GetQuestIndex(PyObject*, PyObject*) { return stub_call_named("quest.GetQuestIndex", Py_BuildValue("i", 0)); }
|
|
||||||
PyObject* stub_quest_GetQuestLastTime(PyObject*, PyObject*) { return stub_call_named("quest.GetQuestLastTime", Py_BuildValue("si", "", 0)); }
|
|
||||||
PyObject* stub_quest_Clear(PyObject*, PyObject*) { return stub_call_named("quest.Clear", Py_BuildNone()); }
|
|
||||||
PyMethodDef methods_quest[] = {
|
|
||||||
{ "GetQuestCount", stub_quest_GetQuestCount, METH_VARARGS },
|
|
||||||
{ "GetQuestData", stub_quest_GetQuestData, METH_VARARGS },
|
|
||||||
{ "GetQuestIndex", stub_quest_GetQuestIndex, METH_VARARGS },
|
|
||||||
{ "GetQuestLastTime", stub_quest_GetQuestLastTime, METH_VARARGS },
|
|
||||||
{ "Clear", stub_quest_Clear, METH_VARARGS },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
// 40250 UserInterface/PythonSafeBox.cpp: safebox export names.
|
// 40250 UserInterface/PythonSafeBox.cpp: safebox export names.
|
||||||
PyObject* stub_safebox_GetCurrentSafeboxSize(PyObject*, PyObject*) { return stub_call_named("safebox.GetCurrentSafeboxSize", Py_BuildValue("i", 0)); }
|
PyObject* stub_safebox_GetCurrentSafeboxSize(PyObject*, PyObject*) { return stub_call_named("safebox.GetCurrentSafeboxSize", Py_BuildValue("i", 0)); }
|
||||||
PyObject* stub_safebox_GetItemID(PyObject*, PyObject*) { return stub_call_named("safebox.GetItemID", Py_BuildValue("i", 0)); }
|
PyObject* stub_safebox_GetItemID(PyObject*, PyObject*) { return stub_call_named("safebox.GetItemID", Py_BuildValue("i", 0)); }
|
||||||
@@ -344,16 +271,6 @@ PyMethodDef methods_udp[] = {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void init_2v0_gameplay_stubs() {
|
void init_2v0_gameplay_stubs() {
|
||||||
{
|
|
||||||
PyObject* module = Py_InitModule("event", methods_event);
|
|
||||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
|
||||||
AddStubConstants_event(module);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
PyObject* module = Py_InitModule("eventMgr", methods_eventMgr);
|
|
||||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
|
||||||
AddStubConstants_eventMgr(module);
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
PyObject* module = Py_InitModule("guild", methods_guild);
|
PyObject* module = Py_InitModule("guild", methods_guild);
|
||||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
||||||
@@ -369,11 +286,6 @@ void init_2v0_gameplay_stubs() {
|
|||||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
||||||
AddStubConstants_profiler(module);
|
AddStubConstants_profiler(module);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
PyObject* module = Py_InitModule("quest", methods_quest);
|
|
||||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
|
||||||
AddStubConstants_quest(module);
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
PyObject* module = Py_InitModule("safebox", methods_safebox);
|
PyObject* module = Py_InitModule("safebox", methods_safebox);
|
||||||
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
PyModule_AddIntConstant(module, "__port_stub__", 1);
|
||||||
|
|||||||
@@ -400,10 +400,13 @@ bool run_main_script_body(const char* lpCmdLine, std::string* error)
|
|||||||
initTextTail();
|
initTextTail();
|
||||||
initnet();
|
initnet();
|
||||||
initMiniMap();
|
initMiniMap();
|
||||||
|
initEvent();
|
||||||
initeffect();
|
initeffect();
|
||||||
initfly();
|
initfly();
|
||||||
|
initeventmgr();
|
||||||
initshop();
|
initshop();
|
||||||
initskill();
|
initskill();
|
||||||
|
initquest();
|
||||||
initBackground();
|
initBackground();
|
||||||
initServerStateChecker();
|
initServerStateChecker();
|
||||||
init_2v0_gameplay_stubs();
|
init_2v0_gameplay_stubs();
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
// Stand-in for the 40250 logic unit UserInterface/PythonEventManager.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/PythonEventManager.h"
|
|
||||||
|
|
||||||
#include "../../PlatformStub.h"
|
|
||||||
|
|
||||||
CPythonEventManager::CPythonEventManager()
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
CPythonEventManager::~CPythonEventManager()
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonEventManager::RegisterEventSetFromString(const std::string &) -> int
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
return mt_platform_stub_return<int>();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonEventManager::SetVisibleLineCount(int, int) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
// Stand-in for the 40250 logic unit UserInterface/PythonQuest.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/PythonQuest.h"
|
|
||||||
|
|
||||||
#include "../../PlatformStub.h"
|
|
||||||
|
|
||||||
CPythonQuest::CPythonQuest()
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
CPythonQuest::~CPythonQuest()
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::RegisterQuestInstance(const SQuestInstance &) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::DeleteQuestInstance(DWORD) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::IsQuest(DWORD) -> bool
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
return mt_platform_stub_return<bool>();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::MakeQuest(DWORD) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::SetQuestTitle(DWORD, const char *) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::SetQuestClockName(DWORD, const char *) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::SetQuestCounterName(DWORD, const char *) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::SetQuestClockValue(DWORD, int) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::SetQuestCounterValue(DWORD, int) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPythonQuest::SetQuestIconFileName(DWORD, const char *) -> void
|
|
||||||
{
|
|
||||||
MT_PLATFORM_STUB();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,443 @@
|
|||||||
|
#include "StdAfx.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
using namespace script;
|
||||||
|
|
||||||
|
#define ishan(ch) (((ch) & 0xE0) > 0x90)
|
||||||
|
#define isnhspace(ch) (!ishan(ch) && isspace(ch))
|
||||||
|
|
||||||
|
|
||||||
|
extern DWORD GetDefaultCodePage();
|
||||||
|
|
||||||
|
const char* LocaleString_FindChar(const char* base, int len, char test)
|
||||||
|
{
|
||||||
|
if (!base)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
DWORD codePage = GetDefaultCodePage();
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < len)
|
||||||
|
{
|
||||||
|
const char* cur = base + pos;
|
||||||
|
const char* next = CharNextExA(codePage, cur, 0);
|
||||||
|
int cur_len = next - cur;
|
||||||
|
if (cur_len > 1)
|
||||||
|
{
|
||||||
|
pos += cur_len;
|
||||||
|
}
|
||||||
|
else if (1 == cur_len)
|
||||||
|
{
|
||||||
|
if (*cur == test)
|
||||||
|
return cur;
|
||||||
|
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LocaleString_RightTrim(char* base, int len)
|
||||||
|
{
|
||||||
|
DWORD codePage = GetDefaultCodePage();
|
||||||
|
|
||||||
|
int pos = len;
|
||||||
|
|
||||||
|
while (pos > 0)
|
||||||
|
{
|
||||||
|
char* cur = base + pos;
|
||||||
|
char* prev = CharPrevExA(codePage, base, cur , 0);
|
||||||
|
|
||||||
|
int prev_len = cur - prev;
|
||||||
|
if (prev_len != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!isspace((unsigned char) *prev) && *prev != '\n' && *prev != '\r')
|
||||||
|
break;
|
||||||
|
|
||||||
|
*prev = '\0';
|
||||||
|
|
||||||
|
pos -= prev_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos > 0)
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocaleString_RightTrim(char* base)
|
||||||
|
{
|
||||||
|
LocaleString_RightTrim(base, strlen(base));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OLD_rtrim(char* base)
|
||||||
|
{
|
||||||
|
if (!base)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DWORD codePage = GetDefaultCodePage();
|
||||||
|
|
||||||
|
if (949 == codePage || 936 == codePage)
|
||||||
|
{
|
||||||
|
char* end = base + strlen(base) - 1;
|
||||||
|
|
||||||
|
while (end != base)
|
||||||
|
{
|
||||||
|
if (!isnhspace((unsigned char) *end) && *end != '\n' && *end != '\r' || (end!=base && *((unsigned char*)end-1)>0xa0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
end = CharPrevExA(codePage, base, end, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char* end = base + strlen(base);
|
||||||
|
|
||||||
|
while (end != base)
|
||||||
|
{
|
||||||
|
char* prev = CharPrevExA(codePage, base, end, 0);
|
||||||
|
|
||||||
|
int prev_len = end - prev;
|
||||||
|
if (prev_len != 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!isspace((unsigned char) *prev) && *prev != '\n' && *prev != '\r')
|
||||||
|
break;
|
||||||
|
|
||||||
|
*prev = '\0';
|
||||||
|
|
||||||
|
end = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* LocaleString_Skip(DWORD codePage, const char* cur)
|
||||||
|
{
|
||||||
|
int loopCount = 0;
|
||||||
|
|
||||||
|
while (*cur)
|
||||||
|
{
|
||||||
|
if (++loopCount > 9216)
|
||||||
|
{
|
||||||
|
TraceError("Infinite loop in LocaleString_Skip [%s]", cur);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* next = CharNextExA(codePage, cur, 0);
|
||||||
|
int cur_len = next - cur;
|
||||||
|
if (cur_len > 1)
|
||||||
|
{
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
else if (1 == cur_len)
|
||||||
|
{
|
||||||
|
if (!isspace((unsigned char) *cur) && *cur != '\n' && *cur != '\r')
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Group::GetArg(const char *c_arg_base, int arg_len, TArgList & argList)
|
||||||
|
{
|
||||||
|
char szName[32 + 1];
|
||||||
|
char szValue[64 + 1];
|
||||||
|
|
||||||
|
int iNameLen = 0;
|
||||||
|
int iValueLen = 0;
|
||||||
|
int iCharLen = 0;
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
bool isValue = false;
|
||||||
|
|
||||||
|
DWORD codePage = GetDefaultCodePage();
|
||||||
|
|
||||||
|
while (pos < arg_len)
|
||||||
|
{
|
||||||
|
const char* cur = c_arg_base + pos;
|
||||||
|
const char* next = CharNextExA(codePage, cur, 0);
|
||||||
|
iCharLen = next - cur;
|
||||||
|
|
||||||
|
if (iCharLen > 1)
|
||||||
|
{
|
||||||
|
if (isValue)
|
||||||
|
{
|
||||||
|
if (iValueLen >= 64)
|
||||||
|
{
|
||||||
|
TraceError("argument value overflow: must be shorter than 64 letters");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(szValue+iValueLen, cur, iCharLen);
|
||||||
|
iValueLen += iCharLen;
|
||||||
|
szValue[iValueLen] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (iNameLen >= 32)
|
||||||
|
{
|
||||||
|
TraceError("argument name overflow: must be shorter than 32 letters");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(szName+iNameLen, cur, iCharLen);
|
||||||
|
iNameLen += iCharLen;
|
||||||
|
szName[iNameLen] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (iCharLen == 1)
|
||||||
|
{
|
||||||
|
const char c = *cur;
|
||||||
|
if (c == '|')
|
||||||
|
{
|
||||||
|
if (iNameLen == 0)
|
||||||
|
{
|
||||||
|
TraceError("no argument name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValue = false;
|
||||||
|
|
||||||
|
iNameLen = LocaleString_RightTrim(szName, iNameLen);
|
||||||
|
iValueLen = LocaleString_RightTrim(szValue, iValueLen);
|
||||||
|
argList.push_back(TArg(szName, szValue));
|
||||||
|
|
||||||
|
iNameLen = 0;
|
||||||
|
iValueLen = 0;
|
||||||
|
}
|
||||||
|
else if (c == ';')
|
||||||
|
{
|
||||||
|
isValue = true;
|
||||||
|
}
|
||||||
|
// 값이 아니고, 이름이 시작되지 않았을 경우 빈칸은 건너 뛴다.
|
||||||
|
else if (!isValue && iNameLen == 0 && isspace((unsigned char) c))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// 엔터는 건너 뛴다
|
||||||
|
else if (c == '\r' || c == '\n')
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isValue)
|
||||||
|
{
|
||||||
|
if (iValueLen >= 64)
|
||||||
|
{
|
||||||
|
TraceError("argument value overflow: must be shorter than 64 letters");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(szValue+iValueLen, cur, iCharLen);
|
||||||
|
iValueLen += iCharLen;
|
||||||
|
szValue[iValueLen] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (iNameLen >= 32)
|
||||||
|
{
|
||||||
|
TraceError("argument name overflow: must be shorter than 32 letters");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(szName+iNameLen, cur, iCharLen);
|
||||||
|
iNameLen += iCharLen;
|
||||||
|
szName[iNameLen] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += iCharLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iNameLen != 0 && iValueLen != 0)
|
||||||
|
{
|
||||||
|
iNameLen = LocaleString_RightTrim(szName, iNameLen);
|
||||||
|
iValueLen = LocaleString_RightTrim(szValue, iValueLen);
|
||||||
|
argList.push_back(TArg(szName, szValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Group::Create(const std::string & stSource)
|
||||||
|
{
|
||||||
|
m_cmdList.clear();
|
||||||
|
|
||||||
|
if (stSource.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char *str_base = stSource.c_str();
|
||||||
|
if (!str_base || !*str_base)
|
||||||
|
{
|
||||||
|
TraceError("Source file has no content");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int str_len = stSource.length();
|
||||||
|
int str_pos = 0;
|
||||||
|
|
||||||
|
DWORD codePage = GetDefaultCodePage();
|
||||||
|
|
||||||
|
char box_data[1024 + 1];
|
||||||
|
|
||||||
|
static std::string stLetter;
|
||||||
|
|
||||||
|
while (str_pos < str_len)
|
||||||
|
{
|
||||||
|
TCmd cmd;
|
||||||
|
|
||||||
|
const char* word = str_base + str_pos;
|
||||||
|
const char* word_next = CharNextExA(codePage, word, 0);
|
||||||
|
|
||||||
|
int word_len = word_next - word;
|
||||||
|
|
||||||
|
if (word_len > 1)
|
||||||
|
{
|
||||||
|
str_pos += word_len;
|
||||||
|
|
||||||
|
{
|
||||||
|
stLetter.assign(word, word_next);
|
||||||
|
|
||||||
|
cmd.name.assign("LETTER");
|
||||||
|
cmd.argList.push_back(TArg("value", stLetter));
|
||||||
|
|
||||||
|
m_cmdList.push_back(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (word_len == 1)
|
||||||
|
{
|
||||||
|
const char cur = *word;
|
||||||
|
|
||||||
|
if ('[' == cur)
|
||||||
|
{
|
||||||
|
++str_pos;
|
||||||
|
|
||||||
|
const char* box_begin = str_base + str_pos;
|
||||||
|
const char* box_end = LocaleString_FindChar(box_begin, str_len - str_pos, ']');
|
||||||
|
if (!box_end)
|
||||||
|
{
|
||||||
|
TraceError(" !! PARSING ERROR - Syntax Error : %s\n", box_begin);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
str_pos += box_end - box_begin + 1;
|
||||||
|
|
||||||
|
|
||||||
|
int data_len = 0;
|
||||||
|
{
|
||||||
|
const char* data_begin = LocaleString_Skip(codePage, box_begin);
|
||||||
|
const char* data_end = box_end;
|
||||||
|
data_len = data_end - data_begin;
|
||||||
|
if (data_len >= 1024)
|
||||||
|
{
|
||||||
|
TraceError(" !! PARSING ERROR - Buffer Overflow : %d, %s\n", data_len, str_base);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(box_data, data_begin, data_len);
|
||||||
|
box_data[data_len] = '\0';
|
||||||
|
|
||||||
|
data_len = LocaleString_RightTrim(box_data, data_len); // 오른쪽 빈칸 자르기
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char* space = LocaleString_FindChar(box_data, data_len, ' ');
|
||||||
|
if (space) // 인자가 있음
|
||||||
|
{
|
||||||
|
int name_len = space - box_data;
|
||||||
|
cmd.name.assign(box_data, name_len);
|
||||||
|
|
||||||
|
const char* space_next = CharNextExA(codePage, space, 0);
|
||||||
|
const char* arg = LocaleString_Skip(codePage, space_next);
|
||||||
|
|
||||||
|
int arg_len = data_len - (arg - box_data);
|
||||||
|
|
||||||
|
if (!GetArg(arg, arg_len, cmd.argList))
|
||||||
|
{
|
||||||
|
TraceError(" !! PARSING ERROR - Unknown Arguments : %d, %s\n", arg_len, arg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // 인자가 없으므로 모든 스트링이 명령어다.
|
||||||
|
{
|
||||||
|
cmd.name.assign(box_data);
|
||||||
|
cmd.argList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cmdList.push_back(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cur == '\r' || cur == '\n')
|
||||||
|
{
|
||||||
|
++str_pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++str_pos;
|
||||||
|
|
||||||
|
{
|
||||||
|
stLetter.assign(1, cur);
|
||||||
|
cmd.name.assign("LETTER");
|
||||||
|
cmd.argList.push_back(TArg("value", stLetter));
|
||||||
|
m_cmdList.push_back(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Group::GetCmd(TCmd & cmd)
|
||||||
|
{
|
||||||
|
if (m_cmdList.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cmd = m_cmdList.front();
|
||||||
|
m_cmdList.pop_front();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Group::ReadCmd(TCmd & cmd)
|
||||||
|
{
|
||||||
|
if (m_cmdList.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cmd = m_cmdList.front();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string & Group::GetError()
|
||||||
|
{
|
||||||
|
return m_stError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::SetError(const char * c_pszError)
|
||||||
|
{
|
||||||
|
m_stError.assign(c_pszError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Group::Group()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Group::~Group()
|
||||||
|
{
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,315 @@
|
|||||||
|
#include "StdAfx.h"
|
||||||
|
#include "PythonEventManager.h"
|
||||||
|
#include "PythonNetworkStream.h"
|
||||||
|
|
||||||
|
PyObject * eventRegisterEventSet(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
char * szFileName;
|
||||||
|
if (!PyTuple_GetString(poArgs, 0, &szFileName))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int iEventIndex = CPythonEventManager::Instance().RegisterEventSet(szFileName);
|
||||||
|
return Py_BuildValue("i", iEventIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventRegisterEventSetFromString(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
char * szEventString;
|
||||||
|
if (!PyTuple_GetString(poArgs, 0, &szEventString))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int iEventIndex = CPythonEventManager::Instance().RegisterEventSetFromString(szEventString);
|
||||||
|
return Py_BuildValue("i", iEventIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventClearEventSet(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().ClearEventSeti(iIndex);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSetRestrictedCount(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int iCount;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 1, &iCount))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().SetRestrictedCount(iIndex, iCount);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventGetEventSetLocalYPosition(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
return Py_BuildValue("i", CPythonEventManager::Instance().GetEventSetLocalYPosition(iIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventAddEventSetLocalYPosition(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
int iPos;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 1, &iPos))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().AddEventSetLocalYPosition(iIndex, iPos);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventInsertText(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
char * szText;
|
||||||
|
if (!PyTuple_GetString(poArgs, 1, &szText))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().InsertText(iIndex, szText);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventInsertTextInline(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
char * szText;
|
||||||
|
if (!PyTuple_GetString(poArgs, 1, &szText))
|
||||||
|
return Py_BuildException();
|
||||||
|
int iXIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 2, &iXIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().InsertText(iIndex, szText,iXIndex);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventUpdateEventSet(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int ix;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 1, &ix))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int iy;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 2, &iy))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().UpdateEventSet(iIndex, ix, -iy);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventRenderEventSet(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().RenderEventSet(iIndex);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSetEventSetWidth(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
int iWidth;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 1, &iWidth))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().SetEventSetWidth(iIndex, iWidth);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSkip(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().Skip(iIndex);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventIsWait(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
return Py_BuildValue("i", CPythonEventManager::Instance().IsWait(iIndex) == true ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventEndEventProcess(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().EndEventProcess(iIndex);
|
||||||
|
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSetEventHandler(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
PyObject * poEventHandler;
|
||||||
|
if (!PyTuple_GetObject(poArgs, 1, &poEventHandler))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().SetEventHandler(iIndex, poEventHandler);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSelectAnswer(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int iAnswer;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 1, &iAnswer))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().SelectAnswer(iIndex, iAnswer);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventGetLineCount(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int iLineCount = CPythonEventManager::Instance().GetLineCount(iIndex);
|
||||||
|
return Py_BuildValue("i", iLineCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSetVisibleStartLine(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
int iStartLine;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 1, &iStartLine))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager::Instance().SetVisibleStartLine(iIndex, iStartLine);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventGetVisibleStartLine(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
return Py_BuildValue("i", CPythonEventManager::Instance().GetVisibleStartLine(iIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventQuestButtonClick(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonNetworkStream::Instance().SendScriptButtonPacket(iIndex);
|
||||||
|
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSetInterfaceWindow(PyObject* poSelf, PyObject* poArgs)
|
||||||
|
{
|
||||||
|
PyObject * pyHandle;
|
||||||
|
if (!PyTuple_GetObject(poArgs, 0, &pyHandle))
|
||||||
|
return Py_BadArgument();
|
||||||
|
|
||||||
|
CPythonEventManager & rpem = CPythonEventManager::Instance();
|
||||||
|
rpem.SetInterfaceWindow(pyHandle);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventSetLeftTimeString(PyObject* poSelf, PyObject* poArgs)
|
||||||
|
{
|
||||||
|
char * szText;
|
||||||
|
if (!PyTuple_GetString(poArgs, 0, &szText))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CPythonEventManager & rpem = CPythonEventManager::Instance();
|
||||||
|
rpem.SetLeftTimeString(szText);
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * eventDestroy(PyObject* poSelf, PyObject* poArgs)
|
||||||
|
{
|
||||||
|
CPythonEventManager & rpem = CPythonEventManager::Instance();
|
||||||
|
rpem.Destroy();
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initEvent()
|
||||||
|
{
|
||||||
|
static PyMethodDef s_methods[] =
|
||||||
|
{
|
||||||
|
{ "RegisterEventSet", eventRegisterEventSet, METH_VARARGS },
|
||||||
|
{ "RegisterEventSetFromString", eventRegisterEventSetFromString, METH_VARARGS },
|
||||||
|
{ "ClearEventSet", eventClearEventSet, METH_VARARGS },
|
||||||
|
|
||||||
|
{ "SetRestrictedCount", eventSetRestrictedCount, METH_VARARGS },
|
||||||
|
|
||||||
|
{ "GetEventSetLocalYPosition", eventGetEventSetLocalYPosition, METH_VARARGS },
|
||||||
|
{ "AddEventSetLocalYPosition", eventAddEventSetLocalYPosition, METH_VARARGS },
|
||||||
|
{ "InsertText", eventInsertText, METH_VARARGS },
|
||||||
|
{ "InsertTextInline", eventInsertTextInline, METH_VARARGS },
|
||||||
|
|
||||||
|
{ "UpdateEventSet", eventUpdateEventSet, METH_VARARGS },
|
||||||
|
{ "RenderEventSet", eventRenderEventSet, METH_VARARGS },
|
||||||
|
{ "SetEventSetWidth", eventSetEventSetWidth, METH_VARARGS },
|
||||||
|
|
||||||
|
{ "Skip", eventSkip, METH_VARARGS },
|
||||||
|
{ "IsWait", eventIsWait, METH_VARARGS },
|
||||||
|
{ "EndEventProcess", eventEndEventProcess, METH_VARARGS },
|
||||||
|
|
||||||
|
{ "SelectAnswer", eventSelectAnswer, METH_VARARGS },
|
||||||
|
{ "GetLineCount", eventGetLineCount, METH_VARARGS },
|
||||||
|
{ "SetVisibleStartLine", eventSetVisibleStartLine, METH_VARARGS },
|
||||||
|
{ "GetVisibleStartLine", eventGetVisibleStartLine, METH_VARARGS },
|
||||||
|
|
||||||
|
{ "SetEventHandler", eventSetEventHandler, METH_VARARGS },
|
||||||
|
{ "SetInterfaceWindow", eventSetInterfaceWindow, METH_VARARGS },
|
||||||
|
{ "SetLeftTimeString", eventSetLeftTimeString, METH_VARARGS },
|
||||||
|
|
||||||
|
{ "QuestButtonClick", eventQuestButtonClick, METH_VARARGS },
|
||||||
|
{ "Destroy", eventDestroy, METH_VARARGS },
|
||||||
|
{ NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
PyObject * poModule = Py_InitModule("event", s_methods);
|
||||||
|
|
||||||
|
PyModule_AddIntConstant(poModule, "BOX_VISIBLE_LINE_COUNT", CPythonEventManager::BOX_VISIBLE_LINE_COUNT);
|
||||||
|
PyModule_AddIntConstant(poModule, "BUTTON_TYPE_NEXT", CPythonEventManager::BUTTON_TYPE_NEXT);
|
||||||
|
PyModule_AddIntConstant(poModule, "BUTTON_TYPE_DONE", CPythonEventManager::BUTTON_TYPE_DONE);
|
||||||
|
PyModule_AddIntConstant(poModule, "BUTTON_TYPE_CANCEL", CPythonEventManager::BUTTON_TYPE_CANCEL);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#include "StdAfx.h"
|
||||||
|
#include "../gamelib/GameEventManager.h"
|
||||||
|
|
||||||
|
PyObject * eventMgrUpdate(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
float fx;
|
||||||
|
if (!PyTuple_GetFloat(poArgs, 0, &fx))
|
||||||
|
return Py_BuildException();
|
||||||
|
float fy;
|
||||||
|
if (!PyTuple_GetFloat(poArgs, 1, &fy))
|
||||||
|
return Py_BuildException();
|
||||||
|
float fz;
|
||||||
|
if (!PyTuple_GetFloat(poArgs, 2, &fz))
|
||||||
|
return Py_BuildException();
|
||||||
|
|
||||||
|
CGameEventManager::Instance().SetCenterPosition(fx, fy, fz);
|
||||||
|
CGameEventManager::Instance().Update();
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initeventmgr()
|
||||||
|
{
|
||||||
|
static PyMethodDef s_methods[] =
|
||||||
|
{
|
||||||
|
{ "Update", eventMgrUpdate, METH_VARARGS },
|
||||||
|
{ NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
Py_InitModule("eventMgr", s_methods);
|
||||||
|
}
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
#include "StdAfx.h"
|
||||||
|
#include "PythonQuest.h"
|
||||||
|
|
||||||
|
void CPythonQuest::RegisterQuestInstance(const SQuestInstance & c_rQuestInstance)
|
||||||
|
{
|
||||||
|
DeleteQuestInstance(c_rQuestInstance.dwIndex);
|
||||||
|
m_QuestInstanceContainer.push_back(c_rQuestInstance);
|
||||||
|
|
||||||
|
/////
|
||||||
|
|
||||||
|
SQuestInstance & rQuestInstance = *m_QuestInstanceContainer.rbegin();
|
||||||
|
rQuestInstance.iStartTime = int(CTimer::Instance().GetCurrentSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FQuestInstanceCompare
|
||||||
|
{
|
||||||
|
DWORD dwSearchIndex;
|
||||||
|
FQuestInstanceCompare(DWORD dwIndex) : dwSearchIndex(dwIndex) {}
|
||||||
|
bool operator () (const CPythonQuest::SQuestInstance & rQuestInstance)
|
||||||
|
{
|
||||||
|
return dwSearchIndex == rQuestInstance.dwIndex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void CPythonQuest::DeleteQuestInstance(DWORD dwIndex)
|
||||||
|
{
|
||||||
|
TQuestInstanceContainer::iterator itor = std::find_if(m_QuestInstanceContainer.begin(), m_QuestInstanceContainer.end(), FQuestInstanceCompare(dwIndex));
|
||||||
|
if (itor == m_QuestInstanceContainer.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_QuestInstanceContainer.erase(itor);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPythonQuest::IsQuest(DWORD dwIndex)
|
||||||
|
{
|
||||||
|
TQuestInstanceContainer::iterator itor = std::find_if(m_QuestInstanceContainer.begin(), m_QuestInstanceContainer.end(), FQuestInstanceCompare(dwIndex));
|
||||||
|
return itor != m_QuestInstanceContainer.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::MakeQuest(DWORD dwIndex)
|
||||||
|
{
|
||||||
|
DeleteQuestInstance(dwIndex);
|
||||||
|
m_QuestInstanceContainer.push_back(SQuestInstance());
|
||||||
|
|
||||||
|
/////
|
||||||
|
|
||||||
|
SQuestInstance & rQuestInstance = *m_QuestInstanceContainer.rbegin();
|
||||||
|
rQuestInstance.dwIndex = dwIndex;
|
||||||
|
rQuestInstance.iStartTime = int(CTimer::Instance().GetCurrentSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::SetQuestTitle(DWORD dwIndex, const char * c_szTitle)
|
||||||
|
{
|
||||||
|
SQuestInstance * pQuestInstance;
|
||||||
|
if (!__GetQuestInstancePtr(dwIndex, &pQuestInstance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pQuestInstance->strTitle = c_szTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::SetQuestClockName(DWORD dwIndex, const char * c_szClockName)
|
||||||
|
{
|
||||||
|
SQuestInstance * pQuestInstance;
|
||||||
|
if (!__GetQuestInstancePtr(dwIndex, &pQuestInstance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pQuestInstance->strClockName = c_szClockName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::SetQuestCounterName(DWORD dwIndex, const char * c_szCounterName)
|
||||||
|
{
|
||||||
|
SQuestInstance * pQuestInstance;
|
||||||
|
if (!__GetQuestInstancePtr(dwIndex, &pQuestInstance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pQuestInstance->strCounterName = c_szCounterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::SetQuestClockValue(DWORD dwIndex, int iClockValue)
|
||||||
|
{
|
||||||
|
SQuestInstance * pQuestInstance;
|
||||||
|
if (!__GetQuestInstancePtr(dwIndex, &pQuestInstance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pQuestInstance->iClockValue = iClockValue;
|
||||||
|
pQuestInstance->iStartTime = int(CTimer::Instance().GetCurrentSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::SetQuestCounterValue(DWORD dwIndex, int iCounterValue)
|
||||||
|
{
|
||||||
|
SQuestInstance * pQuestInstance;
|
||||||
|
if (!__GetQuestInstancePtr(dwIndex, &pQuestInstance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pQuestInstance->iCounterValue = iCounterValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::SetQuestIconFileName(DWORD dwIndex, const char * c_szIconFileName)
|
||||||
|
{
|
||||||
|
SQuestInstance * pQuestInstance;
|
||||||
|
if (!__GetQuestInstancePtr(dwIndex, &pQuestInstance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pQuestInstance->strIconFileName = c_szIconFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CPythonQuest::GetQuestCount()
|
||||||
|
{
|
||||||
|
return m_QuestInstanceContainer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPythonQuest::GetQuestInstancePtr(DWORD dwArrayIndex, SQuestInstance ** ppQuestInstance)
|
||||||
|
{
|
||||||
|
if (dwArrayIndex >= m_QuestInstanceContainer.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*ppQuestInstance = &m_QuestInstanceContainer[dwArrayIndex];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPythonQuest::__GetQuestInstancePtr(DWORD dwQuestIndex, SQuestInstance ** ppQuestInstance)
|
||||||
|
{
|
||||||
|
TQuestInstanceContainer::iterator itor = std::find_if(m_QuestInstanceContainer.begin(), m_QuestInstanceContainer.end(), FQuestInstanceCompare(dwQuestIndex));
|
||||||
|
if (itor == m_QuestInstanceContainer.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*ppQuestInstance = &(*itor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::__Initialize()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
#ifdef _DEBUG
|
||||||
|
for (int i = 0; i < 7; ++i)
|
||||||
|
{
|
||||||
|
SQuestInstance test;
|
||||||
|
test.dwIndex = i;
|
||||||
|
test.strIconFileName = "";
|
||||||
|
test.strTitle = _getf("test%d", i);
|
||||||
|
test.strClockName = "남은 시간";
|
||||||
|
test.strCounterName = "남은 마리수";
|
||||||
|
test.iClockValue = 1000;
|
||||||
|
test.iCounterValue = 1000;
|
||||||
|
test.iStartTime = 0;
|
||||||
|
RegisterQuestInstance(test);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPythonQuest::Clear()
|
||||||
|
{
|
||||||
|
m_QuestInstanceContainer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CPythonQuest::CPythonQuest()
|
||||||
|
{
|
||||||
|
__Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
CPythonQuest::~CPythonQuest()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
PyObject * questGetQuestCount(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
return Py_BuildValue("i", CPythonQuest::Instance().GetQuestCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * questGetQuestData(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BadArgument();
|
||||||
|
|
||||||
|
CPythonQuest::SQuestInstance * pQuestInstance;
|
||||||
|
if (!CPythonQuest::Instance().GetQuestInstancePtr(iIndex, &pQuestInstance))
|
||||||
|
return Py_BuildException("Failed to find quest by index %d", iIndex);
|
||||||
|
|
||||||
|
CGraphicImage * pImage = NULL;
|
||||||
|
if (!pQuestInstance->strIconFileName.empty())
|
||||||
|
{
|
||||||
|
std::string strIconFileName;
|
||||||
|
strIconFileName = "d:/ymir work/ui/game/quest/questicon/";
|
||||||
|
strIconFileName += pQuestInstance->strIconFileName.c_str();
|
||||||
|
pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(strIconFileName.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// 비어있을 경우 디폴트 이미지를 넣는다.
|
||||||
|
std::string strIconFileName = "season1/icon/scroll_open.tga";
|
||||||
|
pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(strIconFileName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue("sisi", pQuestInstance->strTitle.c_str(),
|
||||||
|
pImage,
|
||||||
|
pQuestInstance->strCounterName.c_str(),
|
||||||
|
pQuestInstance->iCounterValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * questGetQuestIndex(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BadArgument();
|
||||||
|
|
||||||
|
CPythonQuest::SQuestInstance * pQuestInstance;
|
||||||
|
if (!CPythonQuest::Instance().GetQuestInstancePtr(iIndex, &pQuestInstance))
|
||||||
|
return Py_BuildException("Failed to find quest by index %d", iIndex);
|
||||||
|
|
||||||
|
return Py_BuildValue("i", pQuestInstance->dwIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * questGetQuestLastTime(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
int iIndex;
|
||||||
|
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
|
||||||
|
return Py_BadArgument();
|
||||||
|
|
||||||
|
CPythonQuest::SQuestInstance * pQuestInstance;
|
||||||
|
if (!CPythonQuest::Instance().GetQuestInstancePtr(iIndex, &pQuestInstance))
|
||||||
|
return Py_BuildException("Failed to find quest by index %d", iIndex);
|
||||||
|
|
||||||
|
int iLastTime = 0;
|
||||||
|
|
||||||
|
if (pQuestInstance->iClockValue >= 0)
|
||||||
|
{
|
||||||
|
iLastTime = (pQuestInstance->iStartTime + pQuestInstance->iClockValue) - int(CTimer::Instance().GetCurrentSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 시간 증가 처리 코드
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// iLastTime = int(CTimer::Instance().GetCurrentSecond()) - pQuestInstance->iStartTime;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return Py_BuildValue("si", pQuestInstance->strClockName.c_str(), iLastTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * questClear(PyObject * poSelf, PyObject * poArgs)
|
||||||
|
{
|
||||||
|
CPythonQuest::Instance().Clear();
|
||||||
|
return Py_BuildNone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initquest()
|
||||||
|
{
|
||||||
|
static PyMethodDef s_methods[] =
|
||||||
|
{
|
||||||
|
{ "GetQuestCount", questGetQuestCount, METH_VARARGS },
|
||||||
|
{ "GetQuestData", questGetQuestData, METH_VARARGS },
|
||||||
|
{ "GetQuestIndex", questGetQuestIndex, METH_VARARGS },
|
||||||
|
{ "GetQuestLastTime", questGetQuestLastTime, METH_VARARGS },
|
||||||
|
{ "Clear", questClear, METH_VARARGS },
|
||||||
|
{ NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
PyObject * poModule = Py_InitModule("quest", s_methods);
|
||||||
|
PyModule_AddIntConstant(poModule, "QUEST_MAX_NUM", 5);
|
||||||
|
}
|
||||||
@@ -46,6 +46,9 @@ enum
|
|||||||
void initpack();
|
void initpack();
|
||||||
void initime();
|
void initime();
|
||||||
void initshop();
|
void initshop();
|
||||||
|
void initquest();
|
||||||
|
void initEvent();
|
||||||
|
void initeventmgr();
|
||||||
void initapp();
|
void initapp();
|
||||||
void initchr();
|
void initchr();
|
||||||
void initchrmgr();
|
void initchrmgr();
|
||||||
|
|||||||
@@ -391,4 +391,35 @@ int WideCharToMultiByte(UINT CodePage, DWORD, LPCWSTR lpWideCharStr, int cchWide
|
|||||||
return int(bytes.size());
|
return int(bytes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL IsDBCSLeadByteEx(UINT CodePage, BYTE TestChar)
|
||||||
|
{
|
||||||
|
switch (CodePage) {
|
||||||
|
case 932: return (TestChar >= 0x81 && TestChar <= 0x9F) || (TestChar >= 0xE0 && TestChar <= 0xFC);
|
||||||
|
case 936:
|
||||||
|
case 949:
|
||||||
|
case 950: return TestChar >= 0x81 && TestChar <= 0xFE;
|
||||||
|
default: return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LPSTR CharNextExA(WORD CodePage, LPCSTR lpCurrentChar, DWORD)
|
||||||
|
{
|
||||||
|
if (!*lpCurrentChar) return const_cast<LPSTR>(lpCurrentChar);
|
||||||
|
if (IsDBCSLeadByteEx(CodePage, BYTE(*lpCurrentChar)) && lpCurrentChar[1]) return const_cast<LPSTR>(lpCurrentChar + 2);
|
||||||
|
return const_cast<LPSTR>(lpCurrentChar + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LPSTR CharPrevExA(WORD CodePage, LPCSTR lpStart, LPCSTR lpCurrentChar, DWORD dwFlags)
|
||||||
|
{
|
||||||
|
// Walk forward from lpStart so a trail byte is never taken for a lead byte.
|
||||||
|
LPCSTR prev = lpStart;
|
||||||
|
for (LPCSTR p = lpStart; p < lpCurrentChar;) {
|
||||||
|
prev = p;
|
||||||
|
LPCSTR next = CharNextExA(CodePage, p, dwFlags);
|
||||||
|
if (next == p) break;
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
return const_cast<LPSTR>(prev);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // !_WIN32
|
#endif // !_WIN32
|
||||||
|
|||||||
@@ -101,4 +101,10 @@ int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int
|
|||||||
int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
|
int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
|
||||||
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
|
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
|
||||||
|
|
||||||
|
// winnls.h / winuser.h DBCS stepping. Lead bytes follow the double-byte code pages 932, 936, 949 and 950;
|
||||||
|
// every other code page (1252, UTF-8, ...) steps one byte at a time, as Windows does for single-byte pages.
|
||||||
|
BOOL IsDBCSLeadByteEx(UINT CodePage, BYTE TestChar);
|
||||||
|
LPSTR CharNextExA(WORD CodePage, LPCSTR lpCurrentChar, DWORD dwFlags);
|
||||||
|
LPSTR CharPrevExA(WORD CodePage, LPCSTR lpStart, LPCSTR lpCurrentChar, DWORD dwFlags);
|
||||||
|
|
||||||
#endif // !_WIN32
|
#endif // !_WIN32
|
||||||
|
|||||||
@@ -603,6 +603,19 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
|||||||
keeper_update.attack_speed = 100;
|
keeper_update.attack_speed = 100;
|
||||||
if (!c.Send(keeper) || !c.Send(keeper_info) || !c.Send(keeper_update))
|
if (!c.Send(keeper) || !c.Send(keeper_info) || !c.Send(keeper_update))
|
||||||
return Fail(name + ": send shopkeeper");
|
return Fail(name + ": send shopkeeper");
|
||||||
|
GCCharacterAdd elder = keeper;
|
||||||
|
elder.vid = kQuestVID;
|
||||||
|
elder.x = kQuestX;
|
||||||
|
elder.y = kQuestY;
|
||||||
|
elder.race = kQuestRace;
|
||||||
|
GCCharAddInfo elder_info = zeroed<GCCharAddInfo>();
|
||||||
|
elder_info.header = HDR_GC_CHAR_ADDITIONAL_INFO;
|
||||||
|
elder_info.vid = kQuestVID;
|
||||||
|
std::strncpy(elder_info.name, "Oldster", sizeof(elder_info.name) - 1);
|
||||||
|
GCCharacterUpdate elder_update = keeper_update;
|
||||||
|
elder_update.vid = kQuestVID;
|
||||||
|
if (!c.Send(elder) || !c.Send(elder_info) || !c.Send(elder_update))
|
||||||
|
return Fail(name + ": send quest NPC");
|
||||||
Event(name + ":burst_sent");
|
Event(name + ":burst_sent");
|
||||||
|
|
||||||
// A ping after the burst proves that GamePhase consumed every packet above and can reply.
|
// A ping after the burst proves that GamePhase consumed every packet above and can reply.
|
||||||
@@ -619,6 +632,20 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
|||||||
bool shopping = false;
|
bool shopping = false;
|
||||||
std::int32_t gold = kStartGold;
|
std::int32_t gold = kStartGold;
|
||||||
std::uint32_t bag0 = 0; // vnum in inventory cell 0 (the fake character starts with an empty bag)
|
std::uint32_t bag0 = 0; // vnum in inventory cell 0 (the fake character starts with an empty bag)
|
||||||
|
int quest_page = 0; // the quest dialogue's last page sent (1 question, 2 next, 3 done)
|
||||||
|
// CQuestManager::SendScript: packet_script {header, size, skin, src_size} and the script text.
|
||||||
|
auto send_script = [&](const std::string& script) {
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
DynHead head;
|
||||||
|
std::uint8_t skin;
|
||||||
|
std::uint16_t src_size;
|
||||||
|
} __attribute__((packed)) head = {{HDR_GC_SCRIPT, static_cast<std::uint16_t>(sizeof(head) + script.size())}, 1 /* QUEST_SKIN_NORMAL */,
|
||||||
|
static_cast<std::uint16_t>(script.size())};
|
||||||
|
std::string bytes(reinterpret_cast<const char*>(&head), sizeof(head));
|
||||||
|
bytes += script;
|
||||||
|
return c.Send(bytes.data(), bytes.size());
|
||||||
|
};
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
std::uint8_t packet[1024] = {};
|
std::uint8_t packet[1024] = {};
|
||||||
@@ -759,6 +786,11 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
|||||||
CGOnClick click;
|
CGOnClick click;
|
||||||
std::memcpy(&click, packet, sizeof(click));
|
std::memcpy(&click, packet, sizeof(click));
|
||||||
Event(name + ":click " + std::to_string(click.vid));
|
Event(name + ":click " + std::to_string(click.vid));
|
||||||
|
// CHARACTER::OnClick → CQuestManager::Click: say(...) then select("Yes", "No") → GotoSelectState.
|
||||||
|
if (click.vid == kQuestVID && !send_script("Greetings, young warrior.[ENTER]Shall I tell you a story?[ENTER][QUESTION 1;Yes|2;No]"))
|
||||||
|
return Fail(name + ": send GC_SCRIPT question");
|
||||||
|
if (click.vid == kQuestVID)
|
||||||
|
quest_page = 1;
|
||||||
if (click.vid == kShopVID && !shopping)
|
if (click.vid == kShopVID && !shopping)
|
||||||
{
|
{
|
||||||
shopping = true;
|
shopping = true;
|
||||||
@@ -780,6 +812,25 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
|||||||
return Fail(name + ": send GC_SHOP START");
|
return Fail(name + ": send GC_SHOP START");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// CInputMain::ScriptAnswer: an answer above 250 is the [NEXT] button (CQuestManager::Resume), the rest pick
|
||||||
|
// a [QUESTION] choice (CQuestManager::Select, 0-based).
|
||||||
|
if (header == HDR_CG_SCRIPT_ANSWER)
|
||||||
|
{
|
||||||
|
const std::uint8_t answer = packet[1];
|
||||||
|
Event(name + ":answer " + std::to_string(answer));
|
||||||
|
if (quest_page == 1 && answer == 0)
|
||||||
|
{
|
||||||
|
quest_page = 2;
|
||||||
|
if (!send_script("Long ago a dragon slept under this village.[ENTER][NEXT]"))
|
||||||
|
return Fail(name + ": send GC_SCRIPT next");
|
||||||
|
}
|
||||||
|
else if (quest_page == 2 && answer > 250)
|
||||||
|
{
|
||||||
|
quest_page = 3;
|
||||||
|
if (!send_script("It sleeps there still.[ENTER][DONE]"))
|
||||||
|
return Fail(name + ": send GC_SCRIPT done");
|
||||||
|
}
|
||||||
|
}
|
||||||
// CInputMain::Shop: END → CShop::RemoveGuest (GC_SHOP END); BUY → CShop::Buy (PointChange(POINT_GOLD), then
|
// CInputMain::Shop: END → CShop::RemoveGuest (GC_SHOP END); BUY → CShop::Buy (PointChange(POINT_GOLD), then
|
||||||
// CItem::AddToCharacter's GC_ITEM_SET into the first empty cell); SELL2 → CShopManager::Sell (the cell empties
|
// CItem::AddToCharacter's GC_ITEM_SET into the first empty cell); SELL2 → CShopManager::Sell (the cell empties
|
||||||
// with the 42-byte header-20 packet, then PointChange(POINT_GOLD)).
|
// with the 42-byte header-20 packet, then PointChange(POINT_GOLD)).
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ public:
|
|||||||
static constexpr std::int32_t kShopX = kMobX + 400, kShopY = kMobY;
|
static constexpr std::int32_t kShopX = kMobX + 400, kShopY = kMobY;
|
||||||
static constexpr std::uint32_t kShopItemVnum = 27001, kShopItemPrice = 50;
|
static constexpr std::uint32_t kShopItemVnum = 27001, kShopItemPrice = 50;
|
||||||
static constexpr std::int32_t kStartGold = 10000, kShopSellPrice = 9;
|
static constexpr std::int32_t kStartGold = 10000, kShopSellPrice = 9;
|
||||||
|
// An old man (npclist 20009) 3 m east of the store whose click runs a quest dialogue the way CQuestManager
|
||||||
|
// sends it: say + select ([QUESTION]), then a [NEXT] page, then a [DONE] page.
|
||||||
|
static constexpr std::uint32_t kQuestVID = 0x00045678, kQuestRace = 20009;
|
||||||
|
static constexpr std::int32_t kQuestX = kShopX + 300, kQuestY = kShopY;
|
||||||
|
|
||||||
~FakeLoginServer();
|
~FakeLoginServer();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user