-
Notifications
You must be signed in to change notification settings - Fork 98
Add limited extra harbor spots addon #1921
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
base: master
Are you sure you want to change the base?
Changes from all commits
31aec23
7eb7728
676ed66
49cd227
dfa8907
6d9f758
5694b35
653fc4b
a73ec9a
9baf098
83fda19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org) | ||
| // | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
|
|
||
| #pragma once | ||
|
|
||
| #include "AddonBool.h" | ||
| #include "mygettext/mygettext.h" | ||
|
|
||
| class AddonFreeHarborSpots : public AddonBool | ||
| { | ||
| public: | ||
| AddonFreeHarborSpots() | ||
| : AddonBool(AddonId::FREE_HARBOR_SPOTS, AddonGroup::GamePlay, _("Dangerous: Add limited extra harbor spots"), | ||
| _("Advanced option. Adds only a small deterministic set of suitable coastal castle sites as extra " | ||
| "harbor spots. May alter intended map seafaring design.")) | ||
| {} | ||
| }; | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|
|
||||||
| #include "world/MapLoader.h" | ||||||
| #include "BQCalculator.h" | ||||||
| #include "Game.h" | ||||||
| #include "GamePlayer.h" | ||||||
| #include "GameWorldBase.h" | ||||||
|
|
@@ -35,6 +36,8 @@ | |||||
| #include "s25util/Log.h" | ||||||
| #include <boost/filesystem/operations.hpp> | ||||||
| #include <algorithm> | ||||||
| #include <iterator> | ||||||
| #include <limits> | ||||||
| #include <map> | ||||||
| #include <queue> | ||||||
|
|
||||||
|
|
@@ -57,7 +60,7 @@ bool MapLoader::Load(const libsiedler2::ArchivItem_Map& map, Exploration explora | |||||
| return false; | ||||||
| PlaceObjects(map); | ||||||
| PlaceAnimals(map); | ||||||
| if(!InitSeasAndHarbors(world_)) | ||||||
| if(!InitSeasAndHarbors(world_, std::vector<MapPoint>(), world_.GetGGS().isEnabled(AddonId::FREE_HARBOR_SPOTS))) | ||||||
| return false; | ||||||
|
|
||||||
| /// Schatten | ||||||
|
|
@@ -523,7 +526,86 @@ bool MapLoader::PlaceHQs(GameWorldBase& world, const std::vector<MapPoint>& hqPo | |||||
| return true; | ||||||
| } | ||||||
|
|
||||||
| bool MapLoader::InitSeasAndHarbors(World& world, const std::vector<MapPoint>& additionalHarbors) | ||||||
| namespace { | ||||||
| bool hasEligibleHarborCoast(const World& world, const MapPoint pt) | ||||||
| { | ||||||
| for(const auto dir : helpers::EnumRange<Direction>{}) | ||||||
| { | ||||||
| if(dir != Direction::NorthWest && world.GetSeaFromCoastalPoint(world.GetNeighbour(pt, dir))) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. needs a comment on the !=NW |
||||||
| return true; | ||||||
| } | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| bool isFarEnoughFromHarbors(const World& world, const MapPoint pt, const std::vector<MapPoint>& harborPositions) | ||||||
| { | ||||||
| for(const MapPoint harborPt : harborPositions) | ||||||
| { | ||||||
| if(world.CalcDistance(pt, harborPt) < MapLoader::MIN_GENERATED_HARBOR_DISTANCE) | ||||||
| return false; | ||||||
| } | ||||||
| return true; | ||||||
| } | ||||||
|
|
||||||
| unsigned getMinimumHarborDistance(const World& world, const MapPoint pt, const std::vector<MapPoint>& harborPositions) | ||||||
| { | ||||||
| unsigned minDistance = std::numeric_limits<unsigned>::max(); | ||||||
| for(const MapPoint harborPt : harborPositions) | ||||||
| minDistance = std::min(minDistance, world.CalcDistance(pt, harborPt)); | ||||||
| return minDistance; | ||||||
| } | ||||||
|
|
||||||
| std::vector<MapPoint> getGeneratedHarbors(const World& world) | ||||||
| { | ||||||
| std::vector<MapPoint> harborPositions; | ||||||
| harborPositions.reserve(world.GetNumHarborPoints() + MapLoader::MAX_GENERATED_HARBOR_SPOTS); | ||||||
| for(const auto harborId : helpers::idRange<HarborId>(world.GetNumHarborPoints())) | ||||||
| harborPositions.push_back(world.GetHarborPoint(harborId)); | ||||||
|
|
||||||
| std::vector<MapPoint> candidates; | ||||||
| BQCalculator calcBQ(world); | ||||||
| RTTR_FOREACH_PT(MapPoint, world.GetSize()) | ||||||
| { | ||||||
| if(helpers::contains(harborPositions, pt)) | ||||||
| continue; | ||||||
| if(calcBQ(pt, [](const MapPoint&) { return false; }) != BuildingQuality::Castle) | ||||||
| continue; | ||||||
| if(!hasEligibleHarborCoast(world, pt)) | ||||||
| continue; | ||||||
| if(!isFarEnoughFromHarbors(world, pt, harborPositions)) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a wrapper around a raw loop only used here: Always consider using algorithms instead of raw loops. Here I'd rather have:
Suggested change
Or a named var for the lambda if you consider that not readable enough. Or put that into the function instead of the raw loop |
||||||
| continue; | ||||||
|
|
||||||
| candidates.push_back(pt); | ||||||
| } | ||||||
|
|
||||||
| std::vector<MapPoint> generatedHarbors; | ||||||
| while(!candidates.empty() && generatedHarbors.size() < MapLoader::MAX_GENERATED_HARBOR_SPOTS) | ||||||
| { | ||||||
| auto bestCandidate = candidates.begin(); | ||||||
| unsigned bestDistance = getMinimumHarborDistance(world, *bestCandidate, harborPositions); | ||||||
| for(auto it = std::next(candidates.begin()); it != candidates.end(); ++it) | ||||||
|
Comment on lines
+584
to
+586
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say the single saved check per generated harbor isn't worth the readability-hit compared to range-based-for (compare to |
||||||
| { | ||||||
| const unsigned distance = getMinimumHarborDistance(world, *it, harborPositions); | ||||||
| if(distance > bestDistance) | ||||||
| { | ||||||
| bestDistance = distance; | ||||||
| bestCandidate = it; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| if(bestDistance < MapLoader::MIN_GENERATED_HARBOR_DISTANCE) | ||||||
| break; | ||||||
|
|
||||||
| generatedHarbors.push_back(*bestCandidate); | ||||||
| harborPositions.push_back(*bestCandidate); | ||||||
| candidates.erase(bestCandidate); | ||||||
| } | ||||||
| return generatedHarbors; | ||||||
| } | ||||||
| } // namespace | ||||||
|
|
||||||
| bool MapLoader::InitSeasAndHarbors(World& world, const std::vector<MapPoint>& additionalHarbors, | ||||||
| const bool generateHarborSpots) | ||||||
| { | ||||||
| for(MapPoint pt : additionalHarbors) | ||||||
| world.harborData.push_back(HarborPos(pt)); | ||||||
|
|
@@ -549,6 +631,12 @@ bool MapLoader::InitSeasAndHarbors(World& world, const std::vector<MapPoint>& ad | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| if(generateHarborSpots) | ||||||
| { | ||||||
| for(MapPoint pt : getGeneratedHarbors(world)) | ||||||
| world.harborData.push_back(HarborPos(pt)); | ||||||
| } | ||||||
|
|
||||||
| /// Determine seas adjacent to the harbor places | ||||||
| HarborId curHarborId(1); | ||||||
| for(auto it = world.harborData.begin(); it != world.harborData.end();) | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest:
The "limited" isn't required as there is no other option and "only a small" also seems like comparing against something.
Could also replace "suitable coastal castle sites" by "suitable castle sites" or even "suitable points", as e.g. I can't find a good German translation that sounds good and "suitable" should be specific enough