add scenario overrides

This commit is contained in:
IntelOrca 2015-09-08 18:46:22 +01:00
parent 188978936b
commit fddf057d68
5 changed files with 192 additions and 27 deletions

View File

@ -13,6 +13,9 @@ extern "C" {
constexpr rct_string_id ObjectOverrideBase = 0x6000; constexpr rct_string_id ObjectOverrideBase = 0x6000;
constexpr int ObjectOverrideMaxStringCount = 4; constexpr int ObjectOverrideMaxStringCount = 4;
constexpr rct_string_id ScenarioOverrideBase = 0x7000;
constexpr int ScenarioOverrideMaxStringCount = 3;
LanguagePack *LanguagePack::FromFile(int id, const utf8 *path) LanguagePack *LanguagePack::FromFile(int id, const utf8 *path)
{ {
assert(path != NULL); assert(path != NULL);
@ -54,6 +57,7 @@ LanguagePack::LanguagePack(int id, const utf8 *text)
_stringData = NULL; _stringData = NULL;
_currentGroup = NULL; _currentGroup = NULL;
_currentObjectOverride = NULL; _currentObjectOverride = NULL;
_currentScenarioOverride = NULL;
auto reader = UTF8StringReader(text); auto reader = UTF8StringReader(text);
while (reader.CanRead()) { while (reader.CanRead()) {
@ -74,6 +78,14 @@ LanguagePack::LanguagePack(int id, const utf8 *text)
} }
} }
} }
for (size_t i = 0; i < _scenarioOverrides.size(); i++) {
for (int j = 0; j < ScenarioOverrideMaxStringCount; j++) {
const utf8 **strPtr = &(_scenarioOverrides[i].strings[j]);
if (*strPtr != NULL) {
*strPtr = (utf8*)(stringDataBaseAddress + (size_t)*strPtr);
}
}
}
// Destruct the string builder to free memory // Destruct the string builder to free memory
_stringDataSB = StringBuilder(); _stringDataSB = StringBuilder();
@ -86,7 +98,17 @@ LanguagePack::~LanguagePack()
} }
const utf8 *LanguagePack::GetString(int stringId) const { const utf8 *LanguagePack::GetString(int stringId) const {
if (stringId >= ObjectOverrideBase) { if (stringId >= ScenarioOverrideBase) {
int offset = stringId - ScenarioOverrideBase;
int ooIndex = offset / ScenarioOverrideMaxStringCount;
int ooStringIndex = offset % ScenarioOverrideMaxStringCount;
if (_scenarioOverrides.size() > (size_t)ooIndex) {
return _scenarioOverrides[ooIndex].strings[ooStringIndex];
} else {
return NULL;
}
}else if (stringId >= ObjectOverrideBase) {
int offset = stringId - ObjectOverrideBase; int offset = stringId - ObjectOverrideBase;
int ooIndex = offset / ObjectOverrideMaxStringCount; int ooIndex = offset / ObjectOverrideMaxStringCount;
int ooStringIndex = offset % ObjectOverrideMaxStringCount; int ooStringIndex = offset % ObjectOverrideMaxStringCount;
@ -124,6 +146,25 @@ rct_string_id LanguagePack::GetObjectOverrideStringId(const char *objectIdentifi
return STR_NONE; return STR_NONE;
} }
rct_string_id LanguagePack::GetScenarioOverrideStringId(const utf8 *scenarioFilename, int index)
{
assert(scenarioFilename != NULL);
assert(index < ScenarioOverrideMaxStringCount);
int ooIndex = 0;
for (const ScenarioOverride &scenarioOverride : _scenarioOverrides) {
if (_stricmp(scenarioOverride.filename, scenarioFilename) == 0) {
if (scenarioOverride.strings[index] == NULL) {
return STR_NONE;
}
return ScenarioOverrideBase + (ooIndex * ScenarioOverrideMaxStringCount) + index;
}
ooIndex++;
}
return STR_NONE;
}
LanguagePack::ObjectOverride *LanguagePack::GetObjectOverride(const char *objectIdentifier) LanguagePack::ObjectOverride *LanguagePack::GetObjectOverride(const char *objectIdentifier)
{ {
assert(objectIdentifier != NULL); assert(objectIdentifier != NULL);
@ -137,6 +178,19 @@ LanguagePack::ObjectOverride *LanguagePack::GetObjectOverride(const char *object
return false; return false;
} }
LanguagePack::ScenarioOverride *LanguagePack::GetScenarioOverride(const utf8 *scenarioIdentifier)
{
assert(scenarioIdentifier != NULL);
for (size_t i = 0; i < _scenarioOverrides.size(); i++) {
ScenarioOverride *so = &_scenarioOverrides[i];
if (_stricmp(so->name, scenarioIdentifier) == 0) {
return so;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Parsing // Parsing
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -209,7 +263,10 @@ void LanguagePack::ParseLine(IStringReader *reader)
SkipToEndOfLine(reader); SkipToEndOfLine(reader);
break; break;
case '[': case '[':
ParseGroup(reader); ParseGroupObject(reader);
break;
case '<':
ParseGroupScenario(reader);
break; break;
case '\r': case '\r':
case '\n': case '\n':
@ -223,7 +280,7 @@ void LanguagePack::ParseLine(IStringReader *reader)
} }
} }
void LanguagePack::ParseGroup(IStringReader *reader) void LanguagePack::ParseGroupObject(IStringReader *reader)
{ {
auto sb = StringBuilder(); auto sb = StringBuilder();
int codepoint; int codepoint;
@ -253,6 +310,7 @@ void LanguagePack::ParseGroup(IStringReader *reader)
if (sb.GetLength() == 8) { if (sb.GetLength() == 8) {
_currentGroup = sb.GetString(); _currentGroup = sb.GetString();
_currentObjectOverride = GetObjectOverride(_currentGroup); _currentObjectOverride = GetObjectOverride(_currentGroup);
_currentScenarioOverride = NULL;
if (_currentObjectOverride == NULL) { if (_currentObjectOverride == NULL) {
_objectOverrides.push_back(ObjectOverride()); _objectOverrides.push_back(ObjectOverride());
_currentObjectOverride = &_objectOverrides[_objectOverrides.size() - 1]; _currentObjectOverride = &_objectOverrides[_objectOverrides.size() - 1];
@ -263,6 +321,42 @@ void LanguagePack::ParseGroup(IStringReader *reader)
} }
} }
void LanguagePack::ParseGroupScenario(IStringReader *reader)
{
auto sb = StringBuilder();
int codepoint;
// Should have already deduced that the next codepoint is a <
reader->Skip();
// Read string up to > or line end
bool closedCorrectly = false;
while (reader->TryPeek(&codepoint)) {
if (IsNewLine(codepoint)) break;
reader->Skip();
if (codepoint == '>') {
closedCorrectly = true;
break;
}
sb.Append(codepoint);
}
if (closedCorrectly) {
SafeFree(_currentGroup);
_currentGroup = sb.GetString();
_currentObjectOverride = NULL;
_currentScenarioOverride = GetScenarioOverride(_currentGroup);
if (_currentScenarioOverride == NULL) {
_scenarioOverrides.push_back(ScenarioOverride());
_currentScenarioOverride = &_scenarioOverrides[_scenarioOverrides.size() - 1];
memset(_currentScenarioOverride, 0, sizeof(ObjectOverride));
_currentScenarioOverride->filename = sb.GetString();
}
}
}
void LanguagePack::ParseString(IStringReader *reader) void LanguagePack::ParseString(IStringReader *reader)
{ {
auto sb = StringBuilder(); auto sb = StringBuilder();
@ -344,7 +438,11 @@ void LanguagePack::ParseString(IStringReader *reader)
_strings[stringId] = relativeOffset; _strings[stringId] = relativeOffset;
} else { } else {
_currentObjectOverride->strings[stringId] = relativeOffset; if (_currentObjectOverride != NULL) {
_currentObjectOverride->strings[stringId] = relativeOffset;
} else {
_currentScenarioOverride->strings[stringId] = relativeOffset;
}
} }
_stringDataSB.Append(sb.GetBuffer()); _stringDataSB.Append(sb.GetBuffer());

View File

@ -30,6 +30,7 @@ public:
} }
rct_string_id GetObjectOverrideStringId(const char *objectIdentifier, int index); rct_string_id GetObjectOverrideStringId(const char *objectIdentifier, int index);
rct_string_id GetScenarioOverrideStringId(const utf8 *scenarioFilename, int index);
private: private:
struct ObjectOverride { struct ObjectOverride {
@ -37,13 +38,27 @@ private:
const utf8 *strings[4]; const utf8 *strings[4];
}; };
struct ScenarioOverride {
const utf8 *filename;
union {
const utf8 *strings[3];
struct {
const utf8 *name;
const utf8 *park;
const utf8 *details;
};
};
};
int _id; int _id;
utf8 *_stringData; utf8 *_stringData;
std::vector<const utf8*> _strings; std::vector<const utf8*> _strings;
std::vector<ObjectOverride> _objectOverrides; std::vector<ObjectOverride> _objectOverrides;
std::vector<ScenarioOverride> _scenarioOverrides;
LanguagePack(int id, const utf8 *text); LanguagePack(int id, const utf8 *text);
ObjectOverride *GetObjectOverride(const char *objectIdentifier); ObjectOverride *GetObjectOverride(const char *objectIdentifier);
ScenarioOverride *GetScenarioOverride(const utf8 *scenarioFilename);
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Parsing // Parsing
@ -51,9 +66,11 @@ private:
StringBuilder _stringDataSB; StringBuilder _stringDataSB;
utf8 *_currentGroup; utf8 *_currentGroup;
ObjectOverride *_currentObjectOverride; ObjectOverride *_currentObjectOverride;
ScenarioOverride *_currentScenarioOverride;
void ParseLine(IStringReader *reader); void ParseLine(IStringReader *reader);
void ParseGroup(IStringReader *reader); void ParseGroupObject(IStringReader *reader);
void ParseGroupScenario(IStringReader *reader);
void ParseString(IStringReader *reader); void ParseString(IStringReader *reader);
bool ParseToken(IStringReader *reader, uint32 *token); bool ParseToken(IStringReader *reader, uint32 *token);

View File

@ -385,4 +385,15 @@ rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/
} }
} }
bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds)
{
outStringIds[0] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 0);
outStringIds[1] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 1);
outStringIds[2] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 2);
return
outStringIds[0] != (rct_string_id)STR_NONE ||
outStringIds[1] != (rct_string_id)STR_NONE ||
outStringIds[2] != (rct_string_id)STR_NONE;
}
} }

