diff --git a/YRpp/CoordStruct.h b/YRpp/CoordStruct.h index 3b08a0606..97e47bc75 100644 --- a/YRpp/CoordStruct.h +++ b/YRpp/CoordStruct.h @@ -63,7 +63,7 @@ struct CoordStruct { // Convert coord to cell, and back again to get the absolute position. const CellStruct cell = this->TocellStruct(); - CoordStruct tmp {cell.X * 256 , cell.Y * 256}; + CoordStruct tmp {cell.X * 256 , cell.Y * 256, 0}; // Snap coord to cell center. tmp.X += 256 / 2; diff --git a/YRpp/Point2D.h b/YRpp/Point2D.h index 67ad704ff..c6091cc79 100644 --- a/YRpp/Point2D.h +++ b/YRpp/Point2D.h @@ -64,10 +64,10 @@ class Point2D COMPILETIMEEVAL Point2D operator/(int factor) const { return {X / factor, Y / factor};} COMPILETIMEEVAL Point2D& operator/=(int factor) { X /= factor; Y /= factor; return *this; } - COMPILETIMEEVAL Point2D operator%(const Point2D& that) const { return {X / that.X, Y / that.Y};} - COMPILETIMEEVAL Point2D operator%=(const Point2D& that) { X /= that.X; Y /= that.Y; return *this; } - COMPILETIMEEVAL Point2D operator%(int factor) const { return {X / factor, Y / factor};} - COMPILETIMEEVAL Point2D& operator%=(int factor) { X /= factor; Y /= factor; return *this; } + COMPILETIMEEVAL Point2D operator%(const Point2D& that) const { return {X % that.X, Y % that.Y};} + COMPILETIMEEVAL Point2D operator%=(const Point2D& that) { X %= that.X; Y %= that.Y; return *this; } + COMPILETIMEEVAL Point2D operator%(int factor) const { return {X % factor, Y % factor};} + COMPILETIMEEVAL Point2D& operator%=(int factor) { X %= factor; Y %= factor; return *this; } COMPILETIMEEVAL Point2D operator&(const Point2D& that) const { return {X & that.X, Y & that.Y};} COMPILETIMEEVAL Point2D operator&=(const Point2D& that) { X &= that.X; Y &= that.Y; return *this; } diff --git a/YRpp/Point3D.h b/YRpp/Point3D.h index 98f975c43..43e933cd1 100644 --- a/YRpp/Point3D.h +++ b/YRpp/Point3D.h @@ -43,10 +43,10 @@ class Point3D COMPILETIMEEVAL Point3D operator*(int factor) const { return {X * factor, Y * factor, Z * factor};} COMPILETIMEEVAL Point3D& operator*=(int factor) { X *= factor; Y *= factor; Z *= factor; return *this; } - COMPILETIMEEVAL Point3D operator%(const Point3D& that) const { return {X / that.X, Y / that.Y, Z / that.Z};} - COMPILETIMEEVAL Point3D operator%=(const Point3D& that) { X /= that.X; Y /= that.Y; Z /= that.Z; return *this; } - COMPILETIMEEVAL Point3D operator%(int factor) const { return {X / factor, Y / factor, Z / factor};} - COMPILETIMEEVAL Point3D& operator%=(int factor) { X /= factor; Y /= factor; Z /= factor; return *this; } + COMPILETIMEEVAL Point3D operator%(const Point3D& that) const { return {X % that.X, Y % that.Y, Z % that.Z};} + COMPILETIMEEVAL Point3D operator%=(const Point3D& that) { X %= that.X; Y %= that.Y; Z %= that.Z; return *this; } + COMPILETIMEEVAL Point3D operator%(int factor) const { return {X % factor, Y % factor, Z % factor};} + COMPILETIMEEVAL Point3D& operator%=(int factor) { X %= factor; Y %= factor; Z %= factor; return *this; } COMPILETIMEEVAL Point3D operator&(const Point3D& that) const { return {X & that.X, Y & that.Y, Z & that.Z};} COMPILETIMEEVAL Point3D operator&=(const Point3D& that) { X &= that.X; Y &= that.Y; Z &= that.Z; return *this; } diff --git a/YRpp/YRMathVector.h b/YRpp/YRMathVector.h index 451d5695a..2b6e65410 100644 --- a/YRpp/YRMathVector.h +++ b/YRpp/YRMathVector.h @@ -355,7 +355,7 @@ template class Vector4D X -= v.X; Y -= v.Y; Z -= v.Z; - W += v.W; + W -= v.W; return *this; } @@ -399,7 +399,7 @@ template class Vector4D }; } - COMPILETIMEEVAL Vector4D& operator-(const Vector4D& v) const + COMPILETIMEEVAL Vector4D operator-(const Vector4D& v) const { return Vector4D { X - v.X, diff --git a/src/Ext/Team/Body.cpp b/src/Ext/Team/Body.cpp index 4db902d84..286ddefc5 100644 --- a/src/Ext/Team/Body.cpp +++ b/src/Ext/Team/Body.cpp @@ -566,7 +566,7 @@ void FakeTeamClass::_TMission_GatherAtEnemy(ScriptActionNode* nNode, bool arg3) false, false, true, - searchParams, + targetCell, false, false ); @@ -1187,7 +1187,8 @@ void FakeTeamClass::_Coordinate_Attack() { // Handle unit initialization (bringing units to formation zone) if (unitToProcess->Health && (Unsorted::ScenarioInit || !unitToProcess->InLimbo) - && !unitToProcess->IsTeamLeader) + && !unitToProcess->IsTeamLeader + && this->Zone) // Need Zone to be set { int allowedStrayDistance = this->_Get_Stray(); @@ -1303,19 +1304,29 @@ void FakeTeamClass::_CoordinateMove() { { const int strayDistance = this->_Get_Stray(); - if (pUnit->DistanceFrom(this->Zone) <= strayDistance) - { - pUnit->IsTeamLeader = true; - } - else + // Need Zone to be set for uninitiated units to move to it + if (this->Zone) { - if (!pUnit->Destination) + if (pUnit->DistanceFrom(this->Zone) <= strayDistance) { - pUnit->QueueMission(Mission::Move, false); - pUnit->SetTarget(nullptr); - pUnit->SetDestination(this->Zone, true); + pUnit->IsTeamLeader = true; } + else + { + if (!pUnit->Destination) + { + pUnit->QueueMission(Mission::Move, false); + pUnit->SetTarget(nullptr); + pUnit->SetDestination(this->Zone, true); + } + finished = false; + } + } + else + { + // If Zone is not set, can't determine if unit is close enough + // Leave unit as uninitiated and mark as not finished finished = false; } } @@ -1544,8 +1555,9 @@ void FakeTeamClass::_CoordinateMove() { // ============================================================ // All units processed - check if mission complete // ============================================================ - if (found && finished && this->IsMoving) + if (found && finished) { + this->IsMoving = false; this->StepCompleted = true; } } @@ -1556,6 +1568,10 @@ bool FakeTeamClass::_Coordinate_Conscript(FootClass* a2) { return 0; } + // Cannot conscript if Zone is not set + if (!this->Zone) + return 1; + int strayDistance = this->_Get_Stray(); if (a2->DistanceFrom(this->Zone) <= strayDistance) { @@ -1579,6 +1595,10 @@ bool FakeTeamClass::_Coordinate_Conscript(FootClass* a2) { void FakeTeamClass::_Coordinate_Do(ScriptActionNode* pNode, CellStruct unused) { auto const& [miss, value] = *pNode; + // Cannot coordinate without Zone + if (!this->Zone) + return; + for (auto i = this->FirstUnit; i; i = i->NextTeamMember) { if (i->IsAlive) { @@ -1878,7 +1898,9 @@ FootClass* FindClosestInfantry(TeamClass* team, int memberIndex, const CoordStru distance += 12800; // Penalty for wrong group // Check if this is a better candidate - if ((minDistance == -1 || distance < minDistance) && + if (team->OwnerHouse == infantry->Owner && + TeamExtData::IsEligible(team->Type->TaskForce->Entries[memberIndex].Type, infantry->Type) && + (minDistance == -1 || distance < minDistance) && ((FakeTeamClass*)team)->_Can_Add(infantry, &memberIndex, 0)) { closestInfantry = infantry; @@ -1909,7 +1931,9 @@ FootClass* FindClosestAircraft(TeamClass* team, int memberIndex, const CoordStru distance += 12800; // Penalty for wrong group // Check if this is a better candidate - if ((minDistance == -1 || distance < minDistance) && + if (team->OwnerHouse == aircraft->Owner && + TeamExtData::IsEligible(team->Type->TaskForce->Entries[memberIndex].Type, aircraft->Type) && + (minDistance == -1 || distance < minDistance) && ((FakeTeamClass*)team)->_Can_Add(aircraft, &memberIndex, 0)) { closestAircraft = aircraft; @@ -2009,7 +2033,7 @@ bool FakeTeamClass::_Recruit(int memberIndex) { { this->_Add2(cargo, false); - // Check if next cargo item is still attached (bit 2 of TargetBitfield) + // Check if next cargo item is still attached (Foot flag) if ((cargo->AbstractFlags & AbstractFlags::Foot) == AbstractFlags::None) break; @@ -2255,7 +2279,15 @@ bool FakeTeamClass::_Recalculate() { } void StopScript(FakeTeamClass* pTeam) { - if (pTeam->IsFullStrength || pTeam->IsForcedActive) { + // Trigger script advancement when: + // 1. Team reaches full strength (IsFullStrength) + // 2. Team is forced active (IsForcedActive) + // 3. Team has had full strength before (IsHasBeen) - allows under-strength teams to advance + // 4. Team has never been started (!IsHasBeen) AND has at least one member - start fresh teams + const bool hasMembers = pTeam->FirstUnit != nullptr; + const bool shouldStart = pTeam->IsFullStrength || pTeam->IsForcedActive || pTeam->IsHasBeen || (!pTeam->IsHasBeen && hasMembers); + + if (shouldStart) { pTeam->_TeamClass_6EA080(); } } @@ -3478,9 +3510,11 @@ void FakeTeamClass::_TMission_Chrono_prep_for_abwp(ScriptActionNode* nNode, bool this->Type->OnlyTargetHouseEnemy )) { // Fire Chronosphere at team zone - CoordStruct zoneCoord = this->Zone->GetCoords(); - CellStruct zoneCell = CellClass::Coord2Cell(zoneCoord); - house->Fire_SW(chronosphere->Type->ArrayIndex, zoneCell); + if (this->Zone) { + CoordStruct zoneCoord = this->Zone->GetCoords(); + CellStruct zoneCell = CellClass::Coord2Cell(zoneCoord); + house->Fire_SW(chronosphere->Type->ArrayIndex, zoneCell); + } // Fire Chronoshift at target building CoordStruct targetCoord = targetBuilding->GetCoords(); @@ -3602,7 +3636,7 @@ void FakeTeamClass::_TMission_Iron_Curtain_Me(ScriptActionNode* nNode, bool arg3 } } - if (found) + if (found && this->Zone) { auto nCoord = this->Zone->GetCoords(); pOwner->Fire_SW(obtain->Type->ArrayIndex, CellClass::Coord2Cell(nCoord)); @@ -3657,9 +3691,11 @@ void FakeTeamClass::_TMission_Chrono_prep_for_aq(ScriptActionNode* nNode, bool a )) { // Fire Chronosphere at zone - CoordStruct zoneCoord = this->Zone->GetCoords(); - CellStruct zoneCell = CellClass::Coord2Cell(zoneCoord); - house->Fire_SW(chronosphere->Type->ArrayIndex, zoneCell); + if (this->Zone) { + CoordStruct zoneCoord = this->Zone->GetCoords(); + CellStruct zoneCell = CellClass::Coord2Cell(zoneCoord); + house->Fire_SW(chronosphere->Type->ArrayIndex, zoneCell); + } // Fire Chronoshift at threat CoordStruct threatCoord = threat->GetCoords(); @@ -4866,6 +4902,12 @@ bool FakeTeamClass::_CoordinateRegroup() return true; } + // Cannot regroup without Zone + if (!this->Zone) { + this->NeedsReGrouping = 0; + return false; + } + int stray = this->_Get_Stray(); // Process each member in the team