Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge for wine addon #1

Merged
merged 12 commits into from
Aug 4, 2024
16 changes: 16 additions & 0 deletions libs/s25main/Replay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Replay.h"
#include "Savegame.h"
#include "enum_cast.hpp"
#include "helpers/format.hpp"
#include "network/PlayerGameCommands.h"
#include "gameTypes/MapInfo.h"
#include <s25util/tmpFile.h>
Expand Down Expand Up @@ -194,10 +195,25 @@ bool Replay::LoadHeader(const boost::filesystem::path& filepath)
// TODO(Replay): Move before mapType to have it as early as possible.
// Previously mapType was an unsigned short, i.e. in little endian the 2nd byte was always unused/zero
subVersion_ = file_.ReadUnsignedChar();
if(subVersion_ > currentReplayDataVersion)
{
lastErrorMsg =
helpers::format(_("Cannot play replay created with a more recent version (Current: %1%, Replay: %2%)"),
currentReplayDataVersion, subVersion_);
return false;
}

if(subVersion_ >= 1)
gcVersion_ = file_.ReadUnsignedChar();
else
gcVersion_ = 0;
if(gcVersion_ > gc::Deserializer::getCurrentVersion())
{
lastErrorMsg =
helpers::format(_("Cannot play replay created with a more recent GC version (Current: %1%, Replay: %2%)"),
gc::Deserializer::getCurrentVersion(), gcVersion_);
return false;
}