View File

@ -82,4 +82,6 @@ int utf8_length(const utf8 *text);
wchar_t *utf8_to_widechar(const utf8 *src); wchar_t *utf8_to_widechar(const utf8 *src);
utf8 *widechar_to_utf8(const wchar_t *src); utf8 *widechar_to_utf8(const wchar_t *src);
bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds);
#endif #endif

View File

@ -73,14 +73,29 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in
SDL_RWclose(rw); SDL_RWclose(rw);
RCT2_GLOBAL(0x009AA00C, uint8) = 0; RCT2_GLOBAL(0x009AA00C, uint8) = 0;
// Checks for a scenario string object (possibly for localisation) // Get filename
if ((info->entry.flags & 0xFF) != 255) { utf8 filename[MAX_PATH];
if (object_get_scenario_text(&info->entry)) { strcpy(filename, path_get_filename(path));
rct_stex_entry* stex_entry = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, rct_stex_entry*); path_remove_extension(filename);
format_string(info->name, stex_entry->scenario_name, NULL);
format_string(info->details, stex_entry->details, NULL); rct_string_id localisedStringIds[3];
RCT2_GLOBAL(0x009AA00C, uint8) = stex_entry->var_06; if (language_get_localised_scenario_strings(filename, localisedStringIds)) {
object_free_scenario_text(); if (localisedStringIds[0] != (rct_string_id)STR_NONE) {
strncpy(info->name, language_get_string(localisedStringIds[0]), 64);
}
if (localisedStringIds[2] != (rct_string_id)STR_NONE) {
strncpy(info->details, language_get_string(localisedStringIds[2]), 256);
}
} else {
// Checks for a scenario string object (possibly for localisation)
if ((info->entry.flags & 0xFF) != 255) {
if (object_get_scenario_text(&info->entry)) {
rct_stex_entry* stex_entry = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, rct_stex_entry*);
format_string(info->name, stex_entry->scenario_name, NULL);
format_string(info->details, stex_entry->details, NULL);
RCT2_GLOBAL(0x009AA00C, uint8) = stex_entry->var_06;
object_free_scenario_text();
}
} }
} }
return 1; return 1;
@ -282,23 +297,45 @@ void scenario_begin()
strcpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, s6Info->details); strcpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, s6Info->details);
strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s6Info->name); strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s6Info->name);
rct_stex_entry* stex = g_stexEntries[0]; {
if ((int)stex != -1) { // Get filename
char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; utf8 filename[MAX_PATH];
strcpy(filename, _scenarioFileName);
path_remove_extension(filename);
// Set localised park name rct_string_id localisedStringIds[3];
format_string(buffer, stex->park_name, 0); if (language_get_localised_scenario_strings(filename, localisedStringIds)) {
park_set_name(buffer); if (localisedStringIds[0] != (rct_string_id)STR_NONE) {
strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, language_get_string(localisedStringIds[0]), 31);
((char*)RCT2_ADDRESS_SCENARIO_NAME)[31] = '\0';
}
if (localisedStringIds[1] != (rct_string_id)STR_NONE) {
park_set_name(language_get_string(localisedStringIds[1]));
}
if (localisedStringIds[2] != (rct_string_id)STR_NONE) {
strncpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, language_get_string(localisedStringIds[2]), 255);
((char*)RCT2_ADDRESS_SCENARIO_DETAILS)[255] = '\0';
}
} else {
rct_stex_entry* stex = g_stexEntries[0];
if ((int)stex != -1) {
char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER;
// Set localised scenario name // Set localised park name
format_string(buffer, stex->scenario_name, 0); format_string(buffer, stex->park_name, 0);
strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, buffer, 31); park_set_name(buffer);
((char*)RCT2_ADDRESS_SCENARIO_NAME)[31] = '\0';
// Set localised scenario details // Set localised scenario name
format_string(buffer, stex->details, 0); format_string(buffer, stex->scenario_name, 0);
strncpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, buffer, 255); strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, buffer, 31);
((char*)RCT2_ADDRESS_SCENARIO_DETAILS)[255] = '\0'; ((char*)RCT2_ADDRESS_SCENARIO_NAME)[31] = '\0';
// Set localised scenario details
format_string(buffer, stex->details, 0);
strncpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, buffer, 255);
((char*)RCT2_ADDRESS_SCENARIO_DETAILS)[255] = '\0';
}
}
} }
// Set the last saved game path // Set the last saved game path