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

+2 -1
View File
@@ -43,6 +43,7 @@
#include <windows.h>
#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,
+15 -4
View File
@@ -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 <string>
#include <vector>
#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<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
// 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<CtorFn>(0x00553080)(event, nullptr, kUiEventBusyDialog, reinterpret_cast<const char*>(kBusyDialogName),
reinterpret_cast<const char*>(kNoSender),
kBusyDialogSetMode, kBusyModePortals, knownPortals, 0, 0, 0);
kBusyDialogSetMode, PortalMode(), knownPortals, 0, 0, 0);
game::PostEvent(event);
using FreeFn = void(__fastcall*)(void*, void*);
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;
if (g_pending) {
g_dialog = static_cast<uint8_t*>(self);
if (mode != kBusyModePortals) {
if (mode != kBusyModePortals && mode != kBusyModeUnderworldPortals) {
g_pending = 0;
}
}