From e45fab0c0f6867d6921b1b2363f466b25ff3764c Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Fri, 16 Feb 2024 01:27:51 +0300 Subject: [PATCH] [mod] Initial 0.0.3 changes. --- examples/mods/aim1_community_fix/my_mod.cpp | 88 ++++++++++++++++----- src/aim1_mod_maker/aim1_mod_maker.h | 54 ++++++++++--- 2 files changed, 108 insertions(+), 34 deletions(-) diff --git a/examples/mods/aim1_community_fix/my_mod.cpp b/examples/mods/aim1_community_fix/my_mod.cpp index 7b41fd3..2927fe5 100644 --- a/examples/mods/aim1_community_fix/my_mod.cpp +++ b/examples/mods/aim1_community_fix/my_mod.cpp @@ -28,9 +28,19 @@ deps: pub.lzwdgc.Polygon4.Tools.aim1_mod_maker-master // patch note: Installation // patch note: Unpack and drop all files near original aim.exe. Replace files if necessary. // patch note: Or you can use mod_activator.exe, put it near aim.exe and drop mod archive -// patch note: onto mod_activator.exe in explorer. +// patch note: onto mod_activator.exe in explorer. // patch note: Game loads .pak files from the latest to oldest, so active mod .pak file must have -// patch note: the latest timestamp on it. +// patch note: the latest timestamp on it. +// patch note: You should start new game after applying this mod. This is necessary for map changes +// patch note: to became visible. +// patch note: +// patch note: Changes from 0.0.2 +// patch note: correctly use .mmo files from the last patch instead of v1.0.0 (from res3.pak) +// patch note: add Finder-2 glider model from aim2 +// patch note: db changes for double weapon gliders +// patch note: +// patch note: Changes from 0.0.1 +// patch note: enable double weapon gliders // patch note: int main(int argc, char *argv[]) { @@ -40,12 +50,12 @@ int main(int argc, char *argv[]) { #else "test_mod"s #endif - + "-0.0.2"s + + "-0.0.3"s ); mod.add_code_file_for_archive(INJECTIONS_FILE_NAME); mod.add_code_file_for_archive(AIM_TYPES_FILE_NAME); - // patch note: CHANGES + // patch note: === LIST OF CHANGES === // patch note: // patch note: General Notes // patch note: enabled WIN key during the game (Solant) @@ -54,20 +64,20 @@ int main(int argc, char *argv[]) { // patch note: Volcano Sector // patch note: rename second FINSWIL-1 to FINSWIL-3 to make this group appear on the map (Streef) - mod.patch("location4.mmo", 0x7F599, 0x31, 0x33); + mod.patch("location4.mmo", 0x0007f9c1, '1', '3'); // patch note: make SWIRE appear (Streef) - mod.patch("location4.mmo", 0x7FA34, 1, 0); + mod.patch_after_pattern("location4.mmo", "SWIRE\0"s, 0x100, 1, 0); // patch note: make SWILHUN appear (Streef) - mod.patch("location4.mmo", 0x7F913, 1, 0); + mod.patch_after_pattern("location4.mmo", "SWILHUN\0"s, 0x120, 1, 0); // patch note: reposition SWILHUN-3 group (Streef) - mod.patch("location4.mmo", 0x7F528, 0x40, 0xB1); + mod.patch_after_pattern("location4.mmo", "SWILHUN-3"s, 0xB8, 0x40, 0xB1); // patch note: reposition SWILHUN-1 group (Streef) - mod.patch("location4.mmo", 0x7EE62, 0xA1, 0xA0); + mod.patch_after_pattern("location4.mmo", "SWILHUN-1"s, 0xB8, 0xA1, 0xA0); // patch note: // patch note: Desert Sector // patch note: reposition SACREFI-2 (Streef) - mod.patch("location5.mmo", 0xBAFF7, 0x18, 0x17); + mod.patch_after_pattern("location5.mmo", "SACREFI-2", 0xB8, 0x18, 0x17); // patch note: fix 'TOV_POLYMER_PLATE' spawn (Streef) mod.replace("location5.scr", "TOV_POLYMER_PLATES", "TOV_POLYMER_PLATE"); // patch note: @@ -77,16 +87,23 @@ int main(int argc, char *argv[]) { mod.add_map_good("location6.mmo", "B_L6_IK_FINDER", "GL_S3_PS_FINDER1", R"( 47 4c 5f 53 33 5f 50 53 5f 46 49 4e 44 45 52 32 00 d2 e2 77 42 04 06 00 35 01 00 00 76 0c 01 30 -54 5f 4c 36 5f 49 4b 5f 46 32 2e 43 4f 4d 50 4c +00 5f 4c 36 5f 49 4b 5f 46 32 2e 43 4f 4d 50 4c 45 54 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -)"_bin); +)"_bin); // 54 + //mod.add_resource("MOD_GL_S3_PS_FINDER1"); + //mod.add_resource("TEX_GL_S3_PS_FINDER1_MASK.TM"); + // patch note: add Finder-2 model and textures from aim2 game (lz) + mod.add_resource("MOD_GL_S3_PS_FINDER2"); + mod.add_resource("TEX_GL_S3_PS_FINDER_2.TM"); + mod.add_resource("TEX_GL_S3_PS_FINDER_2_SPEC.TM"); + mod.add_resource("TEX_GL_S3_PS_FINDER_2_SPEC_1.TM"); // patch note: set correct model for a plant (Streef) - mod.patch("location6.mmo", 0x575DD, 'R', 'F'); + mod.patch("location6.mmo", 0x0005775D, 'R', 'F'); // patch note: fix 'TOV_POLYMER_PLATE' spawn (Streef) mod.replace("location6.scr", "TOV_POLYMER_PLATES", "TOV_POLYMER_PLATE"); // patch note: @@ -110,8 +127,32 @@ int main(int argc, char *argv[]) { // patch note: // patch note: Database Changes + // patch note: DB + // patch note: set glider GL_S3_PS_FINDER2 model to MOD_GL_S3_PS_FINDER2 (lz) + mod.db.db().edit_value((const char *)u8"Глайдеры", "GL_S3_PS_FINDER2", "MODEL", "MOD_GL_S3_PS_FINDER2"); + // patch note: change MOD_GL_S3_PS_FINDER2 model radius to MOD_GL_S3_PS_FINDER1 radius (lz) + mod.db.db().edit_value((const char *)u8"Модели", "MOD_GL_S3_PS_FINDER2", "RADIUS", 4.012578f); + // patch note: double gun for config CFG_NARGOON (double electro discharge) (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_NARGOON", "HEAVYGUN1", "GUN_ELECTRO_DISCHARGER"); + // patch note: double gun for config CFG_NARGOON1 (double two-barreled atomic gun) (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_NARGOON1", "HEAVYGUN1", "GUN_DOUBLE_BARRELED_ATOMIC_GUN"); + // patch note: double gun for config CFG_BASE_NARG - Nargoon (double two-barreled atomic gun) (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_BASE_NARG", "HEAVYGUN1", "GUN_DOUBLE_BARRELED_ATOMIC_GUN"); + // patch note: double gun for config CFG_STNAR-97 - Nargoon (double GUN_INFRAATOMIC_PLASMA_GUN) (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_STNAR-97", "HEAVYGUN1", "GUN_INFRAATOMIC_PLASMA_GUN"); + // patch note: double gun for config CFG_FINDER_1 (std.3): from GUN_MICROWAVE_OSCILLATOR (std.4) and GUN_CHAOS_GENERATOR (std.4) to double GUN_FOUR_BARRELED_IMP_GAZER (std.3) (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_FINDER_1", "LIGHTGUN1", "GUN_FOUR_BARRELED_IMP_GAZER"); + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_FINDER_1", "HEAVYGUN1", "GUN_FOUR_BARRELED_IMP_GAZER"); + // patch note: double gun for config CFG_FINDER_2: from GUN_FOUR_BARRELED_IMP_GAZER (std.3) + GUN_POZITRON_EMITTER (std.4) to double GUN_TACHYON_HEATER (std.3) (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_FINDER_2", "LIGHTGUN1", "GUN_TACHYON_HEATER"); + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_FINDER_2", "HEAVYGUN1", "GUN_TACHYON_HEATER"); + // patch note: double gun for config CFG_EYEDSTONE_1: from GUN_FAST_ELECTROMAGNETIC_BEAM to double GUN_FAST_ELECTROMAGNETIC_BEAM (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_EYEDSTONE_1", "LIGHTGUN1", "GUN_FAST_ELECTROMAGNETIC_BEAM"); + // patch note: double gun for config CFG_EYEDSTONE_2: from GUN_FAST_ELECTROMAGNETIC_BEAM to double GUN_FAST_ELECTROMAGNETIC_BEAM (lz) + mod.db.db().edit_value((const char *)u8"Конфигурации", "CFG_EYEDSTONE_2", "LIGHTGUN1", "GUN_FAST_ELECTROMAGNETIC_BEAM"); + // patch note: INFORMATION // patch note: add name for SINIGR armor, it was unnamed before (lz) - mod.db.quest().add_value("INFORMATION"sv, "EQP_ZERO_ARMOR_S_SIN"sv, "NAME", (const char *)u8"Особая нуль-броня"); + mod.db.quest().add_value("INFORMATION", "EQP_ZERO_ARMOR_S_SIN", "NAME", (const char *)u8"Особая нуль-броня"); // patch note: // patch note: Game Changes @@ -119,12 +160,13 @@ int main(int argc, char *argv[]) { // patch note: double light weapons: GL_M2_PA_NARGOON and GL_S3_PS_FINDER1 // patch note: double heavy weapons: GL_M3_PA_EYEDSTONE and GL_S3_PS_FINDER2 // patch note: (still have many bugs related) - mod.make_injection(0x004072FA); // can trade for buy purposes - mod.make_injection(0x004D62E4); // setup proper weapon slots for a glider - mod.make_injection(0x00417A6D); // put weapon into the right slot after purchase - mod.make_injection(0x004176BC); // sell correct weapon - mod.make_injection(0x004067C4); // empty light weap - mod.make_injection(0x0040688B); // empty heavy weap + mod.make_injection(0x004072FA); // can trade for buy purposes + mod.make_injection(0x004D62E4); // setup proper weapon slots for a glider + mod.make_injection(0x00417A6D); // put weapon into the right slot after purchase + mod.make_injection(0x004176BC); // sell correct weapon + mod.make_injection(0x004067C4); // empty light weap + mod.make_injection(0x0040688B); // empty heavy weap + mod.make_injection(0x0040C20E, 6); // can_leave_trade_window // patch note: // test scripts @@ -148,7 +190,11 @@ int main(int argc, char *argv[]) { _ADDOBJECT(EQP_ZERO_ARMOR_S4) _ADDOBJECT(EQP_SHIELD_GENERATOR4_S4) _ADDOBJECT(GUN_MICROWAVE_OSCILLATOR) - _ADDOBJECT(GUN_RAILGUN) + //_ADDOBJECT(GUN_RAILGUN) + _ADDOBJECT(GUN_IMPULSE_MEGALAZER) + + _ADDOBJECT(EQP_ANALYZER) + _ADDOBJECT(EQP_QUANTUM_TRANSLATOR) _ADDRATING(300000000) _ADDBALANCE(30000000) diff --git a/src/aim1_mod_maker/aim1_mod_maker.h b/src/aim1_mod_maker/aim1_mod_maker.h index b3312c1..8af4476 100644 --- a/src/aim1_mod_maker/aim1_mod_maker.h +++ b/src/aim1_mod_maker/aim1_mod_maker.h @@ -236,6 +236,12 @@ struct mod_maker { } } + template + void patch_after_pattern(path fn, const std::string &pattern, uint32_t offset, T oldval, T val) { + fn = find_real_filename(fn); + files_to_pak.insert(fn); + patch_raw(fn, pattern, offset, oldval, val); + } template void patch(path fn, uint32_t offset, T val) { fn = find_real_filename(fn); @@ -334,6 +340,10 @@ struct mod_maker { void add_code_file_for_archive(const path &fn) { code_files_to_distribute.insert(path{loc.file_name()}.parent_path() / fn); } + void add_resource(path fn) { + fn = find_real_filename(fn); + files_to_pak.insert(fn); + } private: path get_hash_fn(path fn, const byte_array &data) const { @@ -387,20 +397,23 @@ private: ::memcpy(ptr, data.data(), data.size()); ptr += data.size(); } - static auto memmem(auto ptr, auto sz, const byte_array &bytes) { + static auto memmem(auto ptr, auto sz, auto &&bytes) -> decltype(ptr) { sz -= bytes.size(); for (int i = 0; i < sz; ++i) { if (memcmp(ptr + i, bytes.data(), bytes.size()) == 0) { return ptr + i; } } - throw std::runtime_error{"not found"}; + return nullptr; } static auto memreplace(auto base, auto sz, const byte_array &from, const byte_array &to) { if (from.size() != to.size()) { throw std::runtime_error{"size mismatch"}; } auto ptr = memmem(base, sz, from); + if (!ptr) { + throw std::runtime_error{"oldmem not found"}; + } byte_array old; old.resize(from.size()); ::memcpy(old.data(), ptr, old.size()); @@ -517,6 +530,10 @@ FF D7 ; call edi if (fs::exists(fn)) { return fn; } + // free files + if (fs::exists(get_data_dir() / fn)) { + return get_data_dir() / fn; + } if (fn == aim_exe) { return game_dir / fn; } @@ -541,17 +558,17 @@ FF D7 ; call edi auto p = find_file_in_paks(fn, "res3.pak", "maps2.pak", "maps.pak"); if (!fs::exists(p)) { throw SW_RUNTIME_ERROR("Cannot find file in archives: "s + fn.string()); - } - auto dst = get_mod_dir() / p.filename(); - if (!fs::exists(dst)) { - fs::copy_file(p, dst); - } - return dst; - } + } + auto dst = get_mod_dir() / p.filename(); + if (!fs::exists(dst)) { + fs::copy_file(p, dst); + } + return dst; + } default: SW_UNIMPLEMENTED; - } - } + } + } path find_file_in_paks(path fn, auto &&... paks) const { auto find_file = [&](const path &pak) { auto p = get_data_dir() / pak; @@ -567,10 +584,10 @@ FF D7 ; call edi p = p / fn.filename(); if (!fs::exists(p)) { return false; - } + } } else { p /= fn; - } + } fn = p; return true; }; @@ -617,6 +634,17 @@ FF D7 ; call edi return false; } } + template + bool patch_raw(path fn, const std::string &pattern, uint32_t offset, T expected, T val) const { + primitives::templates2::mmap_file f{fn, primitives::templates2::mmap_file::rw{}}; + auto p = memmem(f.p, f.sz, pattern); + if (!p) { + throw std::runtime_error{"pattern not found"}; + } + f.close(); + log("patching {} offset 0x{:X} after pattern {} from {} to {}", fn.string(), offset, pattern, expected, val); + return patch_raw(fn, p - f.p + offset, expected, val); + } path get_mod_dir() const { return get_data_dir() / "mods" / get_full_mod_name(); }