From b34a2d4ba8b60b24a4d8647fed57954e46cb2254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Wed, 13 Nov 2019 00:29:16 +0100 Subject: [PATCH] 0.2.0-alpha - Switch to 64-bit executable: - it allows to add support for modern (64-bit) emulators, without relying on WOW64 API, - add support for `BizHawk 2.3.x` emulator - Drop ***Unicode*** support. Not needed in practice, - Replace `sprintf` with the safe version: `sprintf_s`, - Introduce unified custom type system, inspired by the ***Rust*** data-types: `i8, u8, i16, u16, i32, u32, i64, u64, usize, f32, f64`, - Move types and structs definitions into a separate header file `vst_types.h`, - Move global varibales into a separate header file `vst_init.h`, - Update the file storing the current play-time only if needed, instead of writing to it on every loop iteration, - Display proper location message while the game is loading - Tweak/refine some structs: `location`, `player_stats`, `item_info`, - Replace custom `NELEMS` macro with existing `_countof` macro, - Fix indexing bug for the `AccessoriesList` array: first element is at index 97 instead of 0 or 1. --- .gitattributes | 63 +++ .gitignore | 9 +- build-nodebug.bat | 3 +- build.bat | 2 +- includes/vst_console.h | 38 +- includes/vst_debug.h | 13 +- includes/vst_emulation.h | 10 +- includes/vst_equipment.h | 547 ++++++++++------------- includes/vst_init.h | 79 ++++ includes/vst_location.h | 919 +++++++++++++++++++-------------------- includes/vst_player.h | 231 ++++------ includes/vst_process.h | 545 +++++++++++++++-------- includes/vst_resources.h | 4 +- includes/vst_time.h | 97 ++--- includes/vst_translate.h | 51 +-- includes/vst_types.h | 189 ++++++++ includes/vst_utils.h | 18 +- main.c | 136 ++++-- 18 files changed, 1658 insertions(+), 1296 deletions(-) create mode 100644 .gitattributes create mode 100644 includes/vst_init.h create mode 100644 includes/vst_types.h diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index 8de8a3d..c4b3233 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ # Visual Studio Stuff *.sln +*.filters +*.user +*.vcxproj # Files built by Visual Studio *_i.c @@ -99,5 +102,9 @@ debug/ shell.bat setup.bat log.bat +sub.bat +build.bat + +# Misc +changes.md TODO.md -changes.txt diff --git a/build-nodebug.bat b/build-nodebug.bat index dfc5027..eb1e210 100644 --- a/build-nodebug.bat +++ b/build-nodebug.bat @@ -1,2 +1,3 @@ @echo off -cl main.c /Fe: vstrack-release /nologo /link user32.lib psapi.lib \ No newline at end of file +cl main.c /Fe: vstrack-release /nologo /link user32.lib psapi.lib Wtsapi32.lib Advapi32.lib + \ No newline at end of file diff --git a/build.bat b/build.bat index c8ab22c..4c1e0c4 100644 --- a/build.bat +++ b/build.bat @@ -1,2 +1,2 @@ @echo off -cl main.c /Fe: vstrack /nologo /Zi /link user32.lib psapi.lib \ No newline at end of file +cl main.c /Fe: vstrack /nologo /Zi /link user32.lib psapi.lib Wtsapi32.lib Advapi32.lib \ No newline at end of file diff --git a/includes/vst_console.h b/includes/vst_console.h index aaa83d5..5c22246 100644 --- a/includes/vst_console.h +++ b/includes/vst_console.h @@ -4,12 +4,12 @@ COORD coordScreen, coord; CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hStdout, hStdin, hStderr, hBackBuffer; -SHORT conSizeX, conSizeY; -SHORT conMinSizeX, conMinSizeY; -SHORT conMaxSizeX, conMaxSizeY; +i16 conSizeX, conSizeY; +i16 conMinSizeX, conMinSizeY; +i16 conMaxSizeX, conMaxSizeY; CONSOLE_CURSOR_INFO cciOldCursor, cciNewCursor; -TCHAR szBuffer[1024]; -DWORD dwBytesWritten; +char szBuffer[1024]; +u32 BytesWritten; // Double-buffering structs SMALL_RECT srctReadRect; @@ -23,7 +23,7 @@ COORD coordLargestWindowSize; BOOL fSuccess; void * -AllocateBackBuffer(SHORT conMaxSizeX, SHORT conMaxSizeY) +AllocateBackBuffer(i16 conMaxSizeX, i16 conMaxSizeY) { void *chiBuffer = (void *) malloc(sizeof(CHAR_INFO) * conMaxSizeX * conMaxSizeY); @@ -46,19 +46,19 @@ SetConsoleHandles() } void -SetCursorPosition(HANDLE hConsole, DWORD PositionX, DWORD PositionY) +SetCursorPosition(HANDLE hConsole, u32 PositionX, u32 PositionY) { COORD coordPosition; - coordPosition.X = (SHORT) PositionX; - coordPosition.Y = (SHORT) PositionY; + coordPosition.X = (i16) PositionX; + coordPosition.Y = (i16) PositionY; SetConsoleCursorPosition(hConsole, coordPosition); } void -GetConsoleWindowSize(HANDLE hConsole, SHORT *conSizeX, SHORT *conSizeY, - SHORT *conMaxSizeX, SHORT *conMaxSizeY) +GetConsoleWindowSize(HANDLE hConsole, i16 *conSizeX, i16 *conSizeY, + i16 *conMaxSizeX, i16 *conMaxSizeY) { GetConsoleScreenBufferInfo(hConsole, &csbi); @@ -87,7 +87,7 @@ HideConsoleCursor(HANDLE hConsole, CONSOLE_CURSOR_INFO *cciOldCursor, void WriteToBackBuffer(void) { - WriteConsole(hBackBuffer, szBuffer, lstrlen(szBuffer), &dwBytesWritten, NULL); + WriteConsole(hBackBuffer, szBuffer, strlen(szBuffer), &BytesWritten, NULL); } void @@ -117,7 +117,7 @@ CopyFromBackBuffer() if (!fSuccess) { - printf("ReadConsoleOutput failed - (%d)\n", GetLastError()); + fprintf(stderr, "ReadConsoleOutput failed - (%d)\n", GetLastError()); return; } @@ -136,7 +136,7 @@ CopyFromBackBuffer() if (!fSuccess) { - printf("WriteConsoleOutput failed - (%d)\n", GetLastError()); + fprintf(stderr, "WriteConsoleOutput failed - (%d)\n", GetLastError()); return; } } @@ -145,9 +145,9 @@ void cls(HANDLE hConsole) { COORD coordScreen = { 0, 0 }; // home for the cursor - DWORD cCharsWritten; + u32 cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD dwConSize; + u32 dwConSize; // Get the number of character cells in the current buffer. if (!GetConsoleScreenBufferInfo(hConsole, &csbi)) @@ -193,7 +193,7 @@ cls(HANDLE hConsole) void ClearLine() { - sprintf(szBuffer, "%*s\r", conSizeX - 1, ""); + sprintf_s(szBuffer, _countof(szBuffer), "%*s\r", conSizeX - 1, ""); WriteToBackBuffer(); } @@ -201,8 +201,8 @@ void WriteDebugMessage(HANDLE hConsole) { SetCursorPosition(hConsole, 0, conSizeY - 1); - sprintf(szBuffer, "Debug mode is %s. Press \"D\" to toggle.\n", - DEBUG ? "ON" : "OFF"); + sprintf_s(szBuffer, _countof(szBuffer), + "Debug mode is %s. Press \"D\" to toggle.\n", DEBUG ? "ON" : "OFF"); WriteToBackBuffer(); } diff --git a/includes/vst_debug.h b/includes/vst_debug.h index 588b418..de80602 100644 --- a/includes/vst_debug.h +++ b/includes/vst_debug.h @@ -4,19 +4,20 @@ void WriteDebugInfo(void) { - TCHAR szBuffer[1024]; + char szBuffer[1024]; - processBaseAddress = GetModuleDllBase(processID, szModuleName); - sprintf(szBuffer, "processBaseAddress: 0x%08x\n", processBaseAddress); + sprintf_s(szBuffer, _countof(szBuffer), "processBaseAddress: 0x%016llx\n", + processBaseAddress); WriteDebugLog(szBuffer); // Maximum window dimensions - sprintf( - szBuffer, "conMaxSizeX: %i, conMaxSizeY: %i\n", conMaxSizeX, conMaxSizeY); + sprintf_s(szBuffer, _countof(szBuffer), "conMaxSizeX: %i, conMaxSizeY: %i\n", + conMaxSizeX, conMaxSizeY); WriteDebugLog(szBuffer); // Pointer to the back-buffer memory - sprintf(szBuffer, "chiBuffer address: 0x%08p\n", chiBuffer); + sprintf_s( + szBuffer, _countof(szBuffer), "chiBuffer address: 0x%08p\n", chiBuffer); WriteDebugLog(szBuffer); } diff --git a/includes/vst_emulation.h b/includes/vst_emulation.h index 319c2bd..5766c2e 100644 --- a/includes/vst_emulation.h +++ b/includes/vst_emulation.h @@ -1,13 +1,13 @@ #ifndef _VST_EMULATION_H #define _VST_EMULATION_H -// #define PSX_TO_EPSXE_1900 0x7F5A8660 -#define PSX_TO_EPSXE_1900 0x7F9A8660 +// The formula: +// PSX_TO_EMU = PSX_OFFSET - EMU_OFFSET + EMU_BASE_ADDRESS -// #define PSX_TO_EPSXE_1925 0x7F574960 +#define PSX_TO_EPSXE_1900 0x7F9A8660 #define PSX_TO_EPSXE_1925 0x7F974960 - -// #define PSX_TO_EPSXE_2050 0x7EC4DFE0 #define PSX_TO_EPSXE_2050 0x7F57DFE0 +#define PSX_TO_BIZHAWK_2300 0x7FEE2750 +#define PSX_TO_BIZHAWK_2320 0x7FEE2780 #endif diff --git a/includes/vst_equipment.h b/includes/vst_equipment.h index e171022..b6ab4d8 100644 --- a/includes/vst_equipment.h +++ b/includes/vst_equipment.h @@ -1,106 +1,6 @@ #ifndef _VST_EQUIPMENT_H #define _VST_EQUIPMENT_H -// -// Equipped Item Extended Info -// - -/* - * Area shape (bits 0-2): - * 1 spheroid - * 2 upward cylinder - * 3 up-downward cylinder - * 4 downward cone (base is at casting position) - * 5 upward cone (point is at casting position) - * 6 cuboid - * 7 rhombohedron - * Shape angle (bits 3-7): - * increment by 360°/32, - * center is casting position, - * direction is upward, incrementing backward - */ - -typedef struct -{ - UINT8 x; - UINT8 y; - UINT8 z; - - union { - UINT8 ShapeAngleCompound; - struct - { - UINT8 Shape : 3; - UINT8 Angle : 5; - }; - } ShapeAngle; -} range; - -#pragma pack(push, 1) -typedef struct -{ - UINT16 NamesListPosition; - UINT8 ListPosition; - UINT8 WepFileNumber; - UINT8 Category; - - INT8 STR_Bonus; - INT8 INT_Bonus; - INT8 AGL_Bonus; - - UINT16 DamagePoints; - UINT16 DamagePointsMax; - UINT16 PhantomPoints; - UINT16 PhantomPointsMax; - - // Blades only - // (1=MP 2=RISK 3=HP 4=PP 5=nothing) - UINT8 DamageType; - UINT8 StatsCostType; - UINT8 StatsCostValue; - - UINT8 Material; - - INT8 Padding0; - - UINT8 GemSlots; // grips and shields only - UINT8 GemsSpecialEffects; - - UINT8 EqiupmentListIndex; // RAM only - - range Range; // blades only? - - INT8 Padding1; - - // Type (grips only) - UINT8 TypeBlunt; - UINT8 TypeEdged; - UINT8 TypePiercing; - - // Class - INT8 ClassHuman; - INT8 ClassBeast; - INT8 ClassUndead; - INT8 ClassPhantom; - INT8 ClassDragon; - INT8 ClassEvil; - - INT16 Padding2; - - // Affinity - INT8 AffinityPhysical; - INT8 AffinityAir; - INT8 AffinityFire; - INT8 AffinityEarth; - INT8 AffinityWater; - INT8 AffinityLight; - INT8 AffinityDark; - - INT8 Padding3; -} equip_item_info; - -#pragma pack(pop) - enum which_glove { RIGHT_GLOVE, @@ -295,7 +195,9 @@ char *WeaponsList[91] = { "", "Battle Knife", "Scramasax", "Dirk", "Bardysh", "Brandestoc", "Gastraph Bow", "Light Crossbow", "Target Bow", "Windlass", "Cranequin", "Lug Crossbow", "Siege Bow", "Arbalest" }; -char *AccessoriesList[32] = { "", "Rood Necklace", "Rune Earrings", "Lionhead", +// The first element of this array should start at index 97 (0x61), +// so make adjustments in a funcions reading it. +char *AccessoriesList[31] = { "Rood Necklace", "Rune Earrings", "Lionhead", "Rusted Nails", "Sylphid Ring", "Marduk", "Salamander Ring", "Tamulis Tongue", "Gnome Bracelet", "Palolo\'s Ring", "Undine Bracelet", "Talian Ring", "Agrias\'s Balm", "Kadesh Ring", "Agrippa\'s Choker", "Diadra\'s Earring", @@ -344,20 +246,20 @@ char *ItemClass[10] = { "", "Warrior's ", "Knightly ", "Prestigious ", "Brave ", "Warlord ", "Champion ", "Glorious ", "Supreme ", "Divine " }; void -WriteBladeInfo(DWORD processID) +WriteBladeInfo(u32 processID) { - equip_item_info BladeInfo; + item_info BladeInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory( processID, OFFSET_EQUIPPED_WEAPON_BLADE, BytesToRead, &BladeInfo); // Check for out-of-bound indexes - if (BladeInfo.NamesListPosition > 511 || // - BladeInfo.ListPosition > 90 || // - BladeInfo.Category > 10) + if (BladeInfo.NamesListPosition > _countof(ItemNamesList) - 1 || // + BladeInfo.ListPosition > _countof(WeaponsList) - 1 || // + BladeInfo.Category > _countof(WeaponsCategories) - 1) { return; } @@ -388,18 +290,17 @@ WriteBladeInfo(DWORD processID) // Bonuses fprintf(fpBladeInfoExt, "BONUSES\n"); fprintf(fpBladeInfoExt, "========\n"); - fprintf(fpBladeInfoExt, "STR: %3i\n", BladeInfo.STR_Bonus); - fprintf(fpBladeInfoExt, "INT: %3i\n", BladeInfo.INT_Bonus); - fprintf(fpBladeInfoExt, "AGL: %3i\n", BladeInfo.AGL_Bonus); + fprintf(fpBladeInfoExt, "STR: %3i\n", BladeInfo.STR); + fprintf(fpBladeInfoExt, "INT: %3i\n", BladeInfo.INT); + fprintf(fpBladeInfoExt, "AGL: %3i\n", BladeInfo.AGL); fprintf(fpBladeInfoExt, "\n"); // DP & PP fprintf(fpBladeInfoExt, "DURABILITY\n"); fprintf(fpBladeInfoExt, "===========\n"); - fprintf(fpBladeInfoExt, "DP: %3i/%3i\n", (BladeInfo.DamagePoints + 99) / 100, - (BladeInfo.DamagePointsMax + 99) / 100); - fprintf(fpBladeInfoExt, "PP: %3i/%3i\n", BladeInfo.PhantomPoints, - BladeInfo.PhantomPointsMax); + fprintf(fpBladeInfoExt, "DP: %3i/%3i\n", (BladeInfo.DPCur + 99) / 100, + (BladeInfo.DPMax + 99) / 100); + fprintf(fpBladeInfoExt, "PP: %3i/%3i\n", BladeInfo.PPCur, BladeInfo.PPMax); fprintf(fpBladeInfoExt, "\n"); // Misc @@ -441,21 +342,21 @@ WriteBladeInfo(DWORD processID) } void -WriteBladeInfoShort(DWORD processID) +WriteBladeInfoShort(u32 processID) { - equip_item_info BladeInfo; + item_info BladeInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory( processID, OFFSET_EQUIPPED_WEAPON_BLADE, BytesToRead, &BladeInfo); // Check for out-of-bound indexes - if (BladeInfo.NamesListPosition > 511 || // - BladeInfo.ListPosition > 90 || // - BladeInfo.Material > 7 || // - BladeInfo.Category > 10) + if (BladeInfo.NamesListPosition > _countof(ItemNamesList) - 1 || // + BladeInfo.ListPosition > _countof(WeaponsList) - 1 || // + BladeInfo.Material > _countof(CraftingMaterials) - 1 || // + BladeInfo.Category > _countof(WeaponsCategories) - 1) { return; } @@ -500,16 +401,16 @@ WriteBladeInfoShort(DWORD processID) } void -WriteWeaponInfo(DWORD processID) +WriteWeaponInfo(u32 processID) { - equip_item_info BladeInfo; - equip_item_info GripInfo; - equip_item_info Gem1Info; - equip_item_info Gem2Info; - equip_item_info Gem3Info; + item_info BladeInfo; + item_info GripInfo; + item_info Gem1Info; + item_info Gem2Info; + item_info Gem3Info; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory( processID, OFFSET_EQUIPPED_WEAPON_BLADE, BytesToRead, &BladeInfo); @@ -523,14 +424,14 @@ WriteWeaponInfo(DWORD processID) processID, OFFSET_EQUIPPED_WEAPON_GEM_SLOT3, BytesToRead, &Gem3Info); // Check for out-of-bound indexes - if (BladeInfo.NamesListPosition > 511 || // - BladeInfo.ListPosition > 90 || // - BladeInfo.Category > 10 || // - BladeInfo.Material > 7 || // - GripInfo.ListPosition > 31 || // - Gem1Info.ListPosition > 62 || // - Gem2Info.ListPosition > 62 || // - Gem3Info.ListPosition > 62) + if (BladeInfo.NamesListPosition > _countof(ItemNamesList) - 1 || // + BladeInfo.ListPosition > _countof(WeaponsList) - 1 || // + BladeInfo.Category > _countof(WeaponsCategories) - 1 || // + BladeInfo.Material > _countof(CraftingMaterials) - 1 || // + GripInfo.ListPosition > _countof(GripsList) - 1 || // + Gem1Info.ListPosition > _countof(GemsList) - 1 || // + Gem2Info.ListPosition > _countof(GemsList) - 1 || // + Gem3Info.ListPosition > _countof(GemsList) - 1) { return; } @@ -564,30 +465,26 @@ WriteWeaponInfo(DWORD processID) fprintf(fpWeaponInfo, "\n"); // Bonuses - INT16 STR_BonusTotal = BladeInfo.STR_Bonus + GripInfo.STR_Bonus + - Gem1Info.STR_Bonus + Gem2Info.STR_Bonus + - Gem3Info.STR_Bonus; - INT16 INT_BonusTotal = BladeInfo.INT_Bonus + GripInfo.INT_Bonus + - Gem1Info.INT_Bonus + Gem2Info.INT_Bonus + - Gem3Info.INT_Bonus; - INT16 AGL_BonusTotal = BladeInfo.AGL_Bonus + GripInfo.AGL_Bonus + - Gem1Info.AGL_Bonus + Gem2Info.AGL_Bonus + - Gem3Info.AGL_Bonus; + i16 STRTotal = + BladeInfo.STR + GripInfo.STR + Gem1Info.STR + Gem2Info.STR + Gem3Info.STR; + i16 INTTotal = + BladeInfo.INT + GripInfo.INT + Gem1Info.INT + Gem2Info.INT + Gem3Info.INT; + i16 AGLTotal = + BladeInfo.AGL + GripInfo.AGL + Gem1Info.AGL + Gem2Info.AGL + Gem3Info.AGL; fprintf(fpWeaponInfo, "BONUSES\n"); fprintf(fpWeaponInfo, "========\n"); - fprintf(fpWeaponInfo, "STR: %3i\n", STR_BonusTotal); - fprintf(fpWeaponInfo, "INT: %3i\n", INT_BonusTotal); - fprintf(fpWeaponInfo, "AGL: %3i\n", AGL_BonusTotal); + fprintf(fpWeaponInfo, "STR: %3i\n", STRTotal); + fprintf(fpWeaponInfo, "INT: %3i\n", INTTotal); + fprintf(fpWeaponInfo, "AGL: %3i\n", AGLTotal); fprintf(fpWeaponInfo, "\n"); // DP & PP fprintf(fpWeaponInfo, "DURABILITY\n"); fprintf(fpWeaponInfo, "===========\n"); - fprintf(fpWeaponInfo, "DP: %3i/%3i\n", (BladeInfo.DamagePoints + 99) / 100, - (BladeInfo.DamagePointsMax + 99) / 100); - fprintf(fpWeaponInfo, "PP: %3i/%3i\n", BladeInfo.PhantomPoints, - BladeInfo.PhantomPointsMax); + fprintf(fpWeaponInfo, "DP: %3i/%3i\n", (BladeInfo.DPCur + 99) / 100, + (BladeInfo.DPMax + 99) / 100); + fprintf(fpWeaponInfo, "PP: %3i/%3i\n", BladeInfo.PPCur, BladeInfo.PPMax); fprintf(fpWeaponInfo, "\n"); // Misc @@ -605,7 +502,7 @@ WriteWeaponInfo(DWORD processID) fprintf(fpWeaponInfo, "\n"); // Gems - UINT8 GemSlots = GripInfo.GemSlots; + u8 GemSlots = GripInfo.GemSlots; if (GemSlots) { fprintf(fpWeaponInfo, "GEMS\n"); @@ -638,35 +535,35 @@ WriteWeaponInfo(DWORD processID) fprintf(fpWeaponInfo, "\n"); // Class summary - INT16 ClassHumanTotal = BladeInfo.ClassHuman + Gem1Info.ClassHuman + - Gem2Info.ClassHuman + Gem3Info.ClassHuman; - INT16 ClassBeastTotal = BladeInfo.ClassBeast + Gem1Info.ClassBeast + - Gem2Info.ClassBeast + Gem3Info.ClassBeast; - INT16 ClassUndeadTotal = BladeInfo.ClassUndead + Gem1Info.ClassUndead + - Gem2Info.ClassUndead + Gem3Info.ClassUndead; - INT16 ClassPhantomTotal = BladeInfo.ClassPhantom + Gem1Info.ClassPhantom + - Gem2Info.ClassPhantom + Gem3Info.ClassPhantom; - INT16 ClassDragonTotal = BladeInfo.ClassDragon + Gem1Info.ClassDragon + - Gem2Info.ClassDragon + Gem3Info.ClassDragon; - INT16 ClassEvilTotal = BladeInfo.ClassEvil + Gem1Info.ClassEvil + - Gem2Info.ClassEvil + Gem3Info.ClassEvil; + i16 ClassHumanTotal = BladeInfo.ClassHuman + Gem1Info.ClassHuman + + Gem2Info.ClassHuman + Gem3Info.ClassHuman; + i16 ClassBeastTotal = BladeInfo.ClassBeast + Gem1Info.ClassBeast + + Gem2Info.ClassBeast + Gem3Info.ClassBeast; + i16 ClassUndeadTotal = BladeInfo.ClassUndead + Gem1Info.ClassUndead + + Gem2Info.ClassUndead + Gem3Info.ClassUndead; + i16 ClassPhantomTotal = BladeInfo.ClassPhantom + Gem1Info.ClassPhantom + + Gem2Info.ClassPhantom + Gem3Info.ClassPhantom; + i16 ClassDragonTotal = BladeInfo.ClassDragon + Gem1Info.ClassDragon + + Gem2Info.ClassDragon + Gem3Info.ClassDragon; + i16 ClassEvilTotal = BladeInfo.ClassEvil + Gem1Info.ClassEvil + + Gem2Info.ClassEvil + Gem3Info.ClassEvil; // Affinity summary - INT16 AffinityPhysicalTotal = + i16 AffinityPhysicalTotal = BladeInfo.AffinityPhysical + Gem1Info.AffinityPhysical + Gem2Info.AffinityPhysical + Gem3Info.AffinityPhysical; - INT16 AffinityAirTotal = BladeInfo.AffinityAir + Gem1Info.AffinityAir + - Gem2Info.AffinityAir + Gem3Info.AffinityAir; - INT16 AffinityFireTotal = BladeInfo.AffinityFire + Gem1Info.AffinityFire + - Gem2Info.AffinityFire + Gem3Info.AffinityFire; - INT16 AffinityEarthTotal = BladeInfo.AffinityEarth + Gem1Info.AffinityEarth + - Gem2Info.AffinityEarth + Gem3Info.AffinityEarth; - INT16 AffinityWaterTotal = BladeInfo.AffinityWater + Gem1Info.AffinityWater + - Gem2Info.AffinityWater + Gem3Info.AffinityWater; - INT16 AffinityLightTotal = BladeInfo.AffinityLight + Gem1Info.AffinityLight + - Gem2Info.AffinityLight + Gem3Info.AffinityLight; - INT16 AffinityDarkTotal = BladeInfo.AffinityDark + Gem1Info.AffinityDark + - Gem2Info.AffinityDark + Gem3Info.AffinityDark; + i16 AffinityAirTotal = BladeInfo.AffinityAir + Gem1Info.AffinityAir + + Gem2Info.AffinityAir + Gem3Info.AffinityAir; + i16 AffinityFireTotal = BladeInfo.AffinityFire + Gem1Info.AffinityFire + + Gem2Info.AffinityFire + Gem3Info.AffinityFire; + i16 AffinityEarthTotal = BladeInfo.AffinityEarth + Gem1Info.AffinityEarth + + Gem2Info.AffinityEarth + Gem3Info.AffinityEarth; + i16 AffinityWaterTotal = BladeInfo.AffinityWater + Gem1Info.AffinityWater + + Gem2Info.AffinityWater + Gem3Info.AffinityWater; + i16 AffinityLightTotal = BladeInfo.AffinityLight + Gem1Info.AffinityLight + + Gem2Info.AffinityLight + Gem3Info.AffinityLight; + i16 AffinityDarkTotal = BladeInfo.AffinityDark + Gem1Info.AffinityDark + + Gem2Info.AffinityDark + Gem3Info.AffinityDark; // Class fprintf(fpWeaponInfo, "CLASS\n"); @@ -694,15 +591,15 @@ WriteWeaponInfo(DWORD processID) } void -WriteShieldInfo(DWORD processID) +WriteShieldInfo(u32 processID) { - equip_item_info ShieldInfo; - equip_item_info Gem1Info; - equip_item_info Gem2Info; - equip_item_info Gem3Info; + item_info ShieldInfo; + item_info Gem1Info; + item_info Gem2Info; + item_info Gem3Info; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory( processID, OFFSET_EQUIPPED_SHIELD, BytesToRead, &ShieldInfo); @@ -714,11 +611,11 @@ WriteShieldInfo(DWORD processID) processID, OFFSET_EQUIPPED_SHIELD_GEM_SLOT3, BytesToRead, &Gem3Info); // Check for out-of-bound indexes - if (ShieldInfo.ListPosition > 80 || // - ShieldInfo.Material > 7 || // - Gem1Info.ListPosition > 62 || // - Gem2Info.ListPosition > 62 || // - Gem3Info.ListPosition > 62) + if (ShieldInfo.ListPosition > _countof(ArmoursList) - 1 || // + ShieldInfo.Material > _countof(CraftingMaterials) - 1 || // + Gem1Info.ListPosition > _countof(GemsList) - 1 || // + Gem2Info.ListPosition > _countof(GemsList) - 1 || // + Gem3Info.ListPosition > _countof(GemsList) - 1) { return; } @@ -743,34 +640,29 @@ WriteShieldInfo(DWORD processID) fprintf(fpShieldInfoExt, "\n"); // Bonuses - INT16 STR_BonusTotal = ShieldInfo.STR_Bonus + Gem1Info.STR_Bonus + - Gem2Info.STR_Bonus + Gem3Info.STR_Bonus; - INT16 INT_BonusTotal = ShieldInfo.INT_Bonus + Gem1Info.INT_Bonus + - Gem2Info.INT_Bonus + Gem3Info.INT_Bonus; - INT16 AGL_BonusTotal = ShieldInfo.AGL_Bonus + Gem1Info.AGL_Bonus + - Gem2Info.AGL_Bonus + Gem3Info.AGL_Bonus; + i16 STRTotal = ShieldInfo.STR + Gem1Info.STR + Gem2Info.STR + Gem3Info.STR; + i16 INTTotal = ShieldInfo.INT + Gem1Info.INT + Gem2Info.INT + Gem3Info.INT; + i16 AGLTotal = ShieldInfo.AGL + Gem1Info.AGL + Gem2Info.AGL + Gem3Info.AGL; fprintf(fpShieldInfoExt, "BONUSES\n"); fprintf(fpShieldInfoExt, "========\n"); - fprintf(fpShieldInfoExt, "STR: %3i\n", STR_BonusTotal); - fprintf(fpShieldInfoExt, "INT: %3i\n", INT_BonusTotal); - fprintf(fpShieldInfoExt, "AGL: %3i\n", AGL_BonusTotal); + fprintf(fpShieldInfoExt, "STR: %3i\n", STRTotal); + fprintf(fpShieldInfoExt, "INT: %3i\n", INTTotal); + fprintf(fpShieldInfoExt, "AGL: %3i\n", AGLTotal); fprintf(fpShieldInfoExt, "\n"); // DP & PP fprintf(fpShieldInfoExt, "DURABILITY\n"); fprintf(fpShieldInfoExt, "===========\n"); - fprintf(fpShieldInfoExt, "DP: %3i/%3i\n", - (ShieldInfo.DamagePoints + 99) / 100, - (ShieldInfo.DamagePointsMax + 99) / 100); - fprintf(fpShieldInfoExt, "PP: %3i/%3i\n", ShieldInfo.PhantomPoints, - ShieldInfo.PhantomPointsMax); + fprintf(fpShieldInfoExt, "DP: %3i/%3i\n", (ShieldInfo.DPCur + 99) / 100, + (ShieldInfo.DPMax + 99) / 100); + fprintf(fpShieldInfoExt, "PP: %3i/%3i\n", ShieldInfo.PPCur, ShieldInfo.PPMax); fprintf(fpShieldInfoExt, "\n"); // Gems // Gems - UINT8 GemSlots = ShieldInfo.GemSlots; + u8 GemSlots = ShieldInfo.GemSlots; if (GemSlots) { fprintf(fpShieldInfoExt, "GEMS\n"); @@ -800,35 +692,35 @@ WriteShieldInfo(DWORD processID) fprintf(fpShieldInfoExt, "\n"); // Class summary - INT16 ClassHumanTotal = ShieldInfo.ClassHuman + Gem1Info.ClassHuman + - Gem2Info.ClassHuman + Gem3Info.ClassHuman; - INT16 ClassBeastTotal = ShieldInfo.ClassBeast + Gem1Info.ClassBeast + - Gem2Info.ClassBeast + Gem3Info.ClassBeast; - INT16 ClassUndeadTotal = ShieldInfo.ClassUndead + Gem1Info.ClassUndead + - Gem2Info.ClassUndead + Gem3Info.ClassUndead; - INT16 ClassPhantomTotal = ShieldInfo.ClassPhantom + Gem1Info.ClassPhantom + - Gem2Info.ClassPhantom + Gem3Info.ClassPhantom; - INT16 ClassDragonTotal = ShieldInfo.ClassDragon + Gem1Info.ClassDragon + - Gem2Info.ClassDragon + Gem3Info.ClassDragon; - INT16 ClassEvilTotal = ShieldInfo.ClassEvil + Gem1Info.ClassEvil + - Gem2Info.ClassEvil + Gem3Info.ClassEvil; + i16 ClassHumanTotal = ShieldInfo.ClassHuman + Gem1Info.ClassHuman + + Gem2Info.ClassHuman + Gem3Info.ClassHuman; + i16 ClassBeastTotal = ShieldInfo.ClassBeast + Gem1Info.ClassBeast + + Gem2Info.ClassBeast + Gem3Info.ClassBeast; + i16 ClassUndeadTotal = ShieldInfo.ClassUndead + Gem1Info.ClassUndead + + Gem2Info.ClassUndead + Gem3Info.ClassUndead; + i16 ClassPhantomTotal = ShieldInfo.ClassPhantom + Gem1Info.ClassPhantom + + Gem2Info.ClassPhantom + Gem3Info.ClassPhantom; + i16 ClassDragonTotal = ShieldInfo.ClassDragon + Gem1Info.ClassDragon + + Gem2Info.ClassDragon + Gem3Info.ClassDragon; + i16 ClassEvilTotal = ShieldInfo.ClassEvil + Gem1Info.ClassEvil + + Gem2Info.ClassEvil + Gem3Info.ClassEvil; // Affinity summary - INT16 AffinityPhysicalTotal = + i16 AffinityPhysicalTotal = ShieldInfo.AffinityPhysical + Gem1Info.AffinityPhysical + Gem2Info.AffinityPhysical + Gem3Info.AffinityPhysical; - INT16 AffinityAirTotal = ShieldInfo.AffinityAir + Gem1Info.AffinityAir + - Gem2Info.AffinityAir + Gem3Info.AffinityAir; - INT16 AffinityFireTotal = ShieldInfo.AffinityFire + Gem1Info.AffinityFire + - Gem2Info.AffinityFire + Gem3Info.AffinityFire; - INT16 AffinityEarthTotal = ShieldInfo.AffinityEarth + Gem1Info.AffinityEarth + - Gem2Info.AffinityEarth + Gem3Info.AffinityEarth; - INT16 AffinityWaterTotal = ShieldInfo.AffinityWater + Gem1Info.AffinityWater + - Gem2Info.AffinityWater + Gem3Info.AffinityWater; - INT16 AffinityLightTotal = ShieldInfo.AffinityLight + Gem1Info.AffinityLight + - Gem2Info.AffinityLight + Gem3Info.AffinityLight; - INT16 AffinityDarkTotal = ShieldInfo.AffinityDark + Gem1Info.AffinityDark + - Gem2Info.AffinityDark + Gem3Info.AffinityDark; + i16 AffinityAirTotal = ShieldInfo.AffinityAir + Gem1Info.AffinityAir + + Gem2Info.AffinityAir + Gem3Info.AffinityAir; + i16 AffinityFireTotal = ShieldInfo.AffinityFire + Gem1Info.AffinityFire + + Gem2Info.AffinityFire + Gem3Info.AffinityFire; + i16 AffinityEarthTotal = ShieldInfo.AffinityEarth + Gem1Info.AffinityEarth + + Gem2Info.AffinityEarth + Gem3Info.AffinityEarth; + i16 AffinityWaterTotal = ShieldInfo.AffinityWater + Gem1Info.AffinityWater + + Gem2Info.AffinityWater + Gem3Info.AffinityWater; + i16 AffinityLightTotal = ShieldInfo.AffinityLight + Gem1Info.AffinityLight + + Gem2Info.AffinityLight + Gem3Info.AffinityLight; + i16 AffinityDarkTotal = ShieldInfo.AffinityDark + Gem1Info.AffinityDark + + Gem2Info.AffinityDark + Gem3Info.AffinityDark; // Class fprintf(fpShieldInfoExt, "CLASS\n"); @@ -856,19 +748,19 @@ WriteShieldInfo(DWORD processID) } void -WriteShieldInfoShort(DWORD processID) +WriteShieldInfoShort(u32 processID) { - equip_item_info ShieldInfo; + item_info ShieldInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory( processID, OFFSET_EQUIPPED_SHIELD, BytesToRead, &ShieldInfo); // Check for out-of-bound indexes - if (ShieldInfo.ListPosition > 80 || // - ShieldInfo.Material > 7) + if (ShieldInfo.ListPosition > _countof(ArmoursList) - 1 || // + ShieldInfo.Material > _countof(CraftingMaterials) - 1) { return; } @@ -912,30 +804,30 @@ WriteShieldInfoShort(DWORD processID) } void -WriteGloveInfo(DWORD processID, int which_glove) +WriteGloveInfo(u32 processID, u8 which_glove) { - equip_item_info GloveInfo; - SIZE_T offset; + item_info GloveInfo; + usize offset; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; - char FileName[64] = ""; + char szFileName[64] = ""; offset = which_glove ? OFFSET_EQUIPPED_LEFT_ARM : OFFSET_EQUIPPED_RIGHT_ARM; - sprintf(FileName, "game_stats/armor-arm-%s-full.txt", - which_glove ? "left" : "right"); + sprintf_s(szFileName, _countof(szFileName), + "game_stats/armor-arm-%s-full.txt", which_glove ? "left" : "right"); BytesRead = ReadGameMemory(processID, offset, BytesToRead, &GloveInfo); // Check for out-of-bound indexes - if (GloveInfo.ListPosition > 80 || // - GloveInfo.Material > 7) + if (GloveInfo.ListPosition > _countof(ArmoursList) - 1 || // + GloveInfo.Material > _countof(CraftingMaterials) - 1) { return; } - FILE *fpGloveInfoExt = fopen(FileName, "w"); + FILE *fpGloveInfoExt = fopen(szFileName, "w"); // Check if a glove is eqipped. If not, write the warning and skip the rest. if (GloveInfo.ListPosition == 0) @@ -957,16 +849,16 @@ WriteGloveInfo(DWORD processID, int which_glove) // Bonuses fprintf(fpGloveInfoExt, "BONUSES\n"); fprintf(fpGloveInfoExt, "========\n"); - fprintf(fpGloveInfoExt, "STR: %3i\n", GloveInfo.STR_Bonus); - fprintf(fpGloveInfoExt, "INT: %3i\n", GloveInfo.INT_Bonus); - fprintf(fpGloveInfoExt, "AGL: %3i\n", GloveInfo.AGL_Bonus); + fprintf(fpGloveInfoExt, "STR: %3i\n", GloveInfo.STR); + fprintf(fpGloveInfoExt, "INT: %3i\n", GloveInfo.INT); + fprintf(fpGloveInfoExt, "AGL: %3i\n", GloveInfo.AGL); fprintf(fpGloveInfoExt, "\n"); // DP fprintf(fpGloveInfoExt, "DURABILITY\n"); fprintf(fpGloveInfoExt, "===========\n"); - fprintf(fpGloveInfoExt, "DP: %3i/%3i\n", (GloveInfo.DamagePoints + 99) / 100, - (GloveInfo.DamagePointsMax + 99) / 100); + fprintf(fpGloveInfoExt, "DP: %3i/%3i\n", (GloveInfo.DPCur + 99) / 100, + (GloveInfo.DPMax + 99) / 100); fprintf(fpGloveInfoExt, "\n"); // Type @@ -1003,30 +895,30 @@ WriteGloveInfo(DWORD processID, int which_glove) } void -WriteGloveInfoShort(DWORD processID, int which_glove) +WriteGloveInfoShort(u32 processID, u8 which_glove) { - equip_item_info GloveInfo; - SIZE_T offset; + item_info GloveInfo; + usize offset; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; - char FileName[64] = ""; + char szFileName[64] = ""; offset = which_glove ? OFFSET_EQUIPPED_LEFT_ARM : OFFSET_EQUIPPED_RIGHT_ARM; - sprintf(FileName, "game_stats/armor-arm-%s-short.txt", - which_glove ? "left" : "right"); + sprintf_s(szFileName, _countof(szFileName), + "game_stats/armor-arm-%s-short.txt", which_glove ? "left" : "right"); BytesRead = ReadGameMemory(processID, offset, BytesToRead, &GloveInfo); // Check for out-of-bound indexes - if (GloveInfo.ListPosition > 80 || // - GloveInfo.Material > 7) + if (GloveInfo.ListPosition > _countof(ArmoursList) - 1 || // + GloveInfo.Material > _countof(CraftingMaterials) - 1) { return; } - FILE *fpGloveInfoShort = fopen(FileName, "w"); + FILE *fpGloveInfoShort = fopen(szFileName, "w"); // Check if a glove is eqipped. If not, write the warning and skip the rest. if (GloveInfo.ListPosition == 0) @@ -1067,18 +959,18 @@ WriteGloveInfoShort(DWORD processID, int which_glove) } void -WriteHeadArmorInfo(DWORD processID) +WriteHeadArmorInfo(u32 processID) { - equip_item_info HeadInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + item_info HeadInfo; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_EQUIPPED_HEAD, BytesToRead, &HeadInfo); // Check for out-of-bound indexes - if (HeadInfo.ListPosition > 80 || // - HeadInfo.Material > 7) + if (HeadInfo.ListPosition > _countof(ArmoursList) - 1 || // + HeadInfo.Material > _countof(CraftingMaterials) - 1) { return; } @@ -1105,16 +997,16 @@ WriteHeadArmorInfo(DWORD processID) // Bonuses fprintf(fpHeadInfoExt, "BONUSES\n"); fprintf(fpHeadInfoExt, "========\n"); - fprintf(fpHeadInfoExt, "STR: %3i\n", HeadInfo.STR_Bonus); - fprintf(fpHeadInfoExt, "INT: %3i\n", HeadInfo.INT_Bonus); - fprintf(fpHeadInfoExt, "AGL: %3i\n", HeadInfo.AGL_Bonus); + fprintf(fpHeadInfoExt, "STR: %3i\n", HeadInfo.STR); + fprintf(fpHeadInfoExt, "INT: %3i\n", HeadInfo.INT); + fprintf(fpHeadInfoExt, "AGL: %3i\n", HeadInfo.AGL); fprintf(fpHeadInfoExt, "\n"); // DP fprintf(fpHeadInfoExt, "DURABILITY\n"); fprintf(fpHeadInfoExt, "===========\n"); - fprintf(fpHeadInfoExt, "DP: %3i/%3i\n", (HeadInfo.DamagePoints + 99) / 100, - (HeadInfo.DamagePointsMax + 99) / 100); + fprintf(fpHeadInfoExt, "DP: %3i/%3i\n", (HeadInfo.DPCur + 99) / 100, + (HeadInfo.DPMax + 99) / 100); fprintf(fpHeadInfoExt, "\n"); // Type @@ -1151,18 +1043,18 @@ WriteHeadArmorInfo(DWORD processID) } void -WriteHeadArmorInfoShort(DWORD processID) +WriteHeadArmorInfoShort(u32 processID) { - equip_item_info HeadInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + item_info HeadInfo; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_EQUIPPED_HEAD, BytesToRead, &HeadInfo); // Check for out-of-bound indexes - if (HeadInfo.ListPosition > 80 || // - HeadInfo.Material > 7) + if (HeadInfo.ListPosition > _countof(ArmoursList) - 1 || // + HeadInfo.Material > _countof(CraftingMaterials) - 1) { return; } @@ -1207,18 +1099,18 @@ WriteHeadArmorInfoShort(DWORD processID) } void -WriteBodyArmorInfo(DWORD processID) +WriteBodyArmorInfo(u32 processID) { - equip_item_info BodyInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + item_info BodyInfo; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_EQUIPPED_BODY, BytesToRead, &BodyInfo); // Check for out-of-bound indexes - if (BodyInfo.ListPosition > 80 || // - BodyInfo.Material > 7) + if (BodyInfo.ListPosition > _countof(ArmoursList) - 1 || // + BodyInfo.Material > _countof(CraftingMaterials) - 1) { return; } @@ -1246,16 +1138,16 @@ WriteBodyArmorInfo(DWORD processID) // Bonuses fprintf(fpBodyInfoExt, "BONUSES\n"); fprintf(fpBodyInfoExt, "========\n"); - fprintf(fpBodyInfoExt, "STR: %3i\n", BodyInfo.STR_Bonus); - fprintf(fpBodyInfoExt, "INT: %3i\n", BodyInfo.INT_Bonus); - fprintf(fpBodyInfoExt, "AGL: %3i\n", BodyInfo.AGL_Bonus); + fprintf(fpBodyInfoExt, "STR: %3i\n", BodyInfo.STR); + fprintf(fpBodyInfoExt, "INT: %3i\n", BodyInfo.INT); + fprintf(fpBodyInfoExt, "AGL: %3i\n", BodyInfo.AGL); fprintf(fpBodyInfoExt, "\n"); // DP fprintf(fpBodyInfoExt, "DURABILITY\n"); fprintf(fpBodyInfoExt, "===========\n"); - fprintf(fpBodyInfoExt, "DP: %3i/%3i\n", (BodyInfo.DamagePoints + 99) / 100, - (BodyInfo.DamagePointsMax + 99) / 100); + fprintf(fpBodyInfoExt, "DP: %3i/%3i\n", (BodyInfo.DPCur + 99) / 100, + (BodyInfo.DPMax + 99) / 100); fprintf(fpBodyInfoExt, "\n"); // Type @@ -1292,18 +1184,18 @@ WriteBodyArmorInfo(DWORD processID) } void -WriteBodyArmorInfoShort(DWORD processID) +WriteBodyArmorInfoShort(u32 processID) { - equip_item_info BodyInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + item_info BodyInfo; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_EQUIPPED_BODY, BytesToRead, &BodyInfo); // Check for out-of-bound indexes - if (BodyInfo.ListPosition > 80 || // - BodyInfo.Material > 7) + if (BodyInfo.ListPosition > _countof(ArmoursList) - 1 || // + BodyInfo.Material > _countof(CraftingMaterials) - 1) { return; } @@ -1349,18 +1241,18 @@ WriteBodyArmorInfoShort(DWORD processID) } void -WriteLegsArmorInfo(DWORD processID) +WriteLegsArmorInfo(u32 processID) { - equip_item_info LegsInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + item_info LegsInfo; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_EQUIPPED_LEGS, BytesToRead, &LegsInfo); // Check for out-of-bound indexes - if (LegsInfo.ListPosition > 80 || // - LegsInfo.Material > 7) + if (LegsInfo.ListPosition > _countof(ArmoursList) - 1 || // + LegsInfo.Material > _countof(CraftingMaterials) - 1) { return; } @@ -1387,16 +1279,16 @@ WriteLegsArmorInfo(DWORD processID) // Bonuses fprintf(fpLegsInfoExt, "BONUSES\n"); fprintf(fpLegsInfoExt, "========\n"); - fprintf(fpLegsInfoExt, "STR: %3i\n", LegsInfo.STR_Bonus); - fprintf(fpLegsInfoExt, "INT: %3i\n", LegsInfo.INT_Bonus); - fprintf(fpLegsInfoExt, "AGL: %3i\n", LegsInfo.AGL_Bonus); + fprintf(fpLegsInfoExt, "STR: %3i\n", LegsInfo.STR); + fprintf(fpLegsInfoExt, "INT: %3i\n", LegsInfo.INT); + fprintf(fpLegsInfoExt, "AGL: %3i\n", LegsInfo.AGL); fprintf(fpLegsInfoExt, "\n"); // DP fprintf(fpLegsInfoExt, "DURABILITY\n"); fprintf(fpLegsInfoExt, "===========\n"); - fprintf(fpLegsInfoExt, "DP: %3i/%3i\n", (LegsInfo.DamagePoints + 99) / 100, - (LegsInfo.DamagePointsMax + 99) / 100); + fprintf(fpLegsInfoExt, "DP: %3i/%3i\n", (LegsInfo.DPCur + 99) / 100, + (LegsInfo.DPMax + 99) / 100); fprintf(fpLegsInfoExt, "\n"); // Type @@ -1433,18 +1325,18 @@ WriteLegsArmorInfo(DWORD processID) } void -WriteLegsArmorInfoShort(DWORD processID) +WriteLegsArmorInfoShort(u32 processID) { - equip_item_info LegsInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + item_info LegsInfo; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_EQUIPPED_LEGS, BytesToRead, &LegsInfo); // Check for out-of-bound indexes - if (LegsInfo.ListPosition > 80 || // - LegsInfo.Material > 7) + if (LegsInfo.ListPosition > _countof(ArmoursList) - 1 || // + LegsInfo.Material > _countof(CraftingMaterials) - 1) { return; } @@ -1489,17 +1381,19 @@ WriteLegsArmorInfoShort(DWORD processID) } void -WriteNecklaceInfo(DWORD processID) +WriteNecklaceInfo(u32 processID) { - equip_item_info NeckInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + u8 ListPositionMax = 127; + u8 ListPositionMin = (ListPositionMax - (_countof(AccessoriesList) - 1)); + item_info NeckInfo; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_EQUIPPED_NECK, BytesToRead, &NeckInfo); // Check for out-of-bound indexes - if (NeckInfo.NamesListPosition > 31) + if (NeckInfo.NamesListPosition > _countof(ItemNamesList)) { return; } @@ -1508,7 +1402,8 @@ WriteNecklaceInfo(DWORD processID) // Check if a necklace is eqipped. // If not, write the warning and skip the rest. - if (NeckInfo.ListPosition == 0) + if (NeckInfo.ListPosition < ListPositionMin || + NeckInfo.ListPosition > ListPositionMax) { fprintf(fpNeckInfoExt, "No necklace equipped!\n"); fclose(fpNeckInfoExt); @@ -1525,9 +1420,9 @@ WriteNecklaceInfo(DWORD processID) // Bonuses fprintf(fpNeckInfoExt, "BONUSES\n"); fprintf(fpNeckInfoExt, "========\n"); - fprintf(fpNeckInfoExt, "STR: %3i\n", NeckInfo.STR_Bonus); - fprintf(fpNeckInfoExt, "INT: %3i\n", NeckInfo.INT_Bonus); - fprintf(fpNeckInfoExt, "AGL: %3i\n", NeckInfo.AGL_Bonus); + fprintf(fpNeckInfoExt, "STR: %3i\n", NeckInfo.STR); + fprintf(fpNeckInfoExt, "INT: %3i\n", NeckInfo.INT); + fprintf(fpNeckInfoExt, "AGL: %3i\n", NeckInfo.AGL); fprintf(fpNeckInfoExt, "\n"); // Type diff --git a/includes/vst_init.h b/includes/vst_init.h new file mode 100644 index 0000000..1a221ce --- /dev/null +++ b/includes/vst_init.h @@ -0,0 +1,79 @@ +#ifndef _VST_INIT_H +#define _VST_INIT_H + +// Global Variables + +// Diagnostics +BOOL DEBUG = FALSE; + +// Process +u32 processID; +u32 processVersion; +u64 processBaseAddress; +u64 PSX_TO_EMU; + +char szModuleName[MAX_PATH]; +char szExeName[MAX_PATH]; + +// In-game data + +// Time +playtime PlayTimeCurrent = { -1 }; +playtime PlayTimeTemp = { -1 }; +playtime PlayTimeRecord = { -1 }; + +// Equipment +item_info BladeInfo; +item_info BladeInfoTemp; + +item_info GripInfo; +item_info GripInfoTemp; + +item_info Gem1Info; +item_info Gem1InfoTemp; + +item_info Gem2Info; +item_info Gem2InfoTemp; + +item_info Gem3Info; +item_info Gem3InfoTemp; + +item_info ShieldInfo; +item_info ShieldInfoTemp; + +item_info GloveLeftInfo; +item_info GloveLeftInfoTemp; + +item_info GloveRightInfo; +item_info GloveRightInfoTemp; + +item_info HeadInfo; +item_info HeadInfoTemp; + +item_info BodyInfo; +item_info BodyInfoTemp; + +item_info LegsInfo; +item_info LegsInfoTemp; + +item_info NeckInfo; +item_info NeckInfoTemp; + +// Player Data +player_stats PlayerStats; +player_stats PlayerStatsTemp; + +status_effects PlayerEffects; +status_effects PlayerEffectsTemp; + +// Location +location Location; +char szAreaName[MAX_PATH]; +char szRoomName[MAX_PATH]; + +// Misc +u16 LastBossHP = 0xff; +BOOL GameOver = FALSE; // set to TRUE when the last boss is dead +char GlobalWeaponName[18] = ""; + +#endif diff --git a/includes/vst_location.h b/includes/vst_location.h index dd0f864..be4beee 100644 --- a/includes/vst_location.h +++ b/includes/vst_location.h @@ -8,461 +8,445 @@ #define OFFSET_LOCATION_AREA_NUMBER 0x800F1AB0 #define OFFSET_LOCATION_ROOM_NUMBER 0x800F1AB1 -#define NELEMS(x) (sizeof(x) / sizeof(x[0])) - typedef struct { - char unsigned AreaNumber; - char unsigned RoomNumber; - TCHAR *AreaName; - TCHAR *RoomName; + u8 AreaNumber; + u8 RoomNumber; + char *AreaName; + char *RoomName; } room; -typedef struct -{ - union { - UINT16 LocationCompound; - struct - { - UINT8 AreaNumber; - UINT8 RoomNumber; - }; - } Location; -} location; - -static location Location; -static TCHAR szAreaName[MAX_PATH]; -static TCHAR szRoomName[MAX_PATH]; - -room Rooms[] = { // - // Wine Cellar - verified - { 9, 1, _T("Wine Cellar"), _T("Entrance to Darkness") }, - { 9, 2, _T("Wine Cellar"), _T("Room of Cheap Red Wine") }, - { 9, 3, _T("Wine Cellar"), _T("Room of Cheap White Wine") }, - { 9, 4, _T("Wine Cellar"), _T("Hall of Struggle") }, - { 9, 5, _T("Wine Cellar"), _T("Smokebarrel Stair") }, - { 9, 6, _T("Wine Cellar"), _T("Wine Guild Hall") }, - { 9, 7, _T("Wine Cellar"), _T("Wine Magnate's Chambers") }, - { 9, 8, _T("Wine Cellar"), _T("Fine Vintage Vault") }, - { 9, 9, _T("Wine Cellar"), _T("Chamber of Fear") }, // ver.1 - { 9, 10, _T("Wine Cellar"), _T("The Reckoning Room") }, - { 9, 11, _T("Wine Cellar"), _T("A Laborer's Thirst") }, - { 9, 12, _T("Wine Cellar"), _T("The Rich Drown in Wine") }, - { 9, 13, _T("Wine Cellar"), _T("Room of Rotten Grapes") }, // ver.1 - { 9, 14, _T("Wine Cellar"), _T("Chamber of Fear") }, // ver.2 - { 9, 16, _T("Wine Cellar"), _T("The Greedy One's Den") }, - { 9, 17, _T("Wine Cellar"), _T("Worker's Breakroom") }, - { 9, 18, _T("Wine Cellar"), _T("Blackmarket of Wines") }, - { 9, 19, _T("Wine Cellar"), _T("Room of Rotten Grapes") }, // ver.2 - { 11, 1, _T("Wine Cellar"), _T("The Hero's Winehall") }, - { 12, 1, _T("Wine Cellar"), _T("The Gallows") }, // ver.1 - { 12, 2, _T("Wine Cellar"), _T("The Gallows") }, // ver.2 - - // Catacombs - verified - { 13, 1, _T("Catacombs"), _T("Hall of Sworn Revenge") }, - { 13, 2, _T("Catacombs"), _T("The Last Blessing") }, - { 13, 3, _T("Catacombs"), _T("The Weeping Corridor") }, - { 13, 4, _T("Catacombs"), _T("Persecution Hall") }, - { 13, 5, _T("Catacombs"), _T("The Lamenting Mother") }, - { 13, 6, _T("Catacombs"), _T("Rodent-Ridden Chamber") }, - { 13, 7, _T("Catacombs"), _T("Shrine to the Martyrs") }, - { 13, 9, _T("Catacombs"), _T("Hall of Dying Hope") }, - { 13, 10, _T("Catacombs"), _T("Bandits' Hideout") }, - { 13, 11, _T("Catacombs"), _T("The Bloody Hallway") }, - { 13, 12, _T("Catacombs"), _T("Faith Overcame Fear") }, - { 13, 13, _T("Catacombs"), _T("The Withered Spring") }, - { 13, 14, _T("Catacombs"), _T("Repent, O ye Sinners") }, - { 13, 15, _T("Catacombs"), _T("The Reaper's Victims") }, - { 13, 16, _T("Catacombs"), _T("The Last Stab of Hope") }, - { 13, 17, _T("Catacombs"), _T("Hallway of Heroes") }, - { 13, 18, _T("Catacombs"), _T("The Lamenting Mother") }, - { 14, 1, _T("Catacombs"), _T("The Beast's Domain") }, - { 42, 1, _T("Catacombs"), _T("Workshop \"Work of Art\"") }, - - // Sanctum - verified - { 15, 1, _T("Sanctum"), _T("Prisoners' Niche") }, - { 15, 2, _T("Sanctum"), _T("Corridor of the Clerics") }, - { 15, 3, _T("Sanctum"), _T("Priests' Confinement") }, - { 15, 4, _T("Sanctum"), _T("Alchemists' Laboratory") }, - { 15, 5, _T("Sanctum"), _T("Theology Classroom") }, - { 15, 6, _T("Sanctum"), _T("Shrine of the Martyrs") }, - { 15, 7, _T("Sanctum"), _T("Advent Ground") }, - { 15, 8, _T("Sanctum"), _T("Passage of the Refugees") }, // ver.1 - { 15, 9, _T("Sanctum"), _T("Passage of the Refugees") }, // ver.2 - { 15, 11, _T("Sanctum"), _T("Stairway to the Light") }, - { 15, 12, _T("Sanctum"), _T("Hallowed Hope") }, - { 15, 13, _T("Sanctum"), _T("The Academia Corridor") }, - { 16, 1, _T("Sanctum"), _T("Hall of Sacrilege") }, - { 17, 1, _T("Sanctum"), _T("The Cleansing Chantry") }, - - // Abandoned Mines B1 - verified - { 50, 1, _T("Abandoned Mines B1"), _T("Dreamers' Entrance") }, - { 50, 2, _T("Abandoned Mines B1"), _T("Miners' Resting Hall") }, - { 50, 3, _T("Abandoned Mines B1"), _T("The Crossing") }, - { 50, 4, _T("Abandoned Mines B1"), _T("Conflict and Accord") }, - { 50, 5, _T("Abandoned Mines B1"), _T("The Suicide King") }, - { 50, 6, _T("Abandoned Mines B1"), _T("The End of the Line") }, - { 50, 7, _T("Abandoned Mines B1"), _T("The Battle's Beginning") }, - { 50, 8, _T("Abandoned Mines B1"), _T("What Lies Ahead?") }, - { 50, 9, _T("Abandoned Mines B1"), _T("The Fruits of Friendship") }, - { 50, 10, _T("Abandoned Mines B1"), _T("The Earthquake's Mark") }, - { 50, 11, _T("Abandoned Mines B1"), _T("Coal Mine Storage") }, - { 50, 12, _T("Abandoned Mines B1"), _T("The Passion of Lovers") }, - { 50, 13, _T("Abandoned Mines B1"), _T("The Hall of Hope") }, - { 50, 14, _T("Abandoned Mines B1"), _T("The Dark Tunnel") }, - { 50, 15, _T("Abandoned Mines B1"), _T("Rust in Peace") }, - { 50, 16, _T("Abandoned Mines B1"), _T("Everwant Passage") }, - { 50, 17, _T("Abandoned Mines B1"), _T("Mining Regrets") }, - { 50, 18, _T("Abandoned Mines B1"), _T("The Smeltry") }, - { 50, 19, _T("Abandoned Mines B1"), _T("Clash of Hyaenas") }, - { 50, 20, _T("Abandoned Mines B1"), _T("Greed Knows No Bounds") }, - { 50, 21, _T("Abandoned Mines B1"), _T("Live Long and Prosper") }, - { 50, 22, _T("Abandoned Mines B1"), _T("Pray to the Mineral Gods") }, - { 50, 23, _T("Abandoned Mines B1"), _T("Traitor's Parting") }, - { 50, 24, _T("Abandoned Mines B1"), _T("Escapeway") }, - - // Abandoned Mines B2 - verified - { 51, 1, _T("Abandoned Mines B2"), _T("Gambler's Passage") }, - { 51, 2, _T("Abandoned Mines B2"), _T("Treaty Room") }, - { 51, 3, _T("Abandoned Mines B2"), _T("The Miner's End") }, - { 51, 4, _T("Abandoned Mines B2"), _T("Work, Then Die") }, - { 51, 5, _T("Abandoned Mines B2"), _T("Bandits' Hollow") }, - { 51, 6, _T("Abandoned Mines B2"), _T("Delusions of Happiness") }, - { 51, 7, _T("Abandoned Mines B2"), _T("Dining in Darkness") }, - { 51, 8, _T("Abandoned Mines B2"), _T("Subtellurian Horrors") }, - { 51, 9, _T("Abandoned Mines B2"), _T("Hidden Resources") }, - { 51, 10, _T("Abandoned Mines B2"), _T("Way of Lost Children") }, - { 51, 11, _T("Abandoned Mines B2"), _T("Hall of the Empty Sconce") }, - { 51, 12, _T("Abandoned Mines B2"), _T("Acolyte's Burial Vault") }, - { 51, 13, _T("Abandoned Mines B2"), _T("Hall of Contemplation") }, - { 51, 14, _T("Abandoned Mines B2"), _T("The Abandoned Catspaw") }, - { 51, 15, _T("Abandoned Mines B2"), _T("Tomb of the Reborn") }, - { 51, 16, _T("Abandoned Mines B2"), _T("The Fallen Bricklayer") }, - { 51, 17, _T("Abandoned Mines B2"), _T("Crossing of Blood") }, - { 51, 18, _T("Abandoned Mines B2"), _T("Fool's Gold, Fool's Loss") }, - { 51, 19, _T("Abandoned Mines B2"), _T("Cry of the Beast") }, - { 51, 20, _T("Abandoned Mines B2"), _T("Senses Lost") }, - { 51, 21, _T("Abandoned Mines B2"), _T("Desire's Passage") }, - { 51, 22, _T("Abandoned Mines B2"), _T("Kilroy Was Here") }, - { 51, 23, _T("Abandoned Mines B2"), _T("Suicidal Desires") }, - { 51, 24, _T("Abandoned Mines B2"), _T("The Ore of Legend") }, - { 51, 25, _T("Abandoned Mines B2"), _T("Lambs to the Slaughter") }, - { 51, 26, _T("Abandoned Mines B2"), _T("A Wager of Noble Gold") }, - { 51, 27, _T("Abandoned Mines B2"), _T("The Lunatic Veins") }, - { 51, 28, _T("Abandoned Mines B2"), _T("Corridor of Shade") }, - { 51, 29, _T("Abandoned Mines B2"), _T("Revelation Shaft") }, - - // Limestone Quarry - verified - { 53, 1, _T("Limestone Quarry"), _T("Dark Abhors Light") }, - { 53, 2, _T("Limestone Quarry"), _T("Dream of the Holy Land") }, - { 53, 3, _T("Limestone Quarry"), _T("The Ore Road") }, - { 53, 4, _T("Limestone Quarry"), _T("Atone for Eternity") }, - { 53, 5, _T("Limestone Quarry"), _T("The Air Stirs") }, - { 53, 6, _T("Limestone Quarry"), _T("Bonds of Friendship") }, - { 53, 7, _T("Limestone Quarry"), _T("Stair to Sanctuary") }, - { 53, 8, _T("Limestone Quarry"), _T("The Fallen Hall") }, - { 53, 9, _T("Limestone Quarry"), _T("The Rotten Core") }, - { 53, 10, _T("Limestone Quarry"), _T("Bacchus is Cheap") }, - { 53, 11, _T("Limestone Quarry"), _T("Screams of the Wounded") }, - { 53, 12, _T("Limestone Quarry"), _T("The Ore-Bearers") }, - { 53, 13, _T("Limestone Quarry"), _T("The Dreamer's Climb") }, - { 53, 14, _T("Limestone Quarry"), _T("Sinner's Sustenence") }, - { 53, 15, _T("Limestone Quarry"), _T("The Timely Dew of Sleep") }, - { 53, 16, _T("Limestone Quarry"), _T("Companions in Arms") }, - { 53, 17, _T("Limestone Quarry"), _T("The Auction Block") }, - { 53, 18, _T("Limestone Quarry"), _T("Ascension") }, - { 53, 19, _T("Limestone Quarry"), _T("Where the Serpent Hunts") }, - { 53, 20, _T("Limestone Quarry"), _T("Ants Prepare for Winter") }, - { 53, 21, _T("Limestone Quarry"), _T("Drowned in Fleeting Joy") }, - { 53, 22, _T("Limestone Quarry"), _T("The Laborer's Bonfire") }, - { 53, 23, _T("Limestone Quarry"), _T("Stone and Sulfurous Fire") }, - { 53, 24, _T("Limestone Quarry"), _T("Torture Without End") }, - { 53, 25, _T("Limestone Quarry"), _T("Way Down") }, - { 53, 26, _T("Limestone Quarry"), _T("Excavated Hollow") }, - { 53, 27, _T("Limestone Quarry"), _T("Parting Regrets") }, - { 53, 28, _T("Limestone Quarry"), _T("Corridor of Tales") }, - { 53, 29, _T("Limestone Quarry"), _T("Dust Shall Eat the Days") }, - { 53, 30, _T("Limestone Quarry"), _T("Hall of the Wage-Paying") }, - { 53, 32, _T("Limestone Quarry"), _T("Tunnel of the Heartless") }, - - // Temple of Kiltia - verified - { 30, 1, _T("Temple of Kiltia"), _T("The Dark Coast") }, - { 30, 2, _T("Temple of Kiltia"), _T("Hall of Prayer") }, - { 30, 3, _T("Temple of Kiltia"), _T("Those who Drink the Dark") }, - { 30, 4, _T("Temple of Kiltia"), _T("The Chapel of Meschaunce") }, - { 30, 5, _T("Temple of Kiltia"), _T("The Resentful Ones") }, - { 30, 6, _T("Temple of Kiltia"), _T("Those who Fear the Light") }, - { 31, 1, _T("Temple of Kiltia"), _T("Chamber of Reason") }, - { 31, 2, _T("Temple of Kiltia"), _T("Exit to City Center") }, - - // Great Cathedral B1 - verified - { 22, 1, _T("Great Cathedral B1"), _T("Sanity and Madness") }, - { 22, 5, _T("Great Cathedral B1"), _T("Truth and Lies") }, - { 22, 7, _T("Great Cathedral B1"), _T("Order and Chaos") }, - { 22, 8, _T("Great Cathedral B1"), _T("The Victor's Laurels") }, - { 22, 9, _T("Great Cathedral B1"), _T("Struggle for the Soul") }, - { 22, 10, _T("Great Cathedral B1"), _T("An Offering of Souls") }, - - // Great Cathedral L1 - verified - { 24, 1, _T("Great Cathedral L1"), _T("The Flayed Confessional") }, - { 24, 2, _T("Great Cathedral L1"), _T("Monk's Leap") }, - { 24, 3, _T("Great Cathedral L1"), _T("Where Darkness Spreads") }, - { 24, 4, _T("Great Cathedral L1"), _T("Hieratic Recollections") }, - { 24, 5, _T("Great Cathedral L1"), _T("A Light in the Dark") }, - { 24, 6, _T("Great Cathedral L1"), _T("The Poisoned Chapel") }, - { 24, 7, _T("Great Cathedral L1"), _T("Sin and Punishment") }, - { 24, 8, _T("Great Cathedral L1"), _T("Cracked Pleasures") }, - { 24, 9, _T("Great Cathedral L1"), _T("Into Holy Battle") }, - - // Great Cathedral L2 - verified - { 23, 2, _T("Great Cathedral L2"), _T("He Screams for Mercy") }, - { 23, 3, _T("Great Cathedral L2"), _T("Light and Dark Wage War") }, - { 23, 4, _T("Great Cathedral L2"), _T("Abasement from Above") }, - { 24, 10, _T("Great Cathedral L2"), _T("Maelstrom of Malice") }, - { 24, 11, _T("Great Cathedral L2"), _T("The Acolyte's Weakness") }, - { 24, 12, _T("Great Cathedral L2"), _T("The Hall of Broken Vows") }, - { 24, 13, _T("Great Cathedral L2"), _T("The Melodics of Madness") }, - { 24, 14, _T("Great Cathedral L2"), _T("Free from Base Desires") }, - { 24, 15, _T("Great Cathedral L2"), _T("The Convent Room") }, - { 25, 1, _T("Great Cathedral L2"), _T("An Arrow into Darkness") }, - { 25, 2, _T("Great Cathedral L2"), _T("What Ails You, Kills You") }, - - // Great Cathedral L3 - verified - { 23, 5, _T("Great Cathedral L3"), _T("The Heretics' Story") }, - { 23, 6, _T("Great Cathedral L3"), _T("The Wine-Lecher's Fall") }, - { 24, 16, _T("Great Cathedral L3"), _T("Hopes of the Idealist") }, - { 25, 3, _T("Great Cathedral L3"), _T("Where the Soul Rots") }, - { 25, 4, _T("Great Cathedral L3"), _T("Despair of the Fallen") }, - - // Great Cathedral L4 - verified - { 25, 5, _T("Great Cathedral L4"), _T("The Atrium") }, - - // Forgotten Pathway - verified - { 54, 1, _T("Forgotten Pathway"), _T("Stair to the Sinners") }, - { 54, 2, _T("Forgotten Pathway"), _T("Slaugher of the Innocent") }, - { 54, 3, _T("Forgotten Pathway"), _T("The Fallen Knight") }, - { 54, 4, _T("Forgotten Pathway"), _T("The Oracle Sins No More") }, - { 54, 5, _T("Forgotten Pathway"), _T("Awaiting Retribution") }, - - // Escapeway - verified - { 52, 1, _T("Escapeway"), _T("Shelter From the Quake") }, - { 52, 2, _T("Escapeway"), _T("Buried Alive") }, - { 52, 3, _T("Escapeway"), _T("Movement of Fear") }, - { 52, 4, _T("Escapeway"), _T("Facing Your Illusions") }, - { 52, 5, _T("Escapeway"), _T("The Darkness Drinks") }, - { 52, 6, _T("Escapeway"), _T("Fear and Loathing") }, - { 52, 7, _T("Escapeway"), _T("Blood and the Beast") }, - { 52, 8, _T("Escapeway"), _T("Where Body and Soul Part") }, - - // Iron Maiden B1 - verified - { 55, 1, _T("Iron Maiden B1"), _T("The Cage") }, - { 55, 2, _T("Iron Maiden B1"), _T("The Cauldron") }, - { 55, 3, _T("Iron Maiden B1"), _T("Wooden Horse") }, - { 55, 4, _T("Iron Maiden B1"), _T("Starvation") }, - { 55, 5, _T("Iron Maiden B1"), _T("The Breast Ripper") }, - { 55, 6, _T("Iron Maiden B1"), _T("The Pear") }, - { 55, 7, _T("Iron Maiden B1"), _T("The Whirligig") }, - { 55, 8, _T("Iron Maiden B1"), _T("Spanish Tickler") }, - { 55, 9, _T("Iron Maiden B1"), _T("Heretic's Fork") }, - { 55, 10, _T("Iron Maiden B1"), _T("The Chair of Spikes") }, - { 55, 11, _T("Iron Maiden B1"), _T("Blooding") }, - { 55, 12, _T("Iron Maiden B1"), _T("Bootikens") }, - { 55, 13, _T("Iron Maiden B1"), _T("Burial") }, - { 55, 14, _T("Iron Maiden B1"), _T("Burning") }, - { 55, 15, _T("Iron Maiden B1"), _T("Cleansing the Soul") }, - { 55, 16, _T("Iron Maiden B1"), _T("The Garotte") }, - { 55, 17, _T("Iron Maiden B1"), _T("Hanging") }, - { 55, 18, _T("Iron Maiden B1"), _T("Impalement") }, - { 55, 19, _T("Iron Maiden B1"), _T("Knotting") }, - { 55, 20, _T("Iron Maiden B1"), _T("The Branks") }, - { 55, 21, _T("Iron Maiden B1"), _T("The Wheel") }, - { 55, 22, _T("Iron Maiden B1"), _T("The Judas Cradle") }, - { 55, 23, _T("Iron Maiden B1"), _T("The Ducking Stool") }, - - // Iron Maiden B2 - verified - { 56, 1, _T("Iron Maiden B2"), _T("The Eunics' Lot") }, - { 56, 2, _T("Iron Maiden B2"), _T("Ordeal By Fire") }, - { 56, 3, _T("Iron Maiden B2"), _T("Tablillas") }, - { 56, 4, _T("Iron Maiden B2"), _T("The Oven at Neisse") }, - { 56, 5, _T("Iron Maiden B2"), _T("Strangulation") }, - { 56, 6, _T("Iron Maiden B2"), _T("Pressing") }, - { 56, 7, _T("Iron Maiden B2"), _T("The Strappado") }, - { 56, 8, _T("Iron Maiden B2"), _T("The Mind Burns") }, - { 56, 9, _T("Iron Maiden B2"), _T("Thumbscrews") }, - { 56, 10, _T("Iron Maiden B2"), _T("The Rack") }, - { 56, 11, _T("Iron Maiden B2"), _T("The Saw") }, - { 56, 12, _T("Iron Maiden B2"), _T("Ordeal By Water") }, - { 56, 13, _T("Iron Maiden B2"), _T("The Cold's Bridle") }, - { 56, 14, _T("Iron Maiden B2"), _T("Brank") }, - { 56, 15, _T("Iron Maiden B2"), _T("The Shin-Vice") }, - { 56, 16, _T("Iron Maiden B2"), _T("Squassation") }, - { 56, 17, _T("Iron Maiden B2"), _T("The Spider") }, - { 56, 18, _T("Iron Maiden B2"), _T("Lead Sprinkler") }, - { 56, 19, _T("Iron Maiden B2"), _T("Pendulum") }, - { 56, 20, _T("Iron Maiden B2"), _T("Dragging") }, - { 56, 21, _T("Iron Maiden B2"), _T("Tongue Slicer") }, - { 56, 22, _T("Iron Maiden B2"), _T("Tormentum Insomniae") }, - - // Iron Maiden B3 - verified - { 56, 23, _T("Iron Maiden B3"), _T("The Iron Maiden") }, - { 56, 24, _T("Iron Maiden B3"), _T("Saint Elmo's Belt") }, - { 56, 25, _T("Iron Maiden B3"), _T("Judgement") }, - { 56, 26, _T("Iron Maiden B3"), _T("Dunking the Witch") }, - - // Undercity West - verified - { 47, 1, _T("Undercity West"), _T("Workshop \"Godhands\"") }, - { 48, 1, _T("Undercity West"), _T("The Bread Peddler's Way") }, - { 48, 2, _T("Undercity West"), _T("Way of the Mother Lode") }, - { 48, 3, _T("Undercity West"), _T("Sewer of Ravenous Rats") }, - { 48, 4, _T("Undercity West"), _T("Underdark Fishmarket") }, - { 48, 5, _T("Undercity West"), _T("The Sunless Way") }, - { 48, 6, _T("Undercity West"), _T("Remembering Days of Yore") }, - { 48, 7, _T("Undercity West"), _T("Where the Hunter Climbed") }, - { 48, 8, _T("Undercity West"), _T("Larder for a Lean Winter") }, - { 48, 9, _T("Undercity West"), _T("Hall of Poverty") }, - { 48, 10, _T("Undercity West"), _T("The Washing-Woman's Way") }, - { 48, 11, _T("Undercity West"), _T("Beggars of the Mouthharp") }, - { 48, 12, _T("Undercity West"), _T("Corner of the Wretched") }, - { 48, 13, _T("Undercity West"), _T("Path to the Greengrocer") }, - { 48, 14, _T("Undercity West"), _T("Crossroads of Rest") }, - { 48, 15, _T("Undercity West"), _T("Path of the Children") }, - { 48, 16, _T("Undercity West"), _T("Fear of the Fall") }, - { 48, 17, _T("Undercity West"), _T("Sinner's Corner") }, - { 48, 18, _T("Undercity West"), _T("Nameless Dark Oblivion") }, - { 48, 19, _T("Undercity West"), _T("Corner of Prayers") }, - { 48, 20, _T("Undercity West"), _T("Hope Obstructed") }, - { 48, 21, _T("Undercity West"), _T("The Children's Hideout") }, - { 48, 22, _T("Undercity West"), _T("The Crumbling Market") }, - { 48, 23, _T("Undercity West"), _T("Tears from Empty Sockets") }, - { 48, 24, _T("Undercity West"), _T("Where Flood Waters Ran") }, - { 48, 25, _T("Undercity West"), _T("The Body Fragile Yields") }, - { 48, 26, _T("Undercity West"), _T("Salvation for the Mother") }, - { 48, 27, _T("Undercity West"), _T("Bite the Master's Wounds") }, - - { 49, 1, _T("Undercity East"), _T("Hall to a New World") }, - { 49, 2, _T("Undercity East"), _T("Place of Free Words") }, - { 49, 3, _T("Undercity East"), _T("Bazaar of the Bizarre") }, - { 49, 4, _T("Undercity East"), _T("Noble Gold and Silk") }, - { 49, 5, _T("Undercity East"), _T("A Knight Sells his Sword") }, - { 49, 6, _T("Undercity East"), _T("Gemsword Blackmarket") }, - { 49, 7, _T("Undercity East"), _T("The Pirate's Son") }, - { 49, 8, _T("Undercity East"), _T("Sale of the Sword") }, - { 49, 9, _T("Undercity East"), _T("Weapons Not Allowed") }, - { 49, 10, _T("Undercity East"), _T("The Greengrocer's Stair") }, - { 49, 11, _T("Undercity East"), _T("Where Black Waters Ran") }, - { 49, 12, _T("Undercity East"), _T("Arms Against Invaders") }, - { 49, 13, _T("Undercity East"), _T("Catspaw Blackmarket") }, - - // The Keep - verified - { 29, 1, _T("The Keep"), _T("The Warrior's Rest") }, - { 29, 3, _T("The Keep"), _T("The Soldier's Bedding") }, - { 29, 4, _T("The Keep"), _T("A Storm of Arrows") }, - { 29, 5, _T("The Keep"), _T("Urge the Boy On") }, - { 29, 6, _T("The Keep"), _T("A Taste of the Spoils") }, - { 29, 7, _T("The Keep"), _T("Wiping Blood from Blades") }, - { 44, 1, _T("The Keep"), _T("Workshop \"Keane's Crafts\"") }, - - // City Walls West - verified - { 28, 1, _T("City Walls West"), _T("Students of Death") }, - { 28, 2, _T("City Walls West"), _T("The Gabled Hall") }, - { 28, 3, _T("City Walls West"), _T("Where the Master Fell") }, - - // City Walls South - verified - { 28, 4, _T("City Walls South"), _T("The Weeping Boy") }, - { 28, 5, _T("City Walls South"), _T("Swords for the Land") }, - { 28, 6, _T("City Walls South"), _T("In Wait of the Foe") }, - { 28, 7, _T("City Walls South"), _T("Where Weary Riders Rest") }, - { 28, 8, _T("City Walls South"), _T("The Boy's Training Room") }, +room Rooms[] = { + // Game is Loading + { 1, 1, "Loading screen limbo...", "" }, // + + // Wine Cellar + { 9, 1, "Wine Cellar", "Entrance to Darkness" }, // + { 9, 2, "Wine Cellar", "Room of Cheap Red Wine" }, // + { 9, 3, "Wine Cellar", "Room of Cheap White Wine" }, // + { 9, 4, "Wine Cellar", "Hall of Struggle" }, // + { 9, 5, "Wine Cellar", "Smokebarrel Stair" }, // + { 9, 6, "Wine Cellar", "Wine Guild Hall" }, // + { 9, 7, "Wine Cellar", "Wine Magnate's Chambers" }, // + { 9, 8, "Wine Cellar", "Fine Vintage Vault" }, // + { 9, 9, "Wine Cellar", "Chamber of Fear" }, // + { 9, 10, "Wine Cellar", "The Reckoning Room" }, // + { 9, 11, "Wine Cellar", "A Laborer's Thirst" }, // + { 9, 12, "Wine Cellar", "The Rich Drown in Wine" }, // + { 9, 13, "Wine Cellar", "Room of Rotten Grapes" }, // + { 9, 14, "Wine Cellar", "Chamber of Fear" }, // + { 9, 16, "Wine Cellar", "The Greedy One's Den" }, // + { 9, 17, "Wine Cellar", "Worker's Breakroom" }, // + { 9, 18, "Wine Cellar", "Blackmarket of Wines" }, // + { 9, 19, "Wine Cellar", "Room of Rotten Grapes" }, // + { 11, 1, "Wine Cellar", "The Hero's Winehall" }, // + { 12, 1, "Wine Cellar", "The Gallows" }, // + { 12, 2, "Wine Cellar", "The Gallows" }, // + + // Catacombs + { 13, 1, "Catacombs", "Hall of Sworn Revenge" }, // + { 13, 2, "Catacombs", "The Last Blessing" }, // + { 13, 3, "Catacombs", "The Weeping Corridor" }, // + { 13, 4, "Catacombs", "Persecution Hall" }, // + { 13, 5, "Catacombs", "The Lamenting Mother" }, // + { 13, 6, "Catacombs", "Rodent-Ridden Chamber" }, // + { 13, 7, "Catacombs", "Shrine to the Martyrs" }, // + { 13, 9, "Catacombs", "Hall of Dying Hope" }, // + { 13, 10, "Catacombs", "Bandits' Hideout" }, // + { 13, 11, "Catacombs", "The Bloody Hallway" }, // + { 13, 12, "Catacombs", "Faith Overcame Fear" }, // + { 13, 13, "Catacombs", "The Withered Spring" }, // + { 13, 14, "Catacombs", "Repent, O ye Sinners" }, // + { 13, 15, "Catacombs", "The Reaper's Victims" }, // + { 13, 16, "Catacombs", "The Last Stab of Hope" }, // + { 13, 17, "Catacombs", "Hallway of Heroes" }, // + { 13, 18, "Catacombs", "The Lamenting Mother" }, // + { 14, 1, "Catacombs", "The Beast's Domain" }, // + { 42, 1, "Catacombs", "Workshop \"Work of Art\"" }, // + + // Sanctum + { 15, 1, "Sanctum", "Prisoners' Niche" }, // + { 15, 2, "Sanctum", "Corridor of the Clerics" }, // + { 15, 3, "Sanctum", "Priests' Confinement" }, // + { 15, 4, "Sanctum", "Alchemists' Laboratory" }, // + { 15, 5, "Sanctum", "Theology Classroom" }, // + { 15, 6, "Sanctum", "Shrine of the Martyrs" }, // + { 15, 7, "Sanctum", "Advent Ground" }, // + { 15, 8, "Sanctum", "Passage of the Refugees" }, // + { 15, 9, "Sanctum", "Passage of the Refugees" }, // + { 15, 11, "Sanctum", "Stairway to the Light" }, // + { 15, 12, "Sanctum", "Hallowed Hope" }, // + { 15, 13, "Sanctum", "The Academia Corridor" }, // + { 16, 1, "Sanctum", "Hall of Sacrilege" }, // + { 17, 1, "Sanctum", "The Cleansing Chantry" }, // + + // Abandoned Mines B1 + { 50, 1, "Abandoned Mines B1", "Dreamers' Entrance" }, // + { 50, 2, "Abandoned Mines B1", "Miners' Resting Hall" }, // + { 50, 3, "Abandoned Mines B1", "The Crossing" }, // + { 50, 4, "Abandoned Mines B1", "Conflict and Accord" }, // + { 50, 5, "Abandoned Mines B1", "The Suicide King" }, // + { 50, 6, "Abandoned Mines B1", "The End of the Line" }, // + { 50, 7, "Abandoned Mines B1", "The Battle's Beginning" }, // + { 50, 8, "Abandoned Mines B1", "What Lies Ahead?" }, // + { 50, 9, "Abandoned Mines B1", "The Fruits of Friendship" }, // + { 50, 10, "Abandoned Mines B1", "The Earthquake's Mark" }, // + { 50, 11, "Abandoned Mines B1", "Coal Mine Storage" }, // + { 50, 12, "Abandoned Mines B1", "The Passion of Lovers" }, // + { 50, 13, "Abandoned Mines B1", "The Hall of Hope" }, // + { 50, 14, "Abandoned Mines B1", "The Dark Tunnel" }, // + { 50, 15, "Abandoned Mines B1", "Rust in Peace" }, // + { 50, 16, "Abandoned Mines B1", "Everwant Passage" }, // + { 50, 17, "Abandoned Mines B1", "Mining Regrets" }, // + { 50, 18, "Abandoned Mines B1", "The Smeltry" }, // + { 50, 19, "Abandoned Mines B1", "Clash of Hyaenas" }, // + { 50, 20, "Abandoned Mines B1", "Greed Knows No Bounds" }, // + { 50, 21, "Abandoned Mines B1", "Live Long and Prosper" }, // + { 50, 22, "Abandoned Mines B1", "Pray to the Mineral Gods" }, // + { 50, 23, "Abandoned Mines B1", "Traitor's Parting" }, // + { 50, 24, "Abandoned Mines B1", "Escapeway" }, // + + // Abandoned Mines B2 + { 51, 1, "Abandoned Mines B2", "Gambler's Passage" }, // + { 51, 2, "Abandoned Mines B2", "Treaty Room" }, // + { 51, 3, "Abandoned Mines B2", "The Miner's End" }, // + { 51, 4, "Abandoned Mines B2", "Work, Then Die" }, // + { 51, 5, "Abandoned Mines B2", "Bandits' Hollow" }, // + { 51, 6, "Abandoned Mines B2", "Delusions of Happiness" }, // + { 51, 7, "Abandoned Mines B2", "Dining in Darkness" }, // + { 51, 8, "Abandoned Mines B2", "Subtellurian Horrors" }, // + { 51, 9, "Abandoned Mines B2", "Hidden Resources" }, // + { 51, 10, "Abandoned Mines B2", "Way of Lost Children" }, // + { 51, 11, "Abandoned Mines B2", "Hall of the Empty Sconce" }, // + { 51, 12, "Abandoned Mines B2", "Acolyte's Burial Vault" }, // + { 51, 13, "Abandoned Mines B2", "Hall of Contemplation" }, // + { 51, 14, "Abandoned Mines B2", "The Abandoned Catspaw" }, // + { 51, 15, "Abandoned Mines B2", "Tomb of the Reborn" }, // + { 51, 16, "Abandoned Mines B2", "The Fallen Bricklayer" }, // + { 51, 17, "Abandoned Mines B2", "Crossing of Blood" }, // + { 51, 18, "Abandoned Mines B2", "Fool's Gold, Fool's Loss" }, // + { 51, 19, "Abandoned Mines B2", "Cry of the Beast" }, // + { 51, 20, "Abandoned Mines B2", "Senses Lost" }, // + { 51, 21, "Abandoned Mines B2", "Desire's Passage" }, // + { 51, 22, "Abandoned Mines B2", "Kilroy Was Here" }, // + { 51, 23, "Abandoned Mines B2", "Suicidal Desires" }, // + { 51, 24, "Abandoned Mines B2", "The Ore of Legend" }, // + { 51, 25, "Abandoned Mines B2", "Lambs to the Slaughter" }, // + { 51, 26, "Abandoned Mines B2", "A Wager of Noble Gold" }, // + { 51, 27, "Abandoned Mines B2", "The Lunatic Veins" }, // + { 51, 28, "Abandoned Mines B2", "Corridor of Shade" }, // + { 51, 29, "Abandoned Mines B2", "Revelation Shaft" }, // + + // Limestone Quarry + { 53, 1, "Limestone Quarry", "Dark Abhors Light" }, // + { 53, 2, "Limestone Quarry", "Dream of the Holy Land" }, // + { 53, 3, "Limestone Quarry", "The Ore Road" }, // + { 53, 4, "Limestone Quarry", "Atone for Eternity" }, // + { 53, 5, "Limestone Quarry", "The Air Stirs" }, // + { 53, 6, "Limestone Quarry", "Bonds of Friendship" }, // + { 53, 7, "Limestone Quarry", "Stair to Sanctuary" }, // + { 53, 8, "Limestone Quarry", "The Fallen Hall" }, // + { 53, 9, "Limestone Quarry", "The Rotten Core" }, // + { 53, 10, "Limestone Quarry", "Bacchus is Cheap" }, // + { 53, 11, "Limestone Quarry", "Screams of the Wounded" }, // + { 53, 12, "Limestone Quarry", "The Ore-Bearers" }, // + { 53, 13, "Limestone Quarry", "The Dreamer's Climb" }, // + { 53, 14, "Limestone Quarry", "Sinner's Sustenence" }, // + { 53, 15, "Limestone Quarry", "The Timely Dew of Sleep" }, // + { 53, 16, "Limestone Quarry", "Companions in Arms" }, // + { 53, 17, "Limestone Quarry", "The Auction Block" }, // + { 53, 18, "Limestone Quarry", "Ascension" }, // + { 53, 19, "Limestone Quarry", "Where the Serpent Hunts" }, // + { 53, 20, "Limestone Quarry", "Ants Prepare for Winter" }, // + { 53, 21, "Limestone Quarry", "Drowned in Fleeting Joy" }, // + { 53, 22, "Limestone Quarry", "The Laborer's Bonfire" }, // + { 53, 23, "Limestone Quarry", "Stone and Sulfurous Fire" }, // + { 53, 24, "Limestone Quarry", "Torture Without End" }, // + { 53, 25, "Limestone Quarry", "Way Down" }, // + { 53, 26, "Limestone Quarry", "Excavated Hollow" }, // + { 53, 27, "Limestone Quarry", "Parting Regrets" }, // + { 53, 28, "Limestone Quarry", "Corridor of Tales" }, // + { 53, 29, "Limestone Quarry", "Dust Shall Eat the Days" }, // + { 53, 30, "Limestone Quarry", "Hall of the Wage-Paying" }, // + { 53, 32, "Limestone Quarry", "Tunnel of the Heartless" }, // + + // Temple of Kiltia + { 30, 1, "Temple of Kiltia", "The Dark Coast" }, // + { 30, 2, "Temple of Kiltia", "Hall of Prayer" }, // + { 30, 3, "Temple of Kiltia", "Those who Drink the Dark" }, // + { 30, 4, "Temple of Kiltia", "The Chapel of Meschaunce" }, // + { 30, 5, "Temple of Kiltia", "The Resentful Ones" }, // + { 30, 6, "Temple of Kiltia", "Those who Fear the Light" }, // + { 31, 1, "Temple of Kiltia", "Chamber of Reason" }, // + { 31, 2, "Temple of Kiltia", "Exit to City Center" }, // + + // Great Cathedral B1 + { 22, 1, "Great Cathedral B1", "Sanity and Madness" }, // + { 22, 5, "Great Cathedral B1", "Truth and Lies" }, // + { 22, 7, "Great Cathedral B1", "Order and Chaos" }, // + { 22, 8, "Great Cathedral B1", "The Victor's Laurels" }, // + { 22, 9, "Great Cathedral B1", "Struggle for the Soul" }, // + { 22, 10, "Great Cathedral B1", "An Offering of Souls" }, // + + // Great Cathedral L1 + { 24, 1, "Great Cathedral L1", "The Flayed Confessional" }, // + { 24, 2, "Great Cathedral L1", "Monk's Leap" }, // + { 24, 3, "Great Cathedral L1", "Where Darkness Spreads" }, // + { 24, 4, "Great Cathedral L1", "Hieratic Recollections" }, // + { 24, 5, "Great Cathedral L1", "A Light in the Dark" }, // + { 24, 6, "Great Cathedral L1", "The Poisoned Chapel" }, // + { 24, 7, "Great Cathedral L1", "Sin and Punishment" }, // + { 24, 8, "Great Cathedral L1", "Cracked Pleasures" }, // + { 24, 9, "Great Cathedral L1", "Into Holy Battle" }, // + + // Great Cathedral L2 + { 23, 2, "Great Cathedral L2", "He Screams for Mercy" }, // + { 23, 3, "Great Cathedral L2", "Light and Dark Wage War" }, // + { 23, 4, "Great Cathedral L2", "Abasement from Above" }, // + { 24, 10, "Great Cathedral L2", "Maelstrom of Malice" }, // + { 24, 11, "Great Cathedral L2", "The Acolyte's Weakness" }, // + { 24, 12, "Great Cathedral L2", "The Hall of Broken Vows" }, // + { 24, 13, "Great Cathedral L2", "The Melodics of Madness" }, // + { 24, 14, "Great Cathedral L2", "Free from Base Desires" }, // + { 24, 15, "Great Cathedral L2", "The Convent Room" }, // + { 25, 1, "Great Cathedral L2", "An Arrow into Darkness" }, // + { 25, 2, "Great Cathedral L2", "What Ails You, Kills You" }, // + + // Great Cathedral L3 + { 23, 5, "Great Cathedral L3", "The Heretics' Story" }, // + { 23, 6, "Great Cathedral L3", "The Wine-Lecher's Fall" }, // + { 24, 16, "Great Cathedral L3", "Hopes of the Idealist" }, // + { 25, 3, "Great Cathedral L3", "Where the Soul Rots" }, // + { 25, 4, "Great Cathedral L3", "Despair of the Fallen" }, // + + // Great Cathedral L4 + { 25, 5, "Great Cathedral L4", "The Atrium" }, // + + // Forgotten Pathway + { 54, 1, "Forgotten Pathway", "Stair to the Sinners" }, // + { 54, 2, "Forgotten Pathway", "Slaugher of the Innocent" }, // + { 54, 3, "Forgotten Pathway", "The Fallen Knight" }, // + { 54, 4, "Forgotten Pathway", "The Oracle Sins No More" }, // + { 54, 5, "Forgotten Pathway", "Awaiting Retribution" }, // + + // Escapeway + { 52, 1, "Escapeway", "Shelter From the Quake" }, // + { 52, 2, "Escapeway", "Buried Alive" }, // + { 52, 3, "Escapeway", "Movement of Fear" }, // + { 52, 4, "Escapeway", "Facing Your Illusions" }, // + { 52, 5, "Escapeway", "The Darkness Drinks" }, // + { 52, 6, "Escapeway", "Fear and Loathing" }, // + { 52, 7, "Escapeway", "Blood and the Beast" }, // + { 52, 8, "Escapeway", "Where Body and Soul Part" }, // + + // Iron Maiden B1 + { 55, 1, "Iron Maiden B1", "The Cage" }, // + { 55, 2, "Iron Maiden B1", "The Cauldron" }, // + { 55, 3, "Iron Maiden B1", "Wooden Horse" }, // + { 55, 4, "Iron Maiden B1", "Starvation" }, // + { 55, 5, "Iron Maiden B1", "The Breast Ripper" }, // + { 55, 6, "Iron Maiden B1", "The Pear" }, // + { 55, 7, "Iron Maiden B1", "The Whirligig" }, // + { 55, 8, "Iron Maiden B1", "Spanish Tickler" }, // + { 55, 9, "Iron Maiden B1", "Heretic's Fork" }, // + { 55, 10, "Iron Maiden B1", "The Chair of Spikes" }, // + { 55, 11, "Iron Maiden B1", "Blooding" }, // + { 55, 12, "Iron Maiden B1", "Bootikens" }, // + { 55, 13, "Iron Maiden B1", "Burial" }, // + { 55, 14, "Iron Maiden B1", "Burning" }, // + { 55, 15, "Iron Maiden B1", "Cleansing the Soul" }, // + { 55, 16, "Iron Maiden B1", "The Garotte" }, // + { 55, 17, "Iron Maiden B1", "Hanging" }, // + { 55, 18, "Iron Maiden B1", "Impalement" }, // + { 55, 19, "Iron Maiden B1", "Knotting" }, // + { 55, 20, "Iron Maiden B1", "The Branks" }, // + { 55, 21, "Iron Maiden B1", "The Wheel" }, // + { 55, 22, "Iron Maiden B1", "The Judas Cradle" }, // + { 55, 23, "Iron Maiden B1", "The Ducking Stool" }, // + + // Iron Maiden B2 + { 56, 1, "Iron Maiden B2", "The Eunics' Lot" }, // + { 56, 2, "Iron Maiden B2", "Ordeal By Fire" }, // + { 56, 3, "Iron Maiden B2", "Tablillas" }, // + { 56, 4, "Iron Maiden B2", "The Oven at Neisse" }, // + { 56, 5, "Iron Maiden B2", "Strangulation" }, // + { 56, 6, "Iron Maiden B2", "Pressing" }, // + { 56, 7, "Iron Maiden B2", "The Strappado" }, // + { 56, 8, "Iron Maiden B2", "The Mind Burns" }, // + { 56, 9, "Iron Maiden B2", "Thumbscrews" }, // + { 56, 10, "Iron Maiden B2", "The Rack" }, // + { 56, 11, "Iron Maiden B2", "The Saw" }, // + { 56, 12, "Iron Maiden B2", "Ordeal By Water" }, // + { 56, 13, "Iron Maiden B2", "The Cold's Bridle" }, // + { 56, 14, "Iron Maiden B2", "Brank" }, // + { 56, 15, "Iron Maiden B2", "The Shin-Vice" }, // + { 56, 16, "Iron Maiden B2", "Squassation" }, // + { 56, 17, "Iron Maiden B2", "The Spider" }, // + { 56, 18, "Iron Maiden B2", "Lead Sprinkler" }, // + { 56, 19, "Iron Maiden B2", "Pendulum" }, // + { 56, 20, "Iron Maiden B2", "Dragging" }, // + { 56, 21, "Iron Maiden B2", "Tongue Slicer" }, // + { 56, 22, "Iron Maiden B2", "Tormentum Insomniae" }, // + + // Iron Maiden B3 + { 56, 23, "Iron Maiden B3", "The Iron Maiden" }, // + { 56, 24, "Iron Maiden B3", "Saint Elmo's Belt" }, // + { 56, 25, "Iron Maiden B3", "Judgement" }, // + { 56, 26, "Iron Maiden B3", "Dunking the Witch" }, // + + // Undercity West + { 47, 1, "Undercity West", "Workshop \"Godhands\"" }, // + { 48, 1, "Undercity West", "The Bread Peddler's Way" }, // + { 48, 2, "Undercity West", "Way of the Mother Lode" }, // + { 48, 3, "Undercity West", "Sewer of Ravenous Rats" }, // + { 48, 4, "Undercity West", "Underdark Fishmarket" }, // + { 48, 5, "Undercity West", "The Sunless Way" }, // + { 48, 6, "Undercity West", "Remembering Days of Yore" }, // + { 48, 7, "Undercity West", "Where the Hunter Climbed" }, // + { 48, 8, "Undercity West", "Larder for a Lean Winter" }, // + { 48, 9, "Undercity West", "Hall of Poverty" }, // + { 48, 10, "Undercity West", "The Washing-Woman's Way" }, // + { 48, 11, "Undercity West", "Beggars of the Mouthharp" }, // + { 48, 12, "Undercity West", "Corner of the Wretched" }, // + { 48, 13, "Undercity West", "Path to the Greengrocer" }, // + { 48, 14, "Undercity West", "Crossroads of Rest" }, // + { 48, 15, "Undercity West", "Path of the Children" }, // + { 48, 16, "Undercity West", "Fear of the Fall" }, // + { 48, 17, "Undercity West", "Sinner's Corner" }, // + { 48, 18, "Undercity West", "Nameless Dark Oblivion" }, // + { 48, 19, "Undercity West", "Corner of Prayers" }, // + { 48, 20, "Undercity West", "Hope Obstructed" }, // + { 48, 21, "Undercity West", "The Children's Hideout" }, // + { 48, 22, "Undercity West", "The Crumbling Market" }, // + { 48, 23, "Undercity West", "Tears from Empty Sockets" }, // + { 48, 24, "Undercity West", "Where Flood Waters Ran" }, // + { 48, 25, "Undercity West", "The Body Fragile Yields" }, // + { 48, 26, "Undercity West", "Salvation for the Mother" }, // + { 48, 27, "Undercity West", "Bite the Master's Wounds" }, // + + { 49, 1, "Undercity East", "Hall to a New World" }, // + { 49, 2, "Undercity East", "Place of Free Words" }, // + { 49, 3, "Undercity East", "Bazaar of the Bizarre" }, // + { 49, 4, "Undercity East", "Noble Gold and Silk" }, // + { 49, 5, "Undercity East", "A Knight Sells his Sword" }, // + { 49, 6, "Undercity East", "Gemsword Blackmarket" }, // + { 49, 7, "Undercity East", "The Pirate's Son" }, // + { 49, 8, "Undercity East", "Sale of the Sword" }, // + { 49, 9, "Undercity East", "Weapons Not Allowed" }, // + { 49, 10, "Undercity East", "The Greengrocer's Stair" }, // + { 49, 11, "Undercity East", "Where Black Waters Ran" }, // + { 49, 12, "Undercity East", "Arms Against Invaders" }, // + { 49, 13, "Undercity East", "Catspaw Blackmarket" }, // + + // The Keep + { 29, 1, "The Keep", "The Warrior's Rest" }, // + { 29, 3, "The Keep", "The Soldier's Bedding" }, // + { 29, 4, "The Keep", "A Storm of Arrows" }, // + { 29, 5, "The Keep", "Urge the Boy On" }, // + { 29, 6, "The Keep", "A Taste of the Spoils" }, // + { 29, 7, "The Keep", "Wiping Blood from Blades" }, // + { 44, 1, "The Keep", "Workshop \"Keane's Crafts\"" }, // + + // City Walls West + { 28, 1, "City Walls West", "Students of Death" }, // + { 28, 2, "City Walls West", "The Gabled Hall" }, // + { 28, 3, "City Walls West", "Where the Master Fell" }, // + + // City Walls South + { 28, 4, "City Walls South", "The Weeping Boy" }, // + { 28, 5, "City Walls South", "Swords for the Land" }, // + { 28, 6, "City Walls South", "In Wait of the Foe" }, // + { 28, 7, "City Walls South", "Where Weary Riders Rest" }, // + { 28, 8, "City Walls South", "The Boy's Training Room" }, // // City Walls East - { 28, 9, _T("City Walls East"), _T("Train and Grow Strong") }, - { 28, 10, _T("City Walls East"), _T("The Squire's Gathering") }, - { 28, 11, _T("City Walls East"), _T("The Invaders are Found") }, - { 28, 12, _T("City Walls East"), _T("The Dream-Weavers") }, - { 28, 13, _T("City Walls East"), _T("The Cornered Savage") }, - - { 28, 14, _T("City Walls North"), _T("Traces of Invasion Past") }, - { 28, 15, _T("City Walls North"), _T("From Squire to Knight") }, - { 28, 16, _T("City Walls North"), _T("Be for Battle Prepared") }, - { 28, 17, _T("City Walls North"), _T("Destruction and Rebirth") }, - { 28, 18, _T("City Walls North"), _T("From Boy to Hero") }, - { 28, 19, _T("City Walls North"), _T("A Welcome Invasion") }, - - // Snowfly Forest - verified - { 40, 1, _T("Snowfly Forest"), _T("The Hunt Begins") }, - { 40, 2, _T("Snowfly Forest"), _T("Which Way Home") }, - { 40, 3, _T("Snowfly Forest"), _T("The Giving Trees") }, - { 40, 4, _T("Snowfly Forest"), _T("The Wounded Boar") }, - { 40, 5, _T("Snowfly Forest"), _T("Golden Egg Way") }, - { 40, 6, _T("Snowfly Forest"), _T("The Birds and the Bees") }, - { 40, 7, _T("Snowfly Forest"), _T("The Woodcutter's Run") }, - { 40, 8, _T("Snowfly Forest"), _T("The Wolves' Choice") }, - { 40, 9, _T("Snowfly Forest"), _T("Howl of the Wolf King") }, - { 40, 10, _T("Snowfly Forest"), _T("Fluttering Hope") }, - { 40, 11, _T("Snowfly Forest"), _T("Traces of the Beast") }, - { 40, 12, _T("Snowfly Forest"), _T("The Yellow Wood") }, - { 40, 13, _T("Snowfly Forest"), _T("They Also Feed") }, - { 40, 14, _T("Snowfly Forest"), _T("Where Soft Rains Fell") }, - { 40, 15, _T("Snowfly Forest"), _T("The Spirit Trees") }, - { 40, 16, _T("Snowfly Forest"), _T("The Silent Hedges") }, - { 40, 17, _T("Snowfly Forest"), _T("Lamenting to the Moon") }, - { 40, 18, _T("Snowfly Forest"), _T("The Hollow Hills") }, - { 40, 19, _T("Snowfly Forest"), _T("Running with the Wolves") }, - { 40, 20, _T("Snowfly Forest"), _T("You Are the Prey") }, - { 40, 21, _T("Snowfly Forest"), _T("The Secret Path") }, - { 40, 22, _T("Snowfly Forest"), _T("The Faerie Circle") }, - { 40, 23, _T("Snowfly Forest"), _T("Return to the Land") }, - { 40, 24, _T("Snowfly Forest"), _T("Forest River") }, - { 40, 25, _T("Snowfly Forest"), _T("Hewn from Nature") }, - { 40, 26, _T("Snowfly Forest"), _T("The Wood Gate") }, + { 28, 9, "City Walls East", "Train and Grow Strong" }, // + { 28, 10, "City Walls East", "The Squire's Gathering" }, // + { 28, 11, "City Walls East", "The Invaders are Found" }, // + { 28, 12, "City Walls East", "The Dream-Weavers" }, // + { 28, 13, "City Walls East", "The Cornered Savage" }, // + + { 28, 14, "City Walls North", "Traces of Invasion Past" }, // + { 28, 15, "City Walls North", "From Squire to Knight" }, // + { 28, 16, "City Walls North", "Be for Battle Prepared" }, // + { 28, 17, "City Walls North", "Destruction and Rebirth" }, // + { 28, 18, "City Walls North", "From Boy to Hero" }, // + { 28, 19, "City Walls North", "A Welcome Invasion" }, // + + // Snowfly Forest + { 40, 1, "Snowfly Forest", "The Hunt Begins" }, // + { 40, 2, "Snowfly Forest", "Which Way Home" }, // + { 40, 3, "Snowfly Forest", "The Giving Trees" }, // + { 40, 4, "Snowfly Forest", "The Wounded Boar" }, // + { 40, 5, "Snowfly Forest", "Golden Egg Way" }, // + { 40, 6, "Snowfly Forest", "The Birds and the Bees" }, // + { 40, 7, "Snowfly Forest", "The Woodcutter's Run" }, // + { 40, 8, "Snowfly Forest", "The Wolves' Choice" }, // + { 40, 9, "Snowfly Forest", "Howl of the Wolf King" }, // + { 40, 10, "Snowfly Forest", "Fluttering Hope" }, // + { 40, 11, "Snowfly Forest", "Traces of the Beast" }, // + { 40, 12, "Snowfly Forest", "The Yellow Wood" }, // + { 40, 13, "Snowfly Forest", "They Also Feed" }, // + { 40, 14, "Snowfly Forest", "Where Soft Rains Fell" }, // + { 40, 15, "Snowfly Forest", "The Spirit Trees" }, // + { 40, 16, "Snowfly Forest", "The Silent Hedges" }, // + { 40, 17, "Snowfly Forest", "Lamenting to the Moon" }, // + { 40, 18, "Snowfly Forest", "The Hollow Hills" }, // + { 40, 19, "Snowfly Forest", "Running with the Wolves" }, // + { 40, 20, "Snowfly Forest", "You Are the Prey" }, // + { 40, 21, "Snowfly Forest", "The Secret Path" }, // + { 40, 22, "Snowfly Forest", "The Faerie Circle" }, // + { 40, 23, "Snowfly Forest", "Return to the Land" }, // + { 40, 24, "Snowfly Forest", "Forest River" }, // + { 40, 25, "Snowfly Forest", "Hewn from Nature" }, // + { 40, 26, "Snowfly Forest", "The Wood Gate" }, // // Snowfly Forest East - { 41, 1, _T("Snowfly Forest East"), _T("Steady the Boar-Spears") }, - { 41, 2, _T("Snowfly Forest East"), _T("The Boar's Revenge") }, - { 41, 3, _T("Snowfly Forest East"), _T("Nature's Womb") }, - - // Town Center West - verified - { 32, 1, _T("Town Center West"), _T("Rue Vermillion") }, - { 32, 2, _T("Town Center West"), _T("The Rene Coastroad") }, - { 32, 3, _T("Town Center West"), _T("Rue Mal Fallde") }, - { 32, 4, _T("Town Center West"), _T("Tircolas Flow") }, - { 32, 5, _T("Town Center West"), _T("Glacialdra Kirk Ruins") }, - { 32, 6, _T("Town Center West"), _T("Rue Bouquet") }, - { 32, 7, _T("Town Center West"), _T("Villeport Way") }, - { 32, 8, _T("Town Center West"), _T("Rue Sant D'alsa") }, - { 34, 1, _T("Town Center West"), _T("Dinas Walk") }, - { 43, 1, _T("Town Center West"), _T("Workshop \"Magic Hammer\"") }, - - { 32, 9, _T("Town Center South"), _T("Valdiman Gates") }, - { 32, 10, _T("Town Center South"), _T("Rue Faltes") }, - { 32, 11, _T("Town Center South"), _T("Forcas Rise") }, - { 32, 12, _T("Town Center South"), _T("Rue Aliano") }, - { 32, 13, _T("Town Center South"), _T("Rue Volnac") }, - { 32, 14, _T("Town Center South"), _T("Rue Morgue") }, - { 35, 1, _T("Town Center South"), _T("Zebel's Walk") }, - { 37, 1, _T("Town Center South"), _T("The House Khazabas") }, - - { 32, 16, _T("Town Center East"), _T("Rue Lejour") }, - { 32, 17, _T("Town Center East"), _T("Kesch Bridge") }, - { 32, 18, _T("Town Center East"), _T("Rue Crimnade") }, - { 32, 19, _T("Town Center East"), _T("Rue Fisserano") }, - { 32, 20, _T("Town Center East"), _T("Shasras Hill Park") }, - { 36, 1, _T("Town Center East"), _T("Gharmes Walk") }, - { 38, 1, _T("Town Center East"), _T("The House Gilgitte") }, - { 39, 1, _T("Town Center East"), _T("Plateia Lumitar") }, - { 45, 1, _T("Town Center East"), _T("Workshop \"Metal Works\"") }, - { 46, 1, _T("Town Center East"), _T("Workshop \"Junction Point\"") }, - - { 27, 1, _T("The Paling"), _T("Phase 1") }, - { 27, 2, _T("The Paling"), _T("Phase 2") } - + { 41, 1, "Snowfly Forest East", "Steady the Boar-Spears" }, // + { 41, 2, "Snowfly Forest East", "The Boar's Revenge" }, // + { 41, 3, "Snowfly Forest East", "Nature's Womb" }, // + + // Town Center West + { 32, 1, "Town Center West", "Rue Vermillion" }, // + { 32, 2, "Town Center West", "The Rene Coastroad" }, // + { 32, 3, "Town Center West", "Rue Mal Fallde" }, // + { 32, 4, "Town Center West", "Tircolas Flow" }, // + { 32, 5, "Town Center West", "Glacialdra Kirk Ruins" }, // + { 32, 6, "Town Center West", "Rue Bouquet" }, // + { 32, 7, "Town Center West", "Villeport Way" }, // + { 32, 8, "Town Center West", "Rue Sant D'alsa" }, // + { 34, 1, "Town Center West", "Dinas Walk" }, // + { 43, 1, "Town Center West", "Workshop \"Magic Hammer\"" }, // + + { 32, 9, "Town Center South", "Valdiman Gates" }, // + { 32, 10, "Town Center South", "Rue Faltes" }, // + { 32, 11, "Town Center South", "Forcas Rise" }, // + { 32, 12, "Town Center South", "Rue Aliano" }, // + { 32, 13, "Town Center South", "Rue Volnac" }, // + { 32, 14, "Town Center South", "Rue Morgue" }, // + { 35, 1, "Town Center South", "Zebel's Walk" }, // + { 37, 1, "Town Center South", "The House Khazabas" }, // + + { 32, 16, "Town Center East", "Rue Lejour" }, // + { 32, 17, "Town Center East", "Kesch Bridge" }, // + { 32, 18, "Town Center East", "Rue Crimnade" }, // + { 32, 19, "Town Center East", "Rue Fisserano" }, // + { 32, 20, "Town Center East", "Shasras Hill Park" }, // + { 36, 1, "Town Center East", "Gharmes Walk" }, // + { 38, 1, "Town Center East", "The House Gilgitte" }, // + { 39, 1, "Town Center East", "Plateia Lumitar" }, // + { 45, 1, "Town Center East", "Workshop \"Metal Works\"" }, // + { 46, 1, "Town Center East", "Workshop \"Junction Point\"" }, // + + { 27, 1, "The Paling", "Phase 1" }, // + { 27, 2, "The Paling", "Phase 2" } }; void ReadLocation(location *Location) { - SIZE_T BytesToRead = sizeof(location); - DWORD BytesRead; + usize BytesToRead = sizeof(location); + u32 BytesRead; BytesRead = ReadGameMemory(processID, OFFSET_LOCATION, BytesToRead, Location); } @@ -470,10 +454,10 @@ ReadLocation(location *Location) void GetAreaAndRoomName(location *Location, TCHAR *szAreaName, TCHAR *szRoomName) { - UINT8 AreaNumber = Location->Location.AreaNumber; - UINT8 RoomNumber = Location->Location.RoomNumber; + u8 AreaNumber = Location->AreaNumber; + u8 RoomNumber = Location->RoomNumber; - int counter = NELEMS(Rooms); + int counter = _countof(Rooms); for (int i = 0; i < counter; i++) { @@ -491,13 +475,20 @@ GetAreaAndRoomName(location *Location, TCHAR *szAreaName, TCHAR *szRoomName) void WriteLocationIntoFile(location *Location, TCHAR *szAreaName, TCHAR *szRoomName) { - UINT8 AreaNumber = Location->Location.AreaNumber; - UINT8 RoomNumber = Location->Location.RoomNumber; + u8 AreaNumber = Location->AreaNumber; + u8 RoomNumber = Location->RoomNumber; FILE *fpLocation = fopen("game_stats/location.txt", "w"); FILE *fpLocationDebug = fopen("game_stats/location-debug.txt", "w"); - fprintf(fpLocation, "%s / %s\n", szAreaName, szRoomName); + if (AreaNumber >= 9) + { + fprintf(fpLocation, "%s / %s\n", szAreaName, szRoomName); + } + else + { + fprintf(fpLocation, "Loading screen limbo ...\n"); + } fprintf(fpLocationDebug, "Location ( %2i, %2i ):\n%s / %s\n", AreaNumber, RoomNumber, szAreaName, szRoomName); @@ -508,40 +499,28 @@ WriteLocationIntoFile(location *Location, TCHAR *szAreaName, TCHAR *szRoomName) void PrintLocation(location *Location, TCHAR *szAreaName, TCHAR *szRoomName) { - UINT8 AreaNumber = Location->Location.AreaNumber; - UINT8 RoomNumber = Location->Location.RoomNumber; + u8 AreaNumber = Location->AreaNumber; + u8 RoomNumber = Location->RoomNumber; - fprintf(stdout, "\n== LOCATION ==\n\n"); - if (DEBUG) + sprintf(szBuffer, "\n\n== LOCATION ==\n\n"); + WriteToBackBuffer(); + + if (AreaNumber >= 9) { - fprintf(stdout, "Area %2i, Room %2i - %s / %s\n", AreaNumber, RoomNumber, - szAreaName, szRoomName); + sprintf_s(szBuffer, _countof(szBuffer), "%s, %s ( Area %2i, Room %2i )\n", + szAreaName, szRoomName, AreaNumber, RoomNumber); } else { - fprintf(stdout, "%s / %s\n", szAreaName, szRoomName); + sprintf_s(szBuffer, _countof(szBuffer), "Loading screen limbo ...\n"); } -} - -void -PrintLocation2(location *Location, TCHAR *szAreaName, TCHAR *szRoomName) -{ - UINT8 AreaNumber = Location->Location.AreaNumber; - UINT8 RoomNumber = Location->Location.RoomNumber; - - sprintf(szBuffer, "\n\n== LOCATION ==\n\n"); - WriteToBackBuffer(); - - sprintf(szBuffer, "%s, %s ( Area %2i, Room %2i )", szAreaName, szRoomName, - AreaNumber, RoomNumber); WriteToBackBuffer(); } BOOL IsThisTheLastBossRoom(location *Location) { - if ((Location->Location.AreaNumber == 27) && - (Location->Location.RoomNumber == 1)) + if ((Location->AreaNumber == 27) && (Location->RoomNumber == 1)) { return TRUE; } diff --git a/includes/vst_player.h b/includes/vst_player.h index ef6c3f6..3111356 100644 --- a/includes/vst_player.h +++ b/includes/vst_player.h @@ -5,6 +5,8 @@ // Player data // +// Offsets + // Misc #define OFFSET_PLAYER_CURRENT_MODE 0x8011FA10 // NormalMode=0, BattleMode=1 #define OFFSET_PLAYER_EQIPPED_WEAPON_CATEGORY_ID 0x8011FA15 @@ -76,52 +78,6 @@ #define OFFSET_LAST_BOSS_SHD_CUR 0x8017D088 #define OFFSET_LAST_BOSS_SHD_MAX 0x8017D08A -#pragma pack(push, 1) -typedef struct -{ - UINT16 HP_Current; - UINT16 HP_Maximum; - UINT16 MP_Current; - UINT16 MP_Maximum; - UINT16 Risk; - UINT16 STR_Equipped; - UINT16 STR_Original; - UINT16 INT_Equipped; - UINT16 INT_Original; - UINT16 AGL_Equipped; - UINT16 AGL_Original; - - UINT8 Padding0[3]; - - UINT8 WalkingSpeedWithBox; - - UINT8 Padding1; - - UINT8 RunningSpeed; - - UINT32 Padding2; - - range Range; - // UINT8 Range; -} player_stats; -#pragma pack(pop) - -#pragma pack(push, 1) -typedef struct -{ - UINT32 EffectID; // bit mask - - UINT8 Padding0; - - UINT8 DurationOrFrequency; - - UINT8 Padding1; - - UINT32 CanceledBy; // bit mask - UINT32 ImmunizedBy; // bit mask -} status_effect; -#pragma pack(pop) - char *StatusEffectNames[32] = { "DYING Head (silent)", "DYING Right Arm (damage 50%)", "DYING Left Arm (enemy hit% x2)", "DYING Body (RISK decay in Normal Mode as in Battle Mode)", @@ -131,7 +87,7 @@ char *StatusEffectNames[32] = { "DYING Head (silent)", "+Earth", "+Water", "Resist Air", "Resist Fire", "Resist Earth", "Resist Water", "Analyze", "Exorcism/Banish/Drain mind", "Magic Immmunity?" }; -UINT32 StatusEffectMasks[32] = { MASK_STATUS_EFFECT_DYING_HEAD, +u32 StatusEffectMasks[32] = { MASK_STATUS_EFFECT_DYING_HEAD, MASK_STATUS_EFFECT_DYING_RIGHT_ARM, MASK_STATUS_EFFECT_DYING_LEFT_ARM, MASK_STATUS_EFFECT_DYING_BODY, MASK_STATUS_EFFECT_DYING_LEGS, MASK_STATUS_EFFECT_STR_DOWN, MASK_STATUS_EFFECT_STR_UP, @@ -149,13 +105,34 @@ UINT32 StatusEffectMasks[32] = { MASK_STATUS_EFFECT_DYING_HEAD, MASK_STATUS_EFFECT_ANALYZE, MASK_STATUS_EFFECT_EXORCISM, MASK_STATUS_EFFECT_MAGIC_IMMMUNITY }; +void +ReadPlayerStats(player_stats *PlayerStats) +{ + usize Offset = + (usize)(OFFSET_PLAYER_HP_CURRENT - PSX_TO_EMU + processBaseAddress); + + usize BytesToRead = sizeof(player_stats); + + ReadGameMemory(processID, OFFSET_PLAYER_HP_CURRENT, BytesToRead, PlayerStats); +} + +void +ReadPlayerStatus(status_effects *PlayerEffects) +{ + + usize BytesToRead = sizeof(status_effects); + + ReadGameMemory( + processID, OFFSET_PLAYER_STATUS_EFFECTS, BytesToRead, PlayerEffects); +} + void WritePlayerStats(void) { player_stats PlayerStats; - SIZE_T BytesToRead = sizeof(player_stats); - DWORD BytesRead; + usize BytesToRead = sizeof(player_stats); + u32 BytesRead; BytesRead = ReadGameMemory( processID, OFFSET_PLAYER_HP_CURRENT, BytesToRead, &PlayerStats); @@ -164,18 +141,18 @@ WritePlayerStats(void) fprintf(fpPlayerStats, "Player Stats\n\n"); - fprintf(fpPlayerStats, "HP: %3i/%3i\n", PlayerStats.HP_Current, - PlayerStats.HP_Maximum); + fprintf( + fpPlayerStats, "HP: %3i/%3i\n", PlayerStats.HPCur, PlayerStats.HPMax); - fprintf(fpPlayerStats, "MP: %3i/%3i\n", PlayerStats.MP_Current, - PlayerStats.MP_Maximum); + fprintf( + fpPlayerStats, "MP: %3i/%3i\n", PlayerStats.MPCur, PlayerStats.MPMax); - fprintf(fpPlayerStats, "STR: %3i/%3i\n", PlayerStats.STR_Original, - PlayerStats.STR_Equipped); - fprintf(fpPlayerStats, "INT: %3i/%3i\n", PlayerStats.INT_Original, - PlayerStats.INT_Equipped); - fprintf(fpPlayerStats, "AGL: %3i/%3i\n", PlayerStats.AGL_Original, - PlayerStats.AGL_Equipped); + fprintf(fpPlayerStats, "STR: %3i/%3i\n", PlayerStats.STRBase, + PlayerStats.STRCur); + fprintf(fpPlayerStats, "INT: %3i/%3i\n", PlayerStats.INTBase, + PlayerStats.INTCur); + fprintf(fpPlayerStats, "AGL: %3i/%3i\n", PlayerStats.AGLBase, + PlayerStats.AGLCur); fprintf(fpPlayerStats, "RISK: %3i\n\n", PlayerStats.Risk); @@ -191,90 +168,45 @@ WritePlayerStats(void) } void -PrintPlayerStats(void) +PrintPlayerStats(player_stats *PlayerStats, status_effects *PlayerEffects) { - player_stats PlayerStats; - - SIZE_T BytesToRead = sizeof(player_stats); - DWORD BytesRead; - - BytesRead = ReadGameMemory( - processID, OFFSET_PLAYER_HP_CURRENT, BytesToRead, &PlayerStats); - - fprintf(stdout, "\n= PLAYER STATS =\n"); + player_stats Stats = *PlayerStats; + status_effects Effects = *PlayerEffects; - fprintf(stdout, "|HP Cur|HP Max|MP Cur|MP Max|RISK|" - "STR Org|STR Equ|INT Org|INT Equ|AGL Org|AGL Equ|\n"); - - fprintf(stdout, "|------|------|------|------|----|" - "-------|-------|-------|-------|-------|-------|\n"); - fprintf(stdout, "|%6i|%6i|%6i|%6i|%4i|%7i|%7i|%7i|%7i|%7i|%7i|\n", // - PlayerStats.HP_Current, PlayerStats.HP_Maximum, // - PlayerStats.MP_Current, PlayerStats.MP_Maximum, // - PlayerStats.Risk, // - PlayerStats.STR_Original, PlayerStats.STR_Equipped, // - PlayerStats.INT_Original, PlayerStats.INT_Equipped, // - PlayerStats.AGL_Original, PlayerStats.AGL_Equipped); - - if (DEBUG) - { - fprintf(stdout, "\n|Range| |With Box|Running|\n"); - - fprintf(stdout, "|-----| Speed |--------|-------|\n"); - fprintf(stdout, "|%5i| |%8i|%7i|\n", // - PlayerStats.Range.x, // - PlayerStats.WalkingSpeedWithBox, // - PlayerStats.RunningSpeed); - } -} - -void -PrintPlayerStats2(void) -{ - player_stats PlayerStats; - status_effect StatusEffects; - - DWORD BytesRead; - - BytesRead = ReadGameMemory( - processID, OFFSET_PLAYER_HP_CURRENT, sizeof(player_stats), &PlayerStats); - BytesRead = ReadGameMemory(processID, OFFSET_PLAYER_STATUS_EFFECTS, - sizeof(status_effect), &StatusEffects); - - UINT16 STR_Original = PlayerStats.STR_Original; - UINT16 STR_Equipped = PlayerStats.STR_Equipped; - UINT16 INT_Original = PlayerStats.INT_Original; - UINT16 INT_Equipped = PlayerStats.INT_Equipped; - UINT16 AGL_Original = PlayerStats.AGL_Original; - UINT16 AGL_Equipped = PlayerStats.AGL_Equipped; + u16 STRBase = Stats.STRBase; + u16 STRCur = Stats.STRCur; + u16 INTBase = Stats.INTBase; + u16 INTCur = Stats.INTCur; + u16 AGLBase = Stats.AGLBase; + u16 AGLCur = Stats.AGLCur; char STR_Buff = ' '; char INT_Buff = ' '; char AGL_Buff = ' '; - if (STR_Equipped > STR_Original) + if (STRCur > STRBase) { STR_Buff = '+'; } - else if (STR_Equipped < STR_Original) + else if (STRCur < STRBase) { STR_Buff = '-'; } - if (INT_Equipped > INT_Original) + if (INTCur > INTBase) { INT_Buff = '+'; } - else if (INT_Equipped < INT_Original) + else if (INTCur < INTBase) { INT_Buff = '-'; } - if (AGL_Equipped > AGL_Original) + if (AGLCur > AGLBase) { AGL_Buff = '+'; } - else if (AGL_Equipped < AGL_Original) + else if (AGLCur < AGLBase) { AGL_Buff = '-'; } @@ -296,22 +228,22 @@ PrintPlayerStats2(void) sprintf(szBuffer, "| %3i/%3i | %3i/%3i | %4i | %3i/%3i | %3i/%3i | %3i/%3i |" " %5i | | %8i | %7i |\n", // - PlayerStats.HP_Current, PlayerStats.HP_Maximum, // - PlayerStats.MP_Current, PlayerStats.MP_Maximum, // - PlayerStats.Risk, // - STR_Equipped, STR_Original, // - INT_Equipped, INT_Original, // - AGL_Equipped, AGL_Original, - PlayerStats.Range.x, // - PlayerStats.WalkingSpeedWithBox, // - PlayerStats.RunningSpeed); + Stats.HPCur, Stats.HPMax, // + Stats.MPCur, Stats.MPMax, // + Stats.Risk, // + STRCur, STRBase, // + INTCur, INTBase, // + AGLCur, AGLBase, + Stats.Range.x, // + Stats.WalkingSpeedWithBox, // + Stats.RunningSpeed); WriteToBackBuffer(); // Status effects sprintf(szBuffer, "\n-- Status Effects --\n\n"); WriteToBackBuffer(); - UINT32 StatusEffectMask = StatusEffects.EffectID; + u32 StatusEffectMask = Effects.EffectID; if (!StatusEffectMask) // if no Status Effects active, skip it { @@ -337,28 +269,22 @@ PrintPlayerStats2(void) } BOOL -CheckPlayerStats(void) +CheckPlayerStats(player_stats *PlayerStats) { - player_stats PlayerStats; - - DWORD BytesRead; - - BytesRead = ReadGameMemory( - processID, OFFSET_PLAYER_HP_CURRENT, sizeof(player_stats), &PlayerStats); - UINT16 HP_Current = PlayerStats.HP_Current; - UINT16 HP_Maximum = PlayerStats.HP_Maximum; - UINT16 MP_Current = PlayerStats.MP_Current; - UINT16 MP_Maximum = PlayerStats.MP_Maximum; - UINT16 Risk = PlayerStats.Risk; - UINT16 STR_Original = PlayerStats.STR_Original; - UINT16 INT_Original = PlayerStats.INT_Original; - UINT16 AGL_Original = PlayerStats.AGL_Original; + u16 HPCur = PlayerStats->HPCur; + u16 HPMax = PlayerStats->HPMax; + u16 MPCur = PlayerStats->MPCur; + u16 MPMax = PlayerStats->MPMax; + u16 Risk = PlayerStats->Risk; + u16 STRBase = PlayerStats->STRBase; + u16 INTBase = PlayerStats->INTBase; + u16 AGLBase = PlayerStats->AGLBase; // Check for invalid data - if (HP_Current == 0 || HP_Current > 999 || HP_Maximum > 999 || - MP_Current == 0 || MP_Current > 999 || MP_Maximum > 999 || - STR_Original > 999 || INT_Original > 999 || AGL_Original > 999 || + if (HPCur == 0 || HPCur > 999 || HPMax == 0 || HPMax > 999 || MPCur > 999 || + MPMax == 0 || MPMax > 999 || STRBase == 0 || STRBase > 999 || + INTBase == 0 || INTBase > 999 || AGLBase == 0 || AGLBase > 999 || Risk > 100) { return FALSE; @@ -367,11 +293,10 @@ CheckPlayerStats(void) return TRUE; } -DWORD -ReadLastBossHealth(UINT16 *BossHP) +u32 +ReadLastBossHealth(u16 *BossHP) { - DWORD BytesRead = - ReadGameMemory(processID, OFFSET_LAST_BOSS_HP_CUR, 2, BossHP); + u32 BytesRead = ReadGameMemory(processID, OFFSET_LAST_BOSS_HP_CUR, 2, BossHP); return BytesRead; } @@ -394,9 +319,9 @@ LastBossHandleIt2() sprintf(szBuffer, "Guildenstern is dead. Good Job!!!\n"); WriteToBackBuffer(); - ReadPlayTime(&RecordTime); + ReadPlayTime(&PlayTimeRecord); WriteRecordTimeToFile( - &RecordTime, _T("game_stats/records"), _T("record-time.txt")); + &PlayTimeRecord, "game_stats/records", "record-time.txt"); CopyFromBackBuffer(); diff --git a/includes/vst_process.h b/includes/vst_process.h index 4dd7ff4..bbebaf4 100644 --- a/includes/vst_process.h +++ b/includes/vst_process.h @@ -1,38 +1,55 @@ #ifndef _VST_PROCESS_H #define _VST_PROCESS_H -#define LDR_IS_DATAFILE(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR) 1) -#define LDR_IS_IMAGEMAPPING(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR) 2) -#define LDR_IS_RESOURCE(handle) \ - (LDR_IS_IMAGEMAPPING(handle) || LDR_IS_DATAFILE(handle)) - -SIZE_T processBaseAddress; -SIZE_T PSX_TO_EMU; - -DWORD dwPriorityClassValue[6] = { ABOVE_NORMAL_PRIORITY_CLASS, +u32 PriorityClassValue[6] = { ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS }; -TCHAR *szPriorityClassName[6] = { TEXT("ABOVE_NORMAL_PRIORITY_CLASS"), - TEXT("BELOW_NORMAL_PRIORITY_CLASS"), TEXT("HIGH_PRIORITY_CLASS"), - TEXT("IDLE_PRIORITY_CLASS"), TEXT("NORMAL_PRIORITY_CLASS"), - TEXT("REALTIME_PRIORITY_CLASS") }; +char *szPriorityClassName[6] = { "ABOVE_NORMAL_PRIORITY_CLASS", + "BELOW_NORMAL_PRIORITY_CLASS", "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", + "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS" }; + +void +ChangePageProtection(u32 processID, void *lpAddress, usize Size) +{ + u32 flNewProtect = PAGE_READWRITE; + u32 flOldProtect; + + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID); -TCHAR szModuleName[MAX_PATH] = TEXT(""); -TCHAR szExeName[MAX_PATH] = TEXT(""); + VirtualProtectEx(hProcess, lpAddress, Size, flNewProtect, &flOldProtect); +} -SIZE_T -GetModuleDllBase(DWORD processID, TCHAR *szModuleName) +usize +GetRegionSize(u32 processID, const void *lpAddress) { - DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + u32 DesiredAccess = PROCESS_QUERY_INFORMATION; + HANDLE hProcess = OpenProcess(DesiredAccess, FALSE, processID); + + if (hProcess) + { + MEMORY_BASIC_INFORMATION mbiBuffer = { 0 }; + if (VirtualQueryEx(hProcess, lpAddress, &mbiBuffer, sizeof(mbiBuffer))) + { + u32 Protect = mbiBuffer.Protect; + return mbiBuffer.RegionSize; + } + } + return -1; +} + +u64 +GetModuleDllBase(u32 processID, char *szModuleName) +{ + u32 DesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; HANDLE hProcess; HMODULE hModule; MODULEINFO modinfo = { 0 }; - DWORD cbNeeded; + u32 cbNeeded; - SIZE_T lpBaseOfDll; + u64 lpBaseOfDll; - hProcess = OpenProcess(dwDesiredAccess, FALSE, processID); + hProcess = OpenProcess(DesiredAccess, FALSE, processID); if (NULL != hProcess) { @@ -40,59 +57,57 @@ GetModuleDllBase(DWORD processID, TCHAR *szModuleName) { if (GetModuleInformation(hProcess, hModule, &modinfo, sizeof(modinfo))) { - lpBaseOfDll = (SIZE_T) modinfo.lpBaseOfDll; + lpBaseOfDll = (u64) modinfo.lpBaseOfDll; } else { - printf("ERROR: Couldn't read module info structure.\n"); + fprintf(stderr, "ERROR: Couldn't read module info structure.\n"); } } CloseHandle(hProcess); } else { - printf("ERROR: Couldn't open the process.\n"); + fprintf(stderr, "ERROR: Couldn't open the process.\n"); } return lpBaseOfDll; } -DWORD -FindProcessIdByName( - DWORD *dwProcessesList, DWORD dwProcessesNumber, TCHAR *szModuleName) +u32 +FindProcessIdByName(u32 *ProcessesList, u32 ProcessesNumber, char *szModuleName) { - TCHAR szProcessName[MAX_PATH] = TEXT(""); - TCHAR lpFilename[MAX_PATH] = TEXT(""); + char szProcessName[MAX_PATH] = ""; + char lpFilename[MAX_PATH] = ""; HMODULE hMods[1024]; HANDLE hProcess; - TCHAR szBuffer[64]; - DWORD cModules; - DWORD processID = -1; - DWORD dwDesiredAcces = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + char szBuffer[64]; + u32 cModules; + u32 processID = -1; + u32 DesiredAcces = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; - for (int i = 0; i < dwProcessesNumber; i++) + for (int i = 0; i < ProcessesNumber; i++) { - processID = *dwProcessesList++; + processID = *ProcessesList++; - hProcess = OpenProcess(dwDesiredAcces, FALSE, processID); + hProcess = OpenProcess(DesiredAcces, FALSE, processID); // Get the process name. if (NULL != hProcess) { HMODULE hMod; - DWORD cbNeeded; + u32 cbNeeded; if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); ++i) { - /* code */ GetModuleBaseName(hProcess, hMods[i], szProcessName, - sizeof(szProcessName) / sizeof(TCHAR)); + sizeof(szProcessName) / sizeof(char)); // GetModuleFileNameEx(hProcess, hMods[i], lpFilename, MAX_PATH); - // _tprintf(TEXT("%d %s\n"), processID, szProcessName); - // _tprintf(TEXT("%d %s\n"), processID, lpFilename); + // _tprintf("%d %s\n", processID, szProcessName); + // _tprintf("%d %s\n", processID, lpFilename); if (strcmp(szProcessName, szModuleName) == 0) { @@ -112,9 +127,9 @@ FindProcessIdByName( } void -PrintProcessNameAndID(DWORD processID) +PrintProcessNameAndID(u32 processID) { - TCHAR szProcessName[MAX_PATH] = TEXT(""); + char szProcessName[MAX_PATH] = ""; // Get a handle to the process. HANDLE hProcess = OpenProcess( @@ -124,48 +139,47 @@ PrintProcessNameAndID(DWORD processID) if (NULL != hProcess) { HMODULE hMod; - DWORD cbNeeded; + u32 cbNeeded; if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { GetModuleBaseName( - hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR)); + hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(char)); } } // Print the process name and ID. - _tprintf(TEXT("%s (PID: %u)\n"), szProcessName, processID); + fprintf(stderr, "%s (PID: %u)\n", szProcessName, processID); // Release the handle to the process. CloseHandle(hProcess); } -DWORD -ReadMemoryValue(DWORD processID, SIZE_T offset, SIZE_T BytesToRead) +u32 +ReadMemoryValue(u32 processID, usize offset, usize BytesToRead) { - DWORD Value = -1; + u32 Value = -1; // Get a handle to the process. - HANDLE hProcess = OpenProcess( - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID); // Get the process name. if (NULL != hProcess) { - SIZE_T NumberOfBytesActuallyRead = -1; + usize NumberOfBytesActuallyRead = -1; - if (ReadProcessMemory(hProcess, (LPCVOID) offset, &Value, BytesToRead, + if (ReadProcessMemory(hProcess, (const void *) offset, &Value, BytesToRead, &NumberOfBytesActuallyRead)) { if (BytesToRead > NumberOfBytesActuallyRead) { - _tprintf(TEXT("ERROR: Not all bytes read from memory.\n")); + fprintf(stderr, "ERROR: Not all bytes read from memory.\n"); } CloseHandle(hProcess); } else { - _tprintf(TEXT( - "ERROR (ReadMemoryValue): Couldn't read from the process memory\n")); + fprintf(stderr, + "ERROR (ReadMemoryValue): Couldn't read from the process memory\n"); } } @@ -173,17 +187,65 @@ ReadMemoryValue(DWORD processID, SIZE_T offset, SIZE_T BytesToRead) return Value; } -DWORD -_GetProcessMemory( - DWORD processID, SIZE_T Offset, SIZE_T BytesToRead, void *Value) +u8 +ReadByteFromProcessMemory(u32 processID, usize offset) +{ + u8 Value = 0; + // Get a handle to the process. + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID); + + // Get the process name. + if (NULL != hProcess) + { + usize NumberOfBytesActuallyRead = -1; + + if (ReadProcessMemory(hProcess, (const void *) offset, &Value, 1, + &NumberOfBytesActuallyRead)) + { + } + else + { + fprintf(stderr, + "ERROR (ReadMemoryValue): Couldn't read from the process memory\n"); + } + } + + CloseHandle(hProcess); + return Value; +} + +u32 +ReadMemoryValue2(u32 processID, usize offset, usize BytesToRead, void *Value) +{ + usize BytesActuallyRead = -1; + // Get a handle to the process. + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID); + + // Get the process name. + if (NULL != hProcess) + { + + u8 *pvalue = Value; + for (int i = 0; i < BytesToRead; ++i) + { + ReadProcessMemory(hProcess, (const void *) offset++, (void *) pvalue++, 1, + &BytesActuallyRead); + } + } + + // CloseHandle(hProcess); + return BytesActuallyRead; +} + +u32 +_GetProcessMemory(u32 processID, usize Offset, usize BytesToRead, void *Value) { - SIZE_T BytesActuallyRead = -1; - SIZE_T FinalOffset = Offset - PSX_TO_EMU; + usize BytesActuallyRead = -1; + usize FinalOffset = Offset - PSX_TO_EMU + processBaseAddress; - // fprintf(stdout, "FinalOffset: 0x%02x - 0x%02x = 0x%02x\n", Offset, - // PSX_TO_EMU, - // FinalOffset); // Get a handle to the process. + fprintf(stderr, "GetProcessMemory - Offset: 0x%llx\n", FinalOffset); + HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); @@ -192,20 +254,20 @@ _GetProcessMemory( // Get the process name. if (NULL != hProcess) { - if (ReadProcessMemory(hProcess, (LPCVOID) FinalOffset, Value, BytesToRead, - &BytesActuallyRead)) + if (ReadProcessMemory(hProcess, (const void *) FinalOffset, Value, + BytesToRead, &BytesActuallyRead)) { if (BytesToRead > BytesActuallyRead) { - _tprintf(TEXT( - "ERROR (GetProcessMemory): Not all bytes read from memory.\n")); + fprintf(stderr, + "ERROR (GetProcessMemory): Not all bytes read from memory.\n"); } CloseHandle(hProcess); } else { - _tprintf(TEXT( - "ERROR (GetProcessMemory): Couldn't read from the process memory\n")); + fprintf(stderr, + "ERROR (GetProcessMemory): Couldn't read from the process memory\n"); exit(1); } } @@ -213,35 +275,75 @@ _GetProcessMemory( return BytesActuallyRead; } +void * +GetProcessMemory2(u32 processID, usize Offset, usize BytesToRead) +{ + usize BytesActuallyRead = -1; + usize FinalOffset = Offset - PSX_TO_EMU + processBaseAddress; + + // Get a handle to the process. + + u8 *buffer = (u8 *) malloc(BytesToRead); + fprintf(stderr, "GetProcessMemory - Offset: 0x%llx\n", FinalOffset); + + HANDLE hProcess = OpenProcess( + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); + + // fprintf(stdout, "hProcess: %i\n", hProcess); + + // Get the process name. + if (NULL != hProcess) + { + if (ReadProcessMemory(hProcess, (const void *) FinalOffset, buffer, + BytesToRead, &BytesActuallyRead)) + { + if (BytesToRead > BytesActuallyRead) + { + fprintf(stderr, + "ERROR (GetProcessMemory): Not all bytes read from memory.\n"); + } + CloseHandle(hProcess); + } + else + { + fprintf(stderr, + "ERROR (GetProcessMemory): Couldn't read from the process memory\n"); + exit(1); + } + } + // CloseHandle(hProcess); + return buffer; +} + void PrintMemoryValue( - DWORD processID, SIZE_T offset, SIZE_T BytesToRead, TCHAR *szDescription) + u32 processID, usize offset, usize BytesToRead, char *szDescription) { - TCHAR szBuffer[1024] = TEXT(""); + char szBuffer[1024] = ""; // Make sure to change Value size depending from the BytesToRead - short Value = -1; + i16 Value = -1; if (_GetProcessMemory(processID, offset, BytesToRead, &Value)) { - _tprintf(TEXT("Value of %s: %d\n"), szDescription, Value); + fprintf(stdout, "Value of %s: %d\n", szDescription, Value); } else { - _tprintf("ERROR (PrintMemoryValue): Couldn't read the Value\n"); + fprintf(stderr, "ERROR (PrintMemoryValue): Couldn't read the Value\n"); } } void -PrintProcessInfo(DWORD processID) +PrintProcessInfo(u32 processID) { - DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + u32 DesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; HANDLE hProcess; HMODULE hModule; MODULEINFO modinfo; - DWORD cbNeeded; + u32 cbNeeded; - hProcess = OpenProcess(dwDesiredAccess, FALSE, processID); + hProcess = OpenProcess(DesiredAccess, FALSE, processID); if (NULL != hProcess) { @@ -249,17 +351,17 @@ PrintProcessInfo(DWORD processID) { if (GetModuleInformation(hProcess, hModule, &modinfo, sizeof(modinfo))) { - LPVOID lpBaseOfDll = modinfo.lpBaseOfDll; - DWORD SizeOfImage = modinfo.SizeOfImage; - LPVOID EntryPoint = modinfo.EntryPoint; + void *lpBaseOfDll = modinfo.lpBaseOfDll; + u32 SizeOfImage = modinfo.SizeOfImage; + void *EntryPoint = modinfo.EntryPoint; - printf("Base of DLL: %p\n", lpBaseOfDll); - printf("Size of Image: %d\n", SizeOfImage); - printf("Entry Point: %p\n", EntryPoint); + fprintf(stdout, "Base of DLL: %p\n", lpBaseOfDll); + fprintf(stdout, "Size of Image: %d\n", SizeOfImage); + fprintf(stdout, "Entry Point: %p\n", EntryPoint); } else { - printf( + fprintf(stderr, "ERROR (PrintProcessInfo): Couldn't read module info structure.\n"); } } @@ -267,26 +369,27 @@ PrintProcessInfo(DWORD processID) } else { - printf("ERROR (PrintProcessInfo): Couldn't open the process.\n"); + fprintf(stderr, "ERROR (PrintProcessInfo): Couldn't open the process.\n"); } } void -PrintPriorityClass(DWORD processID) +PrintPriorityClass(u32 processID) { - DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; - DWORD dwPriorityClass; + u32 DesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + u32 PriorityClass; HANDLE hProcess; - hProcess = OpenProcess(dwDesiredAccess, FALSE, processID); + hProcess = OpenProcess(DesiredAccess, FALSE, processID); - dwPriorityClass = GetPriorityClass(hProcess); + PriorityClass = GetPriorityClass(hProcess); for (int i = 0; i < 6; i++) { - if (dwPriorityClass == dwPriorityClassValue[i]) + if (PriorityClass == PriorityClassValue[i]) { - printf("Process priority class is: %s\n", szPriorityClassName[i]); + fprintf( + stdout, "Process priority class is: %s\n", szPriorityClassName[i]); break; } } @@ -295,49 +398,49 @@ PrintPriorityClass(DWORD processID) } void -PrintModuleFileName(DWORD processID) +PrintModuleFileName(u32 processID) { - printf("Process ID: %d\n", processID); + fprintf(stdout, "Process ID: %d\n", processID); HANDLE hProcess; HMODULE hModules[32]; HMODULE hModule; - TCHAR lpFilename[MAX_PATH] = TEXT(""); - TCHAR szBaseName[MAX_PATH] = TEXT(""); - DWORD cbNeeded; - DWORD dwDesiredAccess = PROCESS_VM_READ | PROCESS_QUERY_INFORMATION; + char lpFilename[MAX_PATH] = ""; + char szBaseName[MAX_PATH] = ""; + u32 cbNeeded; + u32 DesiredAccess = PROCESS_VM_READ | PROCESS_QUERY_INFORMATION; - hProcess = OpenProcess(dwDesiredAccess, FALSE, processID); + hProcess = OpenProcess(DesiredAccess, FALSE, processID); if (NULL != hProcess) { if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) { - GetModuleBaseName(hProcess, hModules[0], szBaseName, - sizeof(szBaseName) / sizeof(TCHAR)); + GetModuleBaseName( + hProcess, hModules[0], szBaseName, sizeof(szBaseName) / sizeof(char)); GetModuleFileNameEx(hProcess, hModules[0], lpFilename, MAX_PATH); - _tprintf("Base name: %s File name: %s\n", szBaseName, lpFilename); + fprintf(stdout, "Base name: %s File name: %s\n", szBaseName, lpFilename); } CloseHandle(hProcess); } } void -PrintProcessVersion(DWORD processID) +PrintProcessVersion(u32 processID) { - DWORD dwVersion = GetProcessVersion(processID); + u32 Version = GetProcessVersion(processID); - short unsigned major, minor; + u16 major, minor; - major = (dwVersion & 0xFFFF0000) >> 16; - minor = dwVersion & 0x0000FFFF; + major = (Version & 0xFFFF0000) >> 16; + minor = Version & 0x0000FFFF; - printf("Version: %i.%i\n", major, minor); + fprintf(stdout, "Version: %i.%i\n", major, minor); } BOOL -GetProcessIdFromName(DWORD *processID, TCHAR *szModuleName) +GetProcessIdFromName(u32 *processID, char *szModuleName) { HANDLE hProcess = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, 0); @@ -388,7 +491,7 @@ GetProcessIdFromName(DWORD *processID, TCHAR *szModuleName) } BOOL -GetProcessIdFromName2(DWORD *processID, TCHAR *szModuleName) +GetProcessIdFromName2(u32 *processID, char *szModuleName) { HANDLE hProcess = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, 0); @@ -432,34 +535,42 @@ GetProcessIdFromName2(DWORD *processID, TCHAR *szModuleName) return FALSE; } -DWORD -ReadGameMemory(DWORD processID, SIZE_T Offset, SIZE_T BytesToRead, void *Value) +u32 +ReadGameMemory(u32 processID, usize Offset, usize BytesToRead, void *Value) { - SIZE_T BytesActuallyRead = -1; - SIZE_T FinalOffset = Offset - PSX_TO_EMU + processBaseAddress; - - // fprintf(stdout, "FinalOffset: 0x%02x - 0x%02x = 0x%02x\n", Offset, - // PSX_TO_EMU, FinalOffset); - - Toolhelp32ReadProcessMemory(processID, (LPCVOID) FinalOffset, (LPVOID) Value, - BytesToRead, &BytesActuallyRead); - - // if (BytesToRead > BytesActuallyRead) - // { - // _tprintf( - // TEXT("ERROR (ReadGameMemory): Not all bytes read from - // memory.\n")); - // } - // } - // else - // { - // _tprintf(TEXT( - // "ERROR (ReadGameMemory): Couldn't read from the process - // memory\n")); - // } + usize BytesActuallyRead = -1; + usize FinalOffset = + (usize)((usize) Offset - (usize) PSX_TO_EMU + (usize) processBaseAddress); + + Toolhelp32ReadProcessMemory( + processID, (usize *) FinalOffset, Value, BytesToRead, &BytesActuallyRead); + return BytesActuallyRead; } +void * +ReadGameMemory2(u32 processID, usize Offset, usize BytesToRead) +{ + + usize FinalOffset = + (usize) Offset - (usize) PSX_TO_EMU + (usize) processBaseAddress; + + void *pValue = (void *) malloc(BytesToRead); + + HANDLE hProcess = OpenProcess( + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); + + if (NULL != hProcess) + { + ReadProcessMemory( + hProcess, (const void *) FinalOffset, pValue, BytesToRead, NULL); + } + + // CloseHandle(hProcess); + + return pValue; +} + void PrintHeapList(processID) { fprintf(stdout, "Looking for a heap list...\n"); @@ -480,7 +591,7 @@ void PrintHeapList(processID) do { - fprintf(stdout, "Block size: %i\n", he32.dwBlockSize); + fprintf(stdout, "Block size: %I64i\n", he32.dwBlockSize); he32.dwSize = sizeof(HEAPENTRY32); } while (Heap32Next(&he32)); @@ -494,7 +605,7 @@ void PrintHeapList(processID) } BOOL -ListProcessModules(DWORD dwPID) +ListProcessModules(u32 dwPID) { HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; @@ -504,7 +615,7 @@ ListProcessModules(DWORD dwPID) CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwPID); if (hModuleSnap == INVALID_HANDLE_VALUE) { - // printError(TEXT("CreateToolhelp32Snapshot (of modules)")); + // printError("CreateToolhelp32Snapshot (of modules)"); return (FALSE); } me32.dwSize = sizeof(MODULEENTRY32); @@ -513,7 +624,7 @@ ListProcessModules(DWORD dwPID) // and exit if unsuccessful if (!Module32First(hModuleSnap, &me32)) { - // printError(TEXT("Module32First")); // Show cause of failure + // printError("Module32First"); // Show cause of failure CloseHandle(hModuleSnap); // Must clean up the snapshot object! return (FALSE); } @@ -522,25 +633,77 @@ ListProcessModules(DWORD dwPID) // and display information about each module do { - _tprintf(TEXT("\n\n MODULE NAME: %s"), me32.szModule); - _tprintf(TEXT("\n executable = %s"), me32.szExePath); - _tprintf(TEXT("\n process ID = 0x%08X"), me32.th32ProcessID); - _tprintf(TEXT("\n ref count (g) = 0x%04X"), me32.GlblcntUsage); - _tprintf(TEXT("\n ref count (p) = 0x%04X"), me32.ProccntUsage); - _tprintf(TEXT("\n base address = 0x%08X"), (DWORD) me32.modBaseAddr); - _tprintf(TEXT("\n base size = %d"), me32.modBaseSize); + if (strcmp(me32.szModule, szModuleName) == 0) + { + + fprintf(stdout, "\n\n MODULE NAME: %s\n", me32.szModule); + fprintf(stdout, " executable = %s\n", me32.szExePath); + fprintf(stdout, " process ID = 0x%08X\n", me32.th32ProcessID); + fprintf(stdout, " ref count (g) = 0x%04X\n", me32.GlblcntUsage); + fprintf(stdout, " ref count (p) = 0x%04X\n", me32.ProccntUsage); + fprintf(stdout, " base address = 0x%p\n", me32.modBaseAddr); + fprintf(stdout, " base size = %d\n", me32.modBaseSize); + } } while (Module32Next(hModuleSnap, &me32)); - _tprintf(TEXT("\n")); + fprintf(stdout, "\n"); // Do not forget to clean up the snapshot object. CloseHandle(hModuleSnap); return (TRUE); } +u64 +FindDllAddress(u32 dwPID, char *szModulName) +{ + HANDLE hModuleSnap = INVALID_HANDLE_VALUE; + MODULEENTRY32 me32; + + // Take a snapshot of all modules in the specified process. + hModuleSnap = + CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwPID); + if (hModuleSnap == INVALID_HANDLE_VALUE) + { + // printError("CreateToolhelp32Snapshot (of modules)"); + return (FALSE); + } + me32.dwSize = sizeof(MODULEENTRY32); + + // Retrieve information about the first module, + // and exit if unsuccessful + if (!Module32First(hModuleSnap, &me32)) + { + // printError("Module32First"); // Show cause of failure + CloseHandle(hModuleSnap); // Must clean up the snapshot object! + return (FALSE); + } + + // Now walk the module list of the process, + // and display information about each module + do + { + if (strcmp(szModuleName, me32.szModule) == 0) + { + return (u64) me32.modBaseAddr; + } + // _tprintf("\n\n MODULE NAME: %s\n", me32.szModule); + // _tprintf(" executable = %s\n", me32.szExePath); + // _tprintf(" process ID = 0x%08X\n", me32.th32ProcessID); + // _tprintf(" ref count (g) = 0x%04X\n", me32.GlblcntUsage); + // _tprintf(" ref count (p) = 0x%04X\n", me32.ProccntUsage); + // _tprintf(" base address = 0x%p\n", me32.modBaseAddr); + // _tprintf(" base size = %d\n", me32.modBaseSize); + + } while (Module32Next(hModuleSnap, &me32)); + + // Do not forget to clean up the snapshot object. + CloseHandle(hModuleSnap); + return (0); +} + BOOL -ListProcessThreads(DWORD dwPID) +ListProcessThreads(u32 dwPID) { HANDLE hThreadSnap = INVALID_HANDLE_VALUE; THREADENTRY32 te32 = { sizeof(THREADENTRY32) }; @@ -549,7 +712,7 @@ ListProcessThreads(DWORD dwPID) hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) { - // printError(TEXT("CreateToolhelp32Snapshot (of modules)")); + // printError("CreateToolhelp32Snapshot (of modules)"); return (FALSE); } @@ -557,7 +720,7 @@ ListProcessThreads(DWORD dwPID) // and exit if unsuccessful if (!Thread32First(hThreadSnap, &te32)) { - // printError(TEXT("Module32First")); // Show cause of failure + // printError("Module32First"); // Show cause of failure CloseHandle(hThreadSnap); // Must clean up the snapshot object! return (FALSE); } @@ -569,15 +732,15 @@ ListProcessThreads(DWORD dwPID) if (te32.th32OwnerProcessID == dwPID) { - _tprintf(TEXT("\n\n THREAD ID: %i"), te32.th32ThreadID); - _tprintf(TEXT("\n dwSize: %i"), te32.dwSize); - _tprintf(TEXT("\n Base Priority = %i"), te32.tpBasePri); - _tprintf(TEXT("\n Delta Priority = %i"), te32.tpDeltaPri); + fprintf(stdout, "\n\n THREAD ID: %i", te32.th32ThreadID); + fprintf(stdout, "\n dwSize: %i", te32.dwSize); + fprintf(stdout, "\n Base Priority = %i", te32.tpBasePri); + fprintf(stdout, "\n Delta Priority = %i", te32.tpDeltaPri); } } while (Thread32Next(hThreadSnap, &te32)); - _tprintf(TEXT("\n")); + fprintf(stdout, "\n"); // Do not forget to clean up the snapshot object. CloseHandle(hThreadSnap); @@ -585,7 +748,7 @@ ListProcessThreads(DWORD dwPID) } HANDLE -GetProcessHandle(TCHAR *ProcessName, DWORD *ReturnedProcessId) +GetProcessHandle(char *ProcessName, u32 *ReturnedProcessId) { PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; HANDLE hSnap; @@ -622,10 +785,10 @@ GetProcessHandle(TCHAR *ProcessName, DWORD *ReturnedProcessId) return 0; } -ULONG -GetModuleBase(TCHAR *ModuleName, DWORD ProcessId) +usize +GetModuleBase(char *ModuleName, u32 ProcessId) { - _tprintf(_T("Searching for %s\n"), ModuleName); + fprintf(stdout, "Searching for %s\n", ModuleName); MODULEENTRY32 me32 = { sizeof(MODULEENTRY32) }; @@ -641,9 +804,9 @@ GetModuleBase(TCHAR *ModuleName, DWORD ProcessId) { if (!ModuleName || strcmp(me32.szModule, ModuleName) == 0) { - _tprintf("I found the DLL!!!\n"); + fprintf(stdout, "I found the DLL!!!\n"); CloseHandle(hSnap); - return (ULONG) me32.modBaseAddr; + return (usize) me32.modBaseAddr; } bModule = Module32Next(hSnap, &me32); @@ -655,7 +818,7 @@ GetModuleBase(TCHAR *ModuleName, DWORD ProcessId) } HRSRC -GetModuleResource(HANDLE RemoteProcessHandle, TCHAR *szResourceName) +GetModuleResource(HANDLE RemoteProcessHandle, char *szResourceName) { HRSRC hResource = FindResource(RemoteProcessHandle, szResourceName, RT_RCDATA); @@ -664,30 +827,68 @@ GetModuleResource(HANDLE RemoteProcessHandle, TCHAR *szResourceName) } void -EnumProcessModules2(DWORD processID) +EnumProcessModules2(u32 processID) { HANDLE hProcess; - DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + u32 DesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; - hProcess = OpenProcess(dwDesiredAccess, FALSE, processID); + hProcess = OpenProcess(DesiredAccess, FALSE, processID); HMODULE hmArray[256]; - DWORD cb = sizeof(hmArray); - DWORD cbNeeded; - DWORD dwFilterFlag = LIST_MODULES_32BIT | LIST_MODULES_64BIT; - TCHAR szModulName[MAX_PATH]; + u32 cb = sizeof(hmArray); + u32 cbNeeded; + u32 dwFilterFlag = LIST_MODULES_32BIT | LIST_MODULES_64BIT; + char szModulName[MAX_PATH]; EnumProcessModulesEx(hProcess, hmArray, cb, &cbNeeded, dwFilterFlag); - _tprintf("cb: %i, cbNeeded: %i", cb, cbNeeded); + fprintf(stdout, "cb: %i, cbNeeded: %i", cb, cbNeeded); int cbSize = cbNeeded / sizeof(HMODULE); for (int i = 0; i < cbSize; ++i) { GetModuleFileNameEx(hProcess, hmArray[i], szModulName, MAX_PATH); - _tprintf(_T("Module name: %s"), szModuleName); + fprintf(stdout, "Module name: %s\n", szModuleName); + } +} + +BOOL +EnableDebugPrivilege(void) +{ + // Get the privilege value for `SeDebugPrivilege` + LUID luidDebugPrivilege; + LUID luidProfilePrivilege; + + if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebugPrivilege)) + { + ErrorExit("LookupPrivilegeValue"); } + + // Fill up the TOKEN_PRIVILEGES structure + TOKEN_PRIVILEGES tkPrivs; + + tkPrivs.PrivilegeCount = 1; // Modify 2 privileges + tkPrivs.Privileges[0].Luid = + luidDebugPrivilege; // we want to modify `SeDebugPrivilege` + tkPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // enable it + + HANDLE hCurrentProcess = GetCurrentProcess(); + HANDLE hProcessToken; + + if (!OpenProcessToken( + hCurrentProcess, TOKEN_ADJUST_PRIVILEGES, &hProcessToken)) + { + ErrorExit("OpenProcessToken"); + } + + // Let's enable Debug privileges in the token + if (!AdjustTokenPrivileges(hProcessToken, FALSE, &tkPrivs, 0, NULL, NULL)) + { + ErrorExit("AdjustTokenPrivileges"); + } + + return TRUE; } #endif \ No newline at end of file diff --git a/includes/vst_resources.h b/includes/vst_resources.h index e1e8981..438f6bf 100644 --- a/includes/vst_resources.h +++ b/includes/vst_resources.h @@ -7,7 +7,7 @@ BOOL CALLBACK EnumResNameProc( void ListModuleResources(HANDLE hModule, ENUMRESNAMEPROC EnumResNameProc) { - _tprintf(_T("Inside ListModuleResources()")); + _tprintf("Inside ListModuleResources()"); EnumResourceNames(hModule, NULL, EnumResNameProc, NULL); } @@ -15,7 +15,7 @@ BOOL CALLBACK EnumResNameProc( HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam) { - _tprintf(_T("Resource name: %s, type: %s"), lpszName, lpszType); + _tprintf("Resource name: %s, type: %s", lpszName, lpszType); return TRUE; } diff --git a/includes/vst_time.h b/includes/vst_time.h index ad5d587..21a471d 100644 --- a/includes/vst_time.h +++ b/includes/vst_time.h @@ -1,38 +1,15 @@ #ifndef _VST_TIME_H #define _VST_TIME_H -// -// Time Played -// - -// 4 bytes -#define OFFSET_TIME_PLAYED 0x80061074 - -typedef struct -{ - union { - UINT32 TimeCompound; - struct - { - UINT8 Centiseconds; - UINT8 Seconds; - UINT8 Minutes; - UINT8 Hours; - }; - } Time; -} playtime; - -playtime PlayTimeCurrent = { -1 }; -playtime PlayTimeTemp = { -1 }; -playtime RecordTime = { -1 }; +#define OFFSET_TIME_PLAYED 0x80061074 // 4 bytes void PrintPlayTimeFull(playtime *PlayTime) { - UINT8 Centiseconds = PlayTime->Time.Centiseconds; - UINT8 Seconds = PlayTime->Time.Seconds; - UINT8 Minutes = PlayTime->Time.Minutes; - UINT8 Hours = PlayTime->Time.Hours; + u8 Centiseconds = PlayTime->Centiseconds; + u8 Seconds = PlayTime->Seconds; + u8 Minutes = PlayTime->Minutes; + u8 Hours = PlayTime->Hours; fprintf(stdout, "\n= PLAY TIME =\n"); fprintf( @@ -42,59 +19,47 @@ PrintPlayTimeFull(playtime *PlayTime) void PrintPlayTimeShort(playtime *PlayTime) { - UINT8 Seconds = PlayTime->Time.Seconds; - UINT8 Minutes = PlayTime->Time.Minutes; - UINT8 Hours = PlayTime->Time.Hours; + u32 BytesWritten; - fprintf(stdout, "\n= PLAY TIME =\n"); - fprintf(stdout, "%02i:%02i:%02i\n", Hours, Minutes, Seconds); -} + u8 Seconds = PlayTime->Seconds; + u8 Minutes = PlayTime->Minutes; + u8 Hours = PlayTime->Hours; -void -PrintPlayTimeShort2(playtime *PlayTime) -{ - DWORD BytesWritten; - - UINT8 Seconds = PlayTime->Time.Seconds; - UINT8 Minutes = PlayTime->Time.Minutes; - UINT8 Hours = PlayTime->Time.Hours; - - sprintf(szBuffer, "\n\n== PLAY TIME ==\n\n"); + sprintf_s(szBuffer, _countof(szBuffer), "\n\n== PLAY TIME ==\n\n"); WriteToBackBuffer(); - sprintf(szBuffer, "%02i:%02i:%02i\n", Hours, Minutes, Seconds); + sprintf_s(szBuffer, _countof(szBuffer), "%02i:%02i:%02i\n", Hours, Minutes, + Seconds); WriteToBackBuffer(); } void PrintRecordTime(playtime *RecordTime) { - UINT8 Seconds = RecordTime->Time.Seconds; - UINT8 Minutes = RecordTime->Time.Minutes; - UINT8 Hours = RecordTime->Time.Hours; + u8 Seconds = RecordTime->Seconds; + u8 Minutes = RecordTime->Minutes; + u8 Hours = RecordTime->Hours; fprintf(stdout, "\n== RECORD TIME ==\n\n"); fprintf(stdout, "%02i:%02i:%02i\n", Hours, Minutes, Seconds); } -DWORD +void ReadPlayTime(playtime *PlayTime) { - SIZE_T BytesToRead = sizeof(playtime); - DWORD BytesRead; - BytesRead = ReadGameMemory( - processID, OFFSET_TIME_PLAYED, BytesToRead, &PlayTime->Time.TimeCompound); + usize BytesToRead = sizeof(playtime); + usize BytesRead; - return BytesRead; + ReadGameMemory(processID, OFFSET_TIME_PLAYED, BytesToRead, PlayTime); } void WritePlayTimeToFile(playtime *PlayTime, TCHAR FileName[MAX_PATH]) { - UINT8 Seconds = PlayTime->Time.Seconds; - UINT8 Minutes = PlayTime->Time.Minutes; - UINT8 Hours = PlayTime->Time.Hours; + u8 Seconds = PlayTime->Seconds; + u8 Minutes = PlayTime->Minutes; + u8 Hours = PlayTime->Hours; FILE *fpPlayTime = fopen(FileName, "w"); @@ -114,9 +79,9 @@ WriteRecordTimeToFile( sprintf(szFullPath, "%s/%s-%s", szFolderName, szTimeStampFile, FileName); - UINT8 Seconds = RecordTime->Time.Seconds; - UINT8 Minutes = RecordTime->Time.Minutes; - UINT8 Hours = RecordTime->Time.Hours; + u8 Seconds = RecordTime->Seconds; + u8 Minutes = RecordTime->Minutes; + u8 Hours = RecordTime->Hours; FILE *fpRecordTime = fopen(szFullPath, "w"); @@ -129,8 +94,8 @@ WriteRecordTimeToFile( BOOL ComparePlayTimeShort(playtime *Time1, playtime *Time2) { - if ((Time1->Time.TimeCompound & 0x0fff) == - (Time2->Time.TimeCompound & 0x0fff)) + if (Time1->Hours == Time2->Hours && Time1->Minutes == Time2->Minutes && + Time1->Seconds == Time2->Seconds) { return TRUE; } @@ -140,8 +105,12 @@ ComparePlayTimeShort(playtime *Time1, playtime *Time2) BOOL IsItLater(playtime *TimeOld, playtime *TimeNew) { - UINT32 Old = TimeOld->Time.TimeCompound & 0xfff0; - UINT32 New = TimeNew->Time.TimeCompound & 0xfff0; + u32 Old = (u32)(((u32)(TimeOld->Seconds) << 16) | // + ((u32)(TimeOld->Minutes) << 8) | // + ((u32)(TimeOld->Hours))); + u32 New = (u32)(((u32)(TimeNew->Seconds) << 16) | // + ((u32)(TimeNew->Minutes) << 8) | // + ((u32)(TimeNew->Hours))); return New > Old; } diff --git a/includes/vst_translate.h b/includes/vst_translate.h index 2186da9..a63c445 100644 --- a/includes/vst_translate.h +++ b/includes/vst_translate.h @@ -3,16 +3,16 @@ #define OFFSET_EQUIPPED_WEAPON_NAME_STRING 0x8011FA7C -INT8 TranslationTableHex[125] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, - 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, - 0x3B, 0x3C, 0x3D, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x4A, 0x4C, - 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x8F, 0x90, 0x91, 0x94, 0x96, 0x97, 0x98, 0x99, 0x9A, - 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA7, 0xA8, +u8 TranslationTableHex[125] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, + 0x3C, 0x3D, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x4A, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x8F, 0x90, 0x91, 0x94, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA7, 0xA8, 0xE8 }; char TranslationTableChars[125] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', @@ -27,16 +27,16 @@ char TranslationTableChars[125] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', typedef struct { - char Name[18]; + u8 NameHex[18]; } weapon_name; void -GetWeaponName(DWORD processID, char *WeaponName) +GetWeaponName(u32 processID, char *WeaponName) { - equip_item_info BladeInfo; + item_info BladeInfo; - SIZE_T BytesToRead = sizeof(equip_item_info); - DWORD BytesRead; + usize BytesToRead = sizeof(item_info); + u32 BytesRead; BytesRead = ReadGameMemory( processID, OFFSET_EQUIPPED_WEAPON_BLADE, BytesToRead, &BladeInfo); @@ -56,7 +56,7 @@ GetWeaponName(DWORD processID, char *WeaponName) for (int i = 0; i < 18; ++i) { - UINT8 HexCode = WeaponNameStruct.Name[i]; + u8 HexCode = WeaponNameStruct.NameHex[i]; if (HexCode == 0xE7) { break; @@ -64,38 +64,39 @@ GetWeaponName(DWORD processID, char *WeaponName) if (HexCode == 0xFA) { - if (WeaponNameStruct.Name[i + 1] == 0x06) + if (WeaponNameStruct.NameHex[i + 1] == 0x06) { - wsprintf(WeaponName, "%s ", WeaponName); + sprintf(WeaponName, "%s ", WeaponName); i++; continue; } } - for (int j = 0, size = NELEMS(TranslationTableHex); j < size; ++j) + for (int j = 0, size = _countof(TranslationTableHex); j < size; ++j) { if (TranslationTableHex[j] == HexCode) { - wsprintf(WeaponName, "%s%c", WeaponName, TranslationTableChars[j]); + sprintf(WeaponName, "%s%c", WeaponName, TranslationTableChars[j]); } } } // Some DEBUG info - sprintf(szBuffer, "\n\n== WEAPON NAME ==\n\n"); + sprintf_s(szBuffer, _countof(szBuffer), "\n\n== WEAPON NAME ==\n\n"); WriteToBackBuffer(); - sprintf(szBuffer, "In memory (HEX): "); + sprintf_s(szBuffer, _countof(szBuffer), "In memory (HEX): "); WriteToBackBuffer(); for (int i = 0; i < 18; ++i) { - UINT8 HexCode = WeaponNameStruct.Name[i]; + u8 HexCode = WeaponNameStruct.NameHex[i]; - sprintf(szBuffer, "%02X ", HexCode); + sprintf_s(szBuffer, _countof(szBuffer), "%02X ", HexCode); WriteToBackBuffer(); } - sprintf(szBuffer, "\nAfter translation: \"%s\"\n", WeaponName); + sprintf_s(szBuffer, _countof(szBuffer), "\nAfter translation: \"%s\"\n", + WeaponName); WriteToBackBuffer(); } diff --git a/includes/vst_types.h b/includes/vst_types.h new file mode 100644 index 0000000..20744f3 --- /dev/null +++ b/includes/vst_types.h @@ -0,0 +1,189 @@ +#ifndef _VST_TYPES_H +#define _VST_TYPES_H + +// Basic Types +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; + +typedef size_t usize; + +typedef float f32; +typedef double f64; + +// +// In-game structs +// + +// Play Time +#pragma pack(push, 1) +typedef struct +{ + u8 Centiseconds; // 1/100th of a second + u8 Seconds; + u8 Minutes; + u8 Hours; +} playtime; +#pragma pack(pop) + +// Player/Weapon Range +typedef struct +{ + // Area shape (bits 0-2): + // 1 spheroid + // 2 upward cylinder + // 3 up-downward cylinder + // 4 downward cone (base is at casting position) + // 5 upward cone (point is at casting position) + // 6 cuboid + // 7 rhombohedron + + // Shape angle (bits 3-7): + // increment by 360°/32, + // center is casting position, + // direction is upward, incrementing backward + u8 x; + u8 y; + u8 z; + + union { + u8 ShapeAngleCompound; + struct + { + u8 Shape : 3; + u8 Angle : 5; + }; + } ShapeAngle; +} range; + +// Item Extended Info +#pragma pack(push, 1) +typedef struct +{ + u16 NamesListPosition; + u8 ListPosition; + u8 WepFileNumber; + u8 Category; + + i8 STR; + i8 INT; + i8 AGL; + + u16 DPCur; + u16 DPMax; + u16 PPCur; + u16 PPMax; + + // Blades only + // (1=MP 2=RISK 3=HP 4=PP 5=nothing) + u8 DamageType; + u8 StatsCostType; + u8 StatsCostValue; + + u8 Material; + + i8 _padding0; + + u8 GemSlots; // grips and shields only + u8 GemsSpecialEffects; // gems only + + u8 EqiupmentListIndex; // RAM only + + range Range; // blades only + + i8 _padding1; + + // Type (grips only) + u8 TypeBlunt; + u8 TypeEdged; + u8 TypePiercing; + + // Class + i8 ClassHuman; + i8 ClassBeast; + i8 ClassUndead; + i8 ClassPhantom; + i8 ClassDragon; + i8 ClassEvil; + + i16 _padding2; + + // Affinity + i8 AffinityPhysical; + i8 AffinityAir; + i8 AffinityFire; + i8 AffinityEarth; + i8 AffinityWater; + i8 AffinityLight; + i8 AffinityDark; + + i8 _padding3; +} item_info; +#pragma pack(pop) + +// Player Stats +#pragma pack(push, 1) +typedef struct +{ + u16 HPCur; + u16 HPMax; + u16 MPCur; + u16 MPMax; + u16 Risk; + u16 STRCur; + u16 STRBase; + u16 INTCur; + u16 INTBase; + u16 AGLCur; + u16 AGLBase; + + u8 _padding0[3]; + + u8 WalkingSpeedWithBox; + + u8 _padding1; + + u8 RunningSpeed; + + u32 _padding2; + + range Range; +} player_stats; +#pragma pack(pop) + +// Player status effects (buffs / debuffs) +#pragma pack(push, 1) +typedef struct +{ + u32 EffectID; // bit mask + + u8 _padding0; + + u8 DurationOrFrequency; + + u8 _padding1; + + u32 CanceledBy; // bit mask + u32 ImmunizedBy; // bit mask +} status_effects; +#pragma pack(pop) + +// Player Location +#pragma pack(push, 1) +typedef struct +{ + u8 AreaNumber; + u8 RoomNumber; +} location; +#pragma pack(pop) + +#endif diff --git a/includes/vst_utils.h b/includes/vst_utils.h index 217a998..b44f2fe 100644 --- a/includes/vst_utils.h +++ b/includes/vst_utils.h @@ -2,15 +2,15 @@ #define _VST_UTILS_H SYSTEMTIME stLocalTime; -TCHAR szTimeStampDebug[64]; -TCHAR szTimeStampFile[64]; +char szTimeStampDebug[64]; +char szTimeStampFile[64]; void WriteTimeStampDebugString() { GetLocalTime(&stLocalTime); - sprintf(szTimeStampDebug, // + sprintf_s(szTimeStampDebug, _countof(szTimeStampDebug), // "%04d-%02d-%02d %02d:%02d:%02d: ", // stLocalTime.wYear, // stLocalTime.wMonth, // @@ -25,7 +25,7 @@ WriteTimeStampFileString() { GetLocalTime(&stLocalTime); - sprintf(szTimeStampFile, // + sprintf_s(szTimeStampFile, _countof(szTimeStampFile), // "%04d%02d%02dT%02d%02d%02d", // stLocalTime.wYear, // stLocalTime.wMonth, // @@ -35,4 +35,14 @@ WriteTimeStampFileString() stLocalTime.wSecond); } +u16 +ErrorExit(char *Message) +{ + u32 ErrorCode = GetLastError(); + + fprintf(stderr, "\n\n%s failed with the error code %d", Message, ErrorCode); + + exit(ErrorCode); +} + #endif \ No newline at end of file diff --git a/main.c b/main.c index 28532b0..f6aa5da 100644 --- a/main.c +++ b/main.c @@ -5,15 +5,8 @@ #include #include -#define NELEMS(x) (sizeof(x) / sizeof(x[0])) - -UINT16 LastBossHP = 0xff; -BOOL GameOver = FALSE; // set to TRUE when the last boss is dead -char GlobalWeaponName[18] = ""; -DWORD processID; -DWORD processVersion; -BOOL DEBUG; - +#include "includes/vst_types.h" +#include "includes/vst_init.h" #include "includes/vst_utils.h" #include "includes/vst_console.h" #include "includes/vst_process.h" @@ -27,34 +20,37 @@ BOOL DEBUG; // Main int -wmain(int argc, wchar_t *argv[]) +main(int argc, char *argv[]) { - WCHAR ver_s[3]; - UINT8 ver_d = 0; + char ver_s[3]; + u8 ver_d = 0; - do // repeat until the user enters the right option + do // repeat until the user enters a valid option { switch (argc) { case 1: { system("cls"); - printf("1. ePSXe 1.9.00\n"); - printf("2. ePSXe 1.9.25\n"); - printf("3. ePSXe 2.0.50\n"); - printf("0. Exit\n"); - wscanf_s(L"%2s", ver_s, (unsigned) _countof(ver_s)); + fprintf(stdout, "1. ePSXe 1.9.00\n"); + fprintf(stdout, "2. ePSXe 1.9.25\n"); + fprintf(stdout, "3. ePSXe 2.0.50\n"); + fprintf(stdout, "4. BizHawk 2.3.0\n"); + fprintf(stdout, "4. BizHawk 2.3.2\n\n"); + fprintf(stdout, "0. Exit\n\n"); + + scanf_s("%2s", ver_s, (unsigned) _countof(ver_s)); break; } case 2: { - wsprintfW(ver_s, argv[1]); + sprintf_s(ver_s, _countof(ver_s), argv[1]); break; } } - ver_d = _wtoi(ver_s); + ver_d = atoi(ver_s); switch (ver_d) { @@ -66,19 +62,36 @@ wmain(int argc, wchar_t *argv[]) case 1: { PSX_TO_EMU = PSX_TO_EPSXE_1900; - wsprintf(szModuleName, TEXT("%s"), TEXT("ePSXe.exe")); + sprintf_s(szExeName, MAX_PATH, "ePSXe.exe"); + sprintf_s(szModuleName, MAX_PATH, ""); break; } case 2: { PSX_TO_EMU = PSX_TO_EPSXE_1925; - wsprintf(szModuleName, TEXT("%s"), TEXT("ePSXe.exe")); + sprintf_s(szExeName, MAX_PATH, "ePSXe.exe"); + sprintf_s(szModuleName, MAX_PATH, ""); break; } case 3: { PSX_TO_EMU = PSX_TO_EPSXE_2050; - wsprintf(szModuleName, TEXT("%s"), TEXT("ePSXe.exe")); + sprintf_s(szExeName, MAX_PATH, "ePSXe.exe"); + sprintf_s(szModuleName, MAX_PATH, ""); + break; + } + case 4: + { + PSX_TO_EMU = PSX_TO_BIZHAWK_2300; + sprintf_s(szModuleName, MAX_PATH, "octoshock.dll"); + sprintf_s(szExeName, MAX_PATH, "EmuHawk.exe"); + break; + } + case 5: + { + PSX_TO_EMU = PSX_TO_BIZHAWK_2320; + sprintf_s(szModuleName, MAX_PATH, "octoshock.dll"); + sprintf_s(szExeName, MAX_PATH, "EmuHawk.exe"); break; } default: @@ -89,7 +102,7 @@ wmain(int argc, wchar_t *argv[]) } } while (!PSX_TO_EMU); - while (!(GetProcessIdFromName(&processID, szModuleName))) + while (!(GetProcessIdFromName(&processID, szExeName))) { system("cls"); @@ -98,6 +111,16 @@ wmain(int argc, wchar_t *argv[]) Sleep(1000); }; + system("cls"); + + if (!strlen(szModuleName)) + { + processBaseAddress = GetModuleDllBase(processID, szExeName); + } + else + { + processBaseAddress = FindDllAddress(processID, szModuleName); + } // Setup the folders mkdir("debug"); @@ -108,6 +131,15 @@ wmain(int argc, wchar_t *argv[]) // PrintProcessNameAndID(processID); // PrintProcessVersion(processID); // PrintModuleFileName(processID); + // EnumProcessModules2(processID); + fprintf(stdout, "processID: %i\n", processID); + fprintf(stdout, "processBaseAddress: 0x%llx\n", processBaseAddress); + + // processBaseAddress = GetModuleDllBase(processID, "octoshock.dll"); + // ListProcessThreads(processID); + ListProcessModules(processID); + + // getc(stdin); SetConsoleHandles(); cls(hStdout); @@ -128,26 +160,37 @@ wmain(int argc, wchar_t *argv[]) SetCursorPosition(hStdout, 0, 0); SetCursorPosition(hBackBuffer, 0, 0); - // Write player stats into the file + WriteBladeInfo(processID); + ReadPlayerStats(&PlayerStats); - if (CheckPlayerStats()) + if (CheckPlayerStats(&PlayerStats)) { + // TIME + PlayTimeTemp = PlayTimeCurrent; ReadPlayTime(&PlayTimeCurrent); - PrintPlayTimeShort2(&PlayTimeCurrent); - WritePlayTimeToFile(&PlayTimeCurrent, _T("game_stats//play-time.txt")); - // Check player's location + // Check if the time progressed + if (IsItLater(&PlayTimeTemp, &PlayTimeCurrent)) + { + WritePlayTimeToFile(&PlayTimeCurrent, "game_stats/play-time.txt"); + } + PrintPlayTimeShort(&PlayTimeCurrent); + + // LOCATION ReadLocation(&Location); GetAreaAndRoomName(&Location, szAreaName, szRoomName); - PrintLocation2(&Location, szAreaName, szRoomName); + PrintLocation(&Location, szAreaName, szRoomName); WriteLocationIntoFile(&Location, szAreaName, szRoomName); - PrintPlayerStats2(); + // STATS + ReadPlayerStats(&PlayerStats); + ReadPlayerStatus(&PlayerEffects); + PrintPlayerStats(&PlayerStats, &PlayerEffects); WritePlayerStats(); GetWeaponName(processID, GlobalWeaponName); - // Write equipment stats into files + // EQUIPMENT WriteWeaponInfo(processID); WriteBladeInfo(processID); @@ -175,13 +218,20 @@ wmain(int argc, wchar_t *argv[]) } else { - sprintf(szBuffer, "============================\n" - "== VSTracker v0.1.6-alpha ==\n" - "============================\n"); + + sprintf_s(szBuffer, _countof(szBuffer), + "============================\n" + "== VSTracker v0.2.0-alpha ==\n" + "============================\n"); WriteToBackBuffer(); - sprintf(szBuffer, "\nWaiting for the game to load ...\n"); + sprintf_s( + szBuffer, _countof(szBuffer), "\nWaiting for the game to load ...\n"); WriteToBackBuffer(); + + // sprintf_s(szBuffer, _countof(szBuffer), "\nprocessBaseAddress: 0x%p\n", + // (void *) processBaseAddress); + // WriteToBackBuffer(); } // Handle last boss @@ -190,23 +240,15 @@ wmain(int argc, wchar_t *argv[]) LastBossHandleIt2(); } - // SHORT keyState = GetAsyncKeyState(0x44); // 'D' for Debug Mode - - // if (keyState & 0x8000) // 0x8000 is 'D' key code - // { - // DEBUG = !DEBUG; - // FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); - // } - CopyFromBackBuffer(); - Sleep(100); + Sleep(10); } while (!GameOver); cls(hStdout); - PrintRecordTime(&RecordTime); + PrintRecordTime(&PlayTimeRecord); - printf("\nPress any key to exit the program...\n"); + fprintf(stdout, "\nPress any key to exit the program...\n"); getchar(); return 0;