This commit is contained in:
rr- 2021-02-07 21:13:18 +01:00
parent 458abef52b
commit bfaafeb345

445
main.c
View file

@ -1,8 +1,15 @@
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <dbghelp.h>
#define FEATURE_NOCD_DATA
#define FEATURE_KEEP_HEALTH_BETWEEN_LEVELS
#define FEATURE_DISABLE_MEDPACKS
#ifdef FEATURE_KEEP_HEALTH_BETWEEN_LEVELS
static int TR1MStoredLaraHealth = 1000;
#endif
typedef enum {
GBUF_RoomInfos = 11,
@ -122,13 +129,59 @@ typedef struct ItemInfo_t {
__int16 timer;
UINT16 flags; // see IFL_* defines
__int16 shade1;
//__int16 shade2;
//__int16 carriedItem;
LPVOID data;
PHD_3DPOS pos;
UINT16 moreFlags;
} ITEM_INFO;
typedef struct LaraInfo_t {
__int16 itemNumber;
__int16 gunStatus;
__int16 field_4;
__int16 field_6;
__int16 field_8;
__int16 waterStatus;
__int16 field_C;
__int16 field_E;
__int16 field_10;
__int16 air;
__int16 field_14;
__int16 field_16;
__int16 field_18;
__int16 field_1A;
__int32 field_1C;
__int32 field_20;
__int8 field_24[60];
__int32 field_60;
__int8 field_64[4];
__int32 field_68;
__int32 field_6C;
__int32 field_70;
__int32 field_74;
__int8 field_78[6];
__int16 field_7E;
__int8 field_80[6];
__int16 field_86;
__int8 field_88[6];
__int16 field_8E;
__int8 field_90[6];
__int16 field_96;
__int32 field_98;
__int8 field_9C[8];
__int32 field_A4;
__int8 field_A8[8];
__int32 field_B0;
__int8 field_B4[8];
__int32 field_BC;
__int8 field_C0[8];
__int8 field_C8[8];
__int16 field_D0;
__int16 field_D2;
__int16 field_D4;
__int16 field_D6;
__int16 field_D8;
} LARA_INFO;
#pragma pop
HINSTANCE hInstance = NULL;
@ -152,11 +205,98 @@ typedef struct {
#define ARRAY_(address, type, length) (*(type(*)length)(address))
#define INJECT(from,to) { \
((JMP*)(from))->opCode = 0xE9; \
((JMP*)(from))->offset = (DWORD)(to) - ((DWORD)(from) + sizeof(JMP)); \
static void InjectFunc(void *from, void *to) {
DWORD tmp;
TRACE("Patching %p to %p", from, to);
VirtualProtect(from, sizeof(JMP), PAGE_EXECUTE_READWRITE, &tmp);
HANDLE hCurrentProcess = GetCurrentProcess();
JMP buf;
buf.opCode = 0xE9;
buf.offset = (DWORD)(to) - ((DWORD)(from) + sizeof(JMP));
WriteProcessMemory(hCurrentProcess, from, &buf, sizeof(JMP), &tmp);
CloseHandle(hCurrentProcess);
// arsunt style
//((JMP*)(from))->opCode = 0xE9;
//((JMP*)(from))->offset = (DWORD)(to) - ((DWORD)(from) + sizeof(JMP));
}
static void PrintStackTrace() {
const size_t MaxNameLen = 255;
BOOL result;
HANDLE process;
HANDLE thread;
CONTEXT context;
STACKFRAME64 stack;
ULONG frame;
DWORD64 displacement;
IMAGEHLP_SYMBOL64 *pSymbol = malloc(
sizeof(IMAGEHLP_SYMBOL64) + (MaxNameLen + 1) * sizeof(TCHAR)
);
char *name = malloc(MaxNameLen + 1);
RtlCaptureContext(&context);
memset(&stack, 0, sizeof(STACKFRAME64));
process = GetCurrentProcess();
thread = GetCurrentThread();
displacement = 0;
stack.AddrPC.Offset = context.Eip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Esp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Ebp;
stack.AddrFrame.Mode = AddrModeFlat;
for (frame = 0; ; frame++) {
result = StackWalk64(
IMAGE_FILE_MACHINE_I386,
process,
thread,
&stack,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL
);
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
pSymbol->MaxNameLength = MaxNameLen;
SymGetSymFromAddr64(
process, (ULONG64)stack.AddrPC.Offset, &displacement, pSymbol
);
UnDecorateSymbolName(
pSymbol->Name, ( PSTR )name, MaxNameLen, UNDNAME_COMPLETE
);
TRACE(
"Frame %lu:\n"
" Symbol name: %s\n"
" PC address: 0x%08LX\n"
" Stack address: 0x%08LX\n"
" Frame address: 0x%08LX\n"
"\n",
frame,
pSymbol->Name,
(ULONG64)stack.AddrPC.Offset,
(ULONG64)stack.AddrStack.Offset,
(ULONG64)stack.AddrFrame.Offset
);
if (!result) {
break;
}
}
free(pSymbol);
free(name);
}
#define INJECT(from, to) { \
InjectFunc((void*)from, (void*)to); \
}
// data
#define cd_drive VAR_I_(0x0045A010, char, '.')
#define DEMO VAR_I_(0x0045F1C0, __int32, 0)
#define dword_45A1F0 VAR_U_(0x0045A1F0, __int32)
@ -176,15 +316,58 @@ typedef struct {
#define GameAllocMemFree VAR_U_(0x0045E334, __int32)
#define GameMemoryPointer VAR_U_(0x0045A034, __int32)
#define GameMemorySize VAR_U_(0x0045EEF8, __int32)
#define CurrentLevel VAR_U_(0x00453C4C, __int32)
#define Lara VAR_U_(0x0045ED80, LARA_INFO)
#define LaraItem VAR_U_(0x0045EE6C, ITEM_INFO*)
#define LevelNames ARRAY_(0x00453648, const char*, [22])
#define LevelTitles ARRAY_(0x00453DF8, const char*, [22])
#define SecretCounts ARRAY_(0x00453CB0, __int8, [16])
#define IsResetFlag VAR_U_(0x00459F50, int)
#define Word45BB14 VAR_U_(0x0045BB14, __int16)
#define Byte45BB17 VAR_U_(0x0045BB17, __int8)
#define Word45BB08 VAR_U_(0x0045BB08, __int16)
#define InputStatus VAR_U_(0x0045EEF4, int)
#define Kills VAR_U_(0x0045BB0E, int)
#define TimeTaken VAR_U_(0x0045BB0A, int)
#define PickupsTaken VAR_U_(0x0045BB16, int)
#define SecretsTaken VAR_U_(0x0045BB12, int)
#define HiRes VAR_U_(0x00459F64, int)
// foreign game functions
// functions
#define game_malloc ((void __cdecl*(*)(int, int))0x0041E2F0)
#define _fread ((size_t __cdecl(*)(void *a1, size_t a2, size_t a3, FILE *a4))0x00442C20)
#define ins_line ((int __cdecl(*)(int, int, int, int, int, char))0x00402710)
#define _fread ((size_t __cdecl(*)(void *, size_t, size_t, FILE *))0x00442C20)
#define InitialiseItemArray ((void __cdecl(*)(int itemCount))0x00421B10)
#define S_ExitSystem ((void __cdecl(*)(const char *))0x0041E260)
#define InitialiseItem ((void __cdecl(*)(__int16))0x00421CC0)
#define InitialiseLaraInventory ((void __cdecl(*)(int levelID))0x00428170)
#define InitialiseLOT ((void __cdecl(*)())0x0042A780)
#define LoadLevel ((int __cdecl(*)(const char *path, int levelID))0x0041AFB0)
#define T_DrawText ((void __cdecl(*)())0x00439B00)
#define S_DumpScreen ((__int32 __cdecl(*)())0x0042FC70)
#define S_InitialisePolyList ((void __cdecl(*)())0x0042FC60)
#define S_UpdateInput ((void __cdecl(*)())0x0041E550)
#define S_CopyBufferToScreen ((void __cdecl(*)())0x00416A60)
#define S_OutputPolyList ((void __cdecl(*)())0x0042FD10)
#define sub_41CD10 ((void __cdecl(*)())0x0041CD10)
#define sub_434520 ((void __cdecl(*)(int))0x00434520)
#define CreateStartInfo ((void __cdecl(*)(int levelID))0x004345E0)
#define TempVideoRemove ((void __cdecl(*)())0x004167D0)
#define T_InitPrint ((void __cdecl(*)())0x00439750)
#define T_Print ((int* __cdecl(*)(__int16, __int16, __int16, const char *))0x00439780)
#define T_CentreH ((unsigned int* __cdecl(*)(unsigned int*, __int16))0x004399A0)
#define T_CentreV ((unsigned int* __cdecl(*)(unsigned int*, __int16))0x004399C0)
#define TempVideoAdjust ((void __cdecl(*)(int hi_res, double sizer))0x00416550)
// enums
#define ID_LARA 0
#define ID_SMALL_MEDIPACK_ITEM 93
#define ID_LARGE_MEDIPACK_ITEM 94
#define ID_NUMBER_OBJECTS 191
// function reimplementations
void __cdecl init_game_malloc() {
TRACE("");
GameAllocMemPointer = GameMemoryPointer;
GameAllocMemFree = GameMemorySize;
GameAllocMemUsed = 0;
@ -251,6 +434,7 @@ int FindCdDrive() {
}
int LoadRooms(FILE *fp) {
TRACE("");
__int16 wCount;
__int32 dwCount;
@ -337,9 +521,178 @@ int LoadRooms(FILE *fp) {
_fread(&dwCount, sizeof(__int32), 1, fp);
FloorData = game_malloc(sizeof(__int16) * dwCount, GBUF_FloorData);
_fread(FloorData, sizeof(__int16), dwCount, fp);
return 1;
}
void __cdecl LevelStats(int levelID) {
TRACE("");
#ifdef FEATURE_KEEP_HEALTH_BETWEEN_LEVELS
// store Lara health
TR1MStoredLaraHealth = LaraItem ? LaraItem->hitPoints : 1000;
TRACE("Lara pointers: %p/%d", LaraItem, Lara.itemNumber);
TRACE("Storing Lara health: %d", LaraItem ? LaraItem->hitPoints : -1);
#endif
static char buf[100];
TempVideoAdjust(HiRes, 1.0);
T_InitPrint();
sprintf(buf, "%s", LevelTitles[levelID]);
unsigned int *txt = T_Print(0, -50, 0, buf);
T_CentreH(txt, 1);
T_CentreV(txt, 1);
int timeTakenInSeconds = TimeTaken / 0x1Eu;
if (timeTakenInSeconds / 3600) {
sprintf(
buf,
"%s %d:%d%d:%d%d",
"TIME TAKEN",
timeTakenInSeconds / 3600,
((timeTakenInSeconds / 60) % 60) / 10,
((timeTakenInSeconds / 60) % 60) % 10,
(timeTakenInSeconds % 60) / 10,
(timeTakenInSeconds % 60) % 10
);
} else {
sprintf(
buf,
"%s %d:%d%d",
"TIME TAKEN",
(timeTakenInSeconds / 60) % 60,
(timeTakenInSeconds % 60) / 10,
(timeTakenInSeconds % 60) % 10
);
}
txt = T_Print(0, 70, 0, buf);
T_CentreH(txt, 1);
T_CentreV(txt, 1);
int secretsTaken = 0;
int secretsTotal = 16;
do {
if (SecretsTaken & 1) {
++secretsTaken;
}
SecretsTaken >>= 1;
--secretsTotal;
}
while (secretsTotal);
sprintf(buf, "%s %d %s %d", "SECRETS", secretsTaken, "OF", SecretCounts[levelID]);
txt = T_Print(0, 40, 0, buf);
T_CentreH(txt, 1);
T_CentreV(txt, 1);
sprintf(buf, "%s %d", "PICKUPS", PickupsTaken);
txt = T_Print(0, 10, 0, buf);
T_CentreH(txt, 1);
T_CentreV(txt, 1);
sprintf(buf, "%s %d", "KILLS", Kills);
txt = T_Print(0, -20, 0, buf);
T_CentreH(txt, 1);
T_CentreV(txt, 1);
while (InputStatus & 0x100000) {
S_UpdateInput();
}
S_InitialisePolyList();
S_CopyBufferToScreen();
S_UpdateInput();
T_DrawText();
S_OutputPolyList();
S_DumpScreen();
while (!(InputStatus & 0x100000)) {
if (IsResetFlag) {
break;
}
S_InitialisePolyList();
S_CopyBufferToScreen();
S_UpdateInput();
T_DrawText();
S_OutputPolyList();
S_DumpScreen();
}
if (levelID == 15) {
Byte45BB17 = 1;
int tmp = 1;
do
sub_434520(tmp++);
while ( tmp <= 15 );
Word45BB14 = 1;
} else {
CreateStartInfo(levelID + 1);
sub_434520(levelID + 1);
Word45BB14 = levelID + 1;
}
Word45BB08 &= 0xFFFEu;
sub_41CD10();
TempVideoRemove();
}
int __cdecl LoadLevelByID(int levelID) {
TRACE("%d", levelID);
int ret = LoadLevel(LevelNames[levelID], levelID);
#ifdef FEATURE_KEEP_HEALTH_BETWEEN_LEVELS
// check if we're in main menu by seeing if there is Lara item in the
// currently loaded level.
int laraFound = 0;
for (int i = 0; i < LevelItemCount; i++) {
if (Items[i].objectID == ID_LARA) {
laraFound = 1;
}
}
if (!laraFound) {
TRACE("Resetting stored Lara health");
TR1MStoredLaraHealth = 1000;
}
#endif
return ret;
}
int __cdecl S_DrawHealthBar(int percent) {
TRACE("");
int v1; // esi
int result; // eax
int v3; // esi
v1 = 100 * percent / 100;
ins_line(7, 7, 109, 7, -100, 0);
ins_line(7, 8, 109, 8, -100, 0);
ins_line(7, 9, 109, 9, -100, 0);
ins_line(7, 10, 109, 10, -100, 0);
ins_line(7, 11, 109, 11, -100, 0);
ins_line(7, 12, 109, 12, -100, 0);
ins_line(7, 13, 109, 13, -100, 0);
ins_line(6, 14, 110, 14, -200, 17);
ins_line(110, 6, 110, 14, -200, 17);
ins_line(6, 6, 110, 6, -300, 19);
result = ins_line(6, 6, 6, 14, -300, 19);
if ( v1 ) {
v3 = v1 + 8;
ins_line(8, 8, v3, 8, -400, 8);
ins_line(8, 9, v3, 9, -400, 11);
ins_line(8, 10, v3, 10, -400, 8);
ins_line(8, 11, v3, 11, -400, 6);
result = ins_line(8, 12, v3, 12, -400, 24);
}
return result;
}
// int __cdecl my_ins_line(int a1, int a2, int a3, int a4, int a5, char a6) {
// TRACE("");
// return 0;
// }
int __cdecl LoadItems(FILE *handle)
{
int itemCount = 0;
@ -372,13 +725,22 @@ int __cdecl LoadItems(FILE *handle)
_fread(&currentItem->pos.rotY, 2u, 1u, handle);
_fread(&currentItem->shade1, 2u, 1u, handle);
_fread(&currentItem->flags, 2u, 1u, handle);
TRACE("Items[%d].objectID: %d", i, currentItem->objectID);
int objectID = currentItem->objectID;
if ( objectID < 0 || objectID >= 191 )
{
if (objectID < 0 || objectID >= ID_NUMBER_OBJECTS) {
sprintf(StringToShow, "LoadItems(): Bad Object number (%d) on Item %d", objectID, i);
S_ExitSystem(StringToShow);
}
#ifdef FEATURE_DISABLE_MEDPACKS
if (objectID == ID_LARGE_MEDIPACK_ITEM || objectID == ID_SMALL_MEDIPACK_ITEM) {
currentItem->pos.x = -1;
currentItem->pos.y = -1;
currentItem->pos.z = -1;
currentItem->roomNumber = 0;
}
#endif
InitialiseItem(i);
}
}
@ -386,6 +748,61 @@ int __cdecl LoadItems(FILE *handle)
return 1;
}
void __cdecl InitialiseLara(void) {
TRACE("");
LaraItem->moreFlags &= 0xFFDFu;
LaraItem->data = &Lara;
#ifdef FEATURE_KEEP_HEALTH_BETWEEN_LEVELS
TRACE("Restoring Lara health: %d", TR1MStoredLaraHealth);
LaraItem->hitPoints = TR1MStoredLaraHealth;
#else
TRACE("Restoring Lara health: default");
LaraItem->hitPoints = 1000;
#endif
Lara.air = 1800;
Lara.field_8 = 0;
Lara.field_20 = 0;
Lara.field_E = 0;
Lara.field_10 = 0;
Lara.field_16 = 0;
Lara.field_60 = 0;
Lara.field_1C = 0;
Lara.field_1A = 0;
Lara.field_96 = 0;
Lara.field_86 = 0;
Lara.field_8E = 0;
Lara.field_7E = 0;
Lara.field_6C = 0;
Lara.field_68 = 0;
Lara.field_74 = 0;
Lara.field_70 = 0;
TRACE("%x\n", &Lara.field_4 - &Lara.itemNumber);
if (RoomInfo[LaraItem->roomNumber].flags & 1) {
Lara.waterStatus = 1;
LaraItem->fallSpeed = 0;
LaraItem->goalAnimState = 13;
LaraItem->currentAnimState = 13;
LaraItem->animNumber = 108;
LaraItem->frameNumber = 1736;
} else {
Lara.waterStatus = 0;
LaraItem->goalAnimState = 2;
LaraItem->currentAnimState = 2;
LaraItem->animNumber = 11;
LaraItem->frameNumber = 185;
}
Lara.field_18 = 0;
InitialiseLOT(&Lara.field_C8);
Lara.field_D4 = 20480;
Lara.field_D6 = -20480;
Lara.field_D8 = 256;
InitialiseLaraInventory(CurrentLevel);
}
static void Inject() {
INJECT(0x0042A2C0, DB_Log);
INJECT(0x0041C020, FindCdDrive);
@ -395,6 +812,14 @@ static void Inject() {
INJECT(0x0041E3B0, game_free);
INJECT(0x0041BC60, LoadItems);
INJECT(0x00428020, InitialiseLara);
INJECT(0x0041AF90, LoadLevelByID);
INJECT(0x0041D5A0, LevelStats);
//INJECT(0x00402710, my_ins_line);
//INJECT(0x004302D0, S_DrawHealthBar);
//INJECT(0x00430450, S_DrawAirBar);
}
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {