Skip to content
17 changes: 15 additions & 2 deletions libs/common/include/commonDefines.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// 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

#pragma once

#include "RTTR_Assert.h"
#include <type_traits>

/// Call a member function trough an object and a member function pointer
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
Expand All @@ -24,14 +25,26 @@ inline T absDiff(T a, T b)
return (a > b) ? a - b : b - a;
}

/// Same as static_cast<T> but assert that it actually can be casted via dynamic_cast
/// Same as static_cast<T> but assert the correct dynamic type (in debug mode)
/// Use like: checkedCast<Derived*>(basePtr)
template<typename T, typename T_Src>
inline T checkedCast(T_Src* src)
{
static_assert(std::is_pointer_v<T>, "T must be a pointer type");
RTTR_Assert(!src || dynamic_cast<T>(src));
return static_cast<T>(src);
}

/// Same as static_cast<T&> but assert the correct dynamic type (in debug mode)
/// Use like: checkedCast<Derived>(baseRef)
template<typename T, typename T_Src>
inline T& checkedCast(T_Src& src)
{
static_assert(std::is_class_v<T>, "T must be a plain type");
RTTR_Assert(dynamic_cast<T*>(&src));
return static_cast<T&>(src);
Comment thread
Flow86 marked this conversation as resolved.
}

// Fwd decl
namespace boost {
namespace filesystem {
Expand Down
71 changes: 34 additions & 37 deletions libs/s25main/GamePlayer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2005 - 2024 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 @@ -434,7 +434,7 @@ void GamePlayer::AddBuilding(noBuilding* bld, BuildingType bldType)

// Order a worker if needed
const auto& description = BLD_WORK_DESC[bldType];
if(description.job && description.job != Job::Private)
if(description.job && !isSoldierJob(*description.job))
{
AddJobWanted(*description.job, bld);
}
Expand Down Expand Up @@ -620,35 +620,35 @@ void GamePlayer::RoadDestroyed()
}
}

bool GamePlayer::FindCarrierForRoad(RoadSegment* rs) const
bool GamePlayer::FindCarrierForRoad(RoadSegment& rs) const
{
RTTR_Assert(rs->GetF1() != nullptr && rs->GetF2() != nullptr);
RTTR_Assert(rs.GetF1() != nullptr && rs.GetF2() != nullptr);
std::array<unsigned, 2> length;
std::array<nobBaseWarehouse*, 2> best;

// Braucht der ein Boot?
if(rs->GetRoadType() == RoadType::Water)
if(rs.GetRoadType() == RoadType::Water)
{
// dann braucht man Träger UND Boot
best[0] = FindWarehouse(*rs->GetF1(), FW::HasWareAndFigure(GoodType::Boat, Job::Helper, false), false, false,
length.data(), rs);
best[0] = FindWarehouse(*rs.GetF1(), FW::HasWareAndFigure(GoodType::Boat, Job::Helper, false), false, false,
length.data(), &rs);
// 2. Flagge des Weges
best[1] = FindWarehouse(*rs->GetF2(), FW::HasWareAndFigure(GoodType::Boat, Job::Helper, false), false, false,
&length[1], rs);
best[1] = FindWarehouse(*rs.GetF2(), FW::HasWareAndFigure(GoodType::Boat, Job::Helper, false), false, false,
&length[1], &rs);
} else
{
// 1. Flagge des Weges
best[0] = FindWarehouse(*rs->GetF1(), FW::HasFigure(Job::Helper, false), false, false, length.data(), rs);
best[0] = FindWarehouse(*rs.GetF1(), FW::HasFigure(Job::Helper, false), false, false, length.data(), &rs);
// 2. Flagge des Weges
best[1] = FindWarehouse(*rs->GetF2(), FW::HasFigure(Job::Helper, false), false, false, &length[1], rs);
best[1] = FindWarehouse(*rs.GetF2(), FW::HasFigure(Job::Helper, false), false, false, &length[1], &rs);
}

// überhaupt nen Weg gefunden?
// Welche Flagge benutzen?
if(best[0] && (!best[1] || length[0] < length[1]))
best[0]->OrderCarrier(*rs->GetF1(), *rs);
best[0]->OrderCarrier(*rs.GetF1(), rs);
else if(best[1])
best[1]->OrderCarrier(*rs->GetF2(), *rs);
best[1]->OrderCarrier(*rs.GetF2(), rs);
else
return false;
return true;
Expand Down Expand Up @@ -719,7 +719,7 @@ void GamePlayer::FindCarrierForAllRoads()
for(RoadSegment* rs : roads)
{
if(!rs->hasCarrier(0))
FindCarrierForRoad(rs);
FindCarrierForRoad(*rs);
}
}

