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:
1 parent
0ef3cf4bbd
commit
3978060954
4 files changed
+26
-5
No files matched your search
@@ -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.
|
||||||
@@ -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 -----------------------------------------------------
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user