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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<rpcharacters.version>2.0.1</rpcharacters.version>
<tlibs.version>2.0.0</tlibs.version>
<vehicleframework.version>2.0.1</vehicleframework.version>
<vfbuilders.version>2.0.0</vfbuilders.version>
<vfbuilders.version>2.0.4</vfbuilders.version>
</properties>

<dependencies>
Expand Down
1 change: 1 addition & 0 deletions src/main/java/net/tfminecraft/simplefactions/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public static boolean requireProvinces(org.bukkit.command.CommandSender sender)
public static int warBattleVotingDevMinPlayers;
public static boolean warBattleVotingDevMinPlayersEnabled;
public static int warBattleVotingMaxPostponements = 1;
public static int warPostponeFreezeHours = 24;
public static double warAutoresolveLuck = 0.15;
public static double warAutoresolveLoserLossFraction = 0.5;
public static int warBattleLivesPerRegiment;
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/net/tfminecraft/simplefactions/SimpleFactions.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ public class SimpleFactions extends JavaPlugin{
vehicleMaintenancePaySessionManager,
vehicleMaintenancePayService);
private boolean vehicleIntegrationRegistered = false;
private boolean constructionFreezeRegistered;
private final PlayerEconomyManager playerEconomyManager = new PlayerEconomyManager();
private final VehicleUpkeepService vehicleUpkeepService = new VehicleUpkeepService(
vehicleRegistry,
Expand Down Expand Up @@ -582,10 +583,28 @@ public void onPluginEnable(PluginEnableEvent event) {
if ("VFBuilders".equalsIgnoreCase(event.getPlugin().getName())
|| "VehicleFramework".equalsIgnoreCase(event.getPlugin().getName())) {
registerVehicleIntegration();
registerConstructionFreeze();
}
}
}, this);
registerVehicleIntegration();
registerConstructionFreeze();
}

private void registerConstructionFreeze() {
if (constructionFreezeRegistered || !getServer().getPluginManager().isPluginEnabled("VFBuilders")) {
return;
}
constructionFreezeRegistered = true;
try {
Class.forName("net.tfminecraft.vfbuilders.api.ConstructionFreeze");
} catch (ClassNotFoundException | LinkageError e) {
// Loading VfBuildersConstructionFreeze would fail on a VFBuilders without this API.
getLogger().warning("VFBuilders has no ConstructionFreeze API; update it so vehicle "
+ "projects freeze with postponed battles");
return;
}
net.tfminecraft.simplefactions.war.freeze.VfBuildersConstructionFreeze.register(this);
}

