Skip to content

Commit fb40fc9

Browse files
committed
Split granite mine work-everywhere addon
1 parent 2a4936e commit fb40fc9

8 files changed

Lines changed: 116 additions & 21 deletions

File tree

libs/s25main/GlobalGameSettings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ void GlobalGameSettings::registerAllAddons()
7979
AddonHalfCostMilEquip,
8080
AddonInexhaustibleFish,
8181
AddonInexhaustibleGraniteMines,
82+
AddonGraniteMinesWorkEverywhere,
8283
AddonInexhaustibleMines,
8384
AddonLimitCatapults,
8485
AddonManualRoadEnlargement,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later
4+
5+
#pragma once
6+
7+
#include "AddonBool.h"
8+
#include "const_addons.h"
9+
#include "mygettext/mygettext.h"
10+
11+
/**
12+
* Addon for creating finite granite resources below granite mines without explicit stone resources.
13+
*/
14+
class AddonGraniteMinesWorkEverywhere : public AddonBool
15+
{
16+
public:
17+
AddonGraniteMinesWorkEverywhere()
18+
: AddonBool(AddonId::GRANITEMINES_WORK_EVERYWHERE, AddonGroup::Economy, _("Granite Mines Work Everywhere"),
19+
_("Granite mines can create a finite stone resource on otherwise empty mountain spots."))
20+
{}
21+
};

libs/s25main/addons/AddonInexhaustibleGraniteMines.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
#include "mygettext/mygettext.h"
99

1010
/**
11-
* Addon for allowing granite mines to produce independently of stone resources.
11+
* Addon for allowing granite mines to have unlimited resources.
1212
*/
1313
class AddonInexhaustibleGraniteMines : public AddonBool
1414
{
1515
public:
1616
AddonInexhaustibleGraniteMines()
1717
: AddonBool(AddonId::INEXHAUSTIBLE_GRANITEMINES, AddonGroup::Economy, _("Inexhaustible Granite Mines"),
18-
_("Granite mines can produce stone on any mountain spot and never deplete resources."))
18+
_("Granite mines will never deplete stone resources."))
1919
{}
2020
};

libs/s25main/addons/Addons.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include "addons/AddonInexhaustibleFish.h"
3737
#include "addons/AddonInexhaustibleGraniteMines.h"
38+
#include "addons/AddonGraniteMinesWorkEverywhere.h"
3839
#include "addons/AddonMaxRank.h"
3940
#include "addons/AddonMilitaryAid.h"
4041
#include "addons/AddonSeaAttack.h"

libs/s25main/addons/const_addons.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ ENUM_WITH_STRING(AddonId, LIMIT_CATAPULTS = 0x00000000, INEXHAUSTIBLE_MINES = 0x
5555

5656
MILITARY_AID = 0x00700000,
5757

58-
INEXHAUSTIBLE_GRANITEMINES = 0x00800000,
58+
INEXHAUSTIBLE_GRANITEMINES = 0x00800000, GRANITEMINES_WORK_EVERYWHERE = 0x00800001,
5959

6060
MAX_RANK = 0x00900000, SEA_ATTACK = 0x00900001, INEXHAUSTIBLE_FISH = 0x00900002,
6161
MORE_ANIMALS = 0x00900003, BURN_DURATION = 0x00900004, NO_ALLIED_PUSH = 0x00900005,

libs/s25main/figures/nofMiner.cpp

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#include "network/GameClient.h"
1212
#include "ogl/glArchivItem_Bitmap_Player.h"
1313
#include "world/GameWorld.h"
14+
#include "gameTypes/Resource.h"
15+
#include "gameData/GameConsts.h"
16+
#include "random/Random.h"
1417

1518
nofMiner::nofMiner(const MapPoint pos, const unsigned char player, nobUsual* workplace)
1619
: nofWorkman(Job::Miner, pos, player, workplace)
@@ -69,32 +72,63 @@ helpers::OptionalEnum<GoodType> nofMiner::ProduceWare()
6972
}
7073
}
7174

75+
MapPoint nofMiner::FindPointWithResourceQuiet(ResourceType type) const
76+
{
77+
const auto pts = world->GetMatchingPointsInRadius<1>(
78+
pos, MINER_RADIUS, [this, type](const MapPoint pt) { return world->GetNode(pt).resources.has(type); }, true);
79+
return pts.empty() ? MapPoint::Invalid() : pts.front();
80+
}
81+
82+
bool nofMiner::CanCreateWorkEverywhereGraniteResource() const
83+
{
84+
return workplace->GetBuildingType() == BuildingType::GraniteMine
85+
&& world->GetGGS().isEnabled(AddonId::GRANITEMINES_WORK_EVERYWHERE)
86+
&& world->GetNode(pos).resources.getType() == ResourceType::Nothing;
87+
}
88+
89+
MapPoint nofMiner::CreateWorkEverywhereGraniteResource()
90+
{
91+
if(!CanCreateWorkEverywhereGraniteResource())
92+
return MapPoint::Invalid();
93+
94+
world->SetResource(pos, Resource(ResourceType::Granite, static_cast<uint8_t>(8 + RANDOM_RAND(8))));
95+
return pos;
96+
}
97+
7298
bool nofMiner::AreWaresAvailable() const
7399
{
74-
return nofWorkman::AreWaresAvailable()
75-
&& (CanMineWithoutResource() || FindPointWithResource(GetRequiredResType()).isValid());
100+
if(!nofWorkman::AreWaresAvailable())
101+
return false;
102+
103+
if(FindPointWithResourceQuiet(GetRequiredResType()).isValid() || CanCreateWorkEverywhereGraniteResource())
104+
return true;
105+
106+
workplace->OnOutOfResources();
107+
return false;
76108
}
77109

78110
bool nofMiner::StartWorking()
79111
{
80112
const GlobalGameSettings& settings = world->GetGGS();
81-
if(!CanMineWithoutResource())
113+
MapPoint resPt = FindPointWithResourceQuiet(GetRequiredResType());
114+
if(!resPt.isValid())
82115
{
83-
MapPoint resPt = FindPointWithResource(GetRequiredResType());
116+
resPt = CreateWorkEverywhereGraniteResource();
84117
if(!resPt.isValid())
118+
{
119+
workplace->OnOutOfResources();
85120
return false;
86-
if(!settings.isEnabled(AddonId::INEXHAUSTIBLE_MINES))
87-
world->ReduceResource(resPt);
121+
}
88122
}
89-
return nofWorkman::StartWorking();
90-
}
91123

92-
bool nofMiner::CanMineWithoutResource() const
93-
{
94-
return workplace->GetBuildingType() == BuildingType::GraniteMine
95-
&& world->GetGGS().isEnabled(AddonId::INEXHAUSTIBLE_GRANITEMINES);
96-
}
124+
const bool inexhaustibleRes = settings.isEnabled(AddonId::INEXHAUSTIBLE_MINES)
125+
|| (workplace->GetBuildingType() == BuildingType::GraniteMine
126+
&& settings.isEnabled(AddonId::INEXHAUSTIBLE_GRANITEMINES));
127+
if(!inexhaustibleRes)
128+
world->ReduceResource(resPt);
97129

130+
return nofWorkman::StartWorking();
131+
}
98132
ResourceType nofMiner::GetRequiredResType() const
99133
{
100134
switch(workplace->GetBuildingType())

libs/s25main/figures/nofMiner.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ class nofMiner : public nofWorkman
2323
bool AreWaresAvailable() const override;
2424
bool StartWorking() override;
2525
ResourceType GetRequiredResType() const;
26-
bool CanMineWithoutResource() const;
26+
MapPoint FindPointWithResourceQuiet(ResourceType type) const;
27+
bool CanCreateWorkEverywhereGraniteResource() const;
28+
MapPoint CreateWorkEverywhereGraniteResource();
2729

2830
public:
2931
nofMiner(MapPoint pos, unsigned char player, nobUsual* workplace);

tests/s25Main/integration/testProduction.cpp

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ BOOST_AUTO_TEST_SUITE(Production)
2626
namespace {
2727
struct GraniteMineWithoutResourcesFixture : WorldWithGCExecution1P
2828
{
29-
const nobUsual* CreateGraniteMineWithoutResources()
29+
MapPoint CreateGraniteMineWithoutResources()
3030
{
3131
GoodsAndPeopleCounts inv;
32-
inv[GoodType::Fish] = 10;
32+
inv[GoodType::Fish] = 40;
3333
inv[GoodType::PickAxe] = 1;
3434
inv[Job::Miner] = 1;
3535
world.GetSpecObj<nobBaseWarehouse>(hqPos)->AddToInventory(inv, true);
@@ -39,7 +39,7 @@ struct GraniteMineWithoutResourcesFixture : WorldWithGCExecution1P
3939
BuildingFactory::CreateBuilding(world, BuildingType::GraniteMine, minePos, curPlayer, Nation::Romans));
4040
BuildRoad(world.GetNeighbour(minePos, Direction::SouthEast), false, std::vector<Direction>(2, Direction::West));
4141
RTTR_EXEC_TILL(500, mine->HasWorker());
42-
return mine;
42+
return minePos;
4343
}
4444
};
4545
} // namespace
@@ -134,14 +134,50 @@ BOOST_FIXTURE_TEST_CASE(GraniteMineWithoutResourcesNeedsAddon, GraniteMineWithou
134134
BOOST_TEST(curInventory[GoodType::Stones] == initialStones);
135135
}
136136

137-
BOOST_FIXTURE_TEST_CASE(InexhaustibleGraniteMineWorksWithoutResources, GraniteMineWithoutResourcesFixture)
137+
BOOST_FIXTURE_TEST_CASE(InexhaustibleGraniteMineStillNeedsResourceSpot, GraniteMineWithoutResourcesFixture)
138138
{
139139
ggs.setSelection(AddonId::INEXHAUSTIBLE_GRANITEMINES, 1);
140140
CreateGraniteMineWithoutResources();
141141
const Inventory& curInventory = world.GetPlayer(curPlayer).GetInventory();
142142
const unsigned initialStones = curInventory[GoodType::Stones];
143143

144+
RTTR_SKIP_GFS(2000);
145+
146+
BOOST_TEST(curInventory[GoodType::Stones] == initialStones);
147+
}
148+
149+
BOOST_FIXTURE_TEST_CASE(GraniteMineWorkEverywhereCreatesDepletableResource, GraniteMineWithoutResourcesFixture)
150+
{
151+
ggs.setSelection(AddonId::GRANITEMINES_WORK_EVERYWHERE, 1);
152+
const MapPoint minePos = CreateGraniteMineWithoutResources();
153+
const Inventory& curInventory = world.GetPlayer(curPlayer).GetInventory();
154+
const unsigned initialStones = curInventory[GoodType::Stones];
155+
156+
RTTR_EXEC_TILL(2000, curInventory[GoodType::Stones] > initialStones);
157+
BOOST_TEST(world.GetNode(minePos).resources.has(ResourceType::Granite));
158+
159+
RTTR_EXEC_TILL(50000, world.GetNode(minePos).resources.getType() == ResourceType::Granite
160+
&& world.GetNode(minePos).resources.getAmount() == 0u);
161+
BOOST_TEST(static_cast<unsigned>(world.GetNode(minePos).resources.getType()) == static_cast<unsigned>(ResourceType::Granite));
162+
BOOST_TEST(world.GetNode(minePos).resources.getAmount() == 0u);
163+
}
164+
165+
BOOST_FIXTURE_TEST_CASE(GraniteMineWorkEverywhereResourceIsInexhaustibleWithGraniteAddon, GraniteMineWithoutResourcesFixture)
166+
{
167+
ggs.setSelection(AddonId::GRANITEMINES_WORK_EVERYWHERE, 1);
168+
ggs.setSelection(AddonId::INEXHAUSTIBLE_GRANITEMINES, 1);
169+
const MapPoint minePos = CreateGraniteMineWithoutResources();
170+
const Inventory& curInventory = world.GetPlayer(curPlayer).GetInventory();
171+
const unsigned initialStones = curInventory[GoodType::Stones];
172+
144173
RTTR_EXEC_TILL(2000, curInventory[GoodType::Stones] > initialStones);
174+
BOOST_TEST(world.GetNode(minePos).resources.has(ResourceType::Granite));
175+
const unsigned initialResourceAmount = world.GetNode(minePos).resources.getAmount();
176+
177+
RTTR_SKIP_GFS(10000);
178+
179+
BOOST_TEST(world.GetNode(minePos).resources.has(ResourceType::Granite));
180+
BOOST_TEST(world.GetNode(minePos).resources.getAmount() == initialResourceAmount);
145181
}
146182

147183
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)