Skip to content

Commit

Permalink
Battle Commanders / Mobile Spawn Points (#856)
Browse files Browse the repository at this point in the history
* Added battle commanders feature

---------

Authored-by: Goosius1 <[email protected]>
  • Loading branch information
Goosius1 authored Jul 6, 2023
1 parent 06bd28d commit 1a6f996
Show file tree
Hide file tree
Showing 14 changed files with 274 additions and 8 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<java.version>1.8</java.version>
<project.bukkitAPIVersion>1.13</project.bukkitAPIVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<towny.version>0.99.1.0</towny.version>
<towny.version>0.99.3.0</towny.version>
</properties>

<repositories>
Expand Down Expand Up @@ -45,7 +45,7 @@
<dependency>
<groupId>com.palmergames.bukkit.towny</groupId>
<artifactId>towny</artifactId>
<version>0.99.1.0</version>
<version>0.99.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/gmail/goosius/siegewar/SiegeWar.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
public class SiegeWar extends JavaPlugin {

private static SiegeWar plugin;
private final String requiredTownyVersion = "0.99.1.0";
private final String requiredTownyVersion = "0.99.3.0";
private static final SiegeHUDManager siegeHUDManager = new SiegeHUDManager();
private final Object scheduler;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.gmail.goosius.siegewar.utils.BossBarUtil;
import com.gmail.goosius.siegewar.utils.CosmeticUtil;
import com.gmail.goosius.siegewar.utils.SiegeWarMoneyUtil;
import com.gmail.goosius.siegewar.utils.SiegeWarSpawnUtil;
import com.gmail.goosius.siegewar.utils.SiegeWarTownPeacefulnessUtil;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.TownyEconomyHandler;
Expand All @@ -36,7 +37,7 @@

public class SiegeWarCommand implements CommandExecutor, TabCompleter {

private static final List<String> siegewarTabCompletes = Arrays.asList("collect", "town", "nation", "hud", "preference", "version", "nextsession");
private static final List<String> siegewarTabCompletes = Arrays.asList("collect", "town", "nation", "hud", "preference", "version", "nextsession", "spawn");

private static final List<String> siegewarTownTabCompletes = Arrays.asList("togglepeaceful");

Expand All @@ -56,6 +57,7 @@ public List<String> onTabComplete(CommandSender sender, Command command, String
return NameUtil.filterByStart(siegewarTownTabCompletes, args[1]);
break;
case "hud":
case "spawn":
if (args.length == 2)
return NameUtil.filterByStart(new ArrayList<>(SiegeController.getNamesOfActivelySiegedTowns()), args[1]);
break;
Expand All @@ -76,12 +78,18 @@ public List<String> onTabComplete(CommandSender sender, Command command, String
private void showSiegeWarHelp(CommandSender sender) {
TownyMessaging.sendMessage(sender, ChatTools.formatTitle("/siegewar"));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw hud", "[town]", ""));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw spawn", "[town]", ""));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw collect", "", Translatable.of("nation_help_11").forLocale(sender)));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw nation", "paysoldiers [amount]", Translatable.of("nation_help_12").forLocale(sender)));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw town", "togglepeaceful", Translatable.of("town_help_toggle_peaceful").forLocale(sender)));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw preference", "beacons [on/off]", ""));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw nextsession", "", ""));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw version", "", ""));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw preference", "beacons [on/off]", ""));
}

private void showSpawnHelp(CommandSender sender) {
TownyMessaging.sendMessage(sender, ChatTools.formatTitle("/siegewar spawn"));
TownyMessaging.sendMessage(sender, ChatTools.formatCommand("Eg", "/sw spawn", "[town]", ""));
}

