From 2aaaa67becaa7b6ec81ab68bf0e1cc83dc2a335f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:10:32 +0000 Subject: [PATCH 1/3] Initial plan From 6e72c08b3ac0c917db9d0b4c85d538b52a7e0186 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:15:44 +0000 Subject: [PATCH 2/3] Fix critical and minor bugs in FakeTeamClass Co-authored-by: deathreaperz <37824218+deathreaperz@users.noreply.github.com> --- src/Ext/Team/Body.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Ext/Team/Body.cpp b/src/Ext/Team/Body.cpp index 5e9c33baa..5140b74df 100644 --- a/src/Ext/Team/Body.cpp +++ b/src/Ext/Team/Body.cpp @@ -19,7 +19,6 @@ concept ReturnsBool = std::same_as, bool>; template void LoopThruMembers(TeamClass* pTeam, Func&& act) { - FootClass* pCur = nullptr; if (auto pFirst = pTeam->FirstUnit) { do @@ -130,7 +129,7 @@ bool TeamExtData::EnemyOwns(AITriggerTypeClass* pThis, HouseClass* pHouse, House continue; if (pObject->Owner != pHouse - && (!pEnemy || (pEnemy && !pHouse->IsAlliedWith(pEnemy))) + && (!pEnemy || !pHouse->IsAlliedWith(pEnemy)) && !pObject->Owner->Type->MultiplayPassive && pObject->GetTechnoType() == pItem) { @@ -301,7 +300,7 @@ bool TeamExtData::EnemyOwnsAll(AITriggerTypeClass* pThis, HouseClass* pHouse, Ho continue; if (pObject->Owner != pHouse - && (!pEnemy || (pEnemy && !pHouse->IsAlliedWith(pEnemy))) + && (!pEnemy || !pHouse->IsAlliedWith(pEnemy)) && !pObject->Owner->Type->MultiplayPassive && pObject->GetTechnoType() == pItem) { @@ -550,7 +549,7 @@ void FakeTeamClass::_TMission_GatherAtEnemy(ScriptActionNode* nNode, bool arg3) TechnoTypeClass* leaderType = bestLeader->GetTechnoType(); CellStruct finalCell = MapClass::Instance->NearByLocation( targetCell, - leaderType->SpeedType, + leaderType ? leaderType->SpeedType : SpeedType::Track, ZoneType::None, MovementZone::Normal, 0, 3, 3, 0, 0, 0, 1, CellStruct::Empty, 0, 0 ); @@ -1144,6 +1143,7 @@ void FakeTeamClass::_Coordinate_Attack() { if (targetCell && this->FirstUnit + && teamLeader && teamLeader->WhatAmI() != AircraftClass::AbsID) { @@ -1153,7 +1153,7 @@ void FakeTeamClass::_Coordinate_Attack() { } // Check if team leader can fire at target (every 8 frames, on frame 4) - if (Unsorted::CurrentFrame % 8 == 4) { + if (teamLeader && Unsorted::CurrentFrame % 8 == 4) { const int weaponIndex = teamLeader->SelectWeapon(this->ArchiveTarget); if (teamLeader->GetFireError(this->ArchiveTarget, weaponIndex, true) == FireError::ILLEGAL) { @@ -1345,9 +1345,9 @@ void FakeTeamClass::_CoordinateMove() { { int strayDistance = this->_Get_Stray(); - // Double for airborne units + // Triple for airborne units if (unit->IsInAir()){ - strayDistance *= 2; + strayDistance *= 3; } found = true; @@ -3434,7 +3434,7 @@ void FakeTeamClass::_TMission_Play_Animation(ScriptActionNode* nNode, bool arg3) // Validate anim index if (animIndex >= AnimTypeClass::Array->Count) { Debug::FatalErrorAndExit("Team [%s] TMission_Play_Animation: Invalid anim type index %d (max: %d)", - this->Type->ID, animIndex, BuildingTypeClass::Array->Count - 1); + this->Type->ID, animIndex, AnimTypeClass::Array->Count - 1); this->StepCompleted = true; return; From 1a09ee3f13d086fa6701e9032e852fd19697db48 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:20:20 +0000 Subject: [PATCH 3/3] Extract comparator logic to helper function and add named constants Co-authored-by: deathreaperz <37824218+deathreaperz@users.noreply.github.com> --- src/Ext/Team/Body.cpp | 193 +++++++++--------------------------------- 1 file changed, 39 insertions(+), 154 deletions(-) diff --git a/src/Ext/Team/Body.cpp b/src/Ext/Team/Body.cpp index 5140b74df..b4a930392 100644 --- a/src/Ext/Team/Body.cpp +++ b/src/Ext/Team/Body.cpp @@ -13,6 +13,11 @@ #include #include +// Named constants for clarity +constexpr int RECRUIT_WRONG_GROUP_PENALTY = 12800; // Distance penalty for recruiting units from wrong group +constexpr int PATROL_THRESHOLD = 702; // Mission data threshold for patrol behavior +constexpr int FACING_DIRECTION_MULTIPLIER = 8192; // Convert 8-direction facing to 16-bit facing (65536 / 8 = 8192) + template concept ReturnsBool = std::same_as, bool>; @@ -39,6 +44,28 @@ void LoopThruMembers(TeamClass* pTeam, Func&& act) } } +// Helper function for comparator operations +static bool EvaluateComparator(int counter, int comparatorType, int comparatorOperand) +{ + switch (comparatorOperand) + { + case 0: + return counter < comparatorType; + case 1: + return counter <= comparatorType; + case 2: + return counter == comparatorType; + case 3: + return counter >= comparatorType; + case 4: + return counter > comparatorType; + case 5: + return counter != comparatorType; + default: + return false; + } +} + #pragma region ExtFuncs bool TeamExtData::IsEligible(TechnoClass* pGoing, TechnoTypeClass* reinfocement) @@ -65,7 +92,6 @@ void TeamExtData::InvalidatePointer(AbstractClass* ptr, bool bRemoved) bool TeamExtData::HouseOwns(AITriggerTypeClass* pThis, HouseClass* pHouse, bool allies, const Iterator& list) { - bool result = false; int counter = 0; // Count all objects of the list, like an OR operator @@ -85,36 +111,11 @@ bool TeamExtData::HouseOwns(AITriggerTypeClass* pThis, HouseClass* pHouse, bool } } - switch (pThis->Conditions[0].ComparatorOperand) - { - case 0: - result = counter < pThis->Conditions[0].ComparatorType; - break; - case 1: - result = counter <= pThis->Conditions[0].ComparatorType; - break; - case 2: - result = counter == pThis->Conditions[0].ComparatorType; - break; - case 3: - result = counter >= pThis->Conditions[0].ComparatorType; - break; - case 4: - result = counter > pThis->Conditions[0].ComparatorType; - break; - case 5: - result = counter != pThis->Conditions[0].ComparatorType; - break; - default: - break; - } - - return result; + return EvaluateComparator(counter, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand); } bool TeamExtData::EnemyOwns(AITriggerTypeClass* pThis, HouseClass* pHouse, HouseClass* pEnemy, bool onlySelectedEnemy, const Iterator& list) { - bool result = false; int counter = 0; if (pEnemy && pHouse->IsAlliedWith(pEnemy) && !onlySelectedEnemy) @@ -138,36 +139,11 @@ bool TeamExtData::EnemyOwns(AITriggerTypeClass* pThis, HouseClass* pHouse, House } } - switch (pThis->Conditions[0].ComparatorOperand) - { - case 0: - result = counter < pThis->Conditions[0].ComparatorType; - break; - case 1: - result = counter <= pThis->Conditions[0].ComparatorType; - break; - case 2: - result = counter == pThis->Conditions[0].ComparatorType; - break; - case 3: - result = counter >= pThis->Conditions[0].ComparatorType; - break; - case 4: - result = counter > pThis->Conditions[0].ComparatorType; - break; - case 5: - result = counter != pThis->Conditions[0].ComparatorType; - break; - default: - break; - } - - return result; + return EvaluateComparator(counter, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand); } bool TeamExtData::NeutralOwns(AITriggerTypeClass* pThis, const Iterator& list) { - bool result = false; int counter = 0; for (auto pHouse : *HouseClass::Array) @@ -192,31 +168,7 @@ bool TeamExtData::NeutralOwns(AITriggerTypeClass* pThis, const IteratorConditions[0].ComparatorOperand) - { - case 0: - result = counter < pThis->Conditions[0].ComparatorType; - break; - case 1: - result = counter <= pThis->Conditions[0].ComparatorType; - break; - case 2: - result = counter == pThis->Conditions[0].ComparatorType; - break; - case 3: - result = counter >= pThis->Conditions[0].ComparatorType; - break; - case 4: - result = counter > pThis->Conditions[0].ComparatorType; - break; - case 5: - result = counter != pThis->Conditions[0].ComparatorType; - break; - default: - break; - } - - return result; + return EvaluateComparator(counter, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand); } bool TeamExtData::HouseOwnsAll(AITriggerTypeClass* pThis, HouseClass* pHouse, const Iterator& list) @@ -247,29 +199,7 @@ bool TeamExtData::HouseOwnsAll(AITriggerTypeClass* pThis, HouseClass* pHouse, co } } - switch (pThis->Conditions[0].ComparatorOperand) - { - case 0: - result = counter < pThis->Conditions[0].ComparatorType; - break; - case 1: - result = counter <= pThis->Conditions[0].ComparatorType; - break; - case 2: - result = counter == pThis->Conditions[0].ComparatorType; - break; - case 3: - result = counter >= pThis->Conditions[0].ComparatorType; - break; - case 4: - result = counter > pThis->Conditions[0].ComparatorType; - break; - case 5: - result = counter != pThis->Conditions[0].ComparatorType; - break; - default: - break; - } + result = EvaluateComparator(counter, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand); } return result; @@ -308,29 +238,7 @@ bool TeamExtData::EnemyOwnsAll(AITriggerTypeClass* pThis, HouseClass* pHouse, Ho } } - switch (pThis->Conditions[0].ComparatorOperand) - { - case 0: - result = counter < pThis->Conditions[0].ComparatorType; - break; - case 1: - result = counter <= pThis->Conditions[0].ComparatorType; - break; - case 2: - result = counter == pThis->Conditions[0].ComparatorType; - break; - case 3: - result = counter >= pThis->Conditions[0].ComparatorType; - break; - case 4: - result = counter > pThis->Conditions[0].ComparatorType; - break; - case 5: - result = counter != pThis->Conditions[0].ComparatorType; - break; - default: - break; - } + result = EvaluateComparator(counter, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand); } return result; @@ -374,29 +282,7 @@ bool TeamExtData::NeutralOwnsAll(AITriggerTypeClass* pThis, const IteratorConditions[0].ComparatorOperand) - { - case 0: - foundAll = counter < pThis->Conditions[0].ComparatorType; - break; - case 1: - foundAll = counter <= pThis->Conditions[0].ComparatorType; - break; - case 2: - foundAll = counter == pThis->Conditions[0].ComparatorType; - break; - case 3: - foundAll = counter >= pThis->Conditions[0].ComparatorType; - break; - case 4: - foundAll = counter > pThis->Conditions[0].ComparatorType; - break; - case 5: - foundAll = counter != pThis->Conditions[0].ComparatorType; - break; - default: - break; - } + foundAll = EvaluateComparator(counter, pThis->Conditions[0].ComparatorType, pThis->Conditions[0].ComparatorOperand); } if (!foundAll) @@ -1800,7 +1686,7 @@ FootClass* FindClosestInfantry(TeamClass* team, int memberIndex, const CoordStru // Calculate distance with penalty for wrong group int distance = infantry->DistanceFromSquared(&location); if (infantry->Group != targetGroup) - distance += 12800; // Penalty for wrong group + distance += RECRUIT_WRONG_GROUP_PENALTY; // Check if this is a better candidate if ((minDistance == -1 || distance < minDistance) && @@ -1831,7 +1717,7 @@ FootClass* FindClosestAircraft(TeamClass* team, int memberIndex, const CoordStru // Calculate distance with penalty for wrong group int distance = aircraft->DistanceFromSquared(&location); if (aircraft->Group != targetGroup) - distance += 12800; // Penalty for wrong group + distance += RECRUIT_WRONG_GROUP_PENALTY; // Check if this is a better candidate if ((minDistance == -1 || distance < minDistance) && @@ -1862,7 +1748,7 @@ FootClass* FindClosestUnit(TeamClass* team, int memberIndex, const CoordStruct& // Calculate distance with penalty for wrong group int distance = unit->DistanceFromSquared(&location); if (unit->Group != targetGroup) - distance += 12800; // Penalty for wrong group + distance += RECRUIT_WRONG_GROUP_PENALTY; // Check if this unit matches requirements if (unit->Owner == team->OwnerHouse && EligibleToRecruit(team->Type->TaskForce->Entries[memberIndex].Type , unit->Type) && @@ -4197,8 +4083,7 @@ void FakeTeamClass::_AI() } // Target direction (0-7 facing) converted to internal facing units - // Multiply by 8192 (0x2000) to convert 8-direction facing to 16-bit facing (65536 / 8 = 8192) - DirType targetFacing = (DirType)(node.Argument << 13); + DirType targetFacing = (DirType)(node.Argument * FACING_DIRECTION_MULTIPLIER); bool allMembersFacing = true; @@ -4577,8 +4462,8 @@ void FakeTeamClass::_AI() { auto const& [miss, value] = this->CurrentScript->GetCurrentAction(); - // Mission data < 702 is some threshold check (possibly frame-based) - if (value < 702) { + // Mission data threshold check (possibly frame-based) + if (value < PATROL_THRESHOLD) { this->_AssignMissionTarget(waypointCell); } }