diff --git a/examples/mods/aim1_community_fix/my_mod.cpp b/examples/mods/aim1_community_fix/my_mod.cpp index 529d07c..ed5adaf 100644 --- a/examples/mods/aim1_community_fix/my_mod.cpp +++ b/examples/mods/aim1_community_fix/my_mod.cpp @@ -207,6 +207,7 @@ int main(int argc, char *argv[]) { // patch note dev: give powerful glider based on FLASH db["Глайдеры"]["GL_M4_S_TEST"] = db["Глайдеры"]["GL_M4_S_FIRST2"]; db["Глайдеры"]["GL_M4_S_TEST"]["MAXWEIGHT"] = 1'000'000.f; + db["Глайдеры"]["GL_M4_S_TEST"]["ROTATESPEED"] = 75.f; db["Конфигурации"]["CFG_STARTUP"]["GLIDER"] = "GL_M4_S_TEST"; // patch note dev: give powerful reactor add_test_eqp("REACTOR", "EQP_GLUON_REACTOR_S1", 9'000'000.f); @@ -226,6 +227,11 @@ int main(int argc, char *argv[]) { db["Оружие"]["GUN_IMPULSE_MEGALAZER_TEST"]["DAMAGE"] = 40000.f; db["Оружие"]["GUN_IMPULSE_MEGALAZER_TEST"]["STANDARD"] = 1; db["Конфигурации"]["CFG_STARTUP"]["HEAVYGUN1"] = "GUN_IMPULSE_MEGALAZER_TEST"; + // + db["Конфигурации"]["CFG_STARTUP"]["EQP_ANALYZER"] = 1; + db["Конфигурации"]["CFG_STARTUP"]["EQP_QUANTUM_TRANSLATOR"] = 1; + db["Конфигурации"]["CFG_STARTUP"]["EQP_INVISIBILITY_SHIELD"] = 1; + db["Конфигурации"]["CFG_STARTUP"]["EQP_UNIVERSAL_SHIELD"] = 1; // end of db changes in dev mode // patch note dev: allow to buy GL_S3_PS_FINDER1 without pre-quest mod.add_map_good("location6.mmo", "B_L6_IK_FINDER", "GL_S3_PS_FINDER1", mmo_storage2::map_good("GL_S3_PS_FINDER1")); @@ -262,19 +268,39 @@ int main(int argc, char *argv[]) { // mod.clone_mechmind_group("location1.mmo", "MINVACH-6", "MINVACH-666"); - mod.update_mechmind_group_configurations("location1.mmo", "MINVACH-666", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1", - "CFG_INVADER_1" - ); - mod.set_mechmind_organization("location1.mmo", "MINVACH-666", "ORG_PLAYER"); + auto cfg = "CFG_TEST"; + db["Конфигурации"][cfg] = db["Конфигурации"]["CFG_STARTUP"]; + db["Конфигурации"][cfg]["ENGINE"] = "EQP_VACUUM_DRIVE_S4"; + auto make = [&](auto name, int road) { + mod.clone_mechmind_group("location1.mmo", "MINVACH-6", name); + mod.update_mechmind_group_configurations("location1.mmo", name, cfg); + mod.set_mechmind_group_type("location1.mmo", name, 1, road); + }; + for (int i = 0; i < 20; ++i) { + make(std::format("MINVACH-6{}", i), 1000 / 20 * i + 20); + } + /*mod.update_mechmind_group_configurations("location1.mmo", "MINVACH-666", + cfg, + cfg, + cfg, + cfg, + cfg, + + cfg, + cfg, + cfg, + cfg, + cfg + );*/ + //mod.set_mechmind_group_organization("location1.mmo", "MINVACH-666", "ORG_PLAYER"); + //mod.set_mechmind_group_type("location1.mmo", "MINVACH-666", 1); + /*mod.hide_mechmind_group("location1.mmo", "MINVACH-666"); + mod.delete_mechmind_group("location1.mmo", "MINVACH-6"); + for (auto &&[n,_] : mod.get_mmo_storage("location1.mmo").mechs) { + if (n != "SHUN-2") { + mod.delete_mechmind_group("location1.mmo", n); + } + }*/ // does not work, crashes. Maybe different item size // or maybe too many goods @@ -313,10 +339,10 @@ int main(int argc, char *argv[]) { //_ADDOBJECT(GUN_RAILGUN) //_ADDOBJECT(GUN_IMPULSE_MEGALAZER) - _ADDOBJECT(EQP_ANALYZER) - _ADDOBJECT(EQP_QUANTUM_TRANSLATOR) - _ADDOBJECT(EQP_INVISIBILITY_SHIELD) - _ADDOBJECT(EQP_UNIVERSAL_SHIELD) + //_ADDOBJECT(EQP_ANALYZER) + //_ADDOBJECT(EQP_QUANTUM_TRANSLATOR) + //_ADDOBJECT(EQP_INVISIBILITY_SHIELD) + //_ADDOBJECT(EQP_UNIVERSAL_SHIELD) _ADDRATING(300000000) _ADDBALANCE(30000000) @@ -346,6 +372,11 @@ int main(int argc, char *argv[]) { //_INFO(SECTOR9_TEST) //_INFO(SECTOR10_TEST) )"); + //mod.copy_sector_from_aim1(2, 2); + //quest["ru_RU"]["INFORMATION"]["SECTOR2_TEST"]["NAME"] = "test"; + //quest["ru_RU"]["INFORMATION"]["SECTOR2_TEST"]["TEXT"] = ""; + //mod.copy_sector_from_aim1(1, 1); + //mod.copy_sector_from_aim1(2, 2); /*mod.copy_sector_from_aim1(1, 3); mod.copy_sector_from_aim1(1); mod.copy_sector_from_aim1(2); diff --git a/src/aim1_mod_maker/aim1_mod_maker.h b/src/aim1_mod_maker/aim1_mod_maker.h index 7c3e33a..9e8635c 100644 --- a/src/aim1_mod_maker/aim1_mod_maker.h +++ b/src/aim1_mod_maker/aim1_mod_maker.h @@ -475,7 +475,52 @@ struct mod_maker { // increase number of goods ++*(uint32_t *)(f.p + it->second.offset); } + auto get_mmo_storage(path mmo_fn) { + auto fn = find_real_filename(mmo_fn); + mmo_storage2 m{fn}; + m.load(); + return m; + } + void hide_mechmind_group(path mmo_fn, const std::string &name) { + log("hiding mechmind group {} in loc {}", name, mmo_fn.string()); + + auto fn = find_real_filename(mmo_fn); + files_to_pak.insert(fn); + + mmo_storage2 m{fn}; + m.load(); + + auto it = m.mechs.find(name); + if (it == m.mechs.end()) { + throw std::runtime_error{"no such mechmind or group: " + name}; + } + primitives::templates2::mmap_file f{fn, primitives::templates2::mmap_file::rw{}}; + auto n = *(uint32_t*)(f.p + it->second.n_mechs_offset); + auto &hidden = *(uint8_t*)(f.p + it->second.mechs_offset + n * 0x20); + hidden = 1; + } + void delete_mechmind_group(path mmo_fn, const std::string &name) { + log("deleting mechmind group {} in loc {}", name, mmo_fn.string()); + + auto fn = find_real_filename(mmo_fn); + files_to_pak.insert(fn); + + mmo_storage2 m{fn}; + m.load(); + + auto it = m.mechs.find(name); + if (it == m.mechs.end()) { + throw std::runtime_error{"no such mechmind or group: " + name}; + } + primitives::templates2::mmap_file f{fn, primitives::templates2::mmap_file::rw{}}; + auto &n = *(uint32_t*)(f.p + m.n_mech_groups_offset); + --n; + f.close(); + bin_patcher::erase(fn, it->second.offset, it->second.size); + } void clone_mechmind_group(path mmo_fn, const std::string &name, const std::string &newname) { + log("cloninig mechmind group {} in loc {}, new name {}", name, mmo_fn.string(), newname); + auto fn = find_real_filename(mmo_fn); files_to_pak.insert(fn); @@ -498,6 +543,12 @@ struct mod_maker { bin_patcher::insert(fn, m.mech_groups_offset, data); } bool set_mechmind_organization(path mmo_fn, const std::string &name, const std::string &orgname) { + // deprecated, for api stability + return set_mechmind_group_organization(mmo_fn, name, orgname); + } + bool set_mechmind_group_organization(path mmo_fn, const std::string &name, const std::string &orgname) { + log("setting mechmind group {} organization {} in loc {}", name, orgname, mmo_fn.string()); + auto fn = find_real_filename(mmo_fn); files_to_pak.insert(fn); @@ -515,7 +566,32 @@ struct mod_maker { memcpy(f.p + it->second.name_offset + 0x20, orgname.data(), orgname.size() + 1); return true; } + void set_mechmind_group_type(path mmo_fn, const std::string &name, int newtype, int new_road_id = 100) { + log("setting mechmind group {} in loc {} to {}", name, mmo_fn.string(), newtype); + + auto fn = find_real_filename(mmo_fn); + files_to_pak.insert(fn); + + mmo_storage2 m{fn}; + m.load(); + + auto it = m.mechs.find(name); + if (it == m.mechs.end()) { + throw std::runtime_error{"no such mechmind or group: " + name}; + } + primitives::templates2::mmap_file f{fn, primitives::templates2::mmap_file::rw{}}; + auto &type = *(uint32_t*)(f.p + it->second.offset + 0x20 + 0x20); + type = newtype; + auto &road_id = *(uint32_t*)(f.p + it->second.post_comment_offset); + road_id = new_road_id; + if (newtype == 1) { + auto &unk = *(float*)(f.p + it->second.post_comment_offset + 4); + unk = 0; + } + } bool rename_mechmind_group(path mmo_fn, const std::string &name, const std::string &newname) { + log("renaming mechmind group {} in loc {} to {}", name, mmo_fn.string(), newname); + auto fn = find_real_filename(mmo_fn); files_to_pak.insert(fn); @@ -534,6 +610,14 @@ struct mod_maker { return true; } void update_mechmind_group_configurations(path mmo_fn, const std::string &name, auto &&cfg, auto &&...cfgs) { + std::string format; + auto addname = [&](const std::string &cfg) { + format += cfg + ","; + }; + addname(cfg); + (addname(cfgs),...); + log("updating mechmind group {} configurations in loc {} to {}", name, mmo_fn.string(), format); + auto fn = find_real_filename(mmo_fn); files_to_pak.insert(fn); @@ -818,8 +902,11 @@ struct mod_maker { auto mmp = find_real_filename(from + ".mmp"); auto mmo = find_real_filename(from + ".mmo"); auto mmm = find_real_filename(from + ".mmm"); + if (mmp != get_mod_dir() / (to + ".mmp")) fs::copy_file(mmp, get_mod_dir() / (to + ".mmp"), fs::copy_options::update_existing); + if (mmo != get_mod_dir() / (to + ".mmo")) fs::copy_file(mmo, get_mod_dir() / (to + ".mmo"), fs::copy_options::update_existing); + if (mmm != get_mod_dir() / (to + ".mmm")) fs::copy_file(mmm, get_mod_dir() / (to + ".mmm"), fs::copy_options::update_existing); files_to_pak.insert(get_mod_dir() / (to + ".mmp")); files_to_pak.insert(get_mod_dir() / (to + ".mmo")); diff --git a/src/common/mmo2.h b/src/common/mmo2.h index e1c00e0..d597926 100644 --- a/src/common/mmo2.h +++ b/src/common/mmo2.h @@ -62,6 +62,7 @@ struct mmo_storage2 { uint32_t name_offset; uint32_t n_mechs_offset; uint32_t mechs_offset; + uint32_t post_comment_offset; uint32_t offset; uint32_t size; }; @@ -105,6 +106,7 @@ struct mmo_storage2 { m.comment = o.comment; m.name_offset = (uint8_t*)o.name - f.p; m.n_mechs_offset = (uint8_t*)&o.n_mechs - f.p; + m.post_comment_offset = (uint8_t*)s.p - f.p; if (strcmp(o.name, "MINVACH-6") == 0) { int a = 5; @@ -114,16 +116,46 @@ struct mmo_storage2 { int a = 5; a++; } + if (strcmp(o.name, "ETRANNA-1") == 0) { + int a = 5; + a++; + } + if (strcmp(o.name, "SHUN-2") == 0) { + int a = 5; + a++; + } + // mech are spawned on random path when leaving the base + // probably far from player + // + // 0 = stationary + // 0 = CGuardMechGroup? + // 1 = roaming between bases (and trading?) + // 1 = CTransMechGroup! + // 2 = patrol? or roaming and killing? + // 2 = CHunterMechGroup! + // 3 = ? free mechs? spawn pos? flag? free roaming? always 0 except single ORG_FREE mob in location5 + // 3 = CPeopleMechGroup + // 4 = ? platforms? spawn pos? probably only single appearence in the game - location2 GL_PLATFORM + // 4 = CGuardMechGroup? switch (o.type) { case 0: // alive - case 1: { + { uint32_t sector_id = s; // road id? or map sector id float height = s; // height? int a = 5; a++; } break; + case 1: { + uint32_t road_id = s; // road id? or map sector id + float unused_guessed = s; // height? + + int a = 5; + a++; + } break; + // patrol? because transes have type '1' + // and seems pathes are generated ingame between bases case 2: { std::vector t; // current path? uint32_t len = s; @@ -132,9 +164,17 @@ struct mmo_storage2 { } break; case 3: // 3 = free mechanoids only? { + // dead in other mech id? + // object id? base id? + uint32_t t = s; // other mech id? + if (t != 0) { + int a = 5; + a++; + } + int a = 5; a++; - } + } break; case 4: { // dead in other mech id? // object id? base id?