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) <noreply@anthropic.com>
This commit is contained in:
khallaandClaude Opus 5.5 committed 2026-10-21 00:42:55 +02:00
1 parent 0ef3cf4bbd
commit 3978060954
4 files changed
+26 -5

No files matched your search

+8
View File
@@ -32,3 +32,11 @@ one of them.
- The potion is used up (flag, RemoveItem, DestroyObject as UseItem does; a - The potion is used up (flag, RemoveItem, DestroyObject as UseItem does; a
stack loses one) only when cCreature::Teleport is called from the portal stack loses one) only when cCreature::Teleport is called from the portal
case while it is pending; closing the window keeps it. 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.
+1
View File
@@ -28,6 +28,7 @@ constexpr uint32_t WorldToScreen = 0x00623c40;
// --- globals ----------------------------------------------------------------- // --- globals -----------------------------------------------------------------
constexpr uint32_t g_dxDriver = 0x00cda99c; // DxDriver7* constexpr uint32_t g_dxDriver = 0x00cda99c; // DxDriver7*
constexpr uint32_t g_appFlags = 0x0182cdb8; // uint32_t, 0x20000 = inactive 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) constexpr uint32_t g_mouseCursor = 0x00cdbadc; // mouse cursor object*: x +4, y +8 (render pixels)
// --- read-only constants ----------------------------------------------------- // --- read-only constants -----------------------------------------------------
+2 -1
View File
@@ -43,6 +43,7 @@
#include <windows.h> #include <windows.h>
#include "game/addresses.h"
#include "game/engine/events.h" #include "game/engine/events.h"
#include "game/engine/objects.h" #include "game/engine/objects.h"
#include "game/ui/draw.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 // 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 // sets it by entry (0x712180..), cEngine::Load from the save header; the load
// window lists only saves of it (0x71e2b9). // 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 kSessionSinglePlayer = 0x14; // set to 1 by both
constexpr size_t kSessionHeroClass = 0x44; // the start hero's class (Session::SetHeroClass 0x7d7cf0) constexpr size_t kSessionHeroClass = 0x44; // the start hero's class (Session::SetHeroClass 0x7d7cf0)
// cCommand_armaPlay (vtable 0x894ff4): execute (0x755ac0) posts 0x8002 (mode, // cCommand_armaPlay (vtable 0x894ff4): execute (0x755ac0) posts 0x8002 (mode,
+15 -4
View File
@@ -8,7 +8,8 @@
// whose tooltip names the potion too). Touching a teleporter runs // 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 // 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 // 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, // cUI_BusyDlg::HandleEvent (0x720c10) then calls SetMode (0x720180, (mode, a,
// b), ret 0xc). Choosing a portal sends the engine an event whose case // b), ret 0xc). Choosing a portal sends the engine an event whose case
// (0x619671, "EE_USEPORTAL") teleports the hero with cCreature::Teleport // (0x619671, "EE_USEPORTAL") teleports the hero with cCreature::Teleport
@@ -26,11 +27,13 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "game/addresses.h"
#include "game/engine/events.h" #include "game/engine/events.h"
#include "game/engine/items.h" #include "game/engine/items.h"
#include "game/engine/objects.h" #include "game/engine/objects.h"
#include "game/engine/orders.h" #include "game/engine/orders.h"
#include "game/ui/texts.h" #include "game/ui/texts.h"
#include "mods/charfile.h"
#include "mods/skillslots.h" #include "mods/skillslots.h"
#include "re/hook.h" #include "re/hook.h"
#include "re/log.h" #include "re/log.h"
@@ -55,7 +58,8 @@ constexpr uint32_t kUiEventBusyDialog = 0x39;
constexpr uintptr_t kBusyDialogName = 0x0094d700; // "DEFAULT_BUSYDLG" constexpr uintptr_t kBusyDialogName = 0x0094d700; // "DEFAULT_BUSYDLG"
constexpr uintptr_t kNoSender = 0x00aa24bc; // the game's empty name constexpr uintptr_t kNoSender = 0x00aa24bc; // the game's empty name
constexpr uint32_t kBusyDialogSetMode = 2; 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 kUiEventSize = 0x80;
constexpr size_t kUiEventString = 0x68; constexpr size_t kUiEventString = 0x68;
@@ -65,6 +69,13 @@ constexpr uintptr_t kPortalTeleportReturn = 0x006197c8;
constexpr size_t kControlFlags = 0x10; constexpr size_t kControlFlags = 0x10;
constexpr uint32_t kControlVisible = 1; 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<const uint16_t*>(game::addr::g_campaign);
return campaign == characters::kCampaignUnderworld ? kBusyModeUnderworldPortals : kBusyModePortals;
}
// The potion that opened the portal window, until it is used or the window // The potion that opened the portal window, until it is used or the window
// closes; and the dialog, once it showed for it. // closes; and the dialog, once it showed for it.
uint32_t g_pending = 0; uint32_t g_pending = 0;
@@ -77,7 +88,7 @@ void OpenPortalWindow(uint32_t knownPortals) {
uint32_t, uint32_t, uint32_t); uint32_t, uint32_t, uint32_t);
reinterpret_cast<CtorFn>(0x00553080)(event, nullptr, kUiEventBusyDialog, reinterpret_cast<const char*>(kBusyDialogName), reinterpret_cast<CtorFn>(0x00553080)(event, nullptr, kUiEventBusyDialog, reinterpret_cast<const char*>(kBusyDialogName),
reinterpret_cast<const char*>(kNoSender), reinterpret_cast<const char*>(kNoSender),
kBusyDialogSetMode, kBusyModePortals, knownPortals, 0, 0, 0); kBusyDialogSetMode, PortalMode(), knownPortals, 0, 0, 0);
game::PostEvent(event); game::PostEvent(event);
using FreeFn = void(__fastcall*)(void*, void*); using FreeFn = void(__fastcall*)(void*, void*);
reinterpret_cast<FreeFn>(0x006e85d0)(event + kUiEventString, nullptr); reinterpret_cast<FreeFn>(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; using namespace mods::teleportpotion;
if (g_pending) { if (g_pending) {
g_dialog = static_cast<uint8_t*>(self); g_dialog = static_cast<uint8_t*>(self);
if (mode != kBusyModePortals) { if (mode != kBusyModePortals && mode != kBusyModeUnderworldPortals) {
g_pending = 0; g_pending = 0;
} }
} }