From 39780609547f4d9ee3c1f03b6917e754694514be Mon Sep 17 00:00:00 2001 From: Torhan Bartel Date: Wed, 21 Oct 2026 00:42:55 +0200 Subject: [PATCH] Teleportationstrank: the running campaign's portal list In the Underworld the potion opens the Underworld portals (busy dialog mode 6, as the teleporters there do); g_campaign moved to game/addresses.h. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/teleport-potion.md | 8 ++++++++ src/game/addresses.h | 1 + src/mods/characters.cpp | 3 ++- src/mods/teleportpotion.cpp | 19 +++++++++++++++---- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/docs/teleport-potion.md b/docs/teleport-potion.md index 3b48fba..082f23a 100644 --- a/docs/teleport-potion.md +++ b/docs/teleport-potion.md @@ -32,3 +32,11 @@ one of them. - The potion is used up (flag, RemoveItem, DestroyObject as UseItem does; a stack loses one) only when cCreature::Teleport is called from the portal case while it is pending; closing the window keeps it. + +## Campaign (2026-10-21) + +The potion showed Ancaria's portals in the Underworld. cInterpretSQW::Teleporter +(0x4ae330) chooses the busy dialog's mode by the portal touched: index > 0xd +(Underworld) mode 6, else mode 5, both with the hero's known-portal mask +(+0x578). The potion now chooses by the running campaign, g_campaign +(0x182cdc8, u16: 0 Ancaria, 1 Underworld): mode 6 in the Underworld. diff --git a/src/game/addresses.h b/src/game/addresses.h index 025e158..c3a8475 100644 --- a/src/game/addresses.h +++ b/src/game/addresses.h @@ -28,6 +28,7 @@ constexpr uint32_t WorldToScreen = 0x00623c40; // --- globals ----------------------------------------------------------------- constexpr uint32_t g_dxDriver = 0x00cda99c; // DxDriver7* constexpr uint32_t g_appFlags = 0x0182cdb8; // uint32_t, 0x20000 = inactive +constexpr uint32_t g_campaign = 0x0182cdc8; // uint16_t, the running game's campaign: 0 Ancaria, 1 Underworld constexpr uint32_t g_mouseCursor = 0x00cdbadc; // mouse cursor object*: x +4, y +8 (render pixels) // --- read-only constants ----------------------------------------------------- diff --git a/src/mods/characters.cpp b/src/mods/characters.cpp index 13916b2..eb5c1fc 100644 --- a/src/mods/characters.cpp +++ b/src/mods/characters.cpp @@ -43,6 +43,7 @@ #include +#include "game/addresses.h" #include "game/engine/events.h" #include "game/engine/objects.h" #include "game/ui/draw.h" @@ -102,7 +103,7 @@ constexpr uintptr_t kGameLevel = 0x0182cdc4; // g_gameLevel: the difficulty of // g_campaign (u16): the campaign of the game to start / running. The main menu // sets it by entry (0x712180..), cEngine::Load from the save header; the load // window lists only saves of it (0x71e2b9). -constexpr uintptr_t kCampaign = 0x0182cdc8; +constexpr uintptr_t kCampaign = game::addr::g_campaign; constexpr size_t kSessionSinglePlayer = 0x14; // set to 1 by both constexpr size_t kSessionHeroClass = 0x44; // the start hero's class (Session::SetHeroClass 0x7d7cf0) // cCommand_armaPlay (vtable 0x894ff4): execute (0x755ac0) posts 0x8002 (mode, diff --git a/src/mods/teleportpotion.cpp b/src/mods/teleportpotion.cpp index 9d1ff68..08d69fe 100644 --- a/src/mods/teleportpotion.cpp +++ b/src/mods/teleportpotion.cpp @@ -8,7 +8,8 @@ // whose tooltip names the potion too). Touching a teleporter runs // cInterpretSQW::Teleporter (0x4ae330): it adds the portal to the hero's known ones (bit mask at hero +0x578) and posts // a UI event (type 0x39) to DEFAULT_BUSYDLG with +8 = 2, +0xc = 5 (portal -// mode; 6 for the underworld portals above 0xd) and +0x10 = the mask; +// mode; 6 for the underworld portals above 0xd, the same mask) and +0x10 = +// the mask; // cUI_BusyDlg::HandleEvent (0x720c10) then calls SetMode (0x720180, (mode, a, // b), ret 0xc). Choosing a portal sends the engine an event whose case // (0x619671, "EE_USEPORTAL") teleports the hero with cCreature::Teleport @@ -26,11 +27,13 @@ #include #include +#include "game/addresses.h" #include "game/engine/events.h" #include "game/engine/items.h" #include "game/engine/objects.h" #include "game/engine/orders.h" #include "game/ui/texts.h" +#include "mods/charfile.h" #include "mods/skillslots.h" #include "re/hook.h" #include "re/log.h" @@ -55,7 +58,8 @@ constexpr uint32_t kUiEventBusyDialog = 0x39; constexpr uintptr_t kBusyDialogName = 0x0094d700; // "DEFAULT_BUSYDLG" constexpr uintptr_t kNoSender = 0x00aa24bc; // the game's empty name constexpr uint32_t kBusyDialogSetMode = 2; -constexpr uint32_t kBusyModePortals = 5; +constexpr uint32_t kBusyModePortals = 5; // Ancaria's portals +constexpr uint32_t kBusyModeUnderworldPortals = 6; constexpr size_t kUiEventSize = 0x80; constexpr size_t kUiEventString = 0x68; @@ -65,6 +69,13 @@ constexpr uintptr_t kPortalTeleportReturn = 0x006197c8; constexpr size_t kControlFlags = 0x10; constexpr uint32_t kControlVisible = 1; +// The portal list of the running campaign (user, 2026-10-21: the potion +// showed Ancaria's portals in the Underworld), as the teleporters choose it. +uint32_t PortalMode() { + const uint16_t campaign = *reinterpret_cast(game::addr::g_campaign); + return campaign == characters::kCampaignUnderworld ? kBusyModeUnderworldPortals : kBusyModePortals; +} + // The potion that opened the portal window, until it is used or the window // closes; and the dialog, once it showed for it. uint32_t g_pending = 0; @@ -77,7 +88,7 @@ void OpenPortalWindow(uint32_t knownPortals) { uint32_t, uint32_t, uint32_t); reinterpret_cast(0x00553080)(event, nullptr, kUiEventBusyDialog, reinterpret_cast(kBusyDialogName), reinterpret_cast(kNoSender), - kBusyDialogSetMode, kBusyModePortals, knownPortals, 0, 0, 0); + kBusyDialogSetMode, PortalMode(), knownPortals, 0, 0, 0); game::PostEvent(event); using FreeFn = void(__fastcall*)(void*, void*); reinterpret_cast(0x006e85d0)(event + kUiEventString, nullptr); @@ -162,7 +173,7 @@ void __fastcall BusyDlg_SetMode(void* self, void* edx, uint32_t mode, uint32_t a using namespace mods::teleportpotion; if (g_pending) { g_dialog = static_cast(self); - if (mode != kBusyModePortals) { + if (mode != kBusyModePortals && mode != kBusyModeUnderworldPortals) { g_pending = 0; } }