diff --git a/tiberiandawn/bdata.cpp b/tiberiandawn/bdata.cpp index 9f87fd59..311f1050 100644 --- a/tiberiandawn/bdata.cpp +++ b/tiberiandawn/bdata.cpp @@ -4535,7 +4535,7 @@ int BuildingTypeClass::Full_Name(void) const if (Scen.Scenario == 3 && Type == STRUCT_MISSION) { return (TXT_PRISON); } - if (!IsNominal || Special.IsNamed || IsWall || Debug_Map || Type == STRUCT_V23 || Type == STRUCT_V30 + if (!IsNominal || Rule.IsNamed || IsWall || Debug_Map || Type == STRUCT_V23 || Type == STRUCT_V30 || Type == STRUCT_MISSION || Type == STRUCT_BIO_LAB) { return (TechnoTypeClass::Full_Name()); } @@ -4567,7 +4567,7 @@ int BuildingTypeClass::Raw_Cost(void) const int BuildingTypeClass::Cost_Of(void) const { - if (Special.IsSeparate && Type == STRUCT_HELIPAD) { + if (Rule.IsSeparate && Type == STRUCT_HELIPAD) { return (Raw_Cost()); } diff --git a/tiberiandawn/building.cpp b/tiberiandawn/building.cpp index f6211a44..05a4971d 100644 --- a/tiberiandawn/building.cpp +++ b/tiberiandawn/building.cpp @@ -924,7 +924,7 @@ void BuildingClass::AI(void) ** the loop. */ if (Fetch_Stage() == ctrl->Start + ctrl->Count - 1 - || (Special.IsMCVDeploy && *this == STRUCT_CONST && Mission == MISSION_DECONSTRUCTION + || (Is_MCV_Deploy() && *this == STRUCT_CONST && Mission == MISSION_DECONSTRUCTION && Fetch_Stage() == (42 - 19))) { IsReadyToCommence = true; } @@ -1684,7 +1684,7 @@ ResultType BuildingClass::Take_Damage(int& damage, int distance, WarheadType war if (*this != STRUCT_SAM && !House->Is_Ally(source) && Class->Primary != WEAPON_NONE && (!Target_Legal(TarCom) || !In_Range(TarCom))) { - if (source->What_Am_I() != RTTI_AIRCRAFT && (!House->IsHuman || Special.IsSmartDefense)) { + if (source->What_Am_I() != RTTI_AIRCRAFT && (!House->IsHuman || Rule.IsSmartDefense)) { Assign_Target(source->As_Target()); } else { @@ -3177,7 +3177,7 @@ ActionType BuildingClass::What_Action(CELL cell) const Validate(); ActionType action = TechnoClass::What_Action(cell); - if (action == ACTION_MOVE && (*this != STRUCT_CONST || !Special.IsMCVDeploy)) { + if (action == ACTION_MOVE && (*this != STRUCT_CONST || !Is_MCV_Deploy())) { action = ACTION_NONE; } @@ -4096,7 +4096,7 @@ int BuildingClass::Mission_Deconstruction(void) ** members leaving is equal to the unrecovered cost of the building ** divided by 100 (the typical cost of a minigunner infantryman). */ - if (!Target_Legal(ArchiveTarget) || !Special.IsMCVDeploy || *this != STRUCT_CONST) { + if (!Target_Legal(ArchiveTarget) || !Is_MCV_Deploy() || *this != STRUCT_CONST) { int divisor = 200; if (IsCaptured) divisor *= 2; @@ -4186,7 +4186,7 @@ int BuildingClass::Mission_Deconstruction(void) ** Construction yards that deconstruct, really just revert back ** to an MCV. */ - if (Target_Legal(ArchiveTarget) && Special.IsMCVDeploy && *this == STRUCT_CONST && House->IsHuman) { + if (Target_Legal(ArchiveTarget) && Is_MCV_Deploy() && *this == STRUCT_CONST && House->IsHuman) { ScenarioInit++; UnitClass* unit = new UnitClass(UNIT_MCV, House->Class->House); ScenarioInit--; @@ -4512,10 +4512,10 @@ int BuildingClass::Mission_Harvest(void) /* ** Force any bib squaters to scatter. */ - bool old = Special.IsScatter; - Special.IsScatter = true; + bool old = Rule.IsScatter; + Rule.IsScatter = true; Map[Adjacent_Cell(Coord_Cell(Center_Coord()), DIR_SW)].Incoming(0, true); - Special.IsScatter = old; + Rule.IsScatter = old; FootClass* techno = Attached_Object(); if (techno) { @@ -5462,7 +5462,7 @@ CELL BuildingClass::Find_Exit_Cell(TechnoClass const* techno) const bool BuildingClass::Can_Player_Move(void) const { Validate(); - return (*this == STRUCT_CONST && (Mission == MISSION_GUARD) && Special.IsMCVDeploy); + return (*this == STRUCT_CONST && (Mission == MISSION_GUARD) && Is_MCV_Deploy()); } /*********************************************************************************************** diff --git a/tiberiandawn/cell.cpp b/tiberiandawn/cell.cpp index 14a3a4e6..5f3b0784 100644 --- a/tiberiandawn/cell.cpp +++ b/tiberiandawn/cell.cpp @@ -1803,7 +1803,7 @@ void CellClass::Incoming(COORDINATE threat, bool forced, bool nokidding) /* ** Special check to make sure that friendly units never scatter. */ - if (nokidding || Special.IsScatter || (object->Is_Techno() && !((TechnoClass*)object)->House->IsHuman)) { + if (nokidding || Rule.IsScatter || (object->Is_Techno() && !((TechnoClass*)object)->House->IsHuman)) { if (object->What_Am_I() == RTTI_INFANTRY) { object->Scatter(threat, forced, nokidding); } else { diff --git a/tiberiandawn/dllinterface.cpp b/tiberiandawn/dllinterface.cpp index 7ccce4b2..d625ea3b 100644 --- a/tiberiandawn/dllinterface.cpp +++ b/tiberiandawn/dllinterface.cpp @@ -724,14 +724,11 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scena MPlayerSolo = game_options.MPlayerSolo; // 1 = allows a single-player net game MPlayerUnitCount = game_options.MPlayerUnitCount; // # units for non-base multiplayer scenarios - Special.IsMCVDeploy = game_options.IsMCVDeploy; Special.IsVisceroids = game_options.SpawnVisceroids; Special.IsCaptureTheFlag = game_options.CaptureTheFlag; Special.IsEarlyWin = game_options.DestroyStructures; Special.ModernBalance = game_options.ModernBalance; - Rule.AllowSuperWeapons = game_options.EnableSuperweapons; // Are superweapons available - if (MPlayerTiberium) { Special.IsTGrowth = 1; Special.IsTSpread = 1; @@ -740,6 +737,11 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scena Special.IsTSpread = 0; } + Special.IsMCVDeploy = game_options.IsMCVDeploy; + Special.UseMCVDeploy = true; + + Rule.AllowSuperWeapons = game_options.EnableSuperweapons; // Are superweapons available + Scen.Scenario = scenario_index; MPlayerCount = 0; diff --git a/tiberiandawn/drive.cpp b/tiberiandawn/drive.cpp index dc4499d8..16114851 100644 --- a/tiberiandawn/drive.cpp +++ b/tiberiandawn/drive.cpp @@ -83,7 +83,7 @@ void DriveClass::Do_Turn(DirType dir) ** Special rotation track is needed for units that ** cannot rotate in place. */ - if (Special.IsThreePoint && TrackNumber == -1 && Class->Speed == SPEED_WHEEL) { + if (Rule.IsThreePoint && TrackNumber == -1 && Class->Speed == SPEED_WHEEL) { int facediff; // Signed difference between current and desired facing. FacingType face; // Current facing (ordinal value). @@ -239,7 +239,7 @@ void DriveClass::Overrun_Square(CELL cell, bool threaten) /* ** Scattering is controlled by the game difficulty level. */ - if (((GameToPlay == GAME_NORMAL && PlayerPtr->Difficulty == DIFF_HARD) || Special.IsScatter + if (((GameToPlay == GAME_NORMAL && PlayerPtr->Difficulty == DIFF_HARD) || Rule.IsScatter || Scen.Scenario > 8) && !(GameToPlay == GAME_NORMAL && PlayerPtr->Difficulty == DIFF_EASY)) { cellptr->Incoming(0, true); @@ -708,10 +708,10 @@ bool DriveClass::While_Moving(void) case MOVE_TEMP: if (*this == UNIT_HARVESTER || !House->IsHuman) { - bool old = Special.IsScatter; - Special.IsScatter = true; + bool old = Rule.IsScatter; + Rule.IsScatter = true; Map[Coord_Cell(c)].Incoming(0, true); - Special.IsScatter = old; + Rule.IsScatter = old; } break; } @@ -975,10 +975,10 @@ bool DriveClass::Start_Of_Move(void) CellClass* cellptr = &Map[cell]; TechnoClass* blockage = cellptr->Cell_Techno(); if (blockage && House->Is_Ally(blockage)) { - bool old = Special.IsScatter; - Special.IsScatter = true; + bool old = Rule.IsScatter; + Rule.IsScatter = true; cellptr->Incoming(0, true); - Special.IsScatter = old; + Rule.IsScatter = old; } } } @@ -1009,10 +1009,10 @@ bool DriveClass::Start_Of_Move(void) CellClass* cellptr = &Map[cell]; TechnoClass* blockage = cellptr->Cell_Techno(); if (blockage && House->Is_Ally(blockage)) { - bool old = Special.IsScatter; - Special.IsScatter = true; + bool old = Rule.IsScatter; + Rule.IsScatter = true; cellptr->Incoming(0, true); - Special.IsScatter = old; + Rule.IsScatter = old; } } } @@ -1079,10 +1079,10 @@ bool DriveClass::Start_Of_Move(void) ** get out of the way. */ if (cando == MOVE_TEMP) { - bool old = Special.IsScatter; - Special.IsScatter = true; + bool old = Rule.IsScatter; + Rule.IsScatter = true; Map[destcell].Incoming(0, true); - Special.IsScatter = old; + Rule.IsScatter = old; } /* @@ -1210,10 +1210,10 @@ bool DriveClass::Start_Of_Move(void) ** get out of the way. */ if (cando == MOVE_TEMP) { - bool old = Special.IsScatter; - Special.IsScatter = true; + bool old = Rule.IsScatter; + Rule.IsScatter = true; Map[destcell].Incoming(0, true); - Special.IsScatter = old; + Rule.IsScatter = old; } /* @@ -1319,7 +1319,7 @@ void DriveClass::AI(void) ** For tracked units that are rotating in place, perform the rotation now. */ if ((Class->Speed == SPEED_FLOAT || Class->Speed == SPEED_HOVER || Class->Speed == SPEED_TRACK - || (Class->Speed == SPEED_WHEEL && !Special.IsThreePoint)) + || (Class->Speed == SPEED_WHEEL && !Rule.IsThreePoint)) && PrimaryFacing.Is_Rotating()) { if (PrimaryFacing.Rotation_Adjust((int)Class->ROT * House->GroundspeedBias)) { Mark(MARK_CHANGE); @@ -1408,7 +1408,7 @@ void DriveClass::Fixup_Path(PathType* path) /* ** Only wheeled vehicles need a path fixup -- to avoid 3 point turns. */ - if (!Special.IsThreePoint || Class->Speed != SPEED_WHEEL) { + if (!Rule.IsThreePoint || Class->Speed != SPEED_WHEEL) { return; } diff --git a/tiberiandawn/foot.cpp b/tiberiandawn/foot.cpp index eadd7a44..91fcdd7d 100644 --- a/tiberiandawn/foot.cpp +++ b/tiberiandawn/foot.cpp @@ -1175,7 +1175,7 @@ ResultType FootClass::Take_Damage(int& damage, int distance, WarheadType warhead && (source->What_Am_I() != RTTI_AIRCRAFT || BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).IsAntiAircraft) && (!Target_Legal(TarCom) - || ((!House->IsHuman || Special.IsSmartDefense) && (!tweap || !In_Range(TarCom)))) + || ((!House->IsHuman || Rule.IsSmartDefense) && (!tweap || !In_Range(TarCom)))) && // !Target_Legal(NavCom) && (Mission == MISSION_AMBUSH || Mission == MISSION_GUARD || Mission == MISSION_RESCUE @@ -1208,7 +1208,7 @@ ResultType FootClass::Take_Damage(int& damage, int distance, WarheadType warhead ** Simple retaliation cannot occur because the source of the damage ** is too far away. If scatter logic is enabled, then scatter now. */ - if (Special.IsScatter) { + if (Rule.IsScatter) { Scatter(0, true); } } @@ -1218,7 +1218,7 @@ ResultType FootClass::Take_Damage(int& damage, int distance, WarheadType warhead /* ** If this object isn't doing anything important, then scatter. */ - if (!IsDriving && !Target_Legal(TarCom) && !Target_Legal(NavCom) && Special.IsScatter + if (!IsDriving && !Target_Legal(TarCom) && !Target_Legal(NavCom) && Rule.IsScatter && What_Am_I() != RTTI_AIRCRAFT) { Scatter(0, true); } diff --git a/tiberiandawn/idata.cpp b/tiberiandawn/idata.cpp index 83245338..e8e3f980 100644 --- a/tiberiandawn/idata.cpp +++ b/tiberiandawn/idata.cpp @@ -2002,7 +2002,7 @@ BuildingClass* InfantryTypeClass::Who_Can_Build_Me(bool intheory, bool legal, Ho *=============================================================================================*/ int InfantryTypeClass::Full_Name(void) const { - if (Debug_Map || !IsNominal || Special.IsNamed || Type == INFANTRY_C10 || Type == INFANTRY_DELPHI + if (Debug_Map || !IsNominal || Rule.IsNamed || Type == INFANTRY_C10 || Type == INFANTRY_DELPHI || Type == INFANTRY_MOEBIUS) { return (TechnoTypeClass::Full_Name()); } diff --git a/tiberiandawn/infantry.cpp b/tiberiandawn/infantry.cpp index 2293e55d..9c5b7e83 100644 --- a/tiberiandawn/infantry.cpp +++ b/tiberiandawn/infantry.cpp @@ -514,8 +514,7 @@ ResultType InfantryClass::Take_Damage(int& damage, int distance, WarheadType war Scatter(c4); } -#ifdef BOXING - if (IsBoxing) { + if (Rule.IsBoxing && IsBoxing) { int addval = 0; switch (warhead) { @@ -532,7 +531,6 @@ ResultType InfantryClass::Take_Damage(int& damage, int distance, WarheadType war break; } } else { -#endif if (source && Fear < FEAR_SCARED) { if (Class->IsFraidyCat) { Fear = FEAR_PANIC; @@ -545,9 +543,7 @@ ResultType InfantryClass::Take_Damage(int& damage, int distance, WarheadType war morefear /= 4; Fear = MIN((int)Fear + morefear, FEAR_MAXIMUM); } -#ifdef BOXING } -#endif } return (res); } @@ -630,11 +626,9 @@ void InfantryClass::Draw_It(int x, int y, WindowNumberType window) } shapenum += Class->DoControls[doit].Frame; -#ifdef BOXING // BG hack to get him to face right when he's supposed to. - if (IsBoxing && facing < Facing_To_32(DIR_S)) + if (Rule.IsBoxing && IsBoxing && facing < Facing_To_32(DIR_S)) shapenum += 47; -#endif /* ** Actually draw the root body of the unit. @@ -716,7 +710,7 @@ void InfantryClass::Per_Cell_Process(bool center) if (center && Mission == MISSION_SABOTAGE) { BuildingClass* building = cellptr->Cell_Building(); if (building && building->As_Target() == NavCom) { - int temp = Special.IsScatter; + int temp = Rule.IsScatter; building->IsGoingToBlow = true; building->Clicked_As_Target(PlayerPtr->Class->House, @@ -724,12 +718,12 @@ void InfantryClass::Per_Cell_Process(bool center) building->Clicked_As_Target(building->Owner(), 20); building->CountDown.Set(20); building->WhomToRepay = As_Target(); - Special.IsScatter = true; + Rule.IsScatter = true; NavCom = TARGET_NONE; Do_Uncloak(); Arm = Rearm_Delay(true); Scatter(building->Center_Coord(), true); // RUN AWAY! - Special.IsScatter = temp; + Rule.IsScatter = temp; return; } } @@ -1149,19 +1143,18 @@ void InfantryClass::AI(void) break; case FIRE_OK: -#ifdef BOXING ObjectClass* object = As_Object(TarCom); - if (object) { + if (!Rule.IsBoxing || object) { /* If we're engaged in hand-to-hand combat, keep boxing */ - if (IsBoxing) { + if (Rule.IsBoxing && IsBoxing) { IsFiring = true; if (((InfantryClass*)object)->Doing == DO_FIGHT_READY) { Do_Action((DoType)((int)DO_PUNCH + (DoType)(Random_Pick(0, 1) == 1)), true); } } else { - if (Is_Target_Infantry(TarCom) && (Distance(TarCom) <= 0x80) + if (Rule.IsBoxing && Is_Target_Infantry(TarCom) && (Distance(TarCom) <= 0x80) && (Coord_Y(Coord) == Coord_Y(object->Coord))) { // Too close to shoot, so start hand-to-hand combat @@ -1172,8 +1165,6 @@ void InfantryClass::AI(void) } } } else { -#endif - /* ** Start firing animation. */ @@ -1184,9 +1175,7 @@ void InfantryClass::AI(void) Do_Action(DO_FIRE_WEAPON); IsFiring = true; } -#ifdef BOXING } -#endif PrimaryFacing.Set(Direction8(Center_Coord(), As_Coord(TarCom))); @@ -1198,10 +1187,8 @@ void InfantryClass::AI(void) NavCom = TARGET_NONE; Path[0] = FACING_NONE; } -#ifdef BOXING } } -#endif break; } @@ -1216,13 +1203,11 @@ void InfantryClass::AI(void) if (IsProne) firestage = Class->ProneLaunch; -#ifdef BOXING - if (IsBoxing) { + if (Rule.IsBoxing && IsBoxing) { firestage = 1; if (Doing == DO_KICK) firestage = 2; } -#endif if (IsFiring && Fetch_Stage() == firestage) { Fire_At(TarCom, 0); @@ -1254,7 +1239,6 @@ void InfantryClass::AI(void) } break; -#ifdef BOXING case DO_FIGHT_READY: case DO_ON_GUARD: case DO_PUNCH: @@ -1270,7 +1254,6 @@ void InfantryClass::AI(void) Do_Action(DO_READY_WEAPON); } break; -#endif /* ** When death is due to hand-to-hand combat, use the gunfire death @@ -1833,18 +1816,16 @@ FireErrorType InfantryClass::Can_Fire(TARGET target, int which) const Validate(); WeaponTypeClass const* weapon = (which == 0) ? &Weapons[Class->Primary] : &Weapons[Class->Secondary]; -#ifdef BOXING /* ** If in hand-to-hand, and we're currently playing a got-hit animation, ** then we can't punch back yet. */ - if (IsBoxing) { + if (Rule.IsBoxing && IsBoxing) { if ((Doing >= DO_PUNCH_HIT1 && Doing <= DO_KICK_DEATH) || (Doing == DO_ON_GUARD)) return FIRE_BUSY; if (Arm) return (FIRE_BUSY); // don't let fire if still re-arming } -#endif /* ** Don't allow firing if the turret is not ready. @@ -2102,7 +2083,7 @@ void InfantryClass::Scatter(COORDINATE threat, bool forced, bool nokidding) ** For human players, don't scatter the infantry, if the special ** flag has not been enabled that allows infantry scatter. */ - if (!Special.IsScatter && !nokidding && House->IsHuman && !forced && !Team) + if (!Rule.IsScatter && !nokidding && House->IsHuman && !forced && !Team) return; if (forced || Class->IsFraidyCat /*|| !(Random_Pick(1, 4) == 1)*/) { @@ -2387,8 +2368,7 @@ BulletClass* InfantryClass::Fire_At(TARGET target, int which) IsFiring = false; -#ifdef BOXING - if (IsBoxing) { + if (Rule.IsBoxing && IsBoxing) { RadioMessageType hitaction = (Doing == DO_KICK) ? RADIO_KICK : RADIO_PUNCH; /* @@ -2408,8 +2388,6 @@ BulletClass* InfantryClass::Fire_At(TARGET target, int which) Do_Action(DO_READY_WEAPON, true); } } else { -#endif - bullet = FootClass::Fire_At(target, which); if (bullet) { @@ -2431,10 +2409,7 @@ BulletClass* InfantryClass::Fire_At(TARGET target, int which) */ Sound_Effect(weapon->Sound, Coord); } - -#ifdef BOXING } -#endif return (bullet); } @@ -2762,10 +2737,8 @@ RadioMessageType InfantryClass::Receive_Message(RadioClass* from, RadioMessageTy switch (message) { case RADIO_OVER_OUT: -#ifdef BOXING - if (IsBoxing) + if (Rule.IsBoxing && IsBoxing) Do_Action(DO_READY_WEAPON); -#endif break; /* @@ -2773,10 +2746,9 @@ RadioMessageType InfantryClass::Receive_Message(RadioClass* from, RadioMessageTy ** then refuse the offer. */ case RADIO_PREPARE_TO_BOX: -#ifdef BOXING - if (IsBoxing) + if (Rule.IsBoxing && IsBoxing) break; -#endif + if (Contact_With_Whom() == from) { Assign_Target(Contact_With_Whom()->As_Target()); Do_Action(DO_ON_GUARD, true); @@ -2825,11 +2797,11 @@ RadioMessageType InfantryClass::Receive_Message(RadioClass* from, RadioMessageTy int InfantryClass::Rearm_Delay(bool second) const { Validate(); -#ifdef BOXING - if (IsBoxing) { + + if (Rule.IsBoxing && IsBoxing) { return (Random_Pick(5, 50)); } -#endif + return (FootClass::Rearm_Delay(second)); } diff --git a/tiberiandawn/map.cpp b/tiberiandawn/map.cpp index af1c9095..49f9d891 100644 --- a/tiberiandawn/map.cpp +++ b/tiberiandawn/map.cpp @@ -1369,7 +1369,7 @@ void MapClass::Logic(void) /* ** Bail early if there is no allowed growth or spread of Tiberium. */ - if (!Special.IsTGrowth && !Special.IsTSpread) + if (!Rule.IsTGrowth && !Rule.IsTSpread) return; /* @@ -1384,7 +1384,7 @@ void MapClass::Logic(void) cell = (MAP_CELL_TOTAL - 1) - index; CellClass* ptr = &(*this)[cell]; - if (Special.IsTGrowth && ptr->Land_Type() == LAND_TIBERIUM && ptr->OverlayData < 11) { + if (Rule.IsTGrowth && ptr->Land_Type() == LAND_TIBERIUM && ptr->OverlayData < 11) { if (TiberiumGrowthCount < sizeof(TiberiumGrowth) / sizeof(TiberiumGrowth[0])) { TiberiumGrowth[TiberiumGrowthCount++] = cell; } else { @@ -1396,7 +1396,7 @@ void MapClass::Logic(void) ** Heavy Tiberium growth can spread. */ TerrainClass* terrain = ptr->Cell_Terrain(); - if (Special.IsTSpread && (ptr->Land_Type() == LAND_TIBERIUM && ptr->OverlayData > 6) + if (Rule.IsTSpread && (ptr->Land_Type() == LAND_TIBERIUM && ptr->OverlayData > 6) || (terrain && terrain->Class->IsTiberiumSpawn)) { int tries = 1; diff --git a/tiberiandawn/netdlg.cpp b/tiberiandawn/netdlg.cpp index 9462e0cf..3ca5e3ee 100644 --- a/tiberiandawn/netdlg.cpp +++ b/tiberiandawn/netdlg.cpp @@ -4350,6 +4350,7 @@ static int Net_Fake_New_Dialog(void) ........................................................................*/ Special.IsTGrowth = MPlayerTiberium; Special.IsTSpread = MPlayerTiberium; + Rule.IsTSpread = Special.IsTSpread; transmit = 0; /*........................................................................ diff --git a/tiberiandawn/options.cpp b/tiberiandawn/options.cpp index c4206a04..9a731b95 100644 --- a/tiberiandawn/options.cpp +++ b/tiberiandawn/options.cpp @@ -681,14 +681,6 @@ void OptionsClass::Load_Settings(void) char workbuf[128]; - /* - ** Check for and possible enable true object names. - */ - ini.Get_String(OPTIONS, "TrueNames", "", workbuf, sizeof(workbuf)); - if (Obfuscate(workbuf) == PARM_TRUENAME) { - Special.IsNamed = true; - } - /* ** Enable 6 player games if special flag is detected. */ @@ -697,30 +689,6 @@ void OptionsClass::Load_Settings(void) MPlayerMax = 6; } - /* - ** Enable three point turning logic as indicated. - */ - ini.Get_String(OPTIONS, "Rotation", "", workbuf, sizeof(workbuf)); - if (Obfuscate(workbuf) == PARM_3POINT) { - Special.IsThreePoint = true; - } - - /* - ** Allow purchase of the helipad separately from the helicopter. - */ - ini.Get_String(OPTIONS, "Helipad", "", workbuf, sizeof(workbuf)); - if (Obfuscate(workbuf) == PARM_HELIPAD) { - Special.IsSeparate = true; - } - - /* - ** Allow the MCV to undeploy rather than sell. - */ - ini.Get_String(OPTIONS, "MCV", "", workbuf, sizeof(workbuf)); - if (Obfuscate(workbuf) == PARM_MCV) { - Special.IsMCVDeploy = true; - } - /* ** Allow disabling of building bibs so that tigher building packing can occur. */ @@ -729,14 +697,6 @@ void OptionsClass::Load_Settings(void) Special.IsRoad = true; } - /* - ** Allow targeting of trees without having to hold down the shift key. - */ - ini.Get_String(OPTIONS, "TreeTarget", "", workbuf, sizeof(workbuf)); - if (Obfuscate(workbuf) == PARM_TREETARGET) { - Special.IsTreeTarget = true; - } - /* ** Allow infantry to fire while moving. Attacker gets advantage with this flag. */ @@ -753,17 +713,6 @@ void OptionsClass::Load_Settings(void) Special.IsVariation = true; } - /* - ** Smarter self defense logic. Tanks will try to run over adjacent infantry. Buildings - ** will automatically return fire if they are fired upon. Infantry will run from an - ** incoming explosive (grenade or napalm) or damage that can't be directly addressed. - */ - ini.Get_String(OPTIONS, "CombatIQ", "", workbuf, sizeof(workbuf)); - if (Obfuscate(workbuf) == PARM_IQ) { - Special.IsSmartDefense = true; - Special.IsScatter = true; - } - /* ** Enable the infantry squish marks when run over by a vehicle. */ diff --git a/tiberiandawn/rules.cpp b/tiberiandawn/rules.cpp index f1a4ef45..4b4ac4ea 100644 --- a/tiberiandawn/rules.cpp +++ b/tiberiandawn/rules.cpp @@ -123,7 +123,17 @@ RulesClass::RulesClass(void) , IsComputerParanoid(false) , IsCompEasyBonus(false) , IsFineDifficulty(false) + , IsMCVDeploy(false) + , IsSeparate(false) + , IsTreeTarget(false) + , IsTGrowth(true) + , IsTSpread(true) + , IsNamed(false) + , IsSmartDefense(false) + , IsScatter(false) , AllowSuperWeapons(true) + , IsThreePoint(false) + , IsBoxing(false) { #ifndef REMASTER_BUILD Diff[DIFF_EASY].FirepowerBias = "1.2"; @@ -253,6 +263,7 @@ static void Difficulty_Put(CCINIClass& ini, DifficultyClass& diff, char const* s *=============================================================================================*/ bool RulesClass::Process(CCINIClass& ini) { + General(ini); AI(ini); IQ(ini); Difficulty(ini); @@ -276,6 +287,7 @@ bool RulesClass::Process(CCINIClass& ini) *=============================================================================================*/ bool RulesClass::Export(CCINIClass& ini) { + Export_General(ini); Export_AI(ini); Export_IQ(ini); Export_Difficulty(ini); @@ -283,6 +295,80 @@ bool RulesClass::Export(CCINIClass& ini) return (true); } +/*********************************************************************************************** + * RulesClass::General -- Process the general main game rules. * + * * + * This fetches the control constants uses for regular game processing. Any game behavior * + * controlling values that don't properly fit in any of the other catagories will be * + * stored here. * + * * + * INPUT: ini -- Reference to the database to fetch the values from. * + * * + * OUTPUT: bool; Was the general section found and processed? * + * * + * WARNINGS: none * + * * + * HISTORY: * + * 08/08/1996 JLB : Created. * + *=============================================================================================*/ +bool RulesClass::General(CCINIClass& ini) +{ + static char const* const GENERAL = "General"; + + if (ini.Is_Present(GENERAL)) { + IsFineDifficulty = ini.Get_Bool(GENERAL, "FineDiffControl", IsFineDifficulty); + IsScatter = ini.Get_Bool(GENERAL, "PlayerScatter", IsScatter); + IsSmartDefense = ini.Get_Bool(GENERAL, "PlayerReturnFire", IsSmartDefense); + IsNamed = ini.Get_Bool(GENERAL, "NamedCivilians", IsNamed); + IsTGrowth = ini.Get_Bool(GENERAL, "TiberiumGrows", IsTGrowth); + IsTSpread = ini.Get_Bool(GENERAL, "TiberiumSpreads", IsTSpread); + IsTreeTarget = ini.Get_Bool(GENERAL, "TreeTargeting", IsTreeTarget); + IsSeparate = ini.Get_Bool(GENERAL, "SeparateAircraft", IsSeparate); + IsMCVDeploy = ini.Get_Bool(GENERAL, "MCVUndeploy", IsMCVDeploy); + IsThreePoint = ini.Get_Bool(GENERAL, "ThreePointTurns", IsThreePoint); + IsBoxing = ini.Get_Bool(GENERAL, "HandToHand", IsBoxing); + + return (true); + } + + return (false); +} + +/*********************************************************************************************** + * RulesClass::General -- Process the general main game rules. * + * * + * This fetches the control constants uses for regular game processing. Any game behavior * + * controlling values that don't properly fit in any of the other catagories will be * + * stored here. * + * * + * INPUT: ini -- Reference to the database to fetch the values from. * + * * + * OUTPUT: bool; Was the general section found and processed? * + * * + * WARNINGS: none * + * * + * HISTORY: * + * 08/08/1996 JLB : Created. * + *=============================================================================================*/ +bool RulesClass::Export_General(CCINIClass& ini) +{ + static char const GENERAL[] = "General"; + + ini.Put_Bool(GENERAL, "FineDiffControl", IsFineDifficulty); + ini.Put_Bool(GENERAL, "PlayerScatter", IsScatter); + ini.Put_Bool(GENERAL, "PlayerReturnFire", IsSmartDefense); + ini.Put_Bool(GENERAL, "NamedCivilians", IsNamed); + ini.Put_Bool(GENERAL, "TiberiumGrows", IsTGrowth); + ini.Put_Bool(GENERAL, "TiberiumSpreads", IsTSpread); + ini.Put_Bool(GENERAL, "TreeTargeting", IsTreeTarget); + ini.Put_Bool(GENERAL, "SeparateAircraft", IsSeparate); + ini.Put_Bool(GENERAL, "MCVUndeploy", IsMCVDeploy); + ini.Put_Bool(GENERAL, "ThreePointTurns", IsThreePoint); + ini.Put_Bool(GENERAL, "HandToHand", IsBoxing); + + return (true); +} + /*********************************************************************************************** * RulesClass::AI -- Processes the AI control constants from the database. * * * @@ -497,4 +583,24 @@ bool RulesClass::Export_Difficulty(CCINIClass& ini) Difficulty_Put(ini, Diff[DIFF_HARD], "Difficult"); #endif return (true); +} + +/*********************************************************************************************** + * Is_MCV_Deploy -- Check if MCV can be deployed. * + * * + * This routine is used to check if the Construction Yard can revert back into an MCV. * + * It allows the special variables to override anything set by the rules. * + * * + * INPUT: none * + * * + * OUTPUT: bool; Can the Construction Yard revert back into an MCV. * + * * + * WARNINGS: none * + * * + * HISTORY: * + * 10/24/2019 SKY : Created. * + *=============================================================================================*/ +bool Is_MCV_Deploy() +{ + return Special.UseMCVDeploy ? Special.IsMCVDeploy : Rule.IsMCVDeploy; } \ No newline at end of file diff --git a/tiberiandawn/rules.h b/tiberiandawn/rules.h index c9b8cc53..1bacfb38 100644 --- a/tiberiandawn/rules.h +++ b/tiberiandawn/rules.h @@ -66,10 +66,12 @@ class RulesClass RulesClass(void); bool Process(CCINIClass& file); + bool General(CCINIClass& ini); bool AI(CCINIClass& ini); bool IQ(CCINIClass& ini); bool Difficulty(CCINIClass& ini); bool Export(CCINIClass& file); + bool Export_General(CCINIClass& ini); bool Export_AI(CCINIClass& ini); bool Export_IQ(CCINIClass& ini); bool Export_Difficulty(CCINIClass& ini); @@ -265,6 +267,12 @@ class RulesClass */ int InfantryBaseMult; + /* + ** This array controls the difficulty affects on the game. There is one + ** difficulty class object for each difficulty level. + */ + DifficultyClass Diff[DIFF_COUNT]; + /* ** Is the computer paranoid? If so, then it will band together with other computer ** paranoid players when the situation looks rough. @@ -283,16 +291,68 @@ class RulesClass */ bool IsFineDifficulty; + /* + ** If this flag is true, then the construction yard can undeploy back into an MCV. + */ + bool IsMCVDeploy; + + /* + ** Can the helipad (and airfield) be purchased separately from the associated + ** aircraft. + */ + bool IsSeparate; + + /* + ** Give target cursor for trees? Doing this will make targetting of trees easier. + */ + bool IsTreeTarget; + + /* + ** If Tiberium is allowed to grow, then this flag will be true. + */ + bool IsTGrowth; + + /* + ** If Tiberium is allowed to spread, then this flag will be true. + */ + bool IsTSpread; + + /* + ** Should civilan buildings and civilians display their true name rather than + ** the generic "Civilian Building" and "Civilain"? + */ + bool IsNamed; + + /* + ** Should the player controlled buildings and units automatically return fire when + ** fired upon? + */ + bool IsSmartDefense; + + /* + ** Should player controlled units try to scatter more easily in order to + ** avoid damage or threats? + */ + bool IsScatter; + /* ** Are superweapons allowed? */ bool AllowSuperWeapons; /* - ** This array controls the difficulty affects on the game. There is one - ** difficulty class object for each difficulty level. + ** If wheeled vehicles should do a 3-point turn when rotating in place, then + ** this flag is true. */ - DifficultyClass Diff[DIFF_COUNT]; + bool IsThreePoint; + + /* + ** If infantry should engage in fisticuffs, then + ** this flag is true. + */ + bool IsBoxing; }; +bool Is_MCV_Deploy(); + #endif diff --git a/tiberiandawn/special.cpp b/tiberiandawn/special.cpp index d75e44cc..a23683fa 100644 --- a/tiberiandawn/special.cpp +++ b/tiberiandawn/special.cpp @@ -79,11 +79,11 @@ void Special_Dialog(void) bool value = false; switch (_options[index].Description) { case TXT_SEPARATE_HELIPAD: - value = Special.IsSeparate; + value = Rule.IsSeparate; break; case TXT_SHOW_NAMES: - value = Special.IsNamed; + value = Rule.IsNamed; break; case TXT_DEFENDER_ADVANTAGE: @@ -95,19 +95,19 @@ void Special_Dialog(void) break; case TXT_TREE_TARGET: - value = Special.IsTreeTarget; + value = Rule.IsTreeTarget; break; case TXT_MCV_DEPLOY: - value = Special.IsMCVDeploy; + value = Rule.IsMCVDeploy; break; case TXT_SMART_DEFENCE: - value = Special.IsSmartDefense; + value = Rule.IsSmartDefense; break; case TXT_THREE_POINT: - value = Special.IsThreePoint; + value = Rule.IsThreePoint; break; case TXT_TIBERIUM_GROWTH: @@ -127,7 +127,7 @@ void Special_Dialog(void) break; case TXT_SCATTER: - value = Special.IsScatter; + value = Rule.IsScatter; break; } diff --git a/tiberiandawn/special.h b/tiberiandawn/special.h index 78ad08fb..15f8a0a3 100644 --- a/tiberiandawn/special.h +++ b/tiberiandawn/special.h @@ -56,6 +56,7 @@ class BITFIELD_STRUCT SpecialClass IsJuvenile = false; IsSmartDefense = false; IsTreeTarget = false; + UseMCVDeploy = false; IsMCVDeploy = false; IsVisceroids = false; IsMonoEnabled = false; @@ -151,6 +152,7 @@ class BITFIELD_STRUCT SpecialClass /* ** If this flag is true, then the construction yard can undeploy back into an MCV. */ + unsigned UseMCVDeploy : 1; unsigned IsMCVDeploy : 1; /* diff --git a/tiberiandawn/techno.cpp b/tiberiandawn/techno.cpp index 59bf7f8c..dcfe2503 100644 --- a/tiberiandawn/techno.cpp +++ b/tiberiandawn/techno.cpp @@ -2630,9 +2630,9 @@ ActionType TechnoClass::What_Action(ObjectClass* object) const // Changed for multiplayer. ST - 3/13/2019 5:52PM if (Is_Owned_By_Player() && (ctrldown || !House->Is_Ally(object)) && (ctrldown || object->Class_Of().IsLegalTarget - || (Special.IsTreeTarget && object->What_Am_I() == RTTI_TERRAIN))) { + || (Rule.IsTreeTarget && object->What_Am_I() == RTTI_TERRAIN))) { // if (IsOwnedByPlayer && (ctrldown || !House->Is_Ally(object)) && (ctrldown || - // object->Class_Of().IsLegalTarget || (Special.IsTreeTarget && object->What_Am_I() == RTTI_TERRAIN))) { + // object->Class_Of().IsLegalTarget || (Rule.IsTreeTarget && object->What_Am_I() == RTTI_TERRAIN))) { if (Can_Player_Move() || In_Range(object, 0)) { // Check for anti-air capability if (object->What_Am_I() != RTTI_AIRCRAFT) { diff --git a/tiberiandawn/unit.cpp b/tiberiandawn/unit.cpp index f90f7bff..17e7ca46 100644 --- a/tiberiandawn/unit.cpp +++ b/tiberiandawn/unit.cpp @@ -994,7 +994,7 @@ ResultType UnitClass::Take_Damage(int& damage, int distance, WarheadType warhead ** Try to crush anyone that fires on this unit if possible. The harvester ** typically is the only one that will qualify here. */ - if (!Team && source && !IsTethered && !House->Is_Ally(source) && (!House->IsHuman || Special.IsSmartDefense)) { + if (!Team && source && !IsTethered && !House->Is_Ally(source) && (!House->IsHuman || Rule.IsSmartDefense)) { /* ** Try to crush the attacker if it can be crushed by this unit and this unit is