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
2 changes: 1 addition & 1 deletion external/turtle
2 changes: 1 addition & 1 deletion libs/s25main/CheatCommandTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ void CheatCommandTracker::onSpecialKeyEvent(const KeyEvent& ke)

switch(ke.kt)
{
case KeyType::F6: cheats_.toggleHumanAIPlayer(); break;
case KeyType::F7:
{
if(ke.alt)
Expand All @@ -65,7 +66,6 @@ void CheatCommandTracker::onSpecialKeyEvent(const KeyEvent& ke)
cheats_.toggleAllVisible();
}
break;
case KeyType::F10: cheats_.toggleHumanAIPlayer(); break;
default: break;
}
}
Expand Down
3 changes: 2 additions & 1 deletion libs/s25main/Replay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ uint8_t Replay::GetLatestMinorVersion() const
// 8.1: Portraits support
// 8.2: Set correct initial distributions if replay starts without savegame for leather addon (see GameClient.cpp
// StartReplay function for detailed description)
return 2;
// 8.3 Remove invalid fish for replays started from start (i.e. map instead of savegame)
return 3;
}

uint8_t Replay::GetLatestMajorVersion() const
Expand Down
6 changes: 3 additions & 3 deletions libs/s25main/figures/nofFisher.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ class nofFisher : public nofFarmhand
/// 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, bool isBeforeWork) const override;

public:
nofFisher(MapPoint pos, unsigned char player, nobUsual* workplace);
nofFisher(SerializedGameData& sgd, unsigned obj_id);
Expand All @@ -38,4 +35,7 @@ class nofFisher : public nofFarmhand
void Serialize(SerializedGameData& sgd) const override;

GO_Type GetGOT() const final { return GO_Type::NofFisher; }

/// Returns the quality of this working point or determines if the worker can work here at all
PointQuality GetPointQuality(MapPoint pt, bool isBeforeWork) const override;
};
11 changes: 9 additions & 2 deletions libs/s25main/network/GameClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,9 @@ void GameClient::StartGame(const unsigned random_init)
OnError(ClientError::InvalidMap);
return;
}
gameWorld.SetupResources();
// TODO (Replay): Always use true
const bool fixFish = !GetReplay() || GetReplay()->GetMinorVersion() >= 3;
MapLoader::SetupResources(gameWorld, fixFish);
}
gameWorld.InitAfterLoad();

Expand Down Expand Up @@ -1872,9 +1874,14 @@ void GameClient::ToggleHumanAIPlayer(const AI::Info& aiInfo)
auto it = helpers::find_if(game->aiPlayers_,
[id = this->GetPlayerId()](const auto& player) { return player.GetPlayerId() == id; });
if(it != game->aiPlayers_.end())
{
game->aiPlayers_.erase(it);
else
SystemChat(_("Disabled AI for current player"));
} else
{
game->AddAIPlayer(CreateAIPlayer(GetPlayerId(), aiInfo));
SystemChat(_("Enabled AI for current player"));
}
}

void GameClient::RequestSwapToPlayer(const unsigned char newId)
Expand Down
81 changes: 0 additions & 81 deletions libs/s25main/world/GameWorld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,87 +1294,6 @@ bool GameWorld::IsBorderNode(const MapPoint pt, const unsigned char owner) const
return (GetNode(pt).owner == owner && !IsPlayerTerritory(pt, owner));
}

/**
* Konvertiert Ressourcen zwischen Typen hin und her oder löscht sie.
* Für Spiele ohne Gold.
*/
void GameWorld::ConvertMineResourceTypes(ResourceType from, ResourceType to)
{
// LOG.write(("Convert map resources from %i to %i\n", from, to);
if(from == to)
return;

RTTR_FOREACH_PT(MapPoint, GetSize())
{
Resource resources = GetNode(pt).resources;
// Gibt es Ressourcen dieses Typs?
// Wenn ja, dann umwandeln bzw löschen
if(resources.getType() == from)
{
resources.setType(to);
SetResource(pt, resources);
}
}
}

void GameWorld::SetupResources()
{
ResourceType target;
switch(GetGGS().getSelection(AddonId::CHANGE_GOLD_DEPOSITS))
{
case 0:
default: target = ResourceType::Gold; break;
case 1: target = ResourceType::Nothing; break;
case 2: target = ResourceType::Iron; break;
case 3: target = ResourceType::Coal; break;
case 4: target = ResourceType::Granite; break;
}
ConvertMineResourceTypes(ResourceType::Gold, target);
PlaceAndFixWater();
}

/**
* Fills water depending on terrain and Addon setting
*/
void GameWorld::PlaceAndFixWater()
{
bool waterEverywhere = GetGGS().getSelection(AddonId::EXHAUSTIBLE_WATER) == 1;

RTTR_FOREACH_PT(MapPoint, GetSize())
{
Resource curNodeResource = GetNode(pt).resources;

if(curNodeResource.getType() == ResourceType::Nothing)
{
if(!waterEverywhere)
continue;
} else if(curNodeResource.getType() != ResourceType::Water)
{
// do not override maps resource.
continue;
}

uint8_t minHumidity = 100;
for(const DescIdx<TerrainDesc> tIdx : GetTerrainsAround(pt))
{
const uint8_t curHumidity = GetDescription().get(tIdx).humidity;
if(curHumidity < minHumidity)
{
minHumidity = curHumidity;
if(minHumidity == 0)
break;
}
}
if(minHumidity)
curNodeResource =
Resource(ResourceType::Water, waterEverywhere ? 7 : helpers::iround<uint8_t>(minHumidity * 7. / 100.));
else
curNodeResource = Resource(ResourceType::Nothing, 0);

SetResource(pt, curNodeResource);
}
}

/// Gründet vom Schiff aus eine neue Kolonie
bool GameWorld::FoundColony(const HarborId harbor, const unsigned char player, const SeaId seaId)
{
Expand Down
9 changes: 0 additions & 9 deletions libs/s25main/world/GameWorld.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,6 @@ class GameWorld : public GameWorldBase
/// Return whether this is a border node (node belongs to player, but not all others around)
bool IsBorderNode(MapPoint pt, unsigned char owner) const;

// Konvertiert Ressourcen zwischen Typen hin und her oder löscht sie.
// Für Spiele ohne Gold.
void ConvertMineResourceTypes(ResourceType from, ResourceType to);
// Setup resources like gold and water after loading a new map
void SetupResources();

// Fills water depending on terrain and Addon setting
void PlaceAndFixWater();

/// Gründet vom Schiff aus eine neue Kolonie, gibt true zurück bei Erfolg
bool FoundColony(HarborId harbor, unsigned char player, SeaId seaId);
/// Registriert eine Baustelle eines Hafens, die vom Schiff aus gesetzt worden ist
Expand Down
105 changes: 104 additions & 1 deletion libs/s25main/world/MapLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
#include "GlobalGameSettings.h"
#include "PointOutput.h"
#include "RttrForeachPt.h"
#include "addons/const_addons.h"
#include "buildings/nobHQ.h"
#include "factories/BuildingFactory.h"
#include "helpers/IdRange.h"
#include "helpers/Range.h"
#include "helpers/containerUtils.h"
#include "helpers/mathFuncs.h"
#include "lua/GameDataLoader.h"
#include "pathfinding/PathConditionShip.h"
#include "random/Random.h"
Expand Down Expand Up @@ -106,6 +110,105 @@ bool MapLoader::PlaceHQs(bool addStartWares)
return PlaceHQs(world_, hqPositions, addStartWares);
}

void MapLoader::SetupResources(GameWorldBase& world, const bool fixFish)
{
ResourceType target;
switch(world.GetGGS().getSelection(AddonId::CHANGE_GOLD_DEPOSITS))
{
case 0:
default: target = ResourceType::Gold; break;
case 1: target = ResourceType::Nothing; break;
case 2: target = ResourceType::Iron; break;
case 3: target = ResourceType::Coal; break;
case 4: target = ResourceType::Granite; break;
}
ConvertMineResourceTypes(world, ResourceType::Gold, target);
PlaceAndFixWater(world);
if(fixFish)
RemoveUnusableFishResources(world);
}

void MapLoader::ConvertMineResourceTypes(GameWorldBase& world, ResourceType from, ResourceType to)
{
// LOG.write(("Convert map resources from %i to %i\n", from, to);
if(from == to)
return;

RTTR_FOREACH_PT(MapPoint, world.GetSize())
{
Resource resources = world.GetNode(pt).resources;
// Gibt es Ressourcen dieses Typs?
// Wenn ja, dann umwandeln bzw löschen
if(resources.getType() == from)
{
resources.setType(to);
world.SetResource(pt, resources);
}
}
}