private void registerVehicleIntegration() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public class WarData {
public boolean autoresolveProposedByAttacker;
public boolean autoresolveProposedByDefender;
public Integer postponementsThisCycle;
public String preparationFrozenUntil;
public boolean defenderChoiceResolved;
public String initiativeHolderCoalition;
public String pushTarget;
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/net/tfminecraft/simplefactions/guild/Guild.java
Original file line number Diff line number Diff line change
Expand Up @@ -314,13 +314,19 @@ public List<StabilityModifier> getPillageHits() {
}

public void tick() {
tickUpgradeQueue();
tick(false);
}

/** @param factionFrozen the host faction's battle was postponed; war-related upgrades hold */
public void tick(boolean factionFrozen) {
tickUpgradeQueue(factionFrozen);
if(company != null) company.tick();
}

private void tickUpgradeQueue() {
private void tickUpgradeQueue(boolean factionFrozen) {
if(upgradeQueue.size() == 0) return;
UpgradeExpansion e = upgradeQueue.get(0);
if(factionFrozen && e.getUpgrade().isWarRelated()) return;
e.tick();
if(e.getTimeLeft() != 0) return;
upgradeQueue.remove(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class Upgrade {
private int maxLevel;
private double upkeep;
private int expansionTime;
private boolean warRelated;
private List<GuildType> allowedTypes = new ArrayList<>();
private Map<GuildModifier, BranchModifier> modifiers = new HashMap<>();

Expand All @@ -42,6 +43,7 @@ public Upgrade(String key, ConfigurationSection config) {
level = 0;
maxLevel = config.getInt("max-level", Integer.MAX_VALUE);
expansionTime = config.getInt("expansion-time", 21600);
warRelated = config.getBoolean("war-related", false);
for(String s : config.getStringList("allowed-types")) {
GuildType type = GuildLoader.getByString(s);
if(type != null) allowedTypes.add(type);
Expand Down Expand Up @@ -78,6 +80,7 @@ public Upgrade(Upgrade b, int level) {
allowedTypes = b.allowedTypes;
modifiers = b.modifiers;
expansionTime = b.expansionTime;
warRelated = b.warRelated;
maxLevel = b.maxLevel;
this.description = b.description;
this.level = Math.min(level, maxLevel);
Expand All @@ -96,6 +99,8 @@ public boolean isAllowed(GuildType type) {
public int getLevel() { return level; }
public void setLevel(int level) { this.level = Math.min(level, maxLevel); }
public int getExpansionTime() { return expansionTime; }
/** War-related upgrades stop progressing while a postponed battle freezes the guild's faction. */
public boolean isWarRelated() { return warRelated; }
public int getMaxLevel() { return maxLevel; }
/** Guild upgrades leave max-level unset, so they are unbounded. */
public boolean hasMaxLevel() { return maxLevel != Integer.MAX_VALUE; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ public void loadWar(File warFile) {
Cache.warBattleVotingMaxPostponements = Math.max(
0,
config.getInt("war.battle_voting.max_postponements", 1));
Cache.warPostponeFreezeHours = Math.max(
0,
config.getInt("war.battle_voting.postpone_freeze_hours", 24));
double autoresolveLuck = config.getDouble("war.autoresolve.luck", 0.15);
if (autoresolveLuck < 0) {
autoresolveLuck = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.tfminecraft.simplefactions.managers.inventory;

import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -245,6 +246,9 @@ public ItemStack createSlotQueueItem(MilitaryExpansion expansion, int index, Gui
List<String> lore = new ArrayList<>();
if (index == 0) {
lore.add("搂7Time Left: 搂e" + TimeFormatter.formatTime(expansion.getTimeLeft()));
String frozen = PreparationFreeze.frozenLore(
PreparationFreeze.frozenUntil(guild.getCompany(), java.time.Instant.now()));
if (frozen != null) lore.add(frozen);
} else {
lore.add(StringFormatter.formatHex("#857e59Queued..."));
}
Expand Down Expand Up @@ -341,6 +345,9 @@ public ItemStack createUpgradeQueueItem(UpgradeExpansion expansion, int index, G
List<String> lore = new ArrayList<>();
if (index == 0) {
lore.add("搂7Time Left: 搂e" + TimeFormatter.formatTime(expansion.getTimeLeft()));
String frozen = PreparationFreeze.frozenLore(
PreparationFreeze.frozenUntil(guild.getCompany(), java.time.Instant.now()));
if (frozen != null) lore.add(frozen);
} else {
lore.add(StringFormatter.formatHex("#857e59Queued..."));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.tfminecraft.simplefactions.managers.inventory;

import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;
import net.tfminecraft.simplefactions.util.LegacyModelData;

import java.util.ArrayList;
Expand Down Expand Up @@ -777,6 +778,10 @@ public ItemStack createUpgradeQueueItem(UpgradeExpansion expansion, int index, G
List<String> lore = new ArrayList<>();
if(index == 0) {
lore.add("搂7Time Left: 搂e" + TimeFormatter.formatTime(expansion.getTimeLeft()));
if(expansion.getUpgrade().isWarRelated()) {
String frozen = PreparationFreeze.frozenLore(PreparationFreeze.frozenUntil(guild.getFaction(), java.time.Instant.now()));
if(frozen != null) lore.add(frozen);
}
} else {
lore.add(StringFormatter.formatHex("#857e59Queued..."));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.tfminecraft.simplefactions.managers.inventory;

import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -85,6 +86,8 @@ public ItemStack createConstructionIcon(InstallationConstruction construction, F
lore.add("搂7Province: 搂e" + construction.getProvince());
lore.add("搂7Coords: 搂e" + construction.getCenterX() + ", " + construction.getCenterZ());
lore.add("搂7Time left: 搂e" + TimeFormatter.formatTime(construction.getTimeLeft()));
String frozen = PreparationFreeze.frozenLore(PreparationFreeze.frozenUntil(faction, java.time.Instant.now()));
if (frozen != null) lore.add(frozen);
lore.add("搂cClick to cancel");
meta.setLore(lore);
meta.getPersistentDataContainer()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.tfminecraft.simplefactions.managers.inventory;

import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -56,6 +57,8 @@ public ItemStack createQueueItem(MilitaryExpansion e, int x, Faction f) {
List<String> lore = new ArrayList<String>();
if(x == 0) {
lore.add("搂7Time Left: 搂e"+TimeFormatter.formatTime(e.getTimeLeft()));
String frozen = PreparationFreeze.frozenLore(PreparationFreeze.frozenUntil(f, java.time.Instant.now()));
if(frozen != null) lore.add(frozen);
} else {
lore.add(StringFormatter.formatHex("#857e59Queued..."));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import net.tfminecraft.simplefactions.mercenary.contract.ContractTerminationService;
import net.tfminecraft.simplefactions.mercenary.contract.MercenaryContract;
import net.tfminecraft.simplefactions.mercenary.contract.TerminationReason;
import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;

/**
* A mercenary company owned by a guild. The company holds its own regiment, so
Expand Down Expand Up @@ -530,6 +531,19 @@ public double getNetPosition() {

public void tick() {
if (enforceCharacterGate()) return;
if (!PreparationFreeze.isFrozen(this)) {
tickGrowth();
}
if (formationRemaining > 0) return;
long now = System.currentTimeMillis();
if (!contractHandler.tickExpiry().isEmpty()
|| !contractHandler.tickAmendments(now).isEmpty()) {
chime(SFGUI.CONTRACT_LIST_VIEW);
}
}

/** Formation, slot and upgrade timers; a postponed battle holds all three. */
private void tickGrowth() {
if (formationRemaining > 0) {
formationRemaining--;
if (formationRemaining == 0 && regiment != null) {
Expand All @@ -541,11 +555,6 @@ public void tick() {
}
tickSlotQueue();
tickUpgradeQueue();
long now = System.currentTimeMillis();
if (!contractHandler.tickExpiry().isEmpty()
|| !contractHandler.tickAmendments(now).isEmpty()) {
chime(SFGUI.CONTRACT_LIST_VIEW);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.tfminecraft.simplefactions.mercenary.contract;

import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -13,6 +14,7 @@
import net.tfminecraft.simplefactions.utils.Formatter;
import net.tfminecraft.simplefactions.mercenary.MercenaryResult;
import net.tfminecraft.simplefactions.mercenary.company.MercenaryCompany;
import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;

/**
* The contracts a company holds, in the shape of
Expand Down Expand Up @@ -120,6 +122,13 @@ public Offer offer(Faction hirer, ContractKind kind, ContractTerms terms, long n
if (hirer == null) {
return new Offer(MercenaryResult.deny("That faction no longer exists."), null);
}
Instant at = Instant.ofEpochMilli(now);
Instant frozenUntil = PreparationFreeze.frozenUntil(hirer, at);
if (frozenUntil != null) {
return new Offer(MercenaryResult.deny(hirer.getName()
+ " had a battle postponed and cannot hire mercenaries for "
+ PreparationFreeze.formatRemaining(frozenUntil, at) + "."), null);
}
MercenaryResult valid = ContractValidator.validate(terms, company, now);
if (!valid.ok()) return new Offer(valid, null);

Expand Down Expand Up @@ -155,6 +164,10 @@ public MercenaryResult accept(String contractId, Faction hirer, String signer) {
if (hirer.getGovernment() == null || !hirer.getGovernment().isCouncilMember(signer)) {
return MercenaryResult.deny("Only a member of your government may sign a contract.");
}
String frozen = PreparationFreeze.hiringBlockedMessage(hirer, Instant.now());
if (frozen != null) {
return MercenaryResult.deny(frozen);
}
MercenaryResult loyal = MercenaryLoyalty.canServe(company, hirer);
if (!loyal.ok()) {
expire(contract);
Expand Down Expand Up @@ -284,6 +297,12 @@ public MercenaryResult acceptSlots(String contractId, Faction hirer, String sign
return MercenaryResult.deny("A battle is underway. Accept the slot change when it ends.");
}
int slots = contract.getPendingSlots(now);
if (slots > contract.getSlots()) {
String frozen = PreparationFreeze.hiringBlockedMessage(hirer, Instant.ofEpochMilli(now));
if (frozen != null) {
return MercenaryResult.deny(frozen);
}
}
if (slots > SlotReservations.maxForAmendment(company, contract, now)) {
contract.clearPendingSlots();
tell(company.getLeader(), "搂cThe slot change on your contract with "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import net.tfminecraft.simplefactions.laws.LawGroup;
import net.tfminecraft.simplefactions.installation.InstallationTransferService;
import net.tfminecraft.simplefactions.installation.handler.InstallationHandler;
import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;
import net.tfminecraft.simplefactions.settlement.handler.SettlementHandler;
import net.tfminecraft.tlibs.objects.api.subapi.StringFormatter;

Expand Down Expand Up @@ -428,10 +429,13 @@ public void tick() {
double tax = getTotalForeignTaxRate();
if(getTaxRate() + tax > 100) setTaxRate(100-tax);

military.tick();
installationHandler.tick();
boolean frozen = PreparationFreeze.isFrozen(this);
if (!frozen) {
military.tick();
installationHandler.tick();
}
for(Guild guild : guildHandler.getGuilds()) {
guild.tick();
guild.tick(frozen);
}
/*
for(FactionModifier m : getModifiers()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import net.tfminecraft.simplefactions.objects.Faction;
import net.tfminecraft.simplefactions.war.core.Side;
import net.tfminecraft.simplefactions.war.core.War;
import net.tfminecraft.simplefactions.war.freeze.PreparationFreeze;
import net.tfminecraft.simplefactions.war.battle.campaign.CampaignBattleLaunchService;
import net.tfminecraft.simplefactions.war.enums.BattleSchedulePhase;
import net.tfminecraft.simplefactions.war.campaign.progression.BelligerentRole;
Expand Down Expand Up @@ -157,13 +158,13 @@ public static BattleScheduleCloseResult closeVote(

int maxPostponements = Math.max(0, Cache.warBattleVotingMaxPostponements);
if (war.getPostponementsThisCycle() < maxPostponements) {
postpone(war);
postpone(war, now);
return BattleScheduleCloseResult.POSTPONED;
}
if (BattleAutoresolveService.resolve(war)) {
return BattleScheduleCloseResult.AUTORESOLVED;
}
postpone(war);
postpone(war, now);
return BattleScheduleCloseResult.POSTPONED;
}

Expand Down Expand Up @@ -233,6 +234,10 @@ public static int castSpoofVotes(
}

public static void postpone(War war) {
postpone(war, Instant.now());
}

public static void postpone(War war, Instant now) {
if (war == null || war.getBattleDay() == null) {
return;
}
Expand All @@ -246,15 +251,21 @@ public static void postpone(War war) {
clearScheduledTargets(war);
war.setPostponementsThisCycle(war.getPostponementsThisCycle() + 1);
war.setDefenderChoiceResolved(false);
PreparationFreeze.applyPostponement(war, now);
}

public static void skipBattleDay(War war) {
skipBattleDay(war, Instant.now());
}

public static void skipBattleDay(War war, Instant now) {
if (war == null || war.getBattleDay() == null) {
return;
}
war.setBattleDay(war.getBattleDay().plusDays(1));
BattleInstallationPickService.clearForNewBattleDay(war);
CampaignRaidService.clearForNewBattleDay(war);
PreparationFreeze.applyPostponement(war, now);
}

public static Integer resolveBattleProvinceId(War war) {
Expand Down
Loading