This commit is contained in:
Sergeanur 2020-05-18 01:28:40 +03:00
parent 37480fb617
commit af22bb1495
3 changed files with 245 additions and 50 deletions

View File

@ -194,7 +194,7 @@ enum Config {
#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more #define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more
#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. not too many things #define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. not too many things
#define MORE_LANGUAGES // Add more translations to the game //#define MORE_LANGUAGES // Add more translations to the game
#define DEFAULT_NATIVE_RESOLUTION // Set default video mode to your native resolution (fixes Windows 10 launch) #define DEFAULT_NATIVE_RESOLUTION // Set default video mode to your native resolution (fixes Windows 10 launch)
#define USE_TXD_CDIMAGE // generate and load textures from txd.img #define USE_TXD_CDIMAGE // generate and load textures from txd.img
#define IMPROVED_VIDEOMODE // save and load videomode parameters instead of a magic number #define IMPROVED_VIDEOMODE // save and load videomode parameters instead of a magic number

View File

@ -7,27 +7,36 @@
#include "Frontend.h" #include "Frontend.h"
#include "Messages.h" #include "Messages.h"
#include "Text.h" #include "Text.h"
#include "Timer.h"
static wchar WideErrorString[25]; static wchar WideErrorString[25];
CText TheText; CText TheText;
//--MIAMI: DONE
CText::CText(void) CText::CText(void)
{ {
encoding = 'e'; encoding = 'e';
bHasMissionTextOffsets = false;
bIsMissionTextLoaded = false;
memset(szMissionTableName, 0, sizeof(szMissionTableName));
memset(WideErrorString, 0, sizeof(WideErrorString)); memset(WideErrorString, 0, sizeof(WideErrorString));
} }
//--MIAMI: DONE
void void
CText::Load(void) CText::Load(void)
{ {
uint8 *filedata; char filename[32];
char filename[32], type[4]; uint32 offset;
int length; int file;
int offset, sectlen; bool tkey_loaded = false, tdat_loaded = false;
ChunkHeader m_ChunkHeader;
bIsMissionTextLoaded = false;
bHasMissionTextOffsets = false;
Unload(); Unload();
filedata = new uint8[0x40000];
CFileMgr::SetDir("TEXT"); CFileMgr::SetDir("TEXT");
switch(CMenuManager::m_PrefsLanguage){ switch(CMenuManager::m_PrefsLanguage){
@ -59,49 +68,64 @@ CText::Load(void)
#endif #endif
} }
length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb"); file = CFileMgr::OpenFile(filename, "rb");
CFileMgr::SetDir("");
offset = 0; offset = 0;
while(offset < length){ while (!tkey_loaded || !tdat_loaded) {
type[0] = filedata[offset++]; ReadChunkHeader(&m_ChunkHeader, file, &offset);
type[1] = filedata[offset++]; if (m_ChunkHeader.size != 0) {
type[2] = filedata[offset++]; if (strncmp(m_ChunkHeader.magic, "TABL", 4) == 0) {
type[3] = filedata[offset++]; MissionTextOffsets.Load(m_ChunkHeader.size, file, &offset, 0x58000);
sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 | bHasMissionTextOffsets = true;
(int)filedata[offset+1]<<8 | (int)filedata[offset+0]; } else if (strncmp(m_ChunkHeader.magic, "TKEY", 4) == 0) {
offset += 4; this->keyArray.Load(m_ChunkHeader.size, file, &offset);
if(sectlen != 0){ tkey_loaded = true;
if(strncmp(type, "TKEY", 4) == 0) } else if (strncmp(m_ChunkHeader.magic, "TDAT", 4) == 0) {
keyArray.Load(sectlen, filedata, &offset); this->data.Load(m_ChunkHeader.size, file, &offset);
else if(strncmp(type, "TDAT", 4) == 0) tdat_loaded = true;
data.Load(sectlen, filedata, &offset); } else {
else CFileMgr::Seek(file, m_ChunkHeader.size, SEEK_CUR);
offset += sectlen; offset += m_ChunkHeader.size;
}
} }
} }
keyArray.Update(data.chars); keyArray.Update(data.chars);
CFileMgr::CloseFile(file);
delete[] filedata; CFileMgr::SetDir("");
} }
//--MIAMI: DONE
void void
CText::Unload(void) CText::Unload(void)
{ {
CMessages::ClearAllMessagesDisplayedByGame(); CMessages::ClearAllMessagesDisplayedByGame();
data.Unload();
keyArray.Unload(); keyArray.Unload();
data.Unload();
mission_keyArray.Unload();
mission_data.Unload();
bIsMissionTextLoaded = false;
memset(szMissionTableName, 0, sizeof(szMissionTableName));
} }
//--MIAMI: DONE
wchar* wchar*
CText::Get(const char *key) CText::Get(const char *key)
{ {
uint8 result = false;
#ifdef FIX_BUGS #ifdef FIX_BUGS
return keyArray.Search(key, data.chars); wchar *outstr = keyArray.Search(key, data.chars, &result);
#else #else
return keyArray.Search(key); wchar *outstr = keyArray.Search(key, &result);
#endif #endif
if (!result && bHasMissionTextOffsets && bIsMissionTextLoaded)
#ifdef FIX_BUGS
outstr = mission_keyArray.Search(key, mission_data.chars, &result);
#else
outstr = mission_keyArray.Search(key, &result);
#endif
return outstr;
} }
wchar UpperCaseTable[128] = { wchar UpperCaseTable[128] = {
@ -134,6 +158,7 @@ wchar FrenchUpperCaseTable[128] = {
253, 254, 255 253, 254, 255
}; };
//--MIAMI: TODO (check tables)
wchar wchar
CText::GetUpperCase(wchar c) CText::GetUpperCase(wchar c)
{ {
@ -165,6 +190,7 @@ CText::GetUpperCase(wchar c)
return c; return c;
} }
//--MIAMI: DONE
void void
CText::UpperCase(wchar *s) CText::UpperCase(wchar *s)
{ {
@ -174,21 +200,131 @@ CText::UpperCase(wchar *s)
} }
} }
//--MIAMI: DONE
void void
CKeyArray::Load(uint32 length, uint8 *data, int *offset) CText::GetNameOfLoadedMissionText(char *outName)
{ {
uint32 i; strcpy(outName, szMissionTableName);
uint8 *rawbytes; }
//--MIAMI: DONE
void
CText::ReadChunkHeader(ChunkHeader *buf, int32 file, uint32 *offset)
{
// original code loops 8 times to read 1 byte with CFileMgr::Read, that's retarded
CFileMgr::Read(file, (char*)buf, sizeof(ChunkHeader));
*offset += sizeof(ChunkHeader);
}
//--MIAMI: DONE
void
CText::LoadMissionText(char *MissionTableName)
{
char filename[32];
mission_keyArray.Unload();
mission_data.Unload();
bool search_result = false;
int missionTableId = 0;
for (missionTableId = 0; missionTableId < MissionTextOffsets.size; missionTableId++) {
if (strncmp(MissionTextOffsets.data[missionTableId].szMissionName, MissionTableName, strlen(MissionTextOffsets.data[missionTableId].szMissionName)) == 0) {
search_result = true;
break;
}
}
if (!search_result) {
printf("CText::LoadMissionText - couldn't find %s", MissionTableName);
return;
}
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;
#ifdef MORE_LANGUAGES
case LANGUAGE_POLISH:
sprintf(filename, "POLISH.GXT");
break;
case LANGUAGE_RUSSIAN:
sprintf(filename, "RUSSIAN.GXT");
break;
case LANGUAGE_JAPANESE:
sprintf(filename, "JAPANESE.GXT");
break;
#endif
}
CTimer::Suspend();
int file = CFileMgr::OpenFile(filename, "rb");
CFileMgr::Seek(file, MissionTextOffsets.data[missionTableId].offset, SEEK_SET);
char TableCheck[8];
CFileMgr::Read(file, TableCheck, 8);
if (strncmp(TableCheck, MissionTableName, 8) != 0)
printf("CText::LoadMissionText - expected to find %s in the text file", MissionTableName);
bool tkey_loaded = false, tdat_loaded = false;
ChunkHeader m_ChunkHeader;
while (!tkey_loaded || !tdat_loaded) {
uint32 bytes_read = 0;
ReadChunkHeader(&m_ChunkHeader, file, &bytes_read);
if (m_ChunkHeader.size != 0) {
if (strncmp(m_ChunkHeader.magic, "TKEY", 4) == 0) {
uint32 bytes_read = 0;
mission_keyArray.Load(m_ChunkHeader.size, file, &bytes_read);
tkey_loaded = true;
} else if (strncmp(m_ChunkHeader.magic, "TDAT", 4) == 0) {
uint32 bytes_read = 0;
mission_data.Load(m_ChunkHeader.size, file, &bytes_read);
tdat_loaded = true;
} else
CFileMgr::Seek(file, m_ChunkHeader.size, SEEK_CUR);
}
}
mission_keyArray.Update(mission_data.chars);
CFileMgr::CloseFile(file);
CTimer::Resume();
CFileMgr::SetDir("");
strcpy(szMissionTableName, MissionTableName);
bIsMissionTextLoaded = true;
}
//--MIAMI: DONE
void
CKeyArray::Load(uint32 length, int file, uint32 *offset)
{
char *rawbytes;
numEntries = length / sizeof(CKeyEntry); numEntries = length / sizeof(CKeyEntry);
entries = new CKeyEntry[numEntries]; entries = new CKeyEntry[numEntries];
rawbytes = (uint8*)entries; rawbytes = (char*)entries;
for(i = 0; i < length; i++) #if DUMB
rawbytes[i] = data[(*offset)++]; for (uint32 i = 0; i < length; i++)
CFileMgr::Read(file, &rawbytes[i], 1);
#else
CFileMgr::Read(file, rawbytes, length);
#endif
} }
//--MIAMI: DONE
void void
CKeyArray::Unload(void) CKeyArray::Unload(void)
{ {
@ -197,6 +333,7 @@ CKeyArray::Unload(void)
numEntries = 0; numEntries = 0;
} }
//--MIAMI: DONE
void void
CKeyArray::Update(wchar *chars) CKeyArray::Update(wchar *chars)
{ {
@ -207,6 +344,7 @@ CKeyArray::Update(wchar *chars)
#endif #endif
} }
//--MIAMI: DONE
CKeyEntry* CKeyEntry*
CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high) CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high)
{ {
@ -227,11 +365,12 @@ CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 hi
return nil; return nil;
} }
//--MIAMI: DONE
wchar* wchar*
#ifdef FIX_BUGS #ifdef FIX_BUGS
CKeyArray::Search(const char *key, wchar *data) CKeyArray::Search(const char *key, wchar *data, uint8 *result)
#else #else
CKeyArray::Search(const char *key) CKeyArray::Search(const char *key, uint8 *result)
#endif #endif
{ {
CKeyEntry *found; CKeyEntry *found;
@ -240,34 +379,47 @@ CKeyArray::Search(const char *key)
#ifdef FIX_BUGS #ifdef FIX_BUGS
found = BinarySearch(key, entries, 0, numEntries-1); found = BinarySearch(key, entries, 0, numEntries-1);
if(found) if (found) {
*result = true;
return (wchar*)((uint8*)data + found->valueOffset); return (wchar*)((uint8*)data + found->valueOffset);
}
#else #else
found = BinarySearch(key, entries, 0, numEntries-1); found = BinarySearch(key, entries, 0, numEntries-1);
if(found) if (found) {
*result = true;
return found->value; return found->value;
}
#endif #endif
*result = false;
#ifdef MASTER
sprintf(errstr, "%");
#else
sprintf(errstr, "%s missing", key); sprintf(errstr, "%s missing", key);
#endif // MASTER
for(i = 0; i < 25; i++) for(i = 0; i < 25; i++)
WideErrorString[i] = errstr[i]; WideErrorString[i] = errstr[i];
return WideErrorString; return WideErrorString;
} }
//--MIAMI: DONE
void void
CData::Load(uint32 length, uint8 *data, int *offset) CData::Load(uint32 length, int file, uint32 *offset)
{ {
uint32 i; char *rawbytes;
uint8 *rawbytes;
numChars = length / sizeof(wchar); numChars = length / sizeof(wchar);
chars = new wchar[numChars]; chars = new wchar[numChars];
rawbytes = (uint8*)chars; rawbytes = (char*)chars;
for(i = 0; i < length; i++) #if DUMB
rawbytes[i] = data[(*offset)++]; for(uint32 i = 0; i < length; i++)
CFileMgr::Read(file, &rawbytes[i], 1);
#else
CFileMgr::Read(file, rawbytes, length);
#endif
} }
//--MIAMI: DONE
void void
CData::Unload(void) CData::Unload(void)
{ {
@ -276,6 +428,16 @@ CData::Unload(void)
numChars = 0; numChars = 0;
} }
//--MIAMI: DONE
void
CMissionTextOffsets::Load(uint32 table_size, int file, uint32 *offset, int)
{
// not exact VC code but smaller and better :P
size = table_size / sizeof(CMissionTextOffsets::Entry);
CFileMgr::Read(file, (char*)data, sizeof(CMissionTextOffsets::Entry) * size);
*offset += sizeof(CMissionTextOffsets::Entry) * size;
}
void void
AsciiToUnicode(const char *src, wchar *dst) AsciiToUnicode(const char *src, wchar *dst)
{ {

View File

@ -28,14 +28,14 @@ public:
CKeyArray(void) : entries(nil), numEntries(0) {} CKeyArray(void) : entries(nil), numEntries(0) {}
~CKeyArray(void) { Unload(); } ~CKeyArray(void) { Unload(); }
void Load(uint32 length, uint8 *data, int *offset); void Load(uint32 length, int file, uint32 *offset);
void Unload(void); void Unload(void);
void Update(wchar *chars); void Update(wchar *chars);
CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high); CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high);
#ifdef FIX_BUGS #ifdef FIX_BUGS
wchar *Search(const char *key, wchar *data); wchar *Search(const char *key, wchar *data, uint8 *result);
#else #else
wchar *Search(const char *key); wchar *Search(const char *key, uint8* result);
#endif #endif
}; };
@ -47,15 +47,45 @@ public:
CData(void) : chars(nil), numChars(0) {} CData(void) : chars(nil), numChars(0) {}
~CData(void) { Unload(); } ~CData(void) { Unload(); }
void Load(uint32 length, uint8 *data, int *offset); void Load(uint32 length, int file, uint32 *offset);
void Unload(void); void Unload(void);
}; };
class CMissionTextOffsets
{
public:
struct Entry
{
char szMissionName[8];
uint32 offset;
};
enum {MAX_MISSION_TEXTS = 90}; // beware that LCS has more
Entry data[MAX_MISSION_TEXTS];
uint16 size;
CMissionTextOffsets(void) : size(0) {}
void Load(uint32 table_size, int file, uint32* bytes_read, int);
};
struct ChunkHeader
{
char magic[4];
int size;
};
class CText class CText
{ {
CKeyArray keyArray; CKeyArray keyArray;
CData data; CData data;
CKeyArray mission_keyArray;
CData mission_data;
char encoding; char encoding;
bool bHasMissionTextOffsets;
bool bIsMissionTextLoaded;
char szMissionTableName[8];
CMissionTextOffsets MissionTextOffsets;
public: public:
CText(void); CText(void);
void Load(void); void Load(void);
@ -63,6 +93,9 @@ public:
wchar *Get(const char *key); wchar *Get(const char *key);
wchar GetUpperCase(wchar c); wchar GetUpperCase(wchar c);
void UpperCase(wchar *s); void UpperCase(wchar *s);
void GetNameOfLoadedMissionText(char *outName);
void ReadChunkHeader(ChunkHeader *buf, int32 file, uint32 *bytes_read);
void LoadMissionText(char *MissionTableName);
}; };
extern CText TheText; extern CText TheText;