Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
ed52f31
Adding ware workflow, buildings and menus for leather addon
ottml Dec 1, 2024
0a375f0
Add distribution tab for ham and make gui more general
ottml Dec 1, 2024
1d64203
Add compatibilty code
ottml Dec 1, 2024
8ba2b06
Add direct transport route
ottml Dec 1, 2024
8f6442e
Add fixed animations from leather_bobs.lst
ottml Dec 1, 2024
eca0f39
Skinner goes out to get skins from carcass if he has no pigs (natural…
ottml Dec 7, 2024
cecf2f6
LeatherAddon military (1): Add SetArmorAllowed game command
ottml Dec 8, 2024
128de04
LeatherAddon military (2): Add logic for armor in military building a…
ottml Dec 8, 2024
0733fba
LeatherAddon military (3): Add armor gui elements to military building
ottml Dec 8, 2024
05a95fc
Add test for SetArmorAllowed
ottml Dec 8, 2024
0d71a79
Add compatibility code for ChangeDistribution and increase game comma…
ottml Dec 8, 2024
71956d7
Add new transportation type leatherworking and compatibility code for…
ottml Jan 19, 2025
73b6b1e
Fix wrong default build order
ottml Jan 19, 2025
db98d2c
Solider has 30 percent chance to not die if he has an armor and is hi…
ottml Jan 19, 2025
f014783
Reduce search range for skinner to hunter distance
ottml May 21, 2025
c95526e
Do not show tabs for goods in distribution gui having only one entry
ottml May 21, 2025
ef84e6a
Add correct default values
ottml May 21, 2025
8c03a76
Fix build after rebase
ottml Jun 2, 2025
d39cb65
Add new base class for armored people
ottml Jun 6, 2025
ddbb198
Use same render code for fighting and armored people
ottml Jun 6, 2025
7d90817
Add armor base class to trade donkey too
ottml Jun 7, 2025
beb3744
Add armored soldiers to inventory and add enums for it
ottml Jun 7, 2025
7d75f28
Add logic for counting armored soldiers in inventory and compatibilit…
ottml Jun 7, 2025
e69bcc1
Add and remove armored soldiers to global inventory add missing adds …
ottml Jun 8, 2025
ed3a831
Add tooltip to inventory to show number of armored soldiers
ottml Jun 8, 2025
96e5307
Show amored soldiers on ship (debug only)
ottml Jun 8, 2025
ec99c8a
Avoid crash in sorted container
ottml Jun 8, 2025
a5ce0b4
Adjust comperators to take armor into account
ottml Jun 8, 2025
74104d8
Avoid crash/inconsisent state due to new comperator including armor
ottml Jun 8, 2025
6b07609
Fix formatting
ottml Jun 8, 2025
a24272c
Handle real inventory correct (Part 1)
ottml Jun 8, 2025
a4d232b
Fix formatting and constexpr
ottml Jun 8, 2025
86133b6
Handle real inventory correct (Part 1)
ottml Jun 8, 2025
e2f6385
Add armored soldiers to reserve
ottml Jun 8, 2025
ea7a78b
Add real for orderJob
ottml Jun 8, 2025
163be20
Use correct lst file (seems to be broken due to fixup from git)
ottml Jun 8, 2025
bb5683e
Handle armor correct when building is destroyed or captured and when …
ottml Jun 9, 2025
8931dcd
Add and remove armored figures correct to visual inventory
ottml Jun 9, 2025
bf5feae
Remove code duplication and draw +1 only if HITPOINTS addon is activa…
ottml Jun 9, 2025
32b04e4
Add addons to disable armor by default and behaviour for armor delive…
ottml Jun 14, 2025
6ab9d28
Add function to avoid code duplication
ottml Jun 14, 2025
cf4330b
Fix clang-tidy warnings
ottml Jun 15, 2025
86d1fbd
Add test for trading and warehouse
ottml Jun 15, 2025
afed411
Add test for soldier losing armor in fight instead of hitpoint
ottml Jun 15, 2025
07c684d
Add replay compatibility for ChangeBuildOrder and SetAllInventorySett…
ottml Jun 19, 2025
8aed2e2
Add comment about GC changes
ottml Jun 19, 2025
5ff5195
Fix circular dependency during deserialization
ottml Jun 22, 2025
60dcde4
Increase minor replay version to be able to set the correct initial d…
ottml Jul 27, 2025
53dab5d
Code review
ottml Oct 14, 2025
41fe745
Code review
ottml Oct 14, 2025
4b9f458
Code review
ottml Oct 14, 2025
121fa8d
Code review
ottml Oct 14, 2025
294c90c
Code review
ottml Oct 14, 2025
ec7bfcb
Code review
ottml Oct 14, 2025
15cf161
Code review: Remove comment
ottml Oct 22, 2025
ae9b390
Code review: Remove comment
ottml Oct 22, 2025
e799396
Apply suggestions from code review
ottml Oct 22, 2025
ead692b
Code review: fix clang tidy warning
ottml Oct 29, 2025
3fdc1d1
Code review: Improve unit test
ottml Oct 29, 2025
10b02a5
Code review: Move addon check functions for unused Ware/Jobs/Building…
ottml Oct 29, 2025
eb21c3f
Code review: Move addon check functions for unused Ware/Jobs/Building…
ottml Oct 29, 2025
9fbe2a5
Code review: Move addon check functions for unused Ware/Jobs/Building…
ottml Oct 29, 2025
67263fc
Code review: Inline functions
ottml Oct 29, 2025
9587714
Code review: Use CamelCase and rename enum class
ottml Oct 30, 2025
5d95f9e
Code review: Rename IsArmorDisabled to IsArmorAllowed
ottml Oct 30, 2025
cafb78f
Code review: Use consistent cast and parse argument as reference. Rem…
ottml Oct 30, 2025
78acaf3
Code review: Remove Invalid state from enum and throw exception when …
ottml Nov 4, 2025
32217de
Code review: Rename functions, remove auto return type and capture ad…
ottml Nov 4, 2025
d7204ff
Code review: Add named constants for deserialization code for better …
ottml Nov 4, 2025
c05a293
Code review: Use checkedCast
ottml Nov 5, 2025
650a826
Code review: Rewrite test and fold 4 cases into one
ottml Nov 5, 2025
a8dd2c8
Code review: Use switch
ottml Nov 5, 2025
55b89ea
Code review: Rename variables and change type
ottml Nov 5, 2025
be76687
Code review: Use constants and rewrite counting of traded soldiers
ottml Nov 5, 2025
31f7ed4
Code review
ottml Nov 5, 2025
cf8ea9a
Code review: Use clearer names for varibles
ottml Nov 6, 2025
a3d378e
Code review: Optimize code
ottml Nov 6, 2025
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
Binary file added data/RTTR/assets/addons/0x01000001/AFR_ICON.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/AFR_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/JAP_ICON.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/JAP_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/ROM_ICON.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/ROM_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/VIK_ICON.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/VIK_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/WAFR_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/WJAP_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/WROM_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/WVIK_Z.LST
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/bab_icon.lst
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/bab_z.lst
Binary file not shown.
Binary file added data/RTTR/assets/addons/0x01000001/wbab_z.lst
Binary file not shown.
Binary file added data/RTTR/assets/base/leather_bobs.lst
Binary file not shown.
7 changes: 7 additions & 0 deletions libs/common/include/commonDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ inline T checkedCast(T_Src* src)
return static_cast<T>(src);
}