private void showNationHelp(CommandSender sender) {
Expand Down Expand Up @@ -127,6 +135,9 @@ private void parseSiegeWarCommand(Player player, String[] args) {
case "hud":
parseSiegeWarHudCommand(player, StringMgmt.remFirstArg(args));
break;
case "spawn":
parseSiegeWarSpawnCommand(player, StringMgmt.remFirstArg(args));
break;
case "town":
parseSiegeWarTownCommand(player, StringMgmt.remFirstArg(args));
break;
Expand Down Expand Up @@ -211,6 +222,21 @@ private void parseSiegeWarHudCommand(Player player, String[] args) {
}
}

private void parseSiegeWarSpawnCommand(Player player, String[] args) {
try {
if (args.length == 0) {
showSpawnHelp(player);
} else {
Town town = TownyUniverse.getInstance().getTown(args[0]);
if (town == null)
throw new TownyException(Translatable.of("msg_err_town_not_registered", args[0]));
SiegeWarSpawnUtil.evaluateSpawnToSiegeRequest(player, town);
}
} catch (TownyException e) {
Messaging.sendErrorMsg(player, e.getMessage(player));
}
}

private void parseSiegeWarNationCommand(Player player, String[] args) {
if (args.length == 0) {
showNationHelp(player);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public enum SiegeWarPermissionNodes {
SIEGEWAR_COMMAND_SIEGEWAR_NATION_PAYSOLDIERS("siegewar.command.siegewar.nation.paysoldiers"),
SIEGEWAR_COMMAND_SIEGEWAR_COLLECT("siegewar.command.siegewar.collect"),
SIEGEWAR_COMMAND_SIEGEWAR_HUD("siegewar.command.siegewar.hud"),
SIEGEWAR_COMMAND_SIEGEWAR_SPAWN("siegewar.command.siegewar.spawn"),
SIEGEWAR_COMMAND_SIEGEWAR_PREFERENCE("siegewar.command.siegewar.preference"),
SIEGEWAR_COMMAND_SIEGEWAR_NEXTSESSION("siegewar.command.siegewar.nextsession"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.gmail.goosius.siegewar.objects.BattleSession;
import com.gmail.goosius.siegewar.utils.DataCleanupUtil;
import com.gmail.goosius.siegewar.utils.SiegeWarNotificationUtil;
import com.gmail.goosius.siegewar.utils.SiegeWarSpawnUtil;
import com.gmail.goosius.siegewar.utils.SiegeWarWarningsUtil;
import org.bukkit.Material;
import org.bukkit.World;
Expand Down Expand Up @@ -163,6 +164,12 @@ public void onPlayerTeleport(PlayerTeleportEvent event) {
if (PluginIntegrations.getInstance().checkCitizens(event.getPlayer()))
return;

// Don't stop a player if they have a teleport pass
if(SiegeWarSpawnUtil.doesPlayerHasTeleportPass(event.getPlayer())) {
SiegeWarSpawnUtil.removePlayerTeleportPass(event.getPlayer());
return;
}

// The teleport destination is in the wilderness.
if (TownyAPI.getInstance().isWilderness(event.getTo())) {
// A part of an active siege zone in the wilderness, we stop it.
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/com/gmail/goosius/siegewar/objects/Siege.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public class Siege {
private int attackerBattlePoints;
private int defenderBattlePoints;
private int numberOfBannerControlReversals;
private Resident attackingCommander;
private Resident defendingCommander;

public Siege(Town town) {
this.town = town;
Expand All @@ -75,6 +77,8 @@ public Siege(Town town) {
attackerBattlePoints = 0;
defenderBattlePoints = 0;
numberOfBannerControlReversals = 0;
attackingCommander = null;
defendingCommander = null;
}

public Town getTown() {
Expand Down Expand Up @@ -405,4 +409,19 @@ public void setNumberOfBannerControlReversals(int numberOfBannerControlReversals
this.numberOfBannerControlReversals = numberOfBannerControlReversals;
}

public Resident getAttackingCommander() {
return attackingCommander;
}

public void setAttackingCommander(Resident attackingCommander) {
this.attackingCommander = attackingCommander;
}

public Resident getDefendingCommander() {
return defendingCommander;
}

public void setDefendingCommander(Resident defendingCommander) {
this.defendingCommander = defendingCommander;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1058,7 +1058,26 @@ public enum ConfigNodes {
"# This value determines the ideal configured occupation-tax value.",
"# Example: If the ideal percentage is 0.375, then on each new day, we want to take 0.375% of the estimated town value.",
"# TIP: Generally you want to keep this low enough so that fake sieges for immunity purposes are not worthwhile.",
"# The default value is 0.375");
"# The default value is 0.375"),
BATTLE_COMMANDERS(
"battle_commanders",
"",
"",
"",
"############################################################",
"# +------------------------------------------------------+ #",
"# | BATTLE COMMANDERS | #",
"# +------------------------------------------------------+ #",
"############################################################",
""),
BATTLE_COMMANDERS_ENABLED(
"battle_commanders.enabled",
"true",
"",
"# If this value is true, then the Battle Commander feature is enabled.",
"# When a battle sessions starts, then for each siege, one player from each side may be designated as the Battle Commander.",
"# To qualify as a battle commander, a player must be an official participant with general or king rank, and be online and in the Siege-Zone.",
"# If one side has a battle commander, then any member can run /sw spawn <town> to spawn on the commander.");
private final String Root;
private final String Default;
private String[] comments;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -554,4 +554,8 @@ public static double getBadConfigWarningsIdealUpfrontCostPercentage() {
public static double getBadConfigWarningsIdealOccupationTaxPercentage() {
return Settings.getDouble(ConfigNodes.BAD_CONFIG_WARNINGS_IDEAL_OCCUPATIONTAX_PERCENTAGE);
}

public static boolean isBattleCommandersEnabled() {
return Settings.getBoolean(ConfigNodes.BATTLE_COMMANDERS_ENABLED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.gmail.goosius.siegewar.utils;

import com.gmail.goosius.siegewar.SiegeController;
import com.gmail.goosius.siegewar.enums.SiegeSide;
import com.gmail.goosius.siegewar.enums.SiegeWarPermissionNodes;
import com.gmail.goosius.siegewar.objects.Siege;
import com.gmail.goosius.siegewar.settings.SiegeWarSettings;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.object.Translatable;
import com.palmergames.bukkit.towny.object.Translation;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.util.Locale;

public class SiegeWarBattleCommanderUtil {

/**
* Assign the siege commanders for this battle session
* To qualify, a player must be:
* - Online
* - In the siege zone
* - Nation king or general
* - An official siege participant
*/
public static void assignBattleCommanders() {
if(!SiegeWarSettings.isBattleCommandersEnabled()) {
return;
}
Player attackingCommander = null;
Player defendingCommander = null;
String attackingCommanderName;
String defendingCommanderName;
for(Siege siege: SiegeController.getSieges()) {
if(siege.getStatus().isActive()) {
//Wipe the current commanders
siege.setAttackingCommander(null);
siege.setDefendingCommander(null);
//Find the commanders for the siege
for(Player player: Bukkit.getOnlinePlayers()) {
if (SiegeWarDistanceUtil.isPlayerRegisteredToActiveSiegeZone(player)
&& player.hasPermission(SiegeWarPermissionNodes.SIEGEWAR_NATION_SIEGE_STARTCONQUESTSIEGE.getNode()))
{
if(SiegeSide.getPlayerSiegeSide(siege,player) == SiegeSide.ATTACKERS) {
if(attackingCommander == null) {
attackingCommander = player;
siege.setAttackingCommander(TownyAPI.getInstance().getResident(player));
}
} else if (SiegeSide.getPlayerSiegeSide(siege,player) == SiegeSide.DEFENDERS) {
if(defendingCommander == null) {
defendingCommander = player;
siege.setDefendingCommander(TownyAPI.getInstance().getResident(player));
}
}
}
}

//Display the commanders to all participants
attackingCommanderName = attackingCommander == null ? Translation.of("no_battle_commander") : attackingCommander.getName();
defendingCommanderName = defendingCommander == null ? Translation.of("no_battle_commander") : defendingCommander.getName();
SiegeWarNotificationUtil.informSiegeParticipants(siege, Translatable.of("msg_battle_commanders_assigned", siege.getTown().getName(), attackingCommanderName, defendingCommanderName));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public static void startBattleSession() {
message.append(Translatable.of("msg_can_also_chat_in_discord", discordLink));
}
Messaging.sendGlobalMessage(message);
//Assign siege commanders
SiegeWarBattleCommanderUtil.assignBattleCommanders();
//Start the bossbar for the Battle Session
BossBarUtil.updateBattleSessionBossBar();
}
Expand Down Expand Up @@ -347,4 +349,5 @@ private static Long getConfiguredStartTimeOfNextBattleSession() {
return null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ public static boolean isPlayerRegisteredToActiveSiegeZone(Player player) {
return playersRegisteredToActiveSiegeZones.containsKey(player);
}

public static Siege getActiveSiegeZonePlayerIsRegisteredTo(Player player) {
return playersRegisteredToActiveSiegeZones.get(player);
}

public static void recalculatePlayersRegisteredToActiveSiegeZones() {
playersRegisteredToActiveSiegeZones.clear();
for(Player player: Bukkit.getOnlinePlayers()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.gmail.goosius.siegewar.utils;

import com.gmail.goosius.siegewar.SiegeController;
import com.gmail.goosius.siegewar.enums.SiegeSide;
import com.gmail.goosius.siegewar.objects.BattleSession;
import com.gmail.goosius.siegewar.objects.Siege;
import com.gmail.goosius.siegewar.settings.SiegeWarSettings;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.exceptions.TownyException;
import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town;
import com.palmergames.bukkit.towny.object.Translatable;
import com.palmergames.bukkit.towny.object.WorldCoord;
import org.bukkit.entity.Player;

import java.util.HashSet;
import java.util.Set;

public class SiegeWarSpawnUtil {

private static final Set<Player> playersWithTeleportPasses = new HashSet<>();

public static boolean doesPlayerHasTeleportPass(Player player) {
return playersWithTeleportPasses.contains(player);
}

private static void grandTeleportPassToPlayer(Player player) {
playersWithTeleportPasses.add(player);
}

public static void removePlayerTeleportPass(Player player) {
playersWithTeleportPasses.remove(player);
}

/**
* Evaluate a spawn to siege request
*
* - If the primary nation/town has just 1 general/mayor in the siegezone, spawn to them.
* - If any allied nation has just 1 general in the siegezone, spawn to them.
* - Otherwise spawn is unavailable.
*
* @param player the player trying to spawn
* @param besiegedTown the besieged town
*/
public static void evaluateSpawnToSiegeRequest(Player player, Town besiegedTown) throws TownyException {
if(!SiegeWarSettings.isBattleCommandersEnabled()) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_feature_not_active"));
}
Siege siege = SiegeController.getSiege(besiegedTown);
if(siege == null) {
throw new TownyException(Translatable.of("msg_err_not_being_sieged", besiegedTown.getName()));
}
if(!siege.getStatus().isActive()) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_siege_not_active"));
}
if(!BattleSession.getBattleSession().isActive()) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_battle_session_not_active"));
}
SiegeSide playerSide = SiegeSide.getPlayerSiegeSide(siege, player);
Resident battleCommanderResident;
switch (playerSide) {
case ATTACKERS:
battleCommanderResident = siege.getAttackingCommander();
break;
case DEFENDERS:
battleCommanderResident = siege.getDefendingCommander();
break;
default:
throw new TownyException(Translatable.of("msg_err_cannot_spawn_not_participant"));
}
if(battleCommanderResident == null) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_no_battle_commander"));
}
Player battleCommander = TownyAPI.getInstance().getPlayer(battleCommanderResident);
if(battleCommander == null || !battleCommander.isOnline()) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_no_battle_commander_offline"));
}
if(battleCommander.isDead()) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_battle_commander_dead"));
}
if(!SiegeWarDistanceUtil.isPlayerRegisteredToActiveSiegeZone(battleCommander)) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_battle_commander_not_in_siegezone"));
}
if(SiegeWarDistanceUtil.getActiveSiegeZonePlayerIsRegisteredTo(battleCommander) != siege) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_battle_commander_not_in_siegezone"));
}
Resident spawnerResident = TownyAPI.getInstance().getResident(player);
if(!WorldCoord.parseWorldCoord(player).equals(spawnerResident.getTown().getHomeBlock().getWorldCoord())) {
throw new TownyException(Translatable.of("msg_err_cannot_spawn_not_in_homeblock"));
}
//Grant teleport pass in order to bypass SW's teleport blocker
grandTeleportPassToPlayer(player);
//SPAWN!
player.teleport(battleCommander);
}
}
Loading

0 comments on commit 1a6f996

Please sign in to comment.