Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions libs/s25main/GamePlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,12 @@ void GamePlayer::FindWarehouseForAllJobs(const Job job)
}
}

static bool IsWareFineWithEmergencyProtocol(GoodType goodType, const noBaseBuilding& goal)
{
return (goodType != GoodType::Boards && goodType != GoodType::Stones)
|| goal.GetBuildingType() == BuildingType::Woodcutter || goal.GetBuildingType() == BuildingType::Sawmill;
}

Ware* GamePlayer::OrderWare(const GoodType ware, noBaseBuilding& goal)
{
/// Gibt es ein Lagerhaus mit dieser Ware?
Expand All @@ -902,8 +908,7 @@ Ware* GamePlayer::OrderWare(const GoodType ware, noBaseBuilding& goal)
else
{
// Wenn Notfallprogramm aktiv nur an Holzfäller und Sägewerke Bretter/Steine liefern
if((ware != GoodType::Boards && ware != GoodType::Stones)
|| goal.GetBuildingType() == BuildingType::Woodcutter || goal.GetBuildingType() == BuildingType::Sawmill)
if(IsWareFineWithEmergencyProtocol(ware, goal))
return wh->OrderWare(ware, goal);
else
return nullptr;
Expand Down Expand Up @@ -2089,6 +2094,24 @@ bool GamePlayer::FindHarborForUnloading(noShip* ship, const MapPoint start, Harb
return false;
}

void GamePlayer::CancelWaresForEmergencyProtocol()
{
for(auto it = ware_list.begin(); it != ware_list.end();)
{
Ware* ware = *it;
// checks if this ware is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incomplete comment?

if(ware->IsWaitingInWarehouse() && ware->GetGoal()
&& !IsWareFineWithEmergencyProtocol(ware->type, *ware->GetGoal()))
{
ware->NotifyGoalAboutLostWare();
static_cast<nobBaseWarehouse*>(ware->GetLocation())->CancelWare(ware);
it = ware_list.erase(it);
continue;
}
it++;
}
}

void GamePlayer::TestForEmergencyProgramm()
{
// we are already defeated, do not even think about an emergency program - it's too late :-(
Expand Down Expand Up @@ -2118,6 +2141,9 @@ void GamePlayer::TestForEmergencyProgramm()
emergency = true;
SendPostMessage(std::make_unique<PostMsg>(
world.GetEvMgr().GetCurrentGF(), _("The emergency program has been activated."), PostCategory::Economy));

// Handle wares already ordered
CancelWaresForEmergencyProtocol();
}
} else
{
Expand Down
2 changes: 2 additions & 0 deletions libs/s25main/GamePlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ class GamePlayer : public GamePlayerInfo
const Statistic& GetStatistic(StatisticTime time) const { return statistic[time]; };
unsigned GetStatisticCurrentValue(StatisticType idx) const { return statisticCurrentData[idx]; }

// remove all wares that are already scheduled but ignoring emergency protocol

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what "ignoring ..." means here. Maybe:

Suggested change
// remove all wares that are already scheduled but ignoring emergency protocol
// Stop wares restricted in emergency mode that are waiting in warehouse to be transported already

void CancelWaresForEmergencyProtocol();
// Testet ob Notfallprogramm aktiviert werden muss und tut dies dann
void TestForEmergencyProgramm();
bool hasEmergency() const { return emergency; }
Expand Down
87 changes: 87 additions & 0 deletions tests/s25Main/integration/testEmergencyProtocol.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

#include "EconomyModeHandler.h"
#include "EventManager.h"
#include "GamePlayer.h"
#include "Savegame.h"
#include "SerializedGameData.h"
#include "addons/AddonEconomyModeGameLength.h"
#include "factories/BuildingFactory.h"
#include "worldFixtures/MockLocalGameState.h"
#include "worldFixtures/WorldFixture.h"
#include "worldFixtures/WorldWithGCExecution.h"
#include "worldFixtures/initGameRNG.hpp"
#include "gameTypes/GO_Type.h"
#include <boost/test/unit_test.hpp>
#include <buildings/nobHQ.h>
#include <buildings/nobUsual.h>

struct EmergencyFixture : public WorldFixture<CreateEmptyWorld, 1>
{
nobHQ* HQ = world.GetPlayer(0).GetHQ();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nobHQ* HQ = world.GetPlayer(0).GetHQ();
nobHQ* hq = world.GetPlayer(0).GetHQ();

EmergencyFixture()
{
HQ->AddToInventory(HQ->getStartInventory(StartWares::VLow), true);
MapPoint pos;

pos = world.GetPlayer(0).GetHQPos() + MapPoint(3, 0);
world.SetBuildingSite(BuildingType::Farm, pos, 0);
world.BuildRoad(0, false, world.GetNeighbour(pos, Direction::SouthEast),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe derive from WorldWithGCExecution and use BuildRoadForBlds which checks the the roads are built. Especially in the tests it is otherwise not fully clear that the building site is actually connected. Here it is reasonably clear, but for GetHQPos() + MapPoint(-1, 2) it is a bit trickier

std::vector<Direction>(3, Direction::West));

pos = world.GetPlayer(0).GetHQPos() + MapPoint(-3, 0);
world.SetBuildingSite(BuildingType::Farm, pos, 0);
world.BuildRoad(0, false, world.GetNeighbour(pos, Direction::SouthEast),
std::vector<Direction>(3, Direction::East));

// wait until emergency protocol should be activated
RTTR_EXEC_TILL(500, HQ->GetInventory()[GoodType::Boards] == 10);

// activate program (with 10 boards it should trigger)
world.GetPlayer(0).TestForEmergencyProgramm();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we test that this is done automatically? I.e. shouldn't the above activate it? Or at least in the next GF


// wait for some more ticks to give time if not working to deliver more boards
RTTR_SKIP_GFS(200);
// check boards are still fine and protocol working
BOOST_TEST_CHECK(world.GetPlayer(0).GetHQ()->GetInventory()[GoodType::Boards] == 10);
Comment on lines +45 to +48

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// wait for some more ticks to give time if not working to deliver more boards
RTTR_SKIP_GFS(200);
// check boards are still fine and protocol working
BOOST_TEST_CHECK(world.GetPlayer(0).GetHQ()->GetInventory()[GoodType::Boards] == 10);
// No more boards are carried out to the farms due to emergency protocol
RTTR_SKIP_GFS(200);
BOOST_TEST_CHECK(hq->GetInventory()[GoodType::Boards] == 10);

}
};

BOOST_FIXTURE_TEST_CASE(EmergencyProtoclActiveWoodcutterAndSawmillCanBuild, EmergencyFixture)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo here and below

Suggested change
BOOST_FIXTURE_TEST_CASE(EmergencyProtoclActiveWoodcutterAndSawmillCanBuild, EmergencyFixture)
BOOST_FIXTURE_TEST_CASE(EmergencyProtocolActiveWoodcutterAndSawmillCanBuild, EmergencyFixture)

{
initGameRNG();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to fixture


MapPoint posWoodcutter = world.GetPlayer(0).GetHQPos() + MapPoint(-1, 2);
world.SetBuildingSite(BuildingType::Woodcutter, posWoodcutter, 0);
world.BuildRoad(0, false, world.GetNeighbour(posWoodcutter, Direction::SouthEast),
std::vector<Direction>(2, Direction::NorthEast));

MapPoint posSawmill = world.GetPlayer(0).GetHQPos() + MapPoint(-2, 4);
world.SetBuildingSite(BuildingType::Sawmill, posSawmill, 0);
world.BuildRoad(0, false, world.GetNeighbour(posSawmill, Direction::SouthEast),
std::vector<Direction>(2, Direction::NorthEast));

// check if inventory boards are given out
RTTR_EXEC_TILL(200, HQ->GetInventory()[GoodType::Boards] < 10);

// check if building where found

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// check if building where found
// check that buildings are built

RTTR_EXEC_TILL(2000, world.GetNO(posWoodcutter)->GetType() == NodalObjectType::Building);
RTTR_EXEC_TILL(2000, world.GetNO(posSawmill)->GetType() == NodalObjectType::Building);
}

BOOST_FIXTURE_TEST_CASE(EmergencyProtoclActiveOtherBuldingsnotBuild, EmergencyFixture)
{
initGameRNG();

MapPoint pos = world.GetPlayer(0).GetHQPos() + MapPoint(-1, 2);
world.SetBuildingSite(BuildingType::Watchtower, pos, 0);
world.BuildRoad(0, false, world.GetNeighbour(pos, Direction::SouthEast),
std::vector<Direction>(2, Direction::NorthEast));

// wait for some more ticks to give time if not working to deliver more boards
RTTR_SKIP_GFS(500);
// check boards are still fine and protocol working
BOOST_TEST_CHECK(world.GetPlayer(0).GetHQ()->GetInventory()[GoodType::Boards] == 10);
Comment on lines +83 to +86

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// wait for some more ticks to give time if not working to deliver more boards
RTTR_SKIP_GFS(500);
// check boards are still fine and protocol working
BOOST_TEST_CHECK(world.GetPlayer(0).GetHQ()->GetInventory()[GoodType::Boards] == 10);
// No boards are carried out to the farms or watchtower due to emergency protocol
RTTR_SKIP_GFS(500);
BOOST_TEST_CHECK(hq->GetInventory()[GoodType::Boards] == 10);

}
Loading