Skip to content

Commit b812545

Browse files
authored
Merge branch 'master' into sidequest/ignore-isolated-fish-resources
2 parents 3b1f698 + 4ec1f62 commit b812545

2 files changed

Lines changed: 92 additions & 21 deletions

File tree

libs/s25main/buildings/nobMilitary.cpp

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,20 @@ void nobMilitary::RegulateTroops()
508508

509509
is_regulating_troops = true;
510510

511+
GamePlayer& owner = world->GetPlayer(player);
512+
std::array<int, NUM_SOLDIER_RANKS> hasReturnWarehouseByRank;
513+
hasReturnWarehouseByRank.fill(-1);
514+
auto canReturnHome = [&](const nofPassiveSoldier& soldier) {
515+
const unsigned rank = soldier.GetRank();
516+
int& hasReturnWarehouse = hasReturnWarehouseByRank[rank];
517+
if(hasReturnWarehouse < 0)
518+
{
519+
hasReturnWarehouse =
520+
owner.FindWarehouse(*this, FW::AcceptsFigure(soldier.GetJobType()), true, false) ? 1 : 0;
521+
}
522+
return hasReturnWarehouse != 0;
523+
};
524+
511525
// This only has an effect if the military control addon is in use and the troop limits have been lowered.
512526
std::array<unsigned, NUM_SOLDIER_RANKS> counts = GetTotalSoldiersByRank();
513527
std::array<unsigned, NUM_SOLDIER_RANKS> lack;
@@ -521,7 +535,7 @@ void nobMilitary::RegulateTroops()
521535
std::vector<nofPassiveSoldier*> notNeededSoldiers;
522536
for(auto it = ordered_troops.begin(); excess && it != ordered_troops.end();)
523537
{
524-
if((*it)->GetRank() == rank)
538+
if((*it)->GetRank() == rank && canReturnHome(**it))
525539
{
526540
notNeededSoldiers.push_back(*it);
527541
it = ordered_troops.erase(it);
@@ -538,12 +552,11 @@ void nobMilitary::RegulateTroops()
538552
// This bit is for ordering troops later
539553
lack[rank] = troop_limits[rank] - counts[rank];
540554
}
541-
if(excess > 0
542-
&& world->GetPlayer(player).FindWarehouse(*this, FW::AcceptsFigure(SOLDIER_JOBS[rank]), true, false))
555+
if(excess > 0)
543556
{
544557
for(auto it = troops.begin(); excess && it != troops.end() && troops.size() > 1;)
545558
{
546-
if((*it)->GetRank() == rank)
559+
if((*it)->GetRank() == rank && canReturnHome(**it))
547560
{
548561
(*it)->LeaveBuilding();
549562
AddLeavingFigure(std::move(*it));
@@ -565,22 +578,35 @@ void nobMilitary::RegulateTroops()
565578
// Zuerst die bestellten Soldaten wegschicken
566579
// Weak ones first
567580
std::vector<nofPassiveSoldier*> notNeededSoldiers;
568-
GamePlayer& owner = world->GetPlayer(player);
569581
if(owner.GetMilitarySetting(1) > MILITARY_SETTINGS_SCALE[1] / 2)
570582
{
571-
for(auto it = ordered_troops.begin(); diff && !ordered_troops.empty(); ++diff)
583+
for(auto it = ordered_troops.begin(); diff && it != ordered_troops.end();)
572584
{
573-
notNeededSoldiers.push_back(*it);
574-
it = ordered_troops.erase(it);
585+
if(canReturnHome(**it))
586+
{
587+
notNeededSoldiers.push_back(*it);
588+
it = ordered_troops.erase(it);
589+
++diff;
590+
} else
591+
{
592+
++it;
593+
}
575594
}
576595
}
577596
// Strong ones first
578597
else
579598
{
580-
for(auto it = ordered_troops.rbegin(); diff && !ordered_troops.empty(); ++diff)
599+
for(auto it = ordered_troops.rbegin(); diff && it != ordered_troops.rend();)
581600
{
582-
notNeededSoldiers.push_back(*it);
583-
it = helpers::erase_reverse(ordered_troops, it);
601+
if(canReturnHome(**it))
602+
{
603+
notNeededSoldiers.push_back(*it);
604+
it = helpers::erase_reverse(ordered_troops, it);
605+
++diff;
606+
} else
607+
{
608+
++it;
609+
}
584610
}
585611
}
586612

@@ -590,32 +616,41 @@ void nobMilitary::RegulateTroops()
590616
notNeededSoldier->NotNeeded();
591617
}
592618

593-
// Nur rausschicken, wenn es einen Weg zu einem Lagerhaus gibt!
594-
if(owner.FindWarehouse(*this, FW::NoCondition(), true, false))
619+
// Dann den Rest (einer muss immer noch drinbleiben!)
620+
// erst die schwachen Soldaten raus
621+
if(owner.GetMilitarySetting(1) > MILITARY_SETTINGS_SCALE[1] / 2)
595622
{
596-
// Dann den Rest (einer muss immer noch drinbleiben!)
597-
// erst die schwachen Soldaten raus
598-
if(owner.GetMilitarySetting(1) > MILITARY_SETTINGS_SCALE[1] / 2)
623+
for(auto it = troops.begin(); diff && it != troops.end() && troops.size() > 1;)
599624
{
600-
for(auto it = troops.begin(); diff && troops.size() > 1; ++diff)
625+
if(canReturnHome(**it))
601626
{
602627
(*it)->LeaveBuilding();
603628
AddLeavingFigure(std::move(*it));
604629
it = troops.erase(it);
630+
++diff;
631+
} else
632+
{
633+
++it;
605634
}
606635
}
607-
// erst die starken Soldaten raus
608-
else
636+
}
637+
// erst die starken Soldaten raus
638+
else
639+
{
640+
for(auto it = troops.rbegin(); diff && it != troops.rend() && troops.size() > 1;)
609641
{
610-
for(auto it = troops.rbegin(); diff && troops.size() > 1; ++diff)
642+
if(canReturnHome(**it))
611643
{
612644
(*it)->LeaveBuilding();
613645
AddLeavingFigure(std::move(*it));
614646
it = helpers::erase_reverse(troops, it);
647+
++diff;
648+
} else
649+
{
650+
++it;
615651
}
616652
}
617653
}
618-
619654
} else if(diff > 0)
620655
{
621656
// Zu wenig Truppen

tests/s25Main/integration/testAttacking.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,42 @@ BOOST_FIXTURE_TEST_CASE(ArmoredSoldierLosesArmorInFight, AttackFixture<>)
543543
BOOST_TEST(milBld1->GetDefender()->GetHitpoints() == HITPOINTS[milBld1->GetDefender()->GetRank()]);
544544
}
545545

546+
BOOST_FIXTURE_TEST_CASE(TroopLimitKeepsOrderedRestrictedSoldier, AttackFixture<>)
547+
{
548+
MilitarySettings milSettings = MILITARY_SETTINGS_SCALE;
549+
milSettings[4 + rttr::enum_cast(FrontierDistance::Far)] = 0;
550+
this->ChangeMilitary(milSettings);
551+
552+
auto* hq = world.GetSpecObj<nobBaseWarehouse>(hqPos[0]);
553+
BOOST_TEST_REQUIRE(hq);
554+
555+
const Job soldierJob = Job::Private;
556+
const unsigned soldierRank = getSoldierRank(soldierJob);
557+
hq->AddToInventory(PeopleCounts::make(soldierJob, 2), true);
558+
const unsigned hqSoldiersBefore = hq->GetNumRealFigures(soldierJob);
559+
BOOST_TEST_REQUIRE(hqSoldiersBefore > 0u);
560+
561+
BuildRoadForBlds(milBld0Pos, hqPos[0]);
562+
milBld0->RegulateTroops();
563+
564+
BOOST_TEST_REQUIRE(milBld0->GetNumTroops() == 0u);
565+
BOOST_TEST_REQUIRE(hq->GetLeavingFigures().size() == 1u);
566+
BOOST_TEST_REQUIRE(hq->GetNumRealFigures(soldierJob) + 1 == hqSoldiersBefore);
567+
568+
this->SetInventorySetting(hqPos[0], soldierJob, EInventorySetting::Stop);
569+
milBld0->SetTroopLimit(soldierRank, 0);
570+
571+
BOOST_TEST_REQUIRE(milBld0->GetNumTroops() == 0u);
572+
BOOST_TEST_REQUIRE(hq->GetLeavingFigures().size() == 1u);
573+
BOOST_TEST_REQUIRE(hq->GetNumRealFigures(soldierJob) + 1 == hqSoldiersBefore);
574+
575+
RTTR_EXEC_TILL(500, milBld0->GetNumTroops() == 1u);
576+
577+
BOOST_TEST_REQUIRE(milBld0->GetNumTroops() == 1u);
578+
BOOST_TEST_REQUIRE(hq->GetNumRealFigures(soldierJob) + 1 == hqSoldiersBefore);
579+
BOOST_TEST_REQUIRE(milBld0->GetLeavingFigures().empty());
580+
}
581+
546582
BOOST_FIXTURE_TEST_CASE(ConquerBldCoinAddonEnable, AttackFixture<>)
547583
{
548584
this->ggs.setSelection(AddonId::COINS_CAPTURED_BLD, 1); // addon is active on second run

0 commit comments

Comments
 (0)