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 int ObjectOverrideMaxStringCount = 4;
constexpr rct_string_id ScenarioOverrideBase = 0x7000;
constexpr int ScenarioOverrideMaxStringCount = 3;
LanguagePack *LanguagePack::FromFile(int id, const utf8 *path)
{
assert(path != NULL);
@ -54,6 +57,7 @@ LanguagePack::LanguagePack(int id, const utf8 *text)
_stringData = NULL;
_currentGroup = NULL;
_currentObjectOverride = NULL;
_currentScenarioOverride = NULL;
auto reader = UTF8StringReader(text);
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
_stringDataSB = StringBuilder();
@ -86,7 +98,17 @@ LanguagePack::~LanguagePack()
}
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 ooIndex = offset / ObjectOverrideMaxStringCount;
int ooStringIndex = offset % ObjectOverrideMaxStringCount;
@ -124,6 +146,25 @@ rct_string_id LanguagePack::GetObjectOverrideStringId(const char *objectIdentifi
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)
{
assert(objectIdentifier != NULL);
@ -137,6 +178,19 @@ LanguagePack::ObjectOverride *LanguagePack::GetObjectOverride(const char *object
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
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -209,7 +263,10 @@ void LanguagePack::ParseLine(IStringReader *reader)
SkipToEndOfLine(reader);
break;
case '[':
ParseGroup(reader);
ParseGroupObject(reader);
break;
case '<':
ParseGroupScenario(reader);
break;
case '\r':
case '\n':
@ -223,7 +280,7 @@ void LanguagePack::ParseLine(IStringReader *reader)
}
}
void LanguagePack::ParseGroup(IStringReader *reader)
void LanguagePack::ParseGroupObject(IStringReader *reader)
{
auto sb = StringBuilder();
int codepoint;
@ -253,6 +310,7 @@ void LanguagePack::ParseGroup(IStringReader *reader)
if (sb.GetLength() == 8) {
_currentGroup = sb.GetString();
_currentObjectOverride = GetObjectOverride(_currentGroup);
_currentScenarioOverride = NULL;
if (_currentObjectOverride == NULL) {
_objectOverrides.push_back(ObjectOverride());
_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)
{
auto sb = StringBuilder();
@ -344,7 +438,11 @@ void LanguagePack::ParseString(IStringReader *reader)
_strings[stringId] = relativeOffset;
} else {
_currentObjectOverride->strings[stringId] = relativeOffset;
if (_currentObjectOverride != NULL) {
_currentObjectOverride->strings[stringId] = relativeOffset;
} else {
_currentScenarioOverride->strings[stringId] = relativeOffset;
}
}
_stringDataSB.Append(sb.GetBuffer());

View File

@ -30,6 +30,7 @@ public:
}
rct_string_id GetObjectOverrideStringId(const char *objectIdentifier, int index);
rct_string_id GetScenarioOverrideStringId(const utf8 *scenarioFilename, int index);
private:
struct ObjectOverride {
@ -37,13 +38,27 @@ private:
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;
utf8 *_stringData;
std::vector<const utf8*> _strings;
std::vector<ObjectOverride> _objectOverrides;
std::vector<ScenarioOverride> _scenarioOverrides;
LanguagePack(int id, const utf8 *text);
ObjectOverride *GetObjectOverride(const char *objectIdentifier);
ScenarioOverride *GetScenarioOverride(const utf8 *scenarioFilename);
///////////////////////////////////////////////////////////////////////////
// Parsing
@ -51,9 +66,11 @@ private:
StringBuilder _stringDataSB;
utf8 *_currentGroup;
ObjectOverride *_currentObjectOverride;
ScenarioOverride *_currentScenarioOverride;
void ParseLine(IStringReader *reader);
void ParseGroup(IStringReader *reader);
void ParseGroupObject(IStringReader *reader);
void ParseGroupScenario(IStringReader *reader);
void ParseString(IStringReader *reader);
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);
utf8 *widechar_to_utf8(const wchar_t *src);
bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds);
#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);
RCT2_GLOBAL(0x009AA00C, uint8) = 0;
// 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();
// Get filename
utf8 filename[MAX_PATH];
strcpy(filename, path_get_filename(path));
path_remove_extension(filename);
rct_string_id localisedStringIds[3];
if (language_get_localised_scenario_strings(filename, localisedStringIds)) {
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;
@ -282,23 +297,45 @@ void scenario_begin()
strcpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, s6Info->details);
strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s6Info->name);
rct_stex_entry* stex = g_stexEntries[0];
if ((int)stex != -1) {
char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER;
{
// Get filename
utf8 filename[MAX_PATH];
strcpy(filename, _scenarioFileName);
path_remove_extension(filename);
// Set localised park name
format_string(buffer, stex->park_name, 0);
park_set_name(buffer);
rct_string_id localisedStringIds[3];
if (language_get_localised_scenario_strings(filename, localisedStringIds)) {
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
format_string(buffer, stex->scenario_name, 0);
strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, buffer, 31);
((char*)RCT2_ADDRESS_SCENARIO_NAME)[31] = '\0';
// Set localised park name
format_string(buffer, stex->park_name, 0);
park_set_name(buffer);
// 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 localised scenario name
format_string(buffer, stex->scenario_name, 0);
strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, buffer, 31);
((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