Expand All @@ -731,8 +731,7 @@ void GamePlayer::FindMaterialForBuildingSites()

void GamePlayer::AddJobWanted(const Job job, noRoadNode* workplace)
{
// Und gleich suchen
if(!FindWarehouseForJob(job, workplace))
if(!FindWarehouseForJob(job, *workplace))
{
JobNeeded jn = {job, workplace};
jobs_wanted.push_back(jn);
Expand Down Expand Up @@ -803,9 +802,9 @@ void GamePlayer::ToolOrderProcessed(Tool tool)
}
}

bool GamePlayer::FindWarehouseForJob(const Job job, noRoadNode* goal) const
bool GamePlayer::FindWarehouseForJob(const Job job, noRoadNode& goal) const
{
nobBaseWarehouse* wh = FindWarehouse(*goal, FW::HasFigure(job, true), false, false);
nobBaseWarehouse* wh = FindWarehouse(goal, FW::HasFigure(job, true), false, false);

if(wh)
{
Expand All @@ -821,7 +820,7 @@ void GamePlayer::FindWarehouseForAllJobs()
{
for(auto it = jobs_wanted.begin(); it != jobs_wanted.end();)
{
if(FindWarehouseForJob(it->job, it->workplace))
if(FindWarehouseForJob(it->job, *it->workplace))
it = jobs_wanted.erase(it);
else
++it;
Expand All @@ -834,7 +833,7 @@ void GamePlayer::FindWarehouseForAllJobs(const Job job)
{
if(it->job == job)
{
if(FindWarehouseForJob(it->job, it->workplace))
if(FindWarehouseForJob(it->job, *it->workplace))
it = jobs_wanted.erase(it);
else
++it;
Expand All @@ -843,10 +842,10 @@ void GamePlayer::FindWarehouseForAllJobs(const Job job)
}
}

Ware* GamePlayer::OrderWare(const GoodType ware, noBaseBuilding* goal)
Ware* GamePlayer::OrderWare(const GoodType ware, noBaseBuilding& goal)
{
/// Gibt es ein Lagerhaus mit dieser Ware?
nobBaseWarehouse* wh = FindWarehouse(*goal, FW::HasMinWares(ware, 1), false, true);
nobBaseWarehouse* wh = FindWarehouse(goal, FW::HasMinWares(ware, 1), false, true);

if(wh)
{
Expand All @@ -857,8 +856,7 @@ Ware* GamePlayer::OrderWare(const GoodType ware, noBaseBuilding* goal)
{
// 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)
|| goal.GetBuildingType() == BuildingType::Woodcutter || goal.GetBuildingType() == BuildingType::Sawmill)
return wh->OrderWare(ware, goal);
else
return nullptr;
Expand All @@ -872,7 +870,7 @@ Ware* GamePlayer::OrderWare(const GoodType ware, noBaseBuilding* goal)
if(curWare->IsLostWare() && curWare->type == ware)
{
// got a lost ware with a road to goal -> find best
unsigned curLength = curWare->CheckNewGoalForLostWare(*goal);
unsigned curLength = curWare->CheckNewGoalForLostWare(goal);
if(curLength < bestLength)
{
bestLength = curLength;
Expand All @@ -889,27 +887,27 @@ Ware* GamePlayer::OrderWare(const GoodType ware, noBaseBuilding* goal)
return nullptr;
}

nofCarrier* GamePlayer::OrderDonkey(RoadSegment* road) const
nofCarrier* GamePlayer::OrderDonkey(RoadSegment& road) const
{
std::array<unsigned, 2> length;
std::array<nobBaseWarehouse*, 2> best;

// 1. Flagge des Weges
best[0] = FindWarehouse(*road->GetF1(), FW::HasFigure(Job::PackDonkey, false), false, false, length.data(), road);
best[0] = FindWarehouse(*road.GetF1(), FW::HasFigure(Job::PackDonkey, false), false, false, length.data(), &road);
// 2. Flagge des Weges
best[1] = FindWarehouse(*road->GetF2(), FW::HasFigure(Job::PackDonkey, false), false, false, &length[1], road);
best[1] = FindWarehouse(*road.GetF2(), FW::HasFigure(Job::PackDonkey, false), false, false, &length[1], &road);

// überhaupt nen Weg gefunden?
// Welche Flagge benutzen?
if(best[0] && (!best[1] || length[0] < length[1]))
return best[0]->OrderDonkey(road, road->GetF1());
return best[0]->OrderDonkey(road, *road.GetF1());
else if(best[1])
return best[1]->OrderDonkey(road, road->GetF2());
return best[1]->OrderDonkey(road, *road.GetF2());
else
return nullptr;
}

RoadSegment* GamePlayer::FindRoadForDonkey(noRoadNode* start, noRoadNode** goal)
RoadSegment* GamePlayer::FindRoadForDonkey(noRoadNode& start, noRoadNode** goal)
{
// Bisher höchste Trägerproduktivität und die entsprechende Straße dazu
unsigned best_productivity = 0;
Expand All @@ -926,9 +924,9 @@ RoadSegment* GamePlayer::FindRoadForDonkey(noRoadNode* start, noRoadNode** goal)
noRoadNode* current_best_goal = nullptr;
// Weg zu beiden Flaggen berechnen
unsigned length1, length2;
bool isF1Reachable = world.FindHumanPathOnRoads(*start, *roadSeg->GetF1(), &length1, nullptr, roadSeg)
bool isF1Reachable = world.FindHumanPathOnRoads(start, *roadSeg->GetF1(), &length1, nullptr, roadSeg)
!= RoadPathDirection::None;
bool isF2Reachable = world.FindHumanPathOnRoads(*start, *roadSeg->GetF2(), &length2, nullptr, roadSeg)
bool isF2Reachable = world.FindHumanPathOnRoads(start, *roadSeg->GetF2(), &length2, nullptr, roadSeg)
!= RoadPathDirection::None;

// Wenn man zu einer Flagge nich kommt, die jeweils andere nehmen
Expand Down Expand Up @@ -1225,7 +1223,7 @@ bool GamePlayer::IsAttackable(const unsigned char playerId) const
return GetPactState(PactType::NonAgressionPact, playerId) != PactState::Accepted;
}

void GamePlayer::OrderTroops(nobMilitary* goal, std::array<unsigned, NUM_SOLDIER_RANKS> counts,
void GamePlayer::OrderTroops(nobMilitary& goal, std::array<unsigned, NUM_SOLDIER_RANKS> counts,
unsigned total_max) const
{
// Solange Lagerhäuser nach Soldaten absuchen, bis entweder keins mehr übrig ist oder alle Soldaten bestellt sind
Expand All @@ -1237,7 +1235,7 @@ void GamePlayer::OrderTroops(nobMilitary* goal, std::array<unsigned, NUM_SOLDIER
for(unsigned i = 0; i < NUM_SOLDIER_RANKS; i++)
desiredRanks[i] = counts[i] > 0;

wh = FindWarehouse(*goal, FW::HasAnyMatchingSoldier(desiredRanks), false, false);
wh = FindWarehouse(goal, FW::HasAnyMatchingSoldier(desiredRanks), false, false);
if(wh)
{
wh->OrderTroops(goal, counts, total_max);
Expand Down Expand Up @@ -1309,9 +1307,8 @@ void GamePlayer::CallFlagWorker(const MapPoint pt, const Job job)
/// Find wh with given job type (e.g. geologist, scout, ...)
nobBaseWarehouse* wh = FindWarehouse(*flag, FW::HasFigure(job, true), false, false);

/// Wenns eins gibt, dann rufen
if(wh)
wh->OrderJob(job, flag, true);
wh->OrderJob(job, *flag, true);
}

bool GamePlayer::IsFlagWorker(const nofFlagWorker* flagworker)
Expand Down
14 changes: 7 additions & 7 deletions libs/s25main/GamePlayer.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2005 - 2024 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 @@ -110,7 +110,7 @@ class GamePlayer : public GamePlayerInfo
/// (Unbesetzte) Straße aus der Liste entfernen
void DeleteRoad(RoadSegment* rs);
/// Sucht einen Träger für die Straße und ruft ggf den Träger aus dem jeweiligen nächsten Lagerhaus
bool FindCarrierForRoad(RoadSegment* rs) const;
bool FindCarrierForRoad(RoadSegment& rs) const;
/// 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
Expand Down Expand Up @@ -143,12 +143,12 @@ class GamePlayer : public GamePlayerInfo
/// Versucht für alle verlorenen Waren ohne Ziel Lagerhaus zu finden
void FindClientForLostWares();
/// Bestellt eine Ware und gibt sie zurück, falls es eine gibt, ansonsten 0
Ware* OrderWare(GoodType ware, noBaseBuilding* goal);
Ware* OrderWare(GoodType ware, noBaseBuilding& goal);
/// Versucht einen Esel zu bestellen, gibt 0 zurück, falls keinen gefunden
nofCarrier* OrderDonkey(RoadSegment* road) const;
nofCarrier* OrderDonkey(RoadSegment& road) const;
/// Versucht für einen Esel eine Straße zu finden, in goal wird die Zielflagge zurückgegeben,
/// sofern eine Straße gefunden wurde, ansonsten ist das ein Lagerhaus oder 0, falls auch das nich gefunden wurde
RoadSegment* FindRoadForDonkey(noRoadNode* start, noRoadNode** goal);
RoadSegment* FindRoadForDonkey(noRoadNode& start, noRoadNode** goal);

/// Sucht für eine (neuproduzierte) Ware einen Abnehmer (wenns keinen gibt, wird ein Lagerhaus gesucht, wenn
/// es auch dorthin keinen Weg gibt, wird 0 zurückgegeben
Expand Down Expand Up @@ -202,7 +202,7 @@ class GamePlayer : public GamePlayerInfo
/// Are these players allied? (-> Teamview, attack support, ...)
bool IsAlly(unsigned char playerId) const;
/// Order troops of each rank according to `counts` without exceeding `total_max` in total
void OrderTroops(nobMilitary* goal, std::array<unsigned, NUM_SOLDIER_RANKS> counts, unsigned total_max) const;
void OrderTroops(nobMilitary& goal, std::array<unsigned, NUM_SOLDIER_RANKS> counts, unsigned total_max) const;
/// Prüft die Besatzung von allen Militärgebäuden und reguliert entsprechend (bei Veränderung der
/// Militäreinstellungen)
void RegulateAllTroops();
Expand Down Expand Up @@ -427,7 +427,7 @@ class GamePlayer : public GamePlayerInfo
/// Called after a pact was changed(added/removed) in both players
void PactChanged(PactType pt);
// Sucht Weg für Job zu entsprechenden noRoadNode
bool FindWarehouseForJob(Job job, noRoadNode* goal) const;
bool FindWarehouseForJob(Job job, noRoadNode& goal) const;
/// Prüft, ob der Spieler besiegt wurde
void TestDefeat();
nobHQ* GetHQ() const;
Expand Down
10 changes: 5 additions & 5 deletions libs/s25main/RoadSegment.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 @@ -181,7 +181,7 @@ void RoadSegment::SplitRoad(noFlag* splitflag)
else if(i == 0)
// If road was unoccupied before then add 2nd part to the unoccupied roads
// (1st is already included)
world->GetPlayer(f1->GetPlayer()).FindCarrierForRoad(second);
world->GetPlayer(f1->GetPlayer()).FindCarrierForRoad(*second);
}
}

Expand Down Expand Up @@ -320,7 +320,7 @@ void RoadSegment::TryGetDonkey()
{
// Nur rufen, falls es eine Eselstraße ist, noch kein Esel da ist, aber schon ein Träger da ist
if(NeedDonkey())
carriers_[1] = world->GetPlayer(f1->GetPlayer()).OrderDonkey(this);
carriers_[1] = world->GetPlayer(f1->GetPlayer()).OrderDonkey(*this);
}

/**
Expand All @@ -333,11 +333,11 @@ void RoadSegment::CarrierAbrogated(nofCarrier* carrier)
{
// Straße wieder unbesetzt, bzw. nur noch Esel
this->carriers_[0] = nullptr;
world->GetPlayer(f1->GetPlayer()).FindCarrierForRoad(this);
world->GetPlayer(f1->GetPlayer()).FindCarrierForRoad(*this);
} else
{
// Kein Esel mehr da, versuchen, neuen zu bestellen
this->carriers_[1] = world->GetPlayer(f1->GetPlayer()).OrderDonkey(this);
this->carriers_[1] = world->GetPlayer(f1->GetPlayer()).OrderDonkey(*this);
}
}
/**
Expand Down
23 changes: 10 additions & 13 deletions libs/s25main/Ware.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 @@ -164,9 +164,8 @@ void Ware::GoalDestroyed()
RTTR_Assert(location);
RTTR_Assert(location->GetPlayer() < MAX_PLAYERS);

// Wird sie gerade aus einem Lagerhaus rausgetragen?
if(location->GetGOT() == GO_Type::NobStorehouse || location->GetGOT() == GO_Type::NobHarborbuilding
|| location->GetGOT() == GO_Type::NobHq)
// Currently carried out of a warehouse?
if(nobBaseWarehouse::isStorehouseGOT(location->GetGOT()))
{
if(location != goal)
{
Expand Down Expand Up @@ -199,11 +198,10 @@ void Ware::GoalDestroyed()
if(goal != location)
{
// find a warehouse for us (if we are entering a warehouse already set this as new goal (should only
// happen if its a harbor for shipping as the building wasnt our goal))
if(location->GetGOT() == GO_Type::NobStorehouse || location->GetGOT() == GO_Type::NobHarborbuilding
|| location->GetGOT()
== GO_Type::NobHq) // currently carried into a warehouse? -> add ware (pathfinding
// will not return this wh because of path lengths 0)
// happen if its a harbor for shipping as the building wasn't our goal))
if(nobBaseWarehouse::isStorehouseGOT(
location->GetGOT())) // currently carried into a warehouse? -> add ware (pathfinding
// will not return this wh because of path lengths 0)
{
if(location->GetGOT() != GO_Type::NobHarborbuilding)
LOG.write("WARNING: Ware::GoalDestroyed() -- ware is currently being carried into warehouse or "
Expand Down Expand Up @@ -364,14 +362,13 @@ Ware::RouteParams Ware::CalcPathToGoal(const noBaseBuilding& newgoal) const
}

/// this assumes that the ware is at a flag (todo: handle carried wares) and that there is a valid path to the goal
void Ware::SetNewGoalForLostWare(noBaseBuilding* newgoal)
void Ware::SetNewGoalForLostWare(noBaseBuilding& newgoal)
{
RTTR_Assert(newgoal);
const auto newDir = CalcPathToGoal(*newgoal).dir;
const auto newDir = CalcPathToGoal(newgoal).dir;
if(newDir != RoadPathDirection::None) // there is a valid path to the goal? -> ordered!
{
next_dir = newDir;
SetGoal(newgoal);
SetGoal(&newgoal);
CallCarrier();
}
}
Expand Down
Loading
Loading