void MapLoader::PlaceAndFixWater(GameWorldBase& world)
{
const bool waterEverywhere = world.GetGGS().getSelection(AddonId::EXHAUSTIBLE_WATER) == 1;

RTTR_FOREACH_PT(MapPoint, world.GetSize())
{
Resource curNodeResource = world.GetNode(pt).resources;

if(curNodeResource.getType() == ResourceType::Nothing)
{
if(!waterEverywhere)
continue;
} else if(curNodeResource.getType() != ResourceType::Water)
continue; // do not override maps resource.

uint8_t minHumidity = 100;
for(const DescIdx<TerrainDesc> tIdx : world.GetTerrainsAround(pt))
{
const uint8_t curHumidity = world.GetDescription().get(tIdx).humidity;
if(curHumidity < minHumidity)
{
minHumidity = curHumidity;
if(minHumidity == 0)
break;
}
}
if(minHumidity)
{
curNodeResource =
Resource(ResourceType::Water, waterEverywhere ? 7 : helpers::iround<uint8_t>(minHumidity * 7. / 100.));
} else
curNodeResource = Resource(ResourceType::Nothing, 0);

world.SetResource(pt, curNodeResource);
}
}

void MapLoader::RemoveUnusableFishResources(GameWorldBase& world)
{
const auto isWaterPoint = [&world](const MapPoint nb) { return world.IsWaterPoint(nb); };
for(const MapCoord y : helpers::range(world.GetHeight()))
{
// Optimization: When there was fish on the previous node (in the same row)
// we do not need to check for isolated water points, as there is at least that water point
bool previousHasFish = false;
for(const MapCoord x : helpers::range(world.GetWidth()))
{
const MapPoint pt(x, y);
bool hasFish = false;

if(world.GetNode(pt).resources.has(ResourceType::Fish))
{
if(isWaterPoint(pt) && (previousHasFish || helpers::contains_if(world.GetNeighbours(pt), isWaterPoint)))
hasFish = true;
else
world.SetResource(pt, Resource(ResourceType::Nothing, 0));
}
previousHasFish = hasFish;
}
}
}

void MapLoader::InitShadows(World& world)
{
RTTR_FOREACH_PT(MapPoint, world.GetSize())
Expand All @@ -117,7 +220,7 @@ void MapLoader::SetMapExplored(World& world)
RTTR_FOREACH_PT(MapPoint, world.GetSize())
{
// For every player
for(unsigned i = 0; i < MAX_PLAYERS; ++i)
for(const auto i : helpers::range(MAX_PLAYERS))
{
// If we have FoW here, save it
if(world.GetNode(pt).fow[i].visibility == Visibility::FogOfWar)
Expand Down
12 changes: 12 additions & 0 deletions libs/s25main/world/MapLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "gameTypes/GameSettingTypes.h"
#include "gameTypes/MapCoordinates.h"
#include "gameTypes/MapTypes.h"
#include "gameTypes/Resource.h"
#include "gameData/DescIdx.h"
#include <boost/filesystem/path.hpp>
#include <vector>
Expand Down Expand Up @@ -50,6 +51,9 @@ class MapLoader
/// Optionally add the starting wares to the HQs.
/// Return false if there was an error (e.g. invalid start position)
bool PlaceHQs(bool addStartWares = true);
/// Setup resources like gold and water after loading a new map.
/// TODO(Replay): Remove fixFish (always set to true)
static void SetupResources(GameWorldBase& world, bool fixFish = true);

/// Return the (original/unshuffled) position of the players HQ (only valid after successful load)
MapPoint GetOriginalHQPos(unsigned player) const { return hqPositions_[player]; }
Expand All @@ -61,4 +65,12 @@ class MapLoader
/// Place the HQs on a loaded map and add starting wares if desired.
/// Return false if there was an error.
static bool PlaceHQs(GameWorldBase& world, const std::vector<MapPoint>& hqPositions, bool addStartWares = true);

private:
/// Converts map resources between types or deletes them. Used for games without gold.
static void ConvertMineResourceTypes(GameWorldBase& world, ResourceType from, ResourceType to);
/// Fills water depending on terrain and Addon setting.
static void PlaceAndFixWater(GameWorldBase& world);
/// Removes fish resources that cannot be reached by fisheries.
static void RemoveUnusableFishResources(GameWorldBase& world);
};
Loading
Loading