if(mapType_ == MapType::Savegame)
{
Expand Down
80 changes: 33 additions & 47 deletions libs/s25main/buildings/BurnedWarehouse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@
#include "EventManager.h"
#include "GamePlayer.h"
#include "SerializedGameData.h"
#include "WineLoader.h"
#include "figures/nofPassiveWorker.h"
#include "helpers/Range.h"
#include "pathfinding/PathConditionHuman.h"
#include "random/Random.h"
#include "world/GameWorld.h"
#include <boost/container/static_vector.hpp>

/// Anzahl der Rausgeh-Etappen
const unsigned GO_OUT_PHASES = 10;
/// Länge zwischen zwei solchen Phasen
const unsigned PHASE_LENGTH = 2;
/// Number of "waves" of workers leaving
constexpr unsigned GO_OUT_PHASES = 10;
/// Time between those phases
constexpr unsigned PHASE_LENGTH = 2;

BurnedWarehouse::BurnedWarehouse(const MapPoint pos, const unsigned char player, const PeopleArray& people)
: noCoordBase(NodalObjectType::BurnedWarehouse, pos), player(player), go_out_phase(0), people(people)
{
// Erstes Event anmelden
// First event
GetEvMgr().AddEvent(this, PHASE_LENGTH, 0);
}

Expand Down Expand Up @@ -51,23 +52,19 @@ void BurnedWarehouse::HandleEvent(const unsigned /*id*/)
{
RTTR_Assert(go_out_phase != GO_OUT_PHASES);

std::array<Direction, helpers::NumEnumValues_v<Direction>> possibleDirs;
unsigned possibleDirCt = 0;

// Mögliche Richtungen zählen und speichern
// Determine valid directions for people
boost::container::static_vector<Direction, helpers::NumEnumValues_v<Direction>> possibleDirs;
PathConditionHuman pathChecker(*world);
for(const auto dir : helpers::EnumRange<Direction>{})
{
if(pathChecker.IsNodeOk(world->GetNeighbour(pos, dir)))
possibleDirs[possibleDirCt++] = dir;
possibleDirs.push_back(dir);
}

// GAR KEINE Richtungen?
if(possibleDirCt == 0)
if(possibleDirs.empty())
{
// Das ist traurig, dann muss die Titanic mit allen restlichen an Board leider untergehen
// No way out for figures -> all die and we can remove this object
GetEvMgr().AddToKillList(world->RemoveFigure(pos, *this));
// restliche Leute von der Inventur abziehen
for(const auto i : helpers::enumRange<Job>())
world->GetPlayer(player).DecreaseInventoryJob(i, people[i]);

Expand All @@ -76,60 +73,49 @@ void BurnedWarehouse::HandleEvent(const unsigned /*id*/)

for(const auto job : helpers::enumRange<Job>())
{
// Anzahl ausrechnen, die in dieser Runde rausgeht
// In the last phase all remaining ones leave, else only some
unsigned count;
if(go_out_phase + 1 >= GO_OUT_PHASES)
count = people[job]; // Take all on last round
count = people[job];
else
count = people[job] / (GO_OUT_PHASES - go_out_phase);

if(count == 0 && wineaddon::isWineAddonJobType(job))
if(count == 0)
continue;

// Von der vorhandenen Abzahl abziehen
// Remove from inventory
people[job] -= count;

// In Alle Richtungen verteilen
// Startrichtung zufällig bestimmen
unsigned start_dir = RANDOM_RAND(helpers::NumEnumValues_v<Direction>);
// Distribute in all directions starting at a random one of the possible ones
const unsigned startIdx = (possibleDirs.size() <= 1u) ? 0 : RANDOM_RAND(possibleDirs.size());
const unsigned numPeoplePerDir = count / possibleDirs.size();

for(unsigned j = 0; j < possibleDirCt; ++j)
for(const unsigned j : helpers::range(possibleDirs.size()))
{
// Aktuelle Richtung, die jetzt dran ist bestimmen
Direction dir = possibleDirs[j] + start_dir;

// Anzahl jetzt für diese Richtung ausrechnen
unsigned numPeopleInDir = count / possibleDirCt;
// Bei letzter Richtung noch den übriggebliebenen Rest dazuaddieren
if(j + 1 == possibleDirCt)
numPeopleInDir += count % possibleDirCt;

// Die Figuren schließlich rausschicken
for(unsigned z = 0; z < numPeopleInDir; ++z)
// Get current direction accounting for startIdx and hence possible wrap around
const unsigned idx = j + startIdx;
const Direction curDir = possibleDirs[idx < possibleDirs.size() ? idx : idx - possibleDirs.size()];
// Take all in last direction
const auto curNumPeople = (j + 1u < possibleDirs.size()) ? numPeoplePerDir : count;
count -= curNumPeople;
for(const auto z : helpers::range(curNumPeople))
{
// Job erzeugen
// Create job and send moving into the current direction
auto& figure = world->AddFigure(pos, std::make_unique<nofPassiveWorker>(job, pos, player, nullptr));
// Losrumirren in die jeweilige Richtung
figure.StartWandering(GetObjId());
figure.StartWalking(dir);
figure.StartWalking(curDir);
}
}
}

// Nächste Runde
// Prepare next phase if any
++go_out_phase;

// Nächste Runde anmelden bzw. sich selbst killen, wenn alle Runden erledigt sind
if(go_out_phase == GO_OUT_PHASES)
{
// fertig, sich selbst töten
// All done
GetEvMgr().AddToKillList(world->RemoveFigure(pos, *this));
// Prüfen, ob alle evakuiert wurden und keiner mehr an Board ist
// There shouldn't be any more
for(unsigned int it : people)
RTTR_Assert(it == 0);
} else
{
// Nächstes Event anmelden
} else // Not done yet
GetEvMgr().AddEvent(this, PHASE_LENGTH, 0);
}
}
14 changes: 7 additions & 7 deletions libs/s25main/figures/nofCharburner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ void nofCharburner::WorkFinished()
if(GetPointQuality(pos) != PointQuality::NotPossible)
{
// Delete previous elements
// Only environt objects and signs are allowed to be removed by the worker!
// Only environ objects and signs are allowed to be removed by the worker!
// Otherwise just do nothing
NodalObjectType noType = no->GetType();

Expand All @@ -105,7 +105,7 @@ void nofCharburner::WorkFinished()
}

/// Fragt abgeleitete Klasse, ob hier Platz bzw ob hier ein Baum etc steht, den z.B. der Holzfäller braucht
nofFarmhand::PointQuality nofCharburner::GetPointQuality(const MapPoint pt) const
nofFarmhand::PointQuality nofCharburner::GetPointQuality(const MapPoint pt, const bool isBeforeWork) const
{
noBase* no = world->GetNO(pt);

Expand All @@ -117,11 +117,11 @@ nofFarmhand::PointQuality nofCharburner::GetPointQuality(const MapPoint pt) cons
if(pileState == noCharburnerPile::State::Smoldering)
return PointQuality::NotPossible;

// Wood stack which stell need resources?
// Wood stack which still need resources?
if(pileState == noCharburnerPile::State::Wood)
{
// Does it need resources and I don't have them hen starting new work (state = Waiting1)?
if(!workplace->WaresAvailable() && this->state == State::Waiting1)
// Only check for resources before going out
if(isBeforeWork && !workplace->WaresAvailable())
return PointQuality::NotPossible;
else
// Only second class, harvest all piles first before continue
Expand All @@ -134,8 +134,8 @@ nofFarmhand::PointQuality nofCharburner::GetPointQuality(const MapPoint pt) cons
}

// Try to "plant" a new pile
// Still enough wares when starting new work (state = Waiting1)?
if(!workplace->WaresAvailable() && state == State::Waiting1)
// Enough wares when starting new work?
if(isBeforeWork && !workplace->WaresAvailable())
return PointQuality::NotPossible;

// Der Platz muss frei sein
Expand Down
8 changes: 3 additions & 5 deletions libs/s25main/figures/nofCharburner.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,16 @@ class nofCharburner : public nofFarmhand
friend constexpr auto maxEnumValue(WareType) { return WareType::Grain; }

private:
/// Malt den Arbeiter beim Arbeiten
void DrawWorking(DrawPoint drawPt) override;
/// Id in jobs.bob or carrier.bob when carrying a ware
/// Has no ID in jobs.bob or carrier.bob
[[noreturn]] unsigned short GetCarryID() const override;

/// Abgeleitete Klasse informieren, wenn sie anfängt zu arbeiten (Vorbereitungen)
void WorkStarted() override;
/// Abgeleitete Klasse informieren, wenn fertig ist mit Arbeiten
void WorkFinished() override;

/// Returns the quality of this working point or determines if the worker can work here at all
PointQuality GetPointQuality(MapPoint pt) const override;
PointQuality GetPointQuality(MapPoint pt, bool isBeforeWork) const override;
using nofFarmhand::GetPointQuality;

/// Inform derived class about the start of the whole working process (at the beginning when walking out of the
/// house)
Expand Down
2 changes: 1 addition & 1 deletion libs/s25main/figures/nofFarmer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ void nofFarmer::WorkFinished()
}

/// Returns the quality of this working point or determines if the worker can work here at all
nofFarmhand::PointQuality nofFarmer::GetPointQuality(const MapPoint pt) const
nofFarmhand::PointQuality nofFarmer::GetPointQuality(const MapPoint pt, bool /* isBeforeWork */) const
{
// Entweder gibts ein Getreidefeld, das wir abernten können...
if(world->GetNO(pt)->GetType() == NodalObjectType::Grainfield)
Expand Down
3 changes: 2 additions & 1 deletion libs/s25main/figures/nofFarmer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class nofFarmer : public nofFarmhand
void WorkAborted() override;

/// Returns the quality of this working point or determines if the worker can work here at all
PointQuality GetPointQuality(MapPoint pt) const override;
PointQuality GetPointQuality(MapPoint pt, bool isBeforeWork) const override;
using nofFarmhand::GetPointQuality;

public:
nofFarmer(MapPoint pos, unsigned char player, nobUsual* workplace);
Expand Down
Loading