From 2bf6674afc6b3a243f536fb30e313b055b35d533 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 30 May 2019 23:00:00 +0200 Subject: [PATCH] added CText --- src/Frontend.cpp | 1 + src/Frontend.h | 10 ++- src/Messages.cpp | 1 + src/Messages.h | 1 + src/Text.cpp | 201 +++++++++++++++++++++++++++++++++++++++++++++++ src/Text.h | 47 +++++++++++ 6 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 src/Text.cpp create mode 100644 src/Text.h diff --git a/src/Frontend.cpp b/src/Frontend.cpp index a96b6623..e1738172 100644 --- a/src/Frontend.cpp +++ b/src/Frontend.cpp @@ -3,6 +3,7 @@ #include "Frontend.h" int &CMenuManager::m_PrefsBrightness = *(int*)0x5F2E50; +int &CMenuManager::m_PrefsLanguage = *(int*)0x941238; CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); } diff --git a/src/Frontend.h b/src/Frontend.h index 3d7b6914..838139df 100644 --- a/src/Frontend.h +++ b/src/Frontend.h @@ -2,6 +2,14 @@ #include "Sprite2d.h" +enum { + LANGUAGE_AMERICAN, + LANGUAGE_FRENCH, + LANGUAGE_GERMAN, + LANGUAGE_ITALIAN, + LANGUAGE_SPANISH, +}; + struct tSkinInfo { int field_0; @@ -11,7 +19,6 @@ struct tSkinInfo int field_304; }; - class CMenuManager { public: @@ -77,6 +84,7 @@ public: int m_nScreenChangeDelayTimer; static int &m_PrefsBrightness; + static int &m_PrefsLanguage; void DrawFrontEnd(void); }; diff --git a/src/Messages.cpp b/src/Messages.cpp index 6754c9ae..e29300f4 100644 --- a/src/Messages.cpp +++ b/src/Messages.cpp @@ -3,3 +3,4 @@ #include "Messages.h" WRAPPER void CMessages::Display(void) { EAXJMP(0x529800); } +WRAPPER void CMessages::ClearAllMessagesDisplayedByGame(void) { EAXJMP(0x52B670); } diff --git a/src/Messages.h b/src/Messages.h index f7f90087..711427f1 100644 --- a/src/Messages.h +++ b/src/Messages.h @@ -4,4 +4,5 @@ class CMessages { public: static void Display(void); + static void ClearAllMessagesDisplayedByGame(void); }; diff --git a/src/Text.cpp b/src/Text.cpp new file mode 100644 index 00000000..0281043d --- /dev/null +++ b/src/Text.cpp @@ -0,0 +1,201 @@ +#include "common.h" +#include "patcher.h" +#include "FileMgr.h" +#include "Frontend.h" +#include "Messages.h" +#include "Text.h" + +static wchar_t WideErrorString[25]; + +CText &TheText = *(CText*)0x941520; + +CText::CText(void) +{ + keyArray.entries = nil; + keyArray.numEntries = 0; + data.chars = nil; + data.numChars = 0; + unknown = 101; // What's this? version number? + memset(WideErrorString, 0, sizeof(WideErrorString)); +} + +CText::~CText(void) +{ + data.Unload(); + keyArray.Unload(); +} + +void +CText::Load(void) +{ + uint8 *filedata; + char filename[32], type[4]; + int length; + int offset, sectlen; + + Unload(); + filedata = new uint8[0x40000]; + + CFileMgr::SetDir("TEXT"); + switch(CMenuManager::m_PrefsLanguage){ + case LANGUAGE_AMERICAN: + sprintf(filename, "AMERICAN.GXT"); + break; + case LANGUAGE_FRENCH: + sprintf(filename, "FRENCH.GXT"); + break; + case LANGUAGE_GERMAN: + sprintf(filename, "GERMAN.GXT"); + break; + case LANGUAGE_ITALIAN: + sprintf(filename, "ITALIAN.GXT"); + break; + case LANGUAGE_SPANISH: + sprintf(filename, "SPANISH.GXT"); + break; + } + + length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb"); + CFileMgr::SetDir(""); + + offset = 0; + while(offset < length){ + type[0] = filedata[offset++]; + type[1] = filedata[offset++]; + type[2] = filedata[offset++]; + type[3] = filedata[offset++]; + sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 | + (int)filedata[offset+1]<<8 | (int)filedata[offset+0]; + offset += 4; + if(sectlen != 0){ + if(strncmp(type, "TKEY", 4) == 0) + keyArray.Load(sectlen, filedata, &offset); + else if(strncmp(type, "TDAT", 4) == 0) + data.Load(sectlen, filedata, &offset); + else + offset += sectlen; + } + } + + keyArray.Update(data.chars); + + delete[] filedata; +} + +void +CText::Unload(void) +{ + CMessages::ClearAllMessagesDisplayedByGame(); + data.Unload(); + keyArray.Unload(); +} + +wchar_t* +CText::Get(const char *key) +{ + return keyArray.Search(key); +} + +void +CKeyArray::Load(uint32 length, uint8 *data, int *offset) +{ + uint32 i; + uint8 *rawbytes; + + numEntries = length / sizeof(CKeyEntry); + entries = new CKeyEntry[numEntries]; + rawbytes = (uint8*)entries; + + for(i = 0; i < length; i++) + rawbytes[i] = data[(*offset)++]; +} + +void +CKeyArray::Unload(void) +{ + delete[] entries; + entries = nil; + numEntries = 0; +} + +void +CKeyArray::Update(wchar_t *chars) +{ + int i; + for(i = 0; i < numEntries; i++) + entries[i].value = (wchar_t*)((uint8*)chars + (uintptr)entries[i].value); +} + +CKeyEntry* +CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high) +{ + int mid; + int diff; + + if(low > high) + return nil; + + mid = (low + high)/2; + diff = strcmp(key, entries[mid].key); + if(diff == 0) + return &entries[mid]; + if(diff < 0) + return BinarySearch(key, entries, low, mid-1); + if(diff > 0) + return BinarySearch(key, entries, mid+1, high); + return nil; +} + +wchar_t* +CKeyArray::Search(const char *key) +{ + CKeyEntry *found; + char errstr[25]; + int i; + + found = BinarySearch(key, entries, 0, numEntries-1); + if(found) + return found->value; + sprintf(errstr, "%s missing", key); + for(i = 0; i < 25; i++) + WideErrorString[i] = errstr[i]; + return WideErrorString; +} + + +void +CData::Load(uint32 length, uint8 *data, int *offset) +{ + uint32 i; + uint8 *rawbytes; + + numChars = length / sizeof(wchar_t); + chars = new wchar_t[numChars]; + rawbytes = (uint8*)chars; + + for(i = 0; i < length; i++) + rawbytes[i] = data[(*offset)++]; +} + +void +CData::Unload(void) +{ + delete[] chars; + chars = nil; + numChars = 0; +} + +STARTPATCHES + InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP); + InjectHook(0x52C580, &CText::Unload, PATCH_JUMP); + InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP); + + InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP); + InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP); + InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP); + InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP); + InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP); + + InjectHook(0x52C120, &CData::Load, PATCH_JUMP); + InjectHook(0x52C200, &CData::Unload, PATCH_JUMP); +ENDPATCHES diff --git a/src/Text.h b/src/Text.h new file mode 100644 index 00000000..c8d4e8b7 --- /dev/null +++ b/src/Text.h @@ -0,0 +1,47 @@ +#pragma once + +struct CKeyEntry +{ + wchar_t *value; + char key[8]; +}; +// If this fails, CKeyArray::Load will have to be fixed +static_assert(sizeof(CKeyEntry) == 12, "CKeyEntry: error"); + +class CKeyArray +{ +public: + CKeyEntry *entries; + int numEntries; + + void Load(uint32 length, uint8 *data, int *offset); + void Unload(void); + void Update(wchar_t *chars); + CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high); + wchar_t *Search(const char *key); +}; + +class CData +{ +public: + wchar_t *chars; + int numChars; + + void Load(uint32 length, uint8 *data, int *offset); + void Unload(void); +}; + +class CText +{ + CKeyArray keyArray; + CData data; + int8 unknown; +public: + CText(void); + ~CText(void); + void Load(void); + void Unload(void); + wchar_t *Get(const char *key); +}; + +extern CText &TheText;