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
17 changes: 7 additions & 10 deletions libs/s25main/GamePlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,10 @@ void GamePlayer::Surrender()
if(isDefeated)
return;

const auto shipsCopy = ships; // copy to avoid modification during iteration
for(auto* ship : shipsCopy)
ship->Sink();

isDefeated = true;

// GUI Bescheid sagen
Expand Down Expand Up @@ -1897,17 +1901,10 @@ bool GamePlayer::OrderShip(nobHarborBuilding& hb)
return (false);
}

/// Meldet das Schiff wieder ab
void GamePlayer::RemoveShip(noShip* ship)
void GamePlayer::RemoveShip(noShip& ship)
{
for(unsigned i = 0; i < ships.size(); ++i)
{
if(ships[i] == ship)
{
ships.erase(ships.begin() + i);
return;
}
}
RTTR_Assert(helpers::contains(ships, &ship));
helpers::erase(ships, &ship);
}

/// Versucht, für ein untätiges Schiff eine Arbeit zu suchen
Expand Down
4 changes: 2 additions & 2 deletions libs/s25main/GamePlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class GamePlayer : public GamePlayerInfo
/// Returns true if the given wh does still exist and hence the ptr is valid
bool IsWarehouseValid(nobBaseWarehouse* wh) const;
/// Gibt erstes Lagerhaus zurück
nobBaseWarehouse* GetFirstWH()
nobBaseWarehouse* GetFirstWH() const
{
return buildings.GetStorehouses().empty() ? nullptr : buildings.GetStorehouses().front();
}
Expand Down Expand Up @@ -234,7 +234,7 @@ class GamePlayer : public GamePlayerInfo
/// Registriert ein Schiff beim Einwohnermeldeamt
void RegisterShip(noShip& ship);
/// Meldet das Schiff wieder ab
void RemoveShip(noShip* ship);
void RemoveShip(noShip& ship);
/// Versucht, für ein untätiges Schiff eine Arbeit zu suchen
void GetJobForShip(noShip& ship);
/// Schiff für Hafen bestellen. Wenn ein Schiff kommt, true.
Expand Down
6 changes: 1 addition & 5 deletions libs/s25main/buildings/nobHarborBuilding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,7 @@ void nobHarborBuilding::StopExplorationExpedition()
/// Bestellt die zusätzlichen erforderlichen Waren für eine Expedition
void nobHarborBuilding::OrderExpeditionWares()
{
RTTR_Assert(!IsBeingDestroyedNow()); // Wares should already be canceled!
if(this->IsBeingDestroyedNow()) // don't order new stuff if we are about to be destroyed
if(IsBeingDestroyedNow()) // don't order new stuff if we are about to be destroyed
return;

if(!expedition.active) // expedition no longer active?
Expand Down Expand Up @@ -496,11 +495,8 @@ void nobHarborBuilding::OrderExpeditionWares()
orderware_ev = GetEvMgr().AddEvent(this, 210, 10);
}

/// Eine bestellte Ware konnte doch nicht kommen
void nobHarborBuilding::WareLost(Ware& ware)
{
RTTR_Assert(!IsBeingDestroyedNow());
// ggf. neue Waren für Expedition bestellen
if(expedition.active && (ware.type == GoodType::Boards || ware.type == GoodType::Stones))
OrderExpeditionWares();
nobBaseWarehouse::WareLost(ware);
Expand Down
26 changes: 24 additions & 2 deletions libs/s25main/nodeObjs/noShip.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

Expand Down Expand Up @@ -104,7 +104,7 @@ void noShip::Destroy()
RTTR_Assert(wares.empty());
world->GetNotifications().publish(ShipNote(ShipNote::Destroyed, ownerId_, pos));
// Schiff wieder abmelden
world->GetPlayer(ownerId_).RemoveShip(this);
world->GetPlayer(ownerId_).RemoveShip(*this);
}

void noShip::Draw(DrawPoint drawPt)
Expand Down Expand Up @@ -1230,3 +1230,25 @@ void noShip::NewHarborBuilt(nobHarborBuilding* hb)
break;
}
}

void noShip::Sink()
{
for(auto& figure : figures)
{
figure->Abrogate();
figure->SetGoalTonullptr();
figure->RemoveFromInventory();
}
figures.clear();

for(auto& ware : wares)
{
ware->WareLost(ownerId_);
ware->Destroy();
}
wares.clear();

GetEvMgr().RemoveEvent(current_ev);
GetEvMgr().AddToKillList(world->RemoveFigure(pos, *this));
world->RecalcVisibilitiesAroundPoint(pos, GetVisualRange(), ownerId_, nullptr);
}
5 changes: 4 additions & 1 deletion libs/s25main/nodeObjs/noShip.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

Expand Down Expand Up @@ -223,4 +223,7 @@ class noShip : public noMovable
void HarborDestroyed(nobHarborBuilding* hb);
/// Sagt dem Schiff, dass ein neuer Hafen erbaut wurde
void NewHarborBuilt(nobHarborBuilding* hb);

/// Destroy the ship immediately
void Sink();
};
71 changes: 70 additions & 1 deletion tests/s25Main/integration/testSeafaring.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

