#pragma once // Every sacred.exe address we use, in one place (Sacred Gold 2.28, image base // 0x400000, no ASLR). Hooks, patches and docs refer to these names; see // docs/function-map.md and docs/widescreen.md for what each one does. #include namespace game::addr { // --- functions --------------------------------------------------------------- constexpr uint32_t Log = 0x0066f1c0; constexpr uint32_t CmdLineHasFlag = 0x00813140; constexpr uint32_t GetMouseClientPos = 0x0066e500; constexpr uint32_t MainWindowProc = 0x008122a0; constexpr uint32_t DxDriver7_SetDisplayMode = 0x00645390; constexpr uint32_t DxDriver7_Flip = 0x00645f70; constexpr uint32_t DxDriver7_BeginScene = 0x00646f50; constexpr uint32_t DxDriver7_LoadingScreen = 0x006469d0; // GDI progress screen, 1024x768 constexpr uint32_t UiManager_ThreadLoop = 0x00756940; // main menu render loop (own thread) constexpr uint32_t Engine_RenderThreadLoop = 0x0060e3f0; // in-game render loop constexpr uint32_t WorldView0_SetupView = 0x00624ae0; constexpr uint32_t WorldView0_SetZoom = 0x00628210; constexpr uint32_t WorldView0_Render = 0x006322b0; 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_mouseCursor = 0x00cdbadc; // mouse cursor object*: x +4, y +8 (render pixels) // --- read-only constants ----------------------------------------------------- constexpr uint32_t kScreenWidthF = 0x0088e6f4; // float 1024.0 constexpr uint32_t kScreenHeightF = 0x00890040; // float 768.0 // Instructions in the world view that read kScreenWidthF / kScreenHeightF as // a memory operand (fmul/fcomp dword ptr [addr]). Redirecting their operand // resizes the world view without touching the UI's uses of the same floats. constexpr uint32_t kViewWidthUsers[] = { 0x0061e5c2, 0x00623c82, 0x00624af2, 0x00628f65, 0x00629294, 0x0062b43a, 0x0062dc32, 0x0062ea2b, 0x0062f30d, 0x00630656, 0x00630f3f, }; constexpr uint32_t kViewHeightUsers[] = { 0x0061e5ec, 0x00623c9c, 0x00624b03, 0x00628f8f, 0x006292bc, 0x0062ea5e, 0x0062f345, 0x0063068a, 0x00630f77, }; // More screen constants the world view reads (float, `f... dword ptr [addr]`). constexpr uint32_t kScreenHalfWidthF = 0x0088e6fc; // float 512.0 (screen centre x) constexpr uint32_t kScreenHalfHeightF = 0x0088e9f0; // float 384.0 (screen centre y) constexpr uint32_t kGroundClipBottomF = 0x0089011c; // float 818.0 (768 + 50) constexpr uint32_t kClipBottom888F = 0x00890124; // float 888.0 (768 + 120) constexpr uint32_t kViewHalfWidthUsers[] = { 0x0062b485, 0x0062dc83, 0x0062e37c, 0x0062e960, 0x0062e989, 0x0062efd8, 0x0062eff2, 0x0063058a, 0x006305b5, 0x00630c08, 0x00630c22, 0x00632032, 0x0063205c, }; constexpr uint32_t kViewHalfHeightUsers[] = { 0x006252fe, 0x00625341, 0x0062b4be, 0x0062dcbe, 0x0062e390, 0x0062e996, 0x0062e9a2, 0x0062f002, 0x0062f00e, 0x006305c2, 0x006305ce, 0x00630c2f, 0x00630c3b, 0x0063206a, 0x0063207a, }; // Outside the world view object, but drawing into the world: the zoom // transform around the screen centre in FUN_0041eaf0. (The 512/1024 in // cGranny::renderComplex case 9 are an effect animation, not the screen.) constexpr uint32_t kCreatureHalfWidthUsers[] = {0x0041ed2b, 0x0041ed35}; constexpr uint32_t kCreatureHalfHeightUsers[] = {0x0041ed41, 0x0041ed4b}; // Precomputed reciprocals of the screen size. 0x623a20 (screen -> view, // inverse of 0x623c40) uses 1/1024 and 1/768. Other users of these constants // are texel/time maths. constexpr uint32_t kScreenInvWidthF = 0x0088e710; // float 1/1024 constexpr uint32_t kScreenInvHeightF = 0x0089005c; // float 1/768 constexpr uint32_t kViewInvWidthUsers[] = {0x00623a49}; constexpr uint32_t kViewInvHeightUsers[] = {0x00623a5f}; constexpr uint32_t kGroundClipBottomUsers[] = {0x0062b464}; constexpr uint32_t kClipBottom888Users[] = {0x0062dc62}; // Screen centre as integer immediates (`add reg, 200h` / `mov reg, 200h` and // the matching 180h), in pairs x, y. constexpr uint32_t kCenterImmediates[][2] = { {0x0062b4c6, 0x0062b4e9}, {0x0062cc40, 0x0062cc50}, {0x0062dcc6, 0x0062dce1}, {0x0062e398, 0x0062e3a9}, {0x0062f967, 0x0062f96d}, {0x0062fe60, 0x0062fe7d}, {0x006315aa, 0x006315b0}, {0x00631aca, 0x00631ae7}, {0x00631c53, 0x00631c70}, // screen positions stored for later (list at +0xce14, up to 1024 entries) {0x0041b184, 0x0041b1a1}, {0x0041b25c, 0x0041b27e}, {0x0041b3f6, 0x0041b3e4}, {0x0041b4d6, 0x0041b4c4}, // floating texts (damage numbers): world -> screen, and back (sub) {0x0041e560, 0x0041e596}, {0x0041eb07, 0x0041eaf7}, }; // cWorldView0 is allocated with `push 970F4h; call operator new` here. constexpr uint32_t kWorldViewAllocSizePush = 0x006101aa; constexpr uint32_t kWorldViewSize = 0x970f4; // cWorldView0's tile draw list: entries of 0x98 bytes at +0x3ff2c, count at // +0x80e3c, room for ~1750 entries and no bounds check (enough for 1024x768 // only). Instructions addressing it by displacement (+0x3ff2c + field): constexpr uint32_t kTileListOffset = 0x3ff2c; constexpr uint32_t kTileListEntrySize = 0x98; constexpr uint32_t kTileListUsers[] = { 0x0062b6d9, 0x0062b6ec, 0x0062b709, 0x0062b730, 0x0062b74b, 0x0062b763, // writer, row renderer FUN_0062b000 0x0062b777, 0x0062b797, 0x0062b7b7, 0x0062b7d7, 0x0062df47, 0x0062e252, // readers (lea base pointer) }; // cWorldView0's ground quad list: 0x90-byte entries at +0xb64 plus a parallel // int array at +0x3e3c4, count at +0x3ff1c, capped at 0x6d5 (1749): beyond // that the last quad is overwritten, so the ground stops drawing. constexpr uint32_t kGroundQuadOffset = 0xb64; constexpr uint32_t kGroundQuadEntrySize = 0x90; constexpr uint32_t kGroundQuadIndexOffset = 0x3e3c4; constexpr uint32_t kGroundQuadCap = 0x6d5; constexpr uint32_t kGroundQuadCapCompare = 0x0062b603; // cmp eax, 6D5h constexpr uint32_t kGroundQuadUsers[] = {0x0062b5e2, 0x0062d58e}; // lea [..+0B64h] / [..+0B7Ch] constexpr uint32_t kGroundQuadIndexUsers[] = {0x0062b5f6, 0x0062d588}; // [..+3E3C4h] // Ortho projection of the 3D models: x -267..267, y -200..200 world units // span the 1024x768 screen (times zoom). Doubles, read with `fmul qword ptr`. constexpr uint32_t kOrthoLeftD = 0x0088ee40; // double -267.0 constexpr uint32_t kOrthoRightD = 0x0088ee48; // double 267.0 constexpr uint32_t kOrthoBottomD = 0x0088ee50; // double -200.0 constexpr uint32_t kOrthoTopD = 0x0088ee58; // double 200.0 // World view instructions `fmul st, qword ptr [kOrtho*D]` (zoomed projection), // four per site, in the order top, bottom, right, left. constexpr uint32_t kOrthoZoomedUsers[][4] = { {0x004b19c1, 0x004b19dc, 0x004b19ed, 0x004b19fe}, // FUN_004b1740, outside the view class {0x00624fdb, 0x00624ff3, 0x00625001, 0x0062500f}, {0x00628355, 0x0062836d, 0x0062837b, 0x00628389}, {0x0062852f, 0x00628547, 0x00628555, 0x00628563}, {0x00628cd7, 0x00628cef, 0x00628d00, 0x00628d11}, }; // Unzoomed projection pushed as immediates: 4 consecutive `push imm32` // (5 bytes each) starting here, in the order top, bottom, right, left. constexpr uint32_t kOrthoPushSequences[] = { 0x0060c1f7, 0x0060da54, 0x00625039, 0x006283b3, 0x0062858d, 0x00628d3b, }; // cGranny::render variants (3D creatures) project in screen pixels with an // ortho camera of x -512..512, y -384..384: 4 consecutive `push imm32` in the // order top (384), bottom (-384), right (512), left (-512). // The last one is cUI_NetGranny (3D items in the HUD, e.g. the belt). It must // be scaled too: game logic (0x44d9f0, camera target) converts world to screen // with whatever projection the device has, which is usually the HUD's, and // uses the (redirected) view width with it. constexpr uint32_t kGrannyOrthoPushSequences[] = {0x0040ebc9, 0x0040f5cf, 0x0040feff, 0x006f1ecb}; // Screen-space labels (object names on Alt, floating texts) are packed without // overlap into a screen-sized area (0x662300), constructed with push 768 / // push 1024: the height push, the width push follows 5 bytes later. constexpr uint32_t kLabelAreaPushes[] = {0x006272f8, 0x0060e940}; // Cinematic letterbox bars (UI frame 0x7587b0): quads from x = 0 to 1024.0f, // stored as immediates. constexpr uint32_t kLetterboxRightImmediates[] = {0x0075895d, 0x007589f0, 0x00758aa5, 0x00758b29}; } // namespace game::addr