Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public enum GuildModifier {
TRADE_UPKEEP("#d6645aTrade Upkeep", false),
PRODUCTION("#f2c94cProduction", true),
INFRASTRUCTURE("#86d1b0Infrastructure", true),
INFRASTRUCTURE_UPKEEP("#86d1b0Infrastructure Upkeep", false),
TRADE_CARRY("#86d1b0Trade Carry", true),
HUB_LIMIT("#c99b70Supply Hub Limit", true),
HUB_UPKEEP("#d6645aSupply Hub Upkeep", false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public Guild(GuildData data, Faction host) {
);
}
}
BranchLoader.replaceDisallowedBranches(branches, type);
int group = 0;
while(group < 10) {
if(!this.branches.containsKey(group)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ public static double estimate(
ProvinceManager after = copy(prepared.snapshot);
double baseline = income(before, guild, current);
double changed = income(after, guild, hypothetical);
double net = (changed - baseline) * (1.0 - taxFraction);
double upkeepChange = Math.max(0.0, hypothetical.getOrDefault(GuildModifier.INFRASTRUCTURE_UPKEEP, 0.0))
- Math.max(0.0, current.getOrDefault(GuildModifier.INFRASTRUCTURE_UPKEEP, 0.0));
double net = (changed - baseline) * (1.0 - taxFraction) - upkeepChange;
return Math.round(net * 100.0) / 100.0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public enum Cashflow {
VEHICLE_UPKEEP("#a6659fVehicle Upkeep", true, false),
MILITARY_UPKEEP("#a6659fMilitary Upkeep", true, false),
NODES("#8a7a5cNodes", true, false),
SUPPLY_HUBS("#b5835aSupply hubs", true, false);
SUPPLY_HUBS("#b5835aSupply hubs", true, false),
INFRASTRUCTURE_UPKEEP("#86d1b0Infrastructure", true, false);

private final String display;
private final boolean affectsInflation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import net.tfminecraft.simplefactions.SimpleFactions;
import net.tfminecraft.simplefactions.guild.Guild;
import net.tfminecraft.simplefactions.guild.GuildModifierOverride;
import net.tfminecraft.simplefactions.guild.hub.SupplyHub;
import net.tfminecraft.simplefactions.guild.hub.HubTaxBreakdown;
import net.tfminecraft.simplefactions.guild.hub.SupplyHubCommands;
Expand All @@ -33,6 +34,7 @@
import net.tfminecraft.simplefactions.utils.Formatter;
import net.tfminecraft.simplefactions.utils.PostSettlementPayouts.PlayerUuidLookup;
import net.tfminecraft.simplefactions.enums.FactionModifiers;
import net.tfminecraft.simplefactions.enums.GuildModifier;
import net.tfminecraft.simplefactions.enums.Rules;
import net.tfminecraft.simplefactions.government.proposal.TaxTarget;
import net.tfminecraft.simplefactions.mercenary.company.MercenaryCompany;
Expand Down Expand Up @@ -363,6 +365,9 @@ public double getIncome(Cashflow cashflow) {
case SUPPLY_HUBS:
amount = -SupplyHubService.dailyCost(guild);
break;
case INFRASTRUCTURE_UPKEEP:
amount = -Math.max(0, GuildModifierOverride.resolve(guild, GuildModifier.INFRASTRUCTURE_UPKEEP));
break;
//Mercenary contracts
case MERCENARY_CONTRACT:
amount = getAggregatedContractEarnings();
Expand Down Expand Up @@ -556,6 +561,7 @@ public double getNetIncome() {
case MILITARY_UPKEEP:
case NODES:
case SUPPLY_HUBS:
case INFRASTRUCTURE_UPKEEP:
case PENALTIES:
case GUILD_PAYMENTS:
case OVERLORD_TAX:
Expand Down Expand Up @@ -632,6 +638,7 @@ public double getDividendBase() {
case MILITARY_UPKEEP:
case NODES:
case SUPPLY_HUBS:
case INFRASTRUCTURE_UPKEEP:
case PENALTIES:
case GUILD_PAYMENTS:
case OVERLORD_TAX:
Expand Down Expand Up @@ -1048,6 +1055,7 @@ private void applySettlementFor(Cashflow cf, DailyGuildTransfers buffer) {
case NODES:
// Supply hubs are a sink. Unpaid hubs were already removed, newest first.
case SUPPLY_HUBS:
case INFRASTRUCTURE_UPKEEP:
buffer.addExternalDelta(guild, getIncome(cf));
return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import net.tfminecraft.simplefactions.guild.branch.Branch;
import net.tfminecraft.simplefactions.guild.Guild;
import net.tfminecraft.simplefactions.guild.GuildType;

public class BranchLoader {
public static Map<String, Branch> map = new HashMap<>();
Expand All @@ -38,12 +39,25 @@ public static Branch getByString(String id) {
return null;
}
public static Branch getByGroup(Guild guild, int group) {
return getByGroup(guild.getType(), group);
}
public static Branch getByGroup(GuildType type, int group) {
for(Branch b : getList()) {
if(b.getGroup() != group) continue;
if(b.isAllowed(guild.getType())) return b;
if(b.isAllowed(type)) return b;
}
return null;
}
public static void replaceDisallowedBranches(Map<Integer, Branch> branches, GuildType type) {
for (Branch branch : branches.values()) {
if (!branch.isAllowed(type)) {
Branch replacement = getByGroup(type, branch.getGroup());
if (replacement != null) {
branches.put(branch.getGroup(), new Branch(replacement, branch.getLevel()));
}
}
}
}
public void load(File configFile) {
FileConfiguration config = new YamlConfiguration();
try {
Expand Down
24 changes: 22 additions & 2 deletions src/main/resources/Guilds/branches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ bureaucracy:
- trade_power 1 0.5
- production 4 0.5
- trade_upkeep 0 0.03
- infrastructure 0 0.1
- prestige 0 5
- prestige_bonus 0 0.5
guild_halls:
Expand Down Expand Up @@ -78,12 +79,31 @@ supply_lines:
- "#d4c9aeEach hub costs more to run."
allowed-types:
- guild
- realm
modifiers:
- hub_limit 2 0.5
- hub_trade 0 0.05
- hub_production 0 0.08
- hub_upkeep 2 0.5
- hub_upkeep 1 0.5
- trade_upkeep 0 0.01
- prestige 0 5
infrastructure:
name: "#86d1b0Infrastructure"
icon: "rail.0"
group: 3
description:
- "#86d1b0Infrastructure #d4c9aeimproves poor"
- "#d4c9aeland in the realm for every guild,"
- "#d4c9aestarting at the capital. Hubs come"
- "#d4c9aemore slowly; each level costs daily upkeep."
allowed-types:
- realm
modifiers:
- infrastructure 0 2
- infrastructure_upkeep 0 1
- hub_limit 2 0.25
- hub_trade 0 0.05
- hub_production 0 0.08
- hub_upkeep 1 0.5
- trade_upkeep 0 0.01
- prestige 0 5
counting_houses:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import net.tfminecraft.simplefactions.database.JsonUtil;
import net.tfminecraft.simplefactions.database.SupplyHubData;
import net.tfminecraft.simplefactions.guild.Guild;
import net.tfminecraft.simplefactions.guild.branch.Branch;
import net.tfminecraft.simplefactions.enums.GuildModifier;
import net.tfminecraft.simplefactions.enums.Rules;
import net.tfminecraft.simplefactions.guild.hub.SupplyHubService.BuildFailure;
Expand Down Expand Up @@ -422,6 +423,57 @@ void ledger_supplyHubsIsItsOwnSinkLine() {
assertEquals(-30.0, ledger.getNetIncome(), 1e-9);
}

@Test
void infrastructureHubLimitFloorsTheFractionalLevels() {
YamlConfiguration yaml = new YamlConfiguration();
yaml.set("group", 3);
yaml.set("modifiers", List.of("HUB_LIMIT 2 0.25"));
Branch prototype = new Branch("infrastructure", yaml);
for (int level : List.of(0, 3, 4, 8)) {
Guild guild = mock(Guild.class);
when(guild.getModifier(GuildModifier.HUB_LIMIT))
.thenReturn(new Branch(prototype, level).getAmount(GuildModifier.HUB_LIMIT));
int expected = level < 4 ? 2 : level < 8 ? 3 : 4;
assertEquals(expected, SupplyHubService.limit(guild));
}
}

@Test
void supplyLinesHubLimitAddsOneHubEveryTwoLevels() {
YamlConfiguration yaml = new YamlConfiguration();
yaml.set("group", 3);
yaml.set("modifiers", List.of("HUB_LIMIT 2 0.5"));
Branch prototype = new Branch("supply_lines", yaml);
for (int level : List.of(0, 2, 4)) {
Guild guild = mock(Guild.class);
when(guild.getModifier(GuildModifier.HUB_LIMIT))
.thenReturn(new Branch(prototype, level).getAmount(GuildModifier.HUB_LIMIT));
assertEquals(2 + level / 2, SupplyHubService.limit(guild));
}
}

@Test
void ledger_infrastructureUpkeepIsShownAndSettledWithoutShedding() {
Guild guild = mock(Guild.class);
Faction faction = mock(Faction.class);
Bank bank = mock(Bank.class);
when(bank.getWealth()).thenReturn(0.0);
when(guild.getModifier(GuildModifier.INFRASTRUCTURE_UPKEEP)).thenReturn(4.0);
Ledger ledger = ledger(faction, guild, bank);

assertTrue(Cashflow.INFRASTRUCTURE_UPKEEP.getDisplay().contains("Infrastructure"));
assertEquals(-4.0, ledger.getIncome(Cashflow.INFRASTRUCTURE_UPKEEP), 1e-9);
assertEquals(-4.0, ledger.getNetIncome(), 1e-9);
DailyGuildTransfers buffer = new DailyGuildTransfers();
ledger.populateDailyTransfers(buffer);
assertEquals(-4.0, buffer.getExternalDeltas().get(guild), 1e-9);

Guild withoutInfrastructure = mock(Guild.class);
when(withoutInfrastructure.getModifier(GuildModifier.INFRASTRUCTURE_UPKEEP)).thenReturn(0.0);
Ledger noInfrastructureLedger = ledger(faction, withoutInfrastructure, bank);
assertEquals(0.0, noInfrastructureLedger.getIncome(Cashflow.INFRASTRUCTURE_UPKEEP), 1e-9);
}

@Test
void ledger_removesEveryHubWhenNoneCanBePaid() {
Guild guild = mock(Guild.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ void concurrentPreviewsStayOnTheirOwnModifiers() throws Exception {
}

@Test
void branchPreviewUsesHypotheticalHubTradeLevel() {
void branchPreviewUsesHypotheticalHubTradeLevel() {
HubNetwork.setLinksForTests(Map.of("fields", List.of(
new Link(capital.getId(), neighbour.getId(), Mode.RAIL, 0, 0.9, 0))));
YamlConfiguration yaml = new YamlConfiguration();
Expand All @@ -183,6 +183,19 @@ void branchPreviewUsesHypotheticalHubTradeLevel() {
Branch supplyLines = new Branch(new Branch("supply_lines", yaml), 0);

assertTrue(live.previewUpgradeIncomeExact(guild, supplyLines) > 0);
assertEquals(0, supplyLines.getLevel());
}
assertEquals(0, supplyLines.getLevel());
}

@Test
void branchPreviewIncludesInfrastructureUpkeepChange() {
YamlConfiguration yaml = new YamlConfiguration();
yaml.set("group", 3);
yaml.set("modifiers", List.of("INFRASTRUCTURE_UPKEEP 0 1"));
Branch infrastructure = new Branch(new Branch("infrastructure", yaml), 2);
when(guild.getModifier(GuildModifier.INFRASTRUCTURE_UPKEEP)).thenReturn(2.0);

assertEquals(-1.0, live.previewUpgradeIncomeExact(guild, infrastructure));
assertEquals(1.0, live.previewDowngradeIncomeExact(guild, infrastructure));
assertEquals(2, infrastructure.getLevel());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void bundledBranchesLoadForGuildsAndRealms() {
YamlConfiguration types = new YamlConfiguration();
types.set("guild.name", "Guild");
types.set("realm.name", "Realm");
types.set("realm.base", true);
GuildLoader.map.put("guild", new GuildType("guild", types.getConfigurationSection("guild")));
GuildLoader.map.put("realm", new GuildType("realm", types.getConfigurationSection("realm")));

Expand All @@ -63,28 +64,77 @@ void bundledBranchesLoadForGuildsAndRealms() {
assertNotNull(freightGuild);
assertNotNull(freightRealm);
assertEquals("supply_lines", supplyGuild.getId());
assertEquals("infrastructure", supplyRealm.getId());
assertEquals("counting_houses", freightRealm.getId());
assertEquals(2.0, supplyGuild.getModifier(GuildModifier.HUB_LIMIT).getBase());
assertEquals(0.5, supplyGuild.getModifier(GuildModifier.HUB_LIMIT).getPerLevel());
assertEquals(0.05, supplyGuild.getModifier(GuildModifier.HUB_TRADE).getPerLevel());
assertEquals(0.08, supplyGuild.getModifier(GuildModifier.HUB_PRODUCTION).getPerLevel());
assertEquals(-0.01, freightRealm.getModifier(GuildModifier.TRADE_UPKEEP).getPerLevel());
assertEquals(2.0, supplyGuild.getModifier(GuildModifier.HUB_UPKEEP).getBase());
assertEquals(1.0, supplyGuild.getModifier(GuildModifier.HUB_UPKEEP).getBase());
assertEquals(0.5, supplyGuild.getModifier(GuildModifier.HUB_UPKEEP).getPerLevel());
Branch infrastructure = new Branch(BranchLoader.getByString("infrastructure"), 10);
assertEquals(20.0, infrastructure.getAmount(GuildModifier.INFRASTRUCTURE));
assertEquals(10.0, infrastructure.getAmount(GuildModifier.INFRASTRUCTURE_UPKEEP));
Branch bureaucracy = new Branch(BranchLoader.getByString("bureaucracy"), 5);
assertEquals(20.5, infrastructure.getAmount(GuildModifier.INFRASTRUCTURE)
+ bureaucracy.getAmount(GuildModifier.INFRASTRUCTURE));
Branch storehouses = new Branch(BranchLoader.getByString("storehouses"), 3);
Branch supplyLines = new Branch(BranchLoader.getByString("supply_lines"), 4);
assertEquals(0.70, storehouses.getAmount(GuildModifier.TRADE_CARRY));
assertEquals(0.09, storehouses.getAmount(GuildModifier.HUB_PRODUCTION));
assertNull(storehouses.getModifier(GuildModifier.HUB_UPKEEP));
assertEquals(2.0, supplyGuild.getAmount(GuildModifier.HUB_UPKEEP));
assertEquals(4.0, supplyLines.getAmount(GuildModifier.HUB_UPKEEP));
assertEquals(1.0, supplyGuild.getAmount(GuildModifier.HUB_UPKEEP));
assertEquals(3.0, supplyLines.getAmount(GuildModifier.HUB_UPKEEP));
Branch twoStorehouses = new Branch(BranchLoader.getByString("storehouses"), 2);
Branch fiveSupplyLines = new Branch(BranchLoader.getByString("supply_lines"), 5);
assertEquals(0.46, twoStorehouses.getAmount(GuildModifier.HUB_PRODUCTION)
+ fiveSupplyLines.getAmount(GuildModifier.HUB_PRODUCTION));
assertTrue(!supplyGuild.getDescription().isEmpty());
}

@Test
void savedBranchesMoveToTheAllowedBranchAtTheSameLevel() {
loadBundledBranches();
Branch supplyLines = new Branch(BranchLoader.getByString("supply_lines"), 3);
Map<Integer, Branch> realmBranches = new HashMap<>(Map.of(3, supplyLines));
Map<Integer, Branch> normalBranches = new HashMap<>(Map.of(3, supplyLines));
BranchLoader.replaceDisallowedBranches(realmBranches, GuildLoader.getByString("realm"));
BranchLoader.replaceDisallowedBranches(normalBranches, GuildLoader.getByString("guild"));

assertEquals("infrastructure", realmBranches.get(3).getId());
assertEquals(3, realmBranches.get(3).getLevel());
assertEquals("supply_lines", normalBranches.get(3).getId());
assertEquals(3, normalBranches.get(3).getLevel());

YamlConfiguration legacyConfig = new YamlConfiguration();
legacyConfig.set("name", "Supply Lines");
legacyConfig.set("group", 3);
legacyConfig.set("allowed-types", java.util.List.of("guild", "realm"));
BranchLoader.map.put("supply_lines", new Branch("supply_lines", legacyConfig));
Map<Integer, Branch> legacyRealmBranches = new HashMap<>(Map.of(3,
new Branch(BranchLoader.getByString("supply_lines"), 0)));
BranchLoader.replaceDisallowedBranches(legacyRealmBranches, GuildLoader.getByString("realm"));
assertEquals("supply_lines", legacyRealmBranches.get(3).getId());
assertEquals(0, legacyRealmBranches.get(3).getLevel());
}

private static void loadBundledBranches() {
YamlConfiguration types = new YamlConfiguration();
types.set("guild.name", "Guild");
types.set("realm.name", "Realm");
types.set("realm.base", true);
GuildLoader.map.clear();
GuildLoader.map.put("guild", new GuildType("guild", types.getConfigurationSection("guild")));
GuildLoader.map.put("realm", new GuildType("realm", types.getConfigurationSection("realm")));
YamlConfiguration config = YamlConfiguration.loadConfiguration(
new File("src/main/resources/Guilds/branches.yml"));
BranchLoader.map.clear();
for (String key : config.getKeys(false)) {
BranchLoader.map.put(key, new Branch(key, config.getConfigurationSection(key)));
}
}

@Test
void freightYardsResolvesToCountingHousesOnlyWhenNoExactBranchExists() {
Branch counting = new Branch("counting_houses", new YamlConfiguration().createSection("counting_houses"));
Expand Down
Loading