Expand Down Expand Up @@ -718,4 +718,73 @@ BOOST_FIXTURE_TEST_CASE(AddWareWithUnreachableGoalToHarbor, ShipAndHarborsReadyF
BOOST_TEST(MockWare::destroyed);
}

BOOST_FIXTURE_TEST_CASE(SinkShipLoosesCargo, ShipAndHarborsReadyFixture<1>)
{
const GamePlayer& player = world.GetPlayer(curPlayer);
noShip& ship = *player.GetShipByID(0);

const auto& harbors = player.GetBuildingRegister().GetHarbors();
BOOST_TEST_REQUIRE(harbors.size() >= 2u);
nobHarborBuilding& harbor1 = *harbors.front();
nobHarborBuilding& harbor2 = **(++harbors.begin());

// Transport something
BOOST_TEST_REQUIRE(harbor1.OrderJob(Job::Woodcutter, harbor2, false));
BOOST_TEST_REQUIRE(harbor1.OrderWare(GoodType::Wood, harbor2));
BOOST_TEST_REQUIRE(harbor1.OrderWare(GoodType::Wood, harbor2));

RTTR_EXEC_TILL(90, ship.IsLoading());
RTTR_EXEC_TILL(200, ship.IsMoving());
BOOST_TEST(ship.GetWares().size() == 2u);
BOOST_TEST(ship.GetFigures().size() == 1u);

const auto shipPos = ship.GetPos();
BOOST_TEST_REQUIRE(player.GetNumShips() == 1u);
BOOST_TEST_REQUIRE(world.GetFigures(shipPos).size() == 1u);
BOOST_TEST_REQUIRE(dynamic_cast<noShip*>(&world.GetFigures(shipPos).front()));

const auto numWood = player.GetInventory()[GoodType::Wood];
const auto numWoodcutters = player.GetInventory()[Job::Woodcutter];
ship.Sink();
RTTR_SKIP_GFS(1); // Handle delayed destruction
BOOST_TEST(player.GetNumShips() == 0u);
BOOST_TEST(world.GetFigures(shipPos).size() == 0u);
BOOST_TEST(player.GetInventory()[GoodType::Wood] == numWood - 2);
BOOST_TEST(player.GetInventory()[Job::Woodcutter] == numWoodcutters - 1);
}

BOOST_FIXTURE_TEST_CASE(RemoveShipsOnDefeat, ShipAndHarborsReadyFixture<2>)
{
const GamePlayer& player = world.GetPlayer(curPlayer);
const noShip& ship = *player.GetShipByID(0);

const auto& harbors = player.GetBuildingRegister().GetHarbors();
BOOST_TEST_REQUIRE(harbors.size() >= 2u);
nobHarborBuilding& harbor1 = *harbors.front();
nobHarborBuilding& harbor2 = **(++harbors.begin());

// Transport something
BOOST_TEST_REQUIRE(harbor1.OrderJob(Job::Woodcutter, harbor2, false));
BOOST_TEST_REQUIRE(harbor1.OrderWare(GoodType::Wood, harbor2));

RTTR_EXEC_TILL(90, ship.IsLoading());
RTTR_EXEC_TILL(200, ship.IsMoving());
const auto numWood = ship.GetWares().size();
const auto numWoodcutters = ship.GetFigures().size();
BOOST_TEST(numWood == 1u);
BOOST_TEST(numWoodcutters == 1u);

const auto shipPos = ship.GetPos();
BOOST_TEST_REQUIRE(player.GetNumShips() == 1u);
BOOST_TEST_REQUIRE(world.GetFigures(shipPos).size() == 1u);
BOOST_TEST_REQUIRE(dynamic_cast<noShip*>(&world.GetFigures(shipPos).front()));
const auto warehouses = player.GetBuildingRegister().GetStorehouses(); // Copy for iteration
for(const auto* bld : warehouses)
world.DestroyBuilding(bld->GetPos(), curPlayer);
RTTR_SKIP_GFS(1); // Handle delayed destruction
BOOST_TEST(player.IsDefeated());
BOOST_TEST(player.GetNumShips() == 0u);
BOOST_TEST(world.GetFigures(shipPos).size() == 0u);
}

BOOST_AUTO_TEST_SUITE_END()
22 changes: 9 additions & 13 deletions tests/s25Main/worldFixtures/TestEventManager.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

Expand All @@ -9,22 +9,18 @@ unsigned TestEventManager::ExecuteNextEvent(unsigned maxGF)
{
if(GetCurrentGF() >= maxGF)
return 0;
if(events.empty())
unsigned numGFs;
if(events.empty() || events.begin()->first > maxGF)
{
unsigned numGFs = maxGF - GetCurrentGF();
numGFs = maxGF - GetCurrentGF();
currentGF = maxGF;
return numGFs;
}
auto itEvents = events.begin();
if(itEvents->first > maxGF)
} else
{
unsigned numGFs = maxGF - GetCurrentGF();
currentGF = maxGF;
return numGFs;
auto itEvents = events.begin();
numGFs = itEvents->first - GetCurrentGF();
currentGF = itEvents->first;
ExecuteEvents(itEvents);
}
unsigned numGFs = itEvents->first - GetCurrentGF();
currentGF = itEvents->first;
ExecuteEvents(itEvents);
DestroyCurrentObjects();
return numGFs;
}
Expand Down