template<typename T, typename T_Src>
inline T& checkedCast(T_Src& src)
{
RTTR_Assert(dynamic_cast<T*>(&src));
return static_cast<T&>(src);
}

// Fwd decl
namespace boost {
namespace filesystem {
Expand Down
57 changes: 57 additions & 0 deletions libs/s25main/AddonHelperFunctions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

#include "AddonHelperFunctions.h"
#include "GlobalGameSettings.h"
#include <LeatherLoader.h>
#include <WineLoader.h>
#include <addons/Addon.h>

std::function<bool(const BuildingType type)> makeIsUnusedBuilding(const GlobalGameSettings& ggs)
{
const bool wineAddonActive = ggs.isEnabled(AddonId::WINE);
const bool charburnerAddonActive = ggs.isEnabled(AddonId::CHARBURNER);
const bool leatherAddonActive = ggs.isEnabled(AddonId::LEATHER);

return [wineAddonActive, charburnerAddonActive, leatherAddonActive](BuildingType const& bld) {
if(!wineAddonActive && wineaddon::isWineAddonBuildingType(bld))
return true;
if(!charburnerAddonActive && bld == BuildingType::Charburner)
return true;
if(!leatherAddonActive && leatheraddon::isLeatherAddonBuildingType(bld))
return true;
return false;
};
}

std::function<bool(const GoodType type)> makeIsUnusedWare(const GlobalGameSettings& ggs)
{
const bool wineAddonActive = ggs.isEnabled(AddonId::WINE);
const bool leatherAddonActive = ggs.isEnabled(AddonId::LEATHER);

return [wineAddonActive, leatherAddonActive](GoodType const& type) {
if(!wineAddonActive && wineaddon::isWineAddonGoodType(type))
return true;
if(!leatherAddonActive && leatheraddon::isLeatherAddonGoodType(type))
return true;
return false;
};
}

std::function<bool(const Job job)> makeIsUnusedJob(const GlobalGameSettings& ggs)
{
const bool wineAddonActive = ggs.isEnabled(AddonId::WINE);
const bool charburnerAddonActive = ggs.isEnabled(AddonId::CHARBURNER);
const bool leatherAddonActive = ggs.isEnabled(AddonId::LEATHER);

return [wineAddonActive, charburnerAddonActive, leatherAddonActive](Job const& job) {
if(!wineAddonActive && wineaddon::isWineAddonJobType(job))
return true;
if(!charburnerAddonActive && job == Job::CharBurner)
return true;
if(!leatherAddonActive && leatheraddon::isLeatherAddonJobType(job))
return true;
return false;
};
}
31 changes: 31 additions & 0 deletions libs/s25main/AddonHelperFunctions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "gameTypes/BuildingType.h"
#include "gameTypes/GoodTypes.h"
#include "gameTypes/JobTypes.h"
#include <functional>

class GlobalGameSettings;

std::function<bool(const BuildingType type)> makeIsUnusedBuilding(const GlobalGameSettings& ggs);
std::function<bool(const GoodType type)> makeIsUnusedWare(const GlobalGameSettings& ggs);
std::function<bool(const Job job)> makeIsUnusedJob(const GlobalGameSettings& ggs);

// Only used for deserialization, can be removed when breaking compatibility (GetGameDataVersion)
constexpr auto numLeatherAddonBuildings = 3u;
constexpr auto numWineAddonBuildings = 3u;
constexpr auto numWineAndLeatherAddonBuildings = numWineAddonBuildings + numLeatherAddonBuildings;

constexpr auto numLeatherAddonGoods = 3u;
constexpr auto numWineAddonGoods = 2u;
constexpr auto numWineAndLeatherAddonGoods = numWineAddonGoods + numLeatherAddonGoods;

constexpr auto numLeatherAddonJobs = 3u;
constexpr auto numWineAddonJobs = 3u;
constexpr auto numWineAndLeatherAddonJobs = numWineAddonJobs + numLeatherAddonJobs;

constexpr uint8_t transportPrioOfLeatherworks = 7;
4 changes: 4 additions & 0 deletions libs/s25main/BuildingRegister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include "BuildingRegister.h"
#include "LeatherLoader.h"
#include "SerializedGameData.h"
#include "WineLoader.h"
#include "buildings/noBuildingSite.h"
Expand Down Expand Up @@ -41,6 +42,9 @@ void BuildingRegister::Deserialize(SerializedGameData& sgd)
if(sgd.GetGameDataVersion() < 11 && wineaddon::isWineAddonBuildingType(bld))
continue;

if(sgd.GetGameDataVersion() < 12 && leatheraddon::isLeatherAddonBuildingType(bld))
continue;

if(BuildingProperties::IsUsual(bld))
sgd.PopObjectContainer(buildings[bld], GO_Type::NobUsual);
}
Expand Down
5 changes: 4 additions & 1 deletion libs/s25main/GameCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ namespace gc {
unsigned Deserializer::getCurrentVersion()
{
// 1: Add wine addon --> 3 new values in distribution
return 1;
// 2: Add leather addon --> 3 new values in distribution, 1 new value in transport order and transport order default
// values changed, 3 new values in custom build order, 3 new jobs/wares in setAllInventory settings
return 2;
}

GameCommandPtr GameCommand::Deserialize(Deserializer& ser)
Expand All @@ -37,6 +39,7 @@ GameCommandPtr GameCommand::Deserialize(Deserializer& ser)
case GCType::Attack: gc = new Attack(ser); break;
case GCType::SeaAttack: gc = new SeaAttack(ser); break;
case GCType::SetCoinsAllowed: gc = new SetCoinsAllowed(ser); break;
case GCType::SetArmorAllowed: gc = new SetArmorAllowed(ser); break;
case GCType::SetProductionEnabled: gc = new SetProductionEnabled(ser); break;
case GCType::SetInventorySetting: gc = new SetInventorySetting(ser); break;
case GCType::SetAllInventorySettings: gc = new SetAllInventorySettings(ser); break;
Expand Down
3 changes: 2 additions & 1 deletion libs/s25main/GameCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ enum class GCType : uint8_t
SetTroopLimit,
NotifyAlliesOfLocation,
SetTempleProductionMode,
SetArmorAllowed,
};
constexpr auto maxEnumValue(GCType)
{
return GCType::SetTempleProductionMode;
return GCType::SetArmorAllowed;
}

class GameCommand
Expand Down
141 changes: 134 additions & 7 deletions libs/s25main/GameCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include "GameCommands.h"
#include "AddonHelperFunctions.h"
#include "GamePlayer.h"
#include "LeatherLoader.h"
#include "WineLoader.h"
#include "buildings/nobBaseWarehouse.h"
#include "buildings/nobHarborBuilding.h"
Expand All @@ -16,6 +18,7 @@
#include "world/GameWorld.h"
#include "nodeObjs/noFlag.h"
#include "nodeObjs/noShip.h"
#include "gameData/SettingTypeConv.h"
#include <algorithm>
#include <stdexcept>

Expand Down Expand Up @@ -90,19 +93,43 @@ void UpgradeRoad::Execute(GameWorld& world, uint8_t playerId)

ChangeDistribution::ChangeDistribution(Deserializer& ser) : GameCommand(GCType::ChangeDistribution)
{
if(ser.getDataVersion() >= 1)
if(ser.getDataVersion() >= 2)
helpers::popContainer(ser, data);
else
{
std::array<Distributions::value_type,
std::tuple_size_v<Distributions> - 3> tmpData; // 3 entries for wine addon
helpers::popContainer(ser, tmpData);
const unsigned wineAddonAdditionalDistributions = 3;
const unsigned leatherAddonAdditionalDistributions = 3;

auto const numNotSavedDistributions =
leatherAddonAdditionalDistributions + (ser.getDataVersion() < 1 ? wineAddonAdditionalDistributions : 0);

std::vector<Distributions::value_type> tmpData(std::tuple_size_v<Distributions> - numNotSavedDistributions);

auto getSkipBuildingAndDefault = [&](DistributionMapping const& mapping) {
// Skipped and standard distribution in skipped case
std::tuple<bool, unsigned int> result = {false, 0};
if(ser.getDataVersion() < 1)
{
// skip over wine buildings
std::get<0>(result) |= wineaddon::isWineAddonBuildingType(std::get<BuildingType>(mapping));
}

// skip over leather addon buildings and leather addon wares only
std::get<0>(result) |= leatheraddon::isLeatherAddonBuildingType(std::get<BuildingType>(mapping));

if(std::get<BuildingType>(mapping) == BuildingType::Slaughterhouse
&& (std::get<GoodType>(mapping) == GoodType::Ham))
result = {true, 8};
return result;
};

helpers::popContainer(ser, tmpData, true);
size_t srcIdx = 0, tgtIdx = 0;
for(const auto& mapping : distributionMap)
{
// skip over wine buildings in tmpData
const auto setting =
wineaddon::isWineAddonBuildingType(std::get<BuildingType>(mapping)) ? 0 : tmpData[srcIdx++];
// skip over not stored buildings in tmpData
const auto [skipped, defaultValue] = getSkipBuildingAndDefault(mapping);
const auto setting = skipped ? defaultValue : tmpData[srcIdx++];
data[tgtIdx++] = setting;
}
}
Expand All @@ -113,6 +140,33 @@ void ChangeDistribution::Execute(GameWorld& world, uint8_t playerId)
world.GetPlayer(playerId).ChangeDistribution(data);
}

ChangeBuildOrder::ChangeBuildOrder(Deserializer& ser)
: GameCommand(GCType::ChangeBuildOrder), useCustomBuildOrder(ser.PopBool())
{
if(ser.getDataVersion() >= 2)
{
for(BuildingType& i : data)
i = helpers::popEnum<BuildingType>(ser);
} else
{
auto countOfNotAvailableBuildingsInSaveGame =
ser.getDataVersion() < 1 ? numWineAndLeatherAddonBuildings : numLeatherAddonBuildings;
std::vector<BuildingType> buildOrder(data.size() - countOfNotAvailableBuildingsInSaveGame);

if(ser.getDataVersion() < 1)
buildOrder.insert(buildOrder.end(), {BuildingType::Vineyard, BuildingType::Winery, BuildingType::Temple});

if(ser.getDataVersion() < 2)
buildOrder.insert(buildOrder.end(),
{BuildingType::Skinner, BuildingType::Tannery, BuildingType::LeatherWorks});

std::generate(buildOrder.begin(), buildOrder.end() - countOfNotAvailableBuildingsInSaveGame,
[&]() { return helpers::popEnum<BuildingType>(ser); });

std::copy(buildOrder.begin(), buildOrder.end(), data.begin());
}
}

void ChangeBuildOrder::Execute(GameWorld& world, uint8_t playerId)
{
world.GetPlayer(playerId).ChangeBuildOrder(useCustomBuildOrder, data);
Expand All @@ -128,6 +182,27 @@ void DestroyBuilding::Execute(GameWorld& world, uint8_t playerId)
world.DestroyBuilding(pt_, playerId);
}

ChangeTransport::ChangeTransport(Deserializer& ser) : GameCommand(GCType::ChangeTransport)
{
if(ser.getDataVersion() >= 2)
helpers::popContainer(ser, data);
else
{
const unsigned leatherAddonAdditionalTransportOrders = 1;
std::vector<TransportOrders::value_type> tmpData(std::tuple_size<TransportOrders>::value
- leatherAddonAdditionalTransportOrders);

helpers::popContainer(ser, tmpData, true);
std::copy(tmpData.begin(), tmpData.end(), data.begin());
// all transport prios greater equal transportPrioOfLeatherworks are increased by one because the new
// leatherwork uses prio transportPrioOfLeatherworks
std::transform(data.begin(), data.end() - leatherAddonAdditionalTransportOrders, data.begin(),
[](uint8_t& prio) { return prio < transportPrioOfLeatherworks ? prio : prio + 1; });
data[std::tuple_size<TransportOrders>::value - leatherAddonAdditionalTransportOrders] =
STD_TRANSPORT_PRIO[GoodType::Leather];
}
}

void ChangeTransport::Execute(GameWorld& world, uint8_t playerId)
{
world.GetPlayer(playerId).ConvertTransportData(data);
Expand Down Expand Up @@ -172,6 +247,13 @@ void SetCoinsAllowed::Execute(GameWorld& world, uint8_t playerId)
bld->SetCoinsAllowed(enabled);
}

void SetArmorAllowed::Execute(GameWorld& world, uint8_t playerId)
{
auto* const bld = world.GetSpecObj<nobMilitary>(pt_);
if(bld && bld->GetPlayer() == playerId)
bld->SetArmorAllowed(enabled);
}

void SetTroopLimit::Execute(GameWorld& world, uint8_t playerId)
{
auto* const bld = world.GetSpecObj<nobMilitary>(pt_);
Expand All @@ -193,6 +275,51 @@ void SetInventorySetting::Execute(GameWorld& world, uint8_t playerId)
bld->SetInventorySetting(what, state);
}

SetAllInventorySettings::SetAllInventorySettings(Deserializer& ser)
: Coords(GCType::SetAllInventorySettings, ser), isJob(ser.PopBool())
{
const uint32_t numStates = (isJob ? helpers::NumEnumValues_v<Job> : helpers::NumEnumValues_v<GoodType>);
if(ser.getDataVersion() >= 2)
{
for(unsigned i = 0; i < numStates; i++)
states.push_back(InventorySetting(ser.PopUnsignedChar()));
} else
{
states.resize(numStates);
if(isJob)
{
auto isJobSkipped = [&](Job const& job) {
return (ser.getDataVersion() < 1 && wineaddon::isWineAddonJobType(job))
|| leatheraddon::isLeatherAddonJobType(job);
};

size_t tgtIdx = 0;
for(const auto i : helpers::enumRange<Job>())
{
// skip over not stored jobs
if(!isJobSkipped(i))
states[tgtIdx] = InventorySetting(ser.PopUnsignedChar());
tgtIdx++;
}
} else
{
auto isWareSkipped = [&](GoodType const& ware) {
return (ser.getDataVersion() < 1 && wineaddon::isWineAddonGoodType(ware))
|| leatheraddon::isLeatherAddonGoodType(ware);
};

size_t tgtIdx = 0;
for(const auto i : helpers::enumRange<GoodType>())
{
// skip over not stored wares
if(!isWareSkipped(i))
states[tgtIdx] = InventorySetting(ser.PopUnsignedChar());
tgtIdx++;
}
}
}
}

void SetAllInventorySettings::Execute(GameWorld& world, uint8_t playerId)
{
auto* const bld = world.GetSpecObj<nobBaseWarehouse>(pt_);
Expand Down
Loading
Loading