From db4ad211d609c4f099ccb2e5dc1af26aed50d3ef Mon Sep 17 00:00:00 2001 From: CCHyper <73803386+CCHyper@users.noreply.github.com> Date: Tue, 27 Dec 2022 13:42:32 +0000 Subject: [PATCH] Adds collection of patches to remove hardcoded properties from various game object types. --- src/extensions/rules/rulesext.cpp | 163 +++++++++++++++++++++++++++++- src/vinifera/vinifera_hooks.cpp | 71 +++++++++++++ 2 files changed, 230 insertions(+), 4 deletions(-) diff --git a/src/extensions/rules/rulesext.cpp b/src/extensions/rules/rulesext.cpp index 79e95850b..1479312f3 100644 --- a/src/extensions/rules/rulesext.cpp +++ b/src/extensions/rules/rulesext.cpp @@ -38,6 +38,8 @@ #include "noinit.h" #include "swizzle.h" #include "addon.h" +#include "session.h" +#include "tibsun_inline.h" #include "vinifera_saveload.h" #include "asserthandler.h" #include "debughandler.h" @@ -590,16 +592,16 @@ void RulesClassExtension::Fixups(CCINIClass &ini) /** * Check to see if the ini files have been modified. */ - bool rule_unmodified = false; + bool is_rule_unmodified = false; if (rule_crc == Unmodified_RuleINI_CRC) { DEBUG_INFO("Rules: RuleINI is unmodified (version 2.03).\n"); - rule_unmodified = true; + is_rule_unmodified = true; } - bool fsrule_unmodified = false; + bool is_fsrule_unmodified = false; if (Addon_Installed(ADDON_FIRESTORM)) { if (fsrule_crc == Unmodified_FSRuleINI_CRC) { DEBUG_INFO("Rules: FSRuleINI is unmodified (version 2.03).\n"); - fsrule_unmodified = true; + is_fsrule_unmodified = true; } } @@ -617,6 +619,159 @@ void RulesClassExtension::Fixups(CCINIClass &ini) is_fsruleini = true; } + /** + * #issue-554 + * + * Various game object types have hardcoded overrides in the binary. We now + * remove those overrides so they can be modified via RULES.INI, but we still + * need to retain the expected gameplay in the original game. + * + * So, we make sure the game has detected the original, unmodified RULES.INI + * and perform this fixup's for each of the object types. + * + * Match criteria; + * - Are we currently processing RuleINI? + * - Does the name of the object exist? + */ + if (is_ruleini && is_rule_unmodified) { + + ObjectTypeClass *objecttype = nullptr; + TechnoTypeClass *technotype = nullptr; + BuildingTypeClass *buildingtype = nullptr; + WarheadTypeClass *warheadtype = nullptr; + WeaponTypeClass *weapontype = nullptr; + TiberiumClass *tiberium = nullptr; + + /** + * TechnoType "HMEC" is expected to have "Strength" with the value of "1200". + * + * We do an additional check of RTTI_UNITTYPE just to make sure it + * is the expected type. + */ + objecttype = const_cast(ObjectTypeClass::As_Pointer("HMEC")); + if (objecttype && objecttype->What_Am_I() == RTTI_UNITTYPE) { + DEBUG_WARNING("Rules: Changing \"MaxStrength\" for ObjectType \"%s\" to \"1200\"!\n", objecttype->Name()); + objecttype->MaxStrength = 1200; + } + + /** + * TechnoType "GAFSDF" is expected to have "GuardRange" with the value of "5", + * and "Cost" with the value of "250". + * + * We do an additional check of RTTI_BUILDINGTYPE just to make sure it + * is the expected type. + */ + technotype = const_cast(TechnoTypeClass::As_Pointer("GAFSDF")); + if (technotype && technotype->What_Am_I() == RTTI_BUILDINGTYPE) { + DEBUG_WARNING("Rules: Changing \"ThreatRange\" for TechnoType \"%s\" to \"%d\"!\n", technotype->Name(), Cell_To_Lepton(5)); + DEBUG_WARNING("Rules: Changing \"Cost\" for TechnoType \"%s\" to \"250\"!\n", technotype->Name()); + technotype->ThreatRange = Cell_To_Lepton(5); + technotype->Cost = 250; + } + + /** + * TechnoType "GAWALL" is expected to have "GuardRange" with the value of "5", + * and "Cost" with the value of "250". + * + * We do an additional check of RTTI_BUILDINGTYPE just to make sure it + * is the expected type. + */ + technotype = const_cast(TechnoTypeClass::As_Pointer("GAWALL")); + if (technotype && technotype->What_Am_I() == RTTI_BUILDINGTYPE) { + DEBUG_WARNING("Rules: Changing \"ThreatRange\" for TechnoType \"%s\" to \"%d\"!\n", technotype->Name(), Cell_To_Lepton(5)); + DEBUG_WARNING("Rules: Changing \"Cost\" for TechnoType \"%s\" to \"250\"!\n", technotype->Name()); + technotype->ThreatRange = Cell_To_Lepton(5); + technotype->Cost = 250; + } + + /** + * TechnoType "NAWALL" is expected to have "GuardRange" with the value of "5", + * and "Cost" with the value of "250". + * + * We do an additional check of RTTI_BUILDINGTYPE just to make sure it + * is the expected type. + */ + technotype = const_cast(TechnoTypeClass::As_Pointer("NAWALL")); + if (technotype && technotype->What_Am_I() == RTTI_BUILDINGTYPE) { + DEBUG_WARNING("Rules: Changing \"ThreatRange\" for TechnoType \"%s\" to \"%d\"!\n", technotype->Name(), Cell_To_Lepton(5)); + DEBUG_WARNING("Rules: Changing \"Cost\" for TechnoType \"%s\" to \"250\"!\n", technotype->Name()); + technotype->ThreatRange = Cell_To_Lepton(5); + technotype->Cost = 250; + } + + /** + * TechnoType "E2" is expected to have "Explodes" with the value of "yes". + * + * We do an additional check of RTTI_INFANTRYTYPE just to make sure it + * is the expected type. + */ + technotype = const_cast(TechnoTypeClass::As_Pointer("E2")); + if (technotype && technotype->What_Am_I() == RTTI_INFANTRYTYPE) { + DEBUG_WARNING("Rules: Changing \"IsExploding\" for TechnoType \"%s\" to \"true\"!\n", technotype->Name()); + technotype->IsExploding = true; + } + + /** + * BuildingType "NAFNCE" is expected to have "BaseNormal" with the value of "no". + */ + buildingtype = const_cast(BuildingTypeClass::As_Pointer("NAFNCE")); + if (buildingtype) { + DEBUG_WARNING("Rules: Changing \"IsBase\" for BuildingType \"%s\" to \"false\"!\n", buildingtype->Name()); + buildingtype->IsBase = false; + } + + /** + * BuildingType "NAPOST" is expected to have "BaseNormal" with the value of "no". + */ + buildingtype = const_cast(BuildingTypeClass::As_Pointer("NAPOST")); + if (buildingtype) { + DEBUG_WARNING("Rules: Changing \"IsBase\" for BuildingType \"%s\" to \"false\"!\n", buildingtype->Name()); + buildingtype->IsBase = false; + } + + /** + * WarheadType "ARTYHE" is expected to have "ProneDamage" with the value of "0.3" + * and "Verses" with the values of "0.4, 0.85, 0.68, 0.35, 0.35". + */ + warheadtype = const_cast(WarheadTypeClass::As_Pointer("ARTYHE")); + if (warheadtype && Session.Type != GAME_NORMAL) { + DEBUG_WARNING("Rules: Changing \"ProneFactor\" for WarheadType \"%s\" to \"0.3\"!\n", warheadtype->Name()); + DEBUG_WARNING("Rules: Changing \"Modifier[ARMOR_NONE]\" for WarheadType \"%s\" to \"0.4\"!\n", warheadtype->Name()); + DEBUG_WARNING("Rules: Changing \"Modifier[ARMOR_WOOD]\" for WarheadType \"%s\" to \"0.85\"!\n", warheadtype->Name()); + DEBUG_WARNING("Rules: Changing \"Modifier[ARMOR_ALUMINUM]\" for WarheadType \"%s\" to \"0.68\"!\n", warheadtype->Name()); + DEBUG_WARNING("Rules: Changing \"Modifier[ARMOR_STEEL]\" for WarheadType \"%s\" to \"0.35\"!\n", warheadtype->Name()); + DEBUG_WARNING("Rules: Changing \"Modifier[ARMOR_CONCRETE]\" for WarheadType \"%s\" to \"0.35\"!\n", warheadtype->Name()); + warheadtype->ProneFactor = 0.3; + warheadtype->Modifier[ARMOR_NONE] = 0.4; + warheadtype->Modifier[ARMOR_WOOD] = 0.85; + warheadtype->Modifier[ARMOR_ALUMINUM] = 0.68; + warheadtype->Modifier[ARMOR_STEEL] = 0.35; + warheadtype->Modifier[ARMOR_CONCRETE] = 0.35; + } + + /** + * WeaponType "155mm" is expected to have "ROF" with the value of "150", + * and "Damage" with the value of "115". + */ + weapontype = const_cast(WeaponTypeClass::As_Pointer("155mm")); + if (weapontype && Session.Type != GAME_NORMAL) { + DEBUG_WARNING("Rules: Changing \"ROF\" for WeaponType \"%s\" to \"150\"!\n", weapontype->Name()); + DEBUG_WARNING("Rules: Changing \"Attack\" for WeaponType \"%s\" to \"115\"!\n", weapontype->Name()); + weapontype->ROF = 150; + weapontype->Attack = 115; + } + + /** + * TiberiumType "Vinifera" is expected to have "Power" with the value of "17". + */ + tiberium = const_cast(TiberiumClass::As_Pointer("Vinifera")); + if (tiberium) { + DEBUG_WARNING("Rules: Changing \"Power\" for TiberiumType \"%s\" to \"17\"!\n", tiberium->Name()); + tiberium->Power = 17; + } + + } + /** * Fix up the multi engineer values if we have possibly detected the original, unmodified ini databases. * diff --git a/src/vinifera/vinifera_hooks.cpp b/src/vinifera/vinifera_hooks.cpp index 5fd189b9b..264c30d3e 100644 --- a/src/vinifera/vinifera_hooks.cpp +++ b/src/vinifera/vinifera_hooks.cpp @@ -50,6 +50,70 @@ #include "asserthandler.h" +/** + * #issue-554 + * + * This function patches out various hardcoded properties for game types. + * + * @author: CCHyper + */ +static void Vinifera_Remove_Hardcoded_Type_Properties() +{ + /** + * Removes hardcoded "Strength=1200" from ObjectType with the name "HMEC". + */ + Patch_Byte_Range(0x00588C5F, 0x90, 6); + Patch_Jump(0x00588C6B, 0x00588C7E); + + /** + * Removes hardcoded values; + * "GuardRange=5" + * "Cost=250" + * + * from TechnoTypes with the names "GAFSDF", "GAWALL" and/or "NAWALL" + */ + Patch_Jump(0x0063BAC8, 0x0063BB6E); + Patch_Jump(0x0063C8E2, 0x0063C988); + + /** + * Removes hardcoded "Explodes=yes" from TechnoType with the name "E2". + */ + Patch_Byte_Range(0x0063BB82, 0x90, 6); + Patch_Jump(0x0063BB8E, 0x0063BBA1); + + /** + * Removes hardcoded "BaseNormal=no" from BuildingTypes with the names "NAFNCE" and/or "NAPOST" + */ + Patch_Byte_Range(0x00440C38, 0x90, 6); + Patch_Jump(0x00440C44, 0x00440C69); + + /** + * Removes hardcoded values; + * "ProneDamage=0.3" + * "Verses=0.4, 0.85, 0.68, 0.35, 0.35" + * + * from WarheadType with the name "ARTYHE". These hardcoded properties + * only applied to multiplayer games, and not the singleplayer campaign. + */ + Patch_Jump(0x0066F4C6, 0x0066F566); + + /** + * Removes hardcoded values; + * "ROF=150" + * "Damage=115" + * + * from WeaponType with the name "155mm". These hardcoded properties + * only applied to multiplayer games, and not the singleplayer campaign. + */ + Patch_Jump(0x00681250, 0x0068129D); + + /** + * Removes hardcoded "Power=17" from TiberiumType "Vinifera". + */ + Patch_Jump(0x00644DB8, 0x00644DD4); +} + + /** * This function is for intercepting the calls to Detach_This_From_All to also * process the object through the extension interface. @@ -892,6 +956,13 @@ void Vinifera_Hooks() Patch_Byte_Range(0x00580377, 0x90, 10); // NewMenuClass::Process_Game_Select #endif + /** + * Remove various hardcoded game object type properties. + * + * See RulesClassExtension::Fixups for more information. + */ + Vinifera_Remove_Hardcoded_Type_Properties(); + /** * Various patches to intercept the games object tracking and heap processing. */