port: P3-d PythonTextTail + textTail module (1:1 40250)

Copy PythonTextTail.cpp/PythonTextTailModule.cpp verbatim, drop the pending
stand-in and the textTail module stub, register initTextTail() after
initChat() and call CPythonTextTail::Initialize() in Create as 40250 does.
Implement CScreen::ProjectPosition/UnprojectPosition (were stubs) with
D3DXVec3Project/Unproject, and ApplicationStringTable_GetString(DWORD) over
UserInterface.rc's English string table. port.login_flow projects the ground
item's name tail in an ALT frame and picks it back by screen position.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-24 01:10:41 +09:00
co-authored by Claude Opus 5.5
parent 72b19b677d
commit 070a27b2cb
19 changed files with 1874 additions and 211 deletions
+25
View File
@@ -51,6 +51,7 @@
#include "UserInterface/PythonItem.h"
#include "UserInterface/StdAfx.h"
#include "UserInterface/PythonExchange.h"
#include "UserInterface/PythonTextTail.h"
#include "UserInterface/PythonCharacterManager.h"
#include "UserInterface/InstanceBase.h"
#include "UserInterface/PythonBackground.h"
@@ -513,10 +514,34 @@ int main(int argc, char** argv)
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);
// CPythonItem::CreateItem registered the item's name tail (CPythonTextTail::RegisterItemTextTail) next to
// the actor's character tail. Shown and projected, the name is pickable on screen: textTail.Pick is how
// game.GameWindow.OnRender finds the item under the cursor while names are shown.
auto tail_info = [] {
std::string info;
CPythonTextTail::Instance().GetInfo(&info);
return info;
};
std::printf("port_login_flow_test: %s\n", tail_info().c_str());
CHECK(tail_info().find("ItemTail (Map 1,") != std::string::npos);
CHECK(tail_info().find("ChrTail (Map 1,") != std::string::npos);
// Holding ALT (game.GameWindow.ShowName) makes OnRender show every tail in range and project it after
// app.RenderGame; the item tail keeps that screen rect, which is what textTail.Pick tests.
PythonBoot::UIKey(DIK_LMENU, true);
pump_until(0.1, [] { return false; });
PythonBoot::UIKey(DIK_LMENU, false);
int picked = -1, pick_x = 0, pick_y = 0;
for (int y = 0; y < 1200 && picked < 0; y += 2)
for (int x = 0; x < 1600 && picked < 0; x += 2)
if ((picked = CPythonTextTail::Instance().Pick(x, y)) >= 0)
pick_x = x, pick_y = y;
std::printf("port_login_flow_test: item name tail picked at %d %d\n", pick_x, pick_y);
CHECK(picked == (int) FakeLoginServer::kGroundItemVID);
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); }));
CHECK(tail_info().find("ItemTail (Map 0,") != std::string::npos);
}
// Exchange (CPythonExchange + exchange module): net.SendExchangeStartPacket → the fake partner's GC_EXCHANGE