diff --git a/CHANGELOG.md b/CHANGELOG.md index 22bcf066..18a0587f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,8 @@ - new opcode **2603 ([is_text_prefix](https://library.sannybuilder.com/#/sa/text/2603))** - new opcode **2604 ([is_text_suffix](https://library.sannybuilder.com/#/sa/text/2604))** - new opcode **2605 ([display_text_formatted](https://library.sannybuilder.com/#/sa/text/2605))** + - new opcode **2606 ([load_fxt](https://library.sannybuilder.com/#/sa/text/2606))** + - new opcode **2607 ([unload_fxt](https://library.sannybuilder.com/#/sa/text/2607))** - new and updated opcodes - implemented support for **memory pointer string** arguments for all game's native opcodes - **0B1E ([sign_extend](https://library.sannybuilder.com/#/sa/bitwise/0B1E))** diff --git a/cleo_plugins/Text/CTextManager.cpp b/cleo_plugins/Text/CTextManager.cpp index 06117f9d..57211694 100644 --- a/cleo_plugins/Text/CTextManager.cpp +++ b/cleo_plugins/Text/CTextManager.cpp @@ -25,14 +25,13 @@ namespace CLEO bool CTextManager::AddFxt(const char *key, const char *value, bool dynamic) { - // TODO: replace this part with in-place construction of FxtEntry, - // when it will be implemented in libstdc++ - // ^^ me iz noob and doesnt can use GNU - auto fxt = fxts.find(key); if (fxt != fxts.end()) { + if (fxt->second->text.compare(value) == 0) + return true; // already present + if (!dynamic || fxt->second->is_static) { LOG_WARNING(0, "Attempting to add FXT \'%s\' - FAILED (GXT conflict)", key, value); @@ -47,6 +46,7 @@ namespace CLEO std::transform(str.begin(), str.end(), str.begin(), ::toupper); fxts[str.c_str()] = new FxtEntry(value, !dynamic); } + return true; } @@ -122,13 +122,13 @@ namespace CLEO { } - size_t CTextManager::ParseFxtFile(std::istream& stream) + size_t CTextManager::ParseFxtFile(std::istream& stream, bool dynamic, bool remove) { static char buf[0x100]; char *key_iterator, *value_iterator, *value_start, *key_start; stream.exceptions(std::ios::badbit); - size_t addedCount = 0; + size_t keyCount = 0; while (true) { if (stream.eof()) break; @@ -142,11 +142,22 @@ namespace CLEO { if (*key_iterator == '#') // start of comment break; - if (*key_iterator == '/' && key_iterator[1] == '/') + if (*key_iterator == '/' && key_iterator[1] == '/') // comment break; + if (isspace(*key_iterator)) { - *key_iterator = '\0'; + *key_iterator = '\0'; // terminate key string + + if (remove) + { + if (RemoveFxt(key_start)) + { + keyCount++; + } + break; + } + // while (isspace(*++key_iterator)) ; // skip leading spaces value_start = value_iterator = key_iterator + 1; while (*value_iterator) @@ -162,9 +173,9 @@ namespace CLEO } // register found fxt entry - if (AddFxt(key_start, value_start, false)) + if (AddFxt(key_start, value_start, dynamic)) { - addedCount++; + keyCount++; } break; @@ -173,6 +184,6 @@ namespace CLEO } } - return addedCount; + return keyCount; } } diff --git a/cleo_plugins/Text/CTextManager.h b/cleo_plugins/Text/CTextManager.h index 5aa76e91..2668e62e 100644 --- a/cleo_plugins/Text/CTextManager.h +++ b/cleo_plugins/Text/CTextManager.h @@ -35,6 +35,6 @@ namespace CLEO const char *LocateFxt(const char *key); // erase all fxts, added by scripts void ClearDynamicFxts(); - size_t ParseFxtFile(std::istream& stream); + size_t ParseFxtFile(std::istream& stream, bool dynamic = false, bool remove = false); }; } diff --git a/cleo_plugins/Text/Text.cpp b/cleo_plugins/Text/Text.cpp index 8614efe4..deada1b5 100644 --- a/cleo_plugins/Text/Text.cpp +++ b/cleo_plugins/Text/Text.cpp @@ -59,6 +59,8 @@ class Text CLEO_RegisterOpcode(0x2603, opcode_2603); // is_text_prefix CLEO_RegisterOpcode(0x2604, opcode_2604); // is_text_sufix CLEO_RegisterOpcode(0x2605, opcode_2605); // display_text_formatted + CLEO_RegisterOpcode(0x2606, opcode_2606); // load_fxt + CLEO_RegisterOpcode(0x2607, opcode_2607); // unload_fxt // register event callbacks CLEO_RegisterCallback(eCallbackId::GameBegin, OnGameBegin); @@ -427,7 +429,7 @@ class Text OPCODE_READ_PARAM_STRING_FORMATTED(text); // new GXT label - // includes unprintable character, to ensure there will be no collision with user GXT lables + // includes unprintable character, to ensure there will be no collision with user GXT labels char gxt[8] = { 0x01, 'C', 'L', 'E', 'O', '_', 0x01, 0x00 }; gxt[6] += CTheScripts::NumberOfIntroTextLinesThisFrame; // unique label for each possible entry @@ -442,6 +444,46 @@ class Text return OR_CONTINUE; } + + //2606=1, load_fxt %1d% + static OpcodeResult __stdcall opcode_2606(CLEO::CRunningScript* thread) + { + OPCODE_READ_PARAM_FILEPATH(filename); + + size_t added = 0; + try + { + std::ifstream stream(filename); + added = textManager.ParseFxtFile(stream, true, false); + } + catch (std::exception& ex) + { + LOG_WARNING(0, "Loading of FXT file '%s' failed: \n%s", filename, ex.what()); + } + + OPCODE_CONDITION_RESULT(added != 0); + return OR_CONTINUE; + } + + //2607=1, unload_fxt %1d% + static OpcodeResult __stdcall opcode_2607(CLEO::CRunningScript* thread) + { + OPCODE_READ_PARAM_FILEPATH(filename); + + size_t removed = 0; + try + { + std::ifstream stream(filename); + removed = textManager.ParseFxtFile(stream, true, true); + } + catch (std::exception& ex) + { + LOG_WARNING(0, "Unloading of FXT file '%s' failed: \n%s", filename, ex.what()); + } + + OPCODE_CONDITION_RESULT(removed != 0); + return OR_CONTINUE; + } } textInstance; CTextManager Text::textManager; diff --git a/tests/cleo_tests/Text/2606.txt b/tests/cleo_tests/Text/2606.txt new file mode 100644 index 00000000..eb85b7fa --- /dev/null +++ b/tests/cleo_tests/Text/2606.txt @@ -0,0 +1,56 @@ +{$CLEO .s} +{$INCLUDE_ONCE ../cleo_tester.inc} + +script_name '2606' +test("2606 (load_fxt)", tests) +terminate_this_custom_script + +function tests + it("GXTs should not exists yet", test1) + it("should load new GXTs", test2) + return + + function test1 + int ptr + + ptr = get_text_label_string {key} 'CLEO_T1' + assert_ptr(ptr) + assert_eqs(ptr, "") + + ptr = get_text_label_string {key} 'CLEO_T2' + assert_ptr(ptr) + assert_eqs(ptr, "") + + ptr = get_text_label_string {key} 'CLEO_T3' + assert_ptr(ptr) + assert_eqs(ptr, "") + end + + function test2 + 2606: load_fxt {filepath} "cleo\cleo_tests\text\non existing file.fxt" + assert_result_false() + + 2606: load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" + assert_result_true() + + int ptr + + ptr = get_text_label_string {key} 'CLEO_T1' + assert_ptr(ptr) + assert_eqs(ptr, "Test one") + + ptr = get_text_label_string {key} 'CLEO_T2' + assert_ptr(ptr) + assert_eqs(ptr, "Test two") + + ptr = get_text_label_string {key} 'CLEO_T3' + assert_ptr(ptr) + assert_eqs(ptr, "Test three") + + // load again + 2606: load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" + assert_result_true() + + unload_fxt {filepath} "cleo\cleo_tests\text\test.fxt" + end +end diff --git a/tests/cleo_tests/Text/2607.txt b/tests/cleo_tests/Text/2607.txt new file mode 100644 index 00000000..1433cf0d --- /dev/null +++ b/tests/cleo_tests/Text/2607.txt @@ -0,0 +1,74 @@ +{$CLEO .s} +{$INCLUDE_ONCE ../cleo_tester.inc} + +script_name '2607' +test("2607 (unload_fxt)", tests) +terminate_this_custom_script + +function tests + it("GXTs should not exists yet", test1) + it("should load new GXTs", test2) + it("should unload GXTs", test3) + return + + function test1 + int ptr + + ptr = get_text_label_string {key} 'CLEO_T1' + assert_ptr(ptr) + assert_eqs(ptr, "") + + ptr = get_text_label_string {key} 'CLEO_T2' + assert_ptr(ptr) + assert_eqs(ptr, "") + + ptr = get_text_label_string {key} 'CLEO_T3' + assert_ptr(ptr) + assert_eqs(ptr, "") + end + + function test2 + load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" + assert_result_true() + + int ptr + + ptr = get_text_label_string {key} 'CLEO_T1' + assert_ptr(ptr) + assert_eqs(ptr, "Test one") + + ptr = get_text_label_string {key} 'CLEO_T2' + assert_ptr(ptr) + assert_eqs(ptr, "Test two") + + ptr = get_text_label_string {key} 'CLEO_T3' + assert_ptr(ptr) + assert_eqs(ptr, "Test three") + + // load again + load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" + assert_result_true() + end + + function test3 + 2607: unload_fxt {filepath} "cleo\cleo_tests\text\non existing file.fxt" + assert_result_false() + + 2607: unload_fxt {filepath} "cleo\cleo_tests\text\test.fxt" + assert_result_true() + + int ptr + + ptr = get_text_label_string {key} 'CLEO_T1' + assert_ptr(ptr) + assert_eqs(ptr, "") + + ptr = get_text_label_string {key} 'CLEO_T2' + assert_ptr(ptr) + assert_eqs(ptr, "") + + ptr = get_text_label_string {key} 'CLEO_T3' + assert_ptr(ptr) + assert_eqs(ptr, "") + end +end diff --git a/tests/cleo_tests/Text/Test.fxt b/tests/cleo_tests/Text/Test.fxt new file mode 100644 index 00000000..82d1ecc1 --- /dev/null +++ b/tests/cleo_tests/Text/Test.fxt @@ -0,0 +1,3 @@ +CLEO_T1 Test one +CLEO_T2 Test two +CLEO_T3 Test three \ No newline at end of file