Skip to content

Commit

Permalink
Adds collection of patches to remove hardcoded properties from variou…
Browse files Browse the repository at this point in the history
…s game object types.
  • Loading branch information
CCHyper committed Dec 27, 2022
1 parent b789478 commit 6ae5ab5
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 3 deletions.
222 changes: 220 additions & 2 deletions src/extensions/rules/rulesext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
#include "wwcrc.h"
#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"
Expand Down Expand Up @@ -78,6 +81,18 @@ RulesClassExtension::RulesClassExtension(const RulesClass *this_ptr) :
IsShowSuperWeaponTimers(true)
{
//if (this_ptr) EXT_DEBUG_TRACE("RulesClassExtension::RulesClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr));

/**
* Due to the changes made when addressing issues #632, 633, and 635, we
* need change the default engineer capture values. These values are from
* Red Alert 1 MPLAYER.INI, and they match the expected hardcoded behavior
* of the Multi Engineer logic in the release version of Tiberian Sun.
*
* Fixing the default values here ensures Multi-Engineer works in Tiberian Sun
* without manually fixing up the ini data (which is required for Firestorm).
*/
This()->EngineerDamage = 0.33f;
This()->EngineerCaptureLevel = 0.66f;
}


Expand Down Expand Up @@ -276,7 +291,7 @@ void RulesClassExtension::Process(CCINIClass &ini)
/**
* Fixup various inconsistencies in the original INI files.
*/
Fixups();
Fixups(ini);
}


Expand Down Expand Up @@ -510,8 +525,210 @@ void RulesClassExtension::Check()
*
* @author: CCHyper
*/
void RulesClassExtension::Fixups()
void RulesClassExtension::Fixups(CCINIClass &ini)
{
DEBUG_INFO("Rules::Fixups(enter)\n");

/**
* These are the CRC values for the unmodified ini files, TS2.03EN.
*/
static const int Unmodified_RuleINI_CRC = 0x9F3ECD2A;
static const int Unmodified_FSRuleINI_CRC = 0xA0738E22;

/**
* Fetch the unique crc values for both rule databases.
*/
int rule_crc = RuleINI->Get_Unique_ID();
DEV_DEBUG_INFO("Rules: RuleINI CRC = %lX\n", rule_crc);

int fsrule_crc = FSRuleINI.Get_Unique_ID();
if (Addon_Installed(ADDON_FIRESTORM)) {
DEV_DEBUG_INFO("Rules: FSRuleINI CRC = %lX\n", fsrule_crc);
}

/**
* Check to see if the ini files have been modified.
*/
bool is_rule_unmodified = false;
if (rule_crc == Unmodified_RuleINI_CRC) {
DEBUG_INFO("Rules: RuleINI is unmodified (version 2.03).\n");
is_rule_unmodified = true;
}
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");
is_fsrule_unmodified = true;
}
}

/**
* Detect which unmodified ini file we are currently processing.
*/
bool is_ruleini = false;
if (ini.Get_Unique_ID() == Unmodified_RuleINI_CRC) {
DEV_DEBUG_INFO("Rules: Current INI is RuleINI.\n");
is_ruleini = true;
}
bool is_fsruleini = false;
if (Addon_Installed(ADDON_FIRESTORM) && ini.Get_Unique_ID() == Unmodified_FSRuleINI_CRC) {
DEV_DEBUG_INFO("Rules: Current INI is FSRuleINI.\n");
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 *>(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 *>(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 *>(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 *>(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 *>(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 *>(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 *>(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 *>(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 *>(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 *>(TiberiumClass::As_Pointer("Vinifera"));
if (tiberium) {
DEBUG_WARNING("Rules: Changing \"Power\" for TiberiumType \"%s\" to \"17\"!\n", tiberium->Name());
tiberium->Power = 17;
}

}

HouseTypeClass *housetype = HouseTypes[HOUSE_NOD];
if (housetype) {

Expand Down Expand Up @@ -573,4 +790,5 @@ void RulesClassExtension::Fixups()

}

DEBUG_INFO("Rules::Fixups(exit)\n");
}
2 changes: 1 addition & 1 deletion src/extensions/rules/rulesext.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class RulesClassExtension final : public GlobalExtensionClass<RulesClass>

private:
void Check();
void Fixups();
void Fixups(CCINIClass &ini);

public:
/**
Expand Down
71 changes: 71 additions & 0 deletions src/vinifera/vinifera_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -890,6 +954,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.
*/
Expand Down

0 comments on commit 6ae5ab5

Please sign in to comment.