Compare commits
25
Commits
e62d0df9df
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4953cec215 | ||
|
|
92f9e732a1 | ||
|
|
95b54d1a03 | ||
|
|
05a63b9a52 | ||
|
|
137e5a5125 | ||
|
|
3c5842a92c | ||
|
|
f5bb1564ae | ||
|
|
fa8d320da9 | ||
|
|
816c429346 | ||
|
|
afbd1a9f09 | ||
|
|
5430af2149 | ||
|
|
ce7297afb8 | ||
|
|
a10607092b | ||
|
|
fe39cdf5a1 | ||
|
|
6008378258 | ||
|
|
18b211f681 | ||
|
|
b5c59cf173 | ||
|
|
436b462ffe | ||
|
|
d11cf25fc8 | ||
|
|
e8c015790f | ||
|
|
ba8fbe83e0 | ||
|
|
d56e8eaea5 | ||
|
|
3550d75634 | ||
|
|
14158f73b8 | ||
|
|
c738f02d17 |
@@ -4,18 +4,17 @@ import com.alttd.ctf.commands.CommandManager;
|
|||||||
import com.alttd.ctf.config.Config;
|
import com.alttd.ctf.config.Config;
|
||||||
import com.alttd.ctf.config.GameConfig;
|
import com.alttd.ctf.config.GameConfig;
|
||||||
import com.alttd.ctf.config.Messages;
|
import com.alttd.ctf.config.Messages;
|
||||||
import com.alttd.ctf.events.InventoryItemInteractionEvent;
|
import com.alttd.ctf.events.*;
|
||||||
import com.alttd.ctf.events.OnPlayerDeath;
|
|
||||||
import com.alttd.ctf.events.OnPlayerOnlineStatus;
|
|
||||||
import com.alttd.ctf.events.SnowballEvent;
|
|
||||||
import com.alttd.ctf.flag.Flag;
|
import com.alttd.ctf.flag.Flag;
|
||||||
import com.alttd.ctf.flag.FlagTryCaptureEvent;
|
import com.alttd.ctf.flag.FlagTryCaptureEvent;
|
||||||
import com.alttd.ctf.game.GameManager;
|
import com.alttd.ctf.game.GameManager;
|
||||||
|
import com.alttd.ctf.game.phases.EndedPhase;
|
||||||
import com.alttd.ctf.gui.ClassSelectionGUI;
|
import com.alttd.ctf.gui.ClassSelectionGUI;
|
||||||
import com.alttd.ctf.gui.GUIInventory;
|
import com.alttd.ctf.gui.GUIInventory;
|
||||||
import com.alttd.ctf.gui.GUIListener;
|
import com.alttd.ctf.gui.GUIListener;
|
||||||
import com.alttd.ctf.json_config.JacksonConfig;
|
import com.alttd.ctf.json_config.JacksonConfig;
|
||||||
import com.alttd.ctf.json_config.JsonConfigManager;
|
import com.alttd.ctf.json_config.JsonConfigManager;
|
||||||
|
import com.alttd.ctf.stats.PlayerStat;
|
||||||
import com.alttd.ctf.team.Team;
|
import com.alttd.ctf.team.Team;
|
||||||
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
|
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -29,16 +28,18 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Main extends JavaPlugin {
|
public class Main extends JavaPlugin {
|
||||||
|
|
||||||
private GameManager gameManager = null;
|
private GameManager gameManager = null;
|
||||||
private Flag flag;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
PlayerStat.main = this;
|
||||||
GUIInventory.setMain(this); // sorry
|
GUIInventory.setMain(this); // sorry
|
||||||
ClassSelectionGUI.setMain(this); // sorry
|
ClassSelectionGUI.setMain(this); // sorry
|
||||||
Package pkg = Main.class.getPackage();
|
Package pkg = Main.class.getPackage();
|
||||||
@@ -47,18 +48,13 @@ public class Main extends JavaPlugin {
|
|||||||
|
|
||||||
reloadConfigs();
|
reloadConfigs();
|
||||||
WorldBorderApi worldBorderApi = worldBorder();
|
WorldBorderApi worldBorderApi = worldBorder();
|
||||||
this.gameManager = new GameManager(worldBorderApi);
|
this.gameManager = new GameManager(this, worldBorderApi);
|
||||||
registerTeams(); //Skipped in reloadConfig if gameManager is not created yet
|
registerTeams(); //Skipped in reloadConfig if gameManager is not created yet
|
||||||
flag = new Flag(this, gameManager);
|
loadPlayerStats(); //Skipped in reloadConfig if gameManager is not created yet
|
||||||
|
Flag flag = new Flag(this, gameManager);
|
||||||
new CommandManager(this, gameManager, flag, worldBorderApi);
|
new CommandManager(this, gameManager, flag, worldBorderApi);
|
||||||
//Ensuring immediate respawn is on in all worlds
|
//Ensuring immediate respawn is on in all worlds
|
||||||
log.info("Enabling immediate respawn for {}.", GameConfig.FLAG.world);
|
enableImmediateRespawn();
|
||||||
World world = Bukkit.getWorld(GameConfig.FLAG.world);
|
|
||||||
if (world != null) {
|
|
||||||
world.setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true);
|
|
||||||
} else {
|
|
||||||
log.error("No valid flag world defined, unable to modify game rules");
|
|
||||||
}
|
|
||||||
registerEvents(flag, worldBorderApi);
|
registerEvents(flag, worldBorderApi);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +64,7 @@ public class Main extends JavaPlugin {
|
|||||||
GameConfig.reload(this);
|
GameConfig.reload(this);
|
||||||
if (gameManager != null) {
|
if (gameManager != null) {
|
||||||
registerTeams();
|
registerTeams();
|
||||||
|
loadPlayerStats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,9 +80,20 @@ public class Main extends JavaPlugin {
|
|||||||
return worldBorderApiRegisteredServiceProvider.getProvider();
|
return worldBorderApiRegisteredServiceProvider.getProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableImmediateRespawn() {
|
||||||
|
log.info("Enabling immediate respawn for {}.", GameConfig.FLAG.world);
|
||||||
|
World world = Bukkit.getWorld(GameConfig.FLAG.world);
|
||||||
|
if (world != null) {
|
||||||
|
world.setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true);
|
||||||
|
} else {
|
||||||
|
log.error("No valid flag world defined, unable to modify game rules");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void registerEvents(Flag flag, WorldBorderApi worldBorderApi) {
|
private void registerEvents(Flag flag, WorldBorderApi worldBorderApi) {
|
||||||
PluginManager pluginManager = getServer().getPluginManager();
|
PluginManager pluginManager = getServer().getPluginManager();
|
||||||
pluginManager.registerEvents(new SnowballEvent(gameManager), this);
|
pluginManager.registerEvents(new SnowballEvent(gameManager), this);
|
||||||
|
pluginManager.registerEvents(new OtherGameEvents(gameManager), this);
|
||||||
pluginManager.registerEvents(new FlagTryCaptureEvent(flag), this);
|
pluginManager.registerEvents(new FlagTryCaptureEvent(flag), this);
|
||||||
pluginManager.registerEvents(new OnPlayerDeath(gameManager, worldBorderApi, this, flag), this);
|
pluginManager.registerEvents(new OnPlayerDeath(gameManager, worldBorderApi, this, flag), this);
|
||||||
pluginManager.registerEvents(new InventoryItemInteractionEvent(), this);
|
pluginManager.registerEvents(new InventoryItemInteractionEvent(), this);
|
||||||
@@ -119,4 +127,39 @@ public class Main extends JavaPlugin {
|
|||||||
teams.forEach(gameManager::registerTeam);
|
teams.forEach(gameManager::registerTeam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadPlayerStats() {
|
||||||
|
JsonConfigManager<PlayerStat> config = new JsonConfigManager<>(JacksonConfig.configureMapper());
|
||||||
|
List<PlayerStat> playerStats;
|
||||||
|
|
||||||
|
try {
|
||||||
|
File playerStatsDirectory = new File(getDataFolder(), "player_stats");
|
||||||
|
if (!playerStatsDirectory.exists() && !playerStatsDirectory.mkdirs()) {
|
||||||
|
log.error("Unable to make playerStats directory at {} shutting down plugin", playerStatsDirectory.getAbsolutePath());
|
||||||
|
}
|
||||||
|
playerStats = config.loadConfigs(PlayerStat.class, playerStatsDirectory);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Unable to load teams, shutting down plugin", e);
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gameManager.setPlayerStats(playerStats);
|
||||||
|
final JsonConfigManager<PlayerStat> jsonConfigManager = new JsonConfigManager<>(JacksonConfig.configureMapper());
|
||||||
|
Runnable runnable = () -> {
|
||||||
|
log.info("Saving player stats");
|
||||||
|
File playerStatsDirectory = new File(getDataFolder(), "player_stats");
|
||||||
|
gameManager.getPlayerStats().stream().filter(PlayerStat::isTouched).forEach(playerStat -> {
|
||||||
|
try {
|
||||||
|
jsonConfigManager.saveConfig(playerStat, playerStatsDirectory, playerStat.getUuid().toString());
|
||||||
|
playerStat.setUnTouched();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed to save player stats for [{}].", playerStat.getUuid(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 1, java.util.concurrent.TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -38,6 +38,7 @@ public class CommandManager implements CommandExecutor, TabExecutor {
|
|||||||
new SkipPhase(gameManager),
|
new SkipPhase(gameManager),
|
||||||
new Start(gameManager, flag),
|
new Start(gameManager, flag),
|
||||||
new CreateTeam(main, gameManager),
|
new CreateTeam(main, gameManager),
|
||||||
|
new HighestStat(gameManager),
|
||||||
new SelectClass(gameManager, worldBorderApi),
|
new SelectClass(gameManager, worldBorderApi),
|
||||||
new Reload(main)
|
new Reload(main)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.alttd.ctf.commands.subcommands;
|
||||||
|
|
||||||
|
import com.alttd.ctf.commands.SubCommand;
|
||||||
|
import com.alttd.ctf.config.Messages;
|
||||||
|
import com.alttd.ctf.game.GameManager;
|
||||||
|
import com.alttd.ctf.stats.PlayerStat;
|
||||||
|
import com.alttd.ctf.stats.Stat;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.TextComponent;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class HighestStat extends SubCommand {
|
||||||
|
|
||||||
|
private final GameManager gameManager;
|
||||||
|
private final MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||||
|
|
||||||
|
public HighestStat(GameManager gameManager) {
|
||||||
|
this.gameManager = gameManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record HighestStatValue(Stat stat, UUID uuid, double value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onCommand(CommandSender commandSender, String[] args) {
|
||||||
|
ArrayList<HighestStatValue> highestStatValues = new ArrayList<>();
|
||||||
|
Collection<PlayerStat> playerStats = gameManager.getPlayerStats();
|
||||||
|
for (Stat stat : Stat.values()) {
|
||||||
|
Optional<PlayerStat> max = playerStats.stream().max(Comparator.comparingDouble(playerStat -> playerStat.getStat(stat)));
|
||||||
|
if (max.isEmpty()) {
|
||||||
|
log.warn("No max stat found for {}", stat.toString());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PlayerStat playerStat = max.get();
|
||||||
|
highestStatValues.add(new HighestStatValue(stat, playerStat.getUuid(), playerStat.getStat(stat)));
|
||||||
|
}
|
||||||
|
Component message = highestStatValues.stream().map(highestStatValue -> {
|
||||||
|
TextComponent messageBuilder = Component.empty();
|
||||||
|
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(highestStatValue.uuid);
|
||||||
|
Player player = offlinePlayer.getPlayer();
|
||||||
|
if (!offlinePlayer.isOnline() || player == null) {
|
||||||
|
messageBuilder = messageBuilder.append(miniMessage.deserialize(offlinePlayer.getName() == null ? highestStatValue.uuid.toString() : offlinePlayer.getName()));
|
||||||
|
} else {
|
||||||
|
messageBuilder = messageBuilder.append(player.name());
|
||||||
|
}
|
||||||
|
messageBuilder = messageBuilder.append(Component.text(": "));
|
||||||
|
messageBuilder = messageBuilder.append(Component.text(highestStatValue.stat.toString()));
|
||||||
|
messageBuilder = messageBuilder.append(Component.text(": "));
|
||||||
|
messageBuilder = messageBuilder.append(Component.text(highestStatValue.value()));
|
||||||
|
return messageBuilder;
|
||||||
|
}).reduce(Component.empty(), (a, b) -> a.append(Component.newline()).append(b));
|
||||||
|
commandSender.sendMessage(message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "higheststat";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelpMessage() {
|
||||||
|
return Messages.HELP.HIGHEST_STAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ public class SelectClass extends SubCommand {
|
|||||||
TeamPlayer teamPlayer = optionalTeamPlayer.get();
|
TeamPlayer teamPlayer = optionalTeamPlayer.get();
|
||||||
if (!teamPlayer.isDead()
|
if (!teamPlayer.isDead()
|
||||||
&& !gamePhase.equals(GamePhase.CLASS_SELECTION)
|
&& !gamePhase.equals(GamePhase.CLASS_SELECTION)
|
||||||
&& teamPlayer.getTeam().getSpawnLocation().distance(player.getLocation()) > 5) {
|
&& teamPlayer.getTeam().getSpawnLocation().distance(player.getLocation()) > 10) {
|
||||||
commandSender.sendRichMessage("<red>You have to be near your spawn to change classes.</red>");
|
commandSender.sendRichMessage("<red>You have to be near your spawn to change classes.</red>");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,10 @@ package com.alttd.ctf.commands.subcommands;
|
|||||||
import com.alttd.ctf.commands.SubCommand;
|
import com.alttd.ctf.commands.SubCommand;
|
||||||
import com.alttd.ctf.config.Messages;
|
import com.alttd.ctf.config.Messages;
|
||||||
import com.alttd.ctf.game.GameManager;
|
import com.alttd.ctf.game.GameManager;
|
||||||
import com.alttd.ctf.team.Team;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
|
||||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class SkipPhase extends SubCommand {
|
public class SkipPhase extends SubCommand {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import com.alttd.ctf.Main;
|
|||||||
import com.alttd.ctf.game.GamePhase;
|
import com.alttd.ctf.game.GamePhase;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -91,7 +90,7 @@ public class GameConfig extends AbstractConfig {
|
|||||||
public static double CAPTURE_RADIUS = 5;
|
public static double CAPTURE_RADIUS = 5;
|
||||||
public static int CAPTURE_SCORE = 50;
|
public static int CAPTURE_SCORE = 50;
|
||||||
public static double TURN_IN_RADIUS = 3;
|
public static double TURN_IN_RADIUS = 3;
|
||||||
public static @NotNull Material MATERIAL = Material.RED_BANNER;
|
public static @NotNull Material MATERIAL = Material.BLACK_BANNER;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static void load() {
|
private static void load() {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class Messages extends AbstractConfig {
|
|||||||
public static String START = "<green>Start a new game: <gold>/ctf start <time_in_minutes></gold></green>";
|
public static String START = "<green>Start a new game: <gold>/ctf start <time_in_minutes></gold></green>";
|
||||||
public static String SELECT_CLASS = "<green>Open class selection: <gold>/ctf selectclass</gold></green>";
|
public static String SELECT_CLASS = "<green>Open class selection: <gold>/ctf selectclass</gold></green>";
|
||||||
public static String SKIP_PHASE = "<green>Skip the current phase: <gold>/ctf skipphase</gold></green>";
|
public static String SKIP_PHASE = "<green>Skip the current phase: <gold>/ctf skipphase</gold></green>";
|
||||||
|
public static String HIGHEST_STAT = "<green>Display the highest stat and the player: <gold>/ctf higheststat</gold></green>";
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static void load() {
|
private static void load() {
|
||||||
@@ -39,6 +40,7 @@ public class Messages extends AbstractConfig {
|
|||||||
START = config.getString(prefix, "start", START);
|
START = config.getString(prefix, "start", START);
|
||||||
SELECT_CLASS = config.getString(prefix, "select-class", SELECT_CLASS);
|
SELECT_CLASS = config.getString(prefix, "select-class", SELECT_CLASS);
|
||||||
SKIP_PHASE = config.getString(prefix, "skip-phase", SKIP_PHASE);
|
SKIP_PHASE = config.getString(prefix, "skip-phase", SKIP_PHASE);
|
||||||
|
HIGHEST_STAT = config.getString(prefix, "highest-stat", HIGHEST_STAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,12 @@ public class OnPlayerOnlineStatus implements Listener {
|
|||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
resetPlayer(player);
|
resetPlayer(player);
|
||||||
handleRunningGame(player);
|
if (!player.hasPermission("ctf.bypass")) {
|
||||||
|
handleRunningGame(player);
|
||||||
|
}
|
||||||
handleDiscordLink(player);
|
handleDiscordLink(player);
|
||||||
|
gameManager.getTeamPlayer(player).ifPresent(teamPlayer ->
|
||||||
|
player.teleportAsync(teamPlayer.getTeam().getSpawnLocation()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleRunningGame(Player player) {
|
private void handleRunningGame(Player player) {
|
||||||
@@ -61,7 +65,7 @@ public class OnPlayerOnlineStatus implements Listener {
|
|||||||
log.error("No team found when attempting to add freshly joined player to a team");
|
log.error("No team found when attempting to add freshly joined player to a team");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
teamPlayer = min.get().addPlayer(player);
|
teamPlayer = gameManager.registerPlayer(min.get(), player);
|
||||||
} else {
|
} else {
|
||||||
teamPlayer = optionalTeamPlayer.get();
|
teamPlayer = optionalTeamPlayer.get();
|
||||||
teamPlayer.getTeam().addToScoreboard(player);
|
teamPlayer.getTeam().addToScoreboard(player);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.alttd.ctf.events;
|
package com.alttd.ctf.events;
|
||||||
|
|
||||||
import com.alttd.ctf.game.GameManager;
|
import com.alttd.ctf.game.GameManager;
|
||||||
|
import com.alttd.ctf.game.GamePhase;
|
||||||
import com.alttd.ctf.stats.Stat;
|
import com.alttd.ctf.stats.Stat;
|
||||||
import com.alttd.ctf.team.TeamPlayer;
|
import com.alttd.ctf.team.TeamPlayer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -12,6 +13,7 @@ import org.bukkit.entity.ThrownPotion;
|
|||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
import org.bukkit.event.entity.PotionSplashEvent;
|
import org.bukkit.event.entity.PotionSplashEvent;
|
||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
@@ -29,7 +31,8 @@ public class OtherGameEvents implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
if (gameManager.getGamePhase().isEmpty()) {
|
Optional<GamePhase> gamePhase = gameManager.getGamePhase();
|
||||||
|
if (gamePhase.isEmpty() || gamePhase.get() == GamePhase.ENDED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!Tag.SNOW.isTagged(event.getBlock().getType())) {
|
if (!Tag.SNOW.isTagged(event.getBlock().getType())) {
|
||||||
@@ -41,8 +44,9 @@ public class OtherGameEvents implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockPlace(BlockBreakEvent event) {
|
public void onBlockPlace(BlockPlaceEvent event) {
|
||||||
if (gameManager.getGamePhase().isEmpty()) {
|
Optional<GamePhase> gamePhase = gameManager.getGamePhase();
|
||||||
|
if (gamePhase.isEmpty() || gamePhase.get() == GamePhase.ENDED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!Tag.SNOW.isTagged(event.getBlock().getType())) {
|
if (!Tag.SNOW.isTagged(event.getBlock().getType())) {
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ package com.alttd.ctf.events;
|
|||||||
import com.alttd.ctf.game.GameManager;
|
import com.alttd.ctf.game.GameManager;
|
||||||
import com.alttd.ctf.game.GamePhase;
|
import com.alttd.ctf.game.GamePhase;
|
||||||
import com.alttd.ctf.game_class.GameClass;
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
|
import com.alttd.ctf.game_class.implementations.Mage;
|
||||||
import com.alttd.ctf.stats.Stat;
|
import com.alttd.ctf.stats.Stat;
|
||||||
import com.alttd.ctf.team.TeamPlayer;
|
import com.alttd.ctf.team.TeamPlayer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.Snowball;
|
import org.bukkit.entity.Snowball;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@@ -17,7 +20,11 @@ import org.bukkit.event.entity.ProjectileLaunchEvent;
|
|||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SnowballEvent implements Listener {
|
public class SnowballEvent implements Listener {
|
||||||
@@ -35,13 +42,14 @@ public class SnowballEvent implements Listener {
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
private interface SnowballThrownConsumer {
|
private interface SnowballThrownConsumer {
|
||||||
void apply(Player shooter, TeamPlayer shooterTeamPlayer);
|
void apply(Player shooter, TeamPlayer shooterTeamPlayer, Snowball snowball);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onSnowballHit(EntityDamageByEntityEvent event) {
|
public void onSnowballHit(EntityDamageByEntityEvent event) {
|
||||||
handleSnowballHit(event, (hitPlayer, shooter, shooterTeamPlayer, snowball) -> {
|
handleSnowballHit(event, (hitPlayer, shooter, shooterTeamPlayer, snowball) -> {
|
||||||
if (blockedAttack(hitPlayer, snowball)) { //Disable damage when it is blocked
|
if (blockedAttack(hitPlayer, shooter, snowball)) {
|
||||||
|
playBlockSounds(hitPlayer, shooter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GameClass shooterClass = shooterTeamPlayer.getGameClass();
|
GameClass shooterClass = shooterTeamPlayer.getGameClass();
|
||||||
@@ -56,22 +64,59 @@ public class SnowballEvent implements Listener {
|
|||||||
}
|
}
|
||||||
log.debug("{} health was set to {} because of a snowball thrown by {}",
|
log.debug("{} health was set to {} because of a snowball thrown by {}",
|
||||||
hitPlayer.getName(), Math.max(newHealth, 0), shooter.getName());
|
hitPlayer.getName(), Math.max(newHealth, 0), shooter.getName());
|
||||||
|
applyDamageEffects(hitPlayer, shooter);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void playBlockSounds(Player hitPlayer, Player shooter) {
|
||||||
|
hitPlayer.playSound(hitPlayer.getLocation(), Sound.ITEM_SHIELD_BLOCK, 1.0f, 1.5f);
|
||||||
|
shooter.playSound(shooter.getLocation(), Sound.ITEM_SHIELD_BLOCK, 1.0f, 1.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyDamageEffects(Player hitPlayer, Player shooter) {
|
||||||
|
hitPlayer.getWorld().playSound(hitPlayer.getLocation(), Sound.ENTITY_PLAYER_HURT, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
hitPlayer.getWorld().spawnParticle(
|
||||||
|
Particle.DAMAGE_INDICATOR,
|
||||||
|
hitPlayer.getLocation().add(0, 1, 0), 10, 0.5, 0.5, 0.5, 0.1
|
||||||
|
);
|
||||||
|
|
||||||
|
shooter.playSound(shooter.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.5f);
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onSnowballThrown(ProjectileLaunchEvent event) {
|
public void onSnowballThrown(ProjectileLaunchEvent event) {
|
||||||
handleSnowballThrown(event, (shooter, shooterTeamPlayer) -> {
|
handleSnowballThrown(event, (shooter, shooterTeamPlayer, snowball) -> {
|
||||||
GameClass shooterClass = shooterTeamPlayer.getGameClass();
|
GameClass shooterClass = shooterTeamPlayer.getGameClass();
|
||||||
|
if (shooterClass == null) {
|
||||||
|
shooter.sendRichMessage("<red>You appear to not have selected a class, please do so by going to spawn and using /ctf selectclass</red>");
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
shooter.setCooldown(Material.SNOWBALL, shooterClass.getThrowTickSpeed());
|
shooter.setCooldown(Material.SNOWBALL, shooterClass.getThrowTickSpeed());
|
||||||
shooterTeamPlayer.increaseStat(Stat.SNOWBALLS_THROWN);
|
shooterTeamPlayer.increaseStat(Stat.SNOWBALLS_THROWN);
|
||||||
|
if (shooterClass instanceof Mage mage) {
|
||||||
|
mage.duplicateSnowBalls(shooter, snowball);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean blockedAttack(@NotNull Player hitPlayer, @NotNull Snowball snowball) {
|
private final HashMap<UUID, LinkedList<Instant>> lastTankHits = new HashMap<>();
|
||||||
|
|
||||||
|
private boolean blockedAttack(@NotNull Player hitPlayer, @NotNull Player shooter, @NotNull Snowball snowball) {
|
||||||
if (!hitPlayer.isBlocking()) {
|
if (!hitPlayer.isBlocking()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (reachedMaxHits(hitPlayer)) {
|
||||||
|
hitPlayer.setCooldown(Material.SHIELD, 40);
|
||||||
|
if (hitPlayer.getInventory().getItemInMainHand().getType().equals(Material.SHIELD)) {
|
||||||
|
hitPlayer.swingMainHand();
|
||||||
|
} else if (hitPlayer.getInventory().getItemInOffHand().getType().equals(Material.SHIELD)) {
|
||||||
|
hitPlayer.swingOffHand();
|
||||||
|
}
|
||||||
|
applyBlockBrokenEffects(hitPlayer, shooter);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Location playerLocation = hitPlayer.getLocation();
|
Location playerLocation = hitPlayer.getLocation();
|
||||||
Vector playerFacing = playerLocation.getDirection().normalize();
|
Vector playerFacing = playerLocation.getDirection().normalize();
|
||||||
Location snowballLocation = snowball.getLocation();
|
Location snowballLocation = snowball.getLocation();
|
||||||
@@ -82,6 +127,37 @@ public class SnowballEvent implements Listener {
|
|||||||
return !(Math.toDegrees(angle) > 80); //Blocked if the angle was <= 80
|
return !(Math.toDegrees(angle) > 80); //Blocked if the angle was <= 80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyBlockBrokenEffects(@NotNull Player hitPlayer, @NotNull Player shooter) {
|
||||||
|
hitPlayer.getWorld().playSound(hitPlayer.getLocation(), Sound.ITEM_SHIELD_BREAK, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
Location shieldLocation = hitPlayer.getLocation()
|
||||||
|
.add(hitPlayer.getLocation().getDirection().normalize().multiply(0.5))
|
||||||
|
.add(0, 0.5, 0);
|
||||||
|
hitPlayer.getWorld().spawnParticle(
|
||||||
|
Particle.CRIT,
|
||||||
|
shieldLocation, 10, 0.5, 0.5, 0.5, 0.1
|
||||||
|
);
|
||||||
|
|
||||||
|
shooter.playSound(shooter.getLocation(), Sound.ITEM_SHIELD_BREAK, 1.0f, 1.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean reachedMaxHits(@NotNull Player hitPlayer) {
|
||||||
|
boolean reachedMaxHits = false;
|
||||||
|
Instant now = Instant.now();
|
||||||
|
LinkedList<Instant> lastHits = lastTankHits.getOrDefault(hitPlayer.getUniqueId(), new LinkedList<>());
|
||||||
|
Instant cutoffTime = now.minusMillis(300);
|
||||||
|
while (!lastHits.isEmpty() && lastHits.peek().isBefore(cutoffTime)) {
|
||||||
|
lastHits.poll();
|
||||||
|
}
|
||||||
|
lastHits.addLast(now);
|
||||||
|
if (lastHits.size() >= 3) {
|
||||||
|
lastHits.clear();
|
||||||
|
reachedMaxHits = true;
|
||||||
|
}
|
||||||
|
lastTankHits.put(hitPlayer.getUniqueId(), lastHits);
|
||||||
|
return reachedMaxHits;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleSnowballThrown(ProjectileLaunchEvent event, SnowballThrownConsumer consumer) {
|
private void handleSnowballThrown(ProjectileLaunchEvent event, SnowballThrownConsumer consumer) {
|
||||||
Optional<GamePhase> optionalGamePhase = gameManager.getGamePhase();
|
Optional<GamePhase> optionalGamePhase = gameManager.getGamePhase();
|
||||||
if (optionalGamePhase.isEmpty()) {
|
if (optionalGamePhase.isEmpty()) {
|
||||||
@@ -101,7 +177,7 @@ public class SnowballEvent implements Listener {
|
|||||||
log.debug("The shooter that threw a snowball was not a team player");
|
log.debug("The shooter that threw a snowball was not a team player");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
consumer.apply(shooter, teamPlayer.get());
|
consumer.apply(shooter, teamPlayer.get(), snowball);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSnowballHit(EntityDamageByEntityEvent event, SnowballHitConsumer consumer) {
|
private void handleSnowballHit(EntityDamageByEntityEvent event, SnowballHitConsumer consumer) {
|
||||||
@@ -146,10 +222,10 @@ public class SnowballEvent implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (teamPlayerHit.get().getTeam().getId() == teamPlayerShooter.get().getTeam().getId()) {
|
if (teamPlayerHit.get().getTeam().getId().equals(teamPlayerShooter.get().getTeam().getId())) {
|
||||||
log.debug("The shooter hit a member of their own team");
|
log.debug("The shooter hit a member of their own team");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
consumer.apply(hitPlayer, shooter, teamPlayerHit.get(), snowball);
|
consumer.apply(hitPlayer, shooter, teamPlayerShooter.get(), snowball);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.bukkit.inventory.EquipmentSlot;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -80,8 +81,22 @@ public class Flag implements Runnable {
|
|||||||
if (flagCarrier != null) {
|
if (flagCarrier != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//TODO knockback enemies from flag location to create space for person who captured mayb short speed boost and heal?
|
Team team = teamPlayer.getTeam();
|
||||||
//TODO add de-buffs and enable buffs for others?
|
flagLocation.getNearbyPlayers(5).forEach(nearbyPlayer -> {
|
||||||
|
if (nearbyPlayer.getUniqueId().equals(player.getUniqueId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Optional<TeamPlayer> nearByTeamPlayer = gameManager.getTeamPlayer(nearbyPlayer);
|
||||||
|
if (nearByTeamPlayer.isEmpty()) {
|
||||||
|
return;
|
||||||
|
} else if (nearByTeamPlayer.get().getTeam().equals(team)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector direction = nearbyPlayer.getLocation().toVector().subtract(flagLocation.toVector()).normalize();
|
||||||
|
direction.setY(0.2);
|
||||||
|
nearbyPlayer.setVelocity(direction.multiply(5));
|
||||||
|
});
|
||||||
player.getInventory().setItem(EquipmentSlot.HEAD, new ItemStack(teamPlayer.getTeam().getFlagMaterial()));
|
player.getInventory().setItem(EquipmentSlot.HEAD, new ItemStack(teamPlayer.getTeam().getFlagMaterial()));
|
||||||
Bukkit.getScheduler().runTask(main, () -> flagLocation.getBlock().setType(Material.AIR));
|
Bukkit.getScheduler().runTask(main, () -> flagLocation.getBlock().setType(Material.AIR));
|
||||||
flagCarrier = player;
|
flagCarrier = player;
|
||||||
@@ -188,7 +203,7 @@ public class Flag implements Runnable {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkedList<Location> particleTrail = new LinkedList<>();
|
private final LinkedList<Location> particleTrail = new LinkedList<>();
|
||||||
|
|
||||||
private void spawnTrail() {
|
private void spawnTrail() {
|
||||||
TeamColor color = winningTeam.getColor();
|
TeamColor color = winningTeam.getColor();
|
||||||
@@ -317,12 +332,13 @@ public class Flag implements Runnable {
|
|||||||
}
|
}
|
||||||
Team winningTeam = teamLongEntry.getKey();
|
Team winningTeam = teamLongEntry.getKey();
|
||||||
|
|
||||||
teamCounts.forEach((team, count) -> {
|
teamFlagPointCount.putIfAbsent(winningTeam.getId(), 0);
|
||||||
teamFlagPointCount.merge(team.getId(), team.equals(winningTeam) ? 1 : -1, (oldValue, delta) -> {
|
teamFlagPointCount.entrySet().forEach(entry -> {
|
||||||
int updatedValue = oldValue + delta;
|
if (entry.getKey().equals(winningTeam.getId())) {
|
||||||
log.debug("Set count to {} for team {}", updatedValue, team.getId());
|
entry.setValue(entry.getValue() + 1);
|
||||||
return Math.max(updatedValue, 0);
|
} else {
|
||||||
});
|
entry.setValue(Math.max(0, entry.getValue() - 1));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
nearbyPlayers.forEach(teamPlayer -> teamPlayer.increaseStat(Stat.TIME_SPEND_CAPTURING_FLAG));
|
nearbyPlayers.forEach(teamPlayer -> teamPlayer.increaseStat(Stat.TIME_SPEND_CAPTURING_FLAG));
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.inventory.EquipmentSlot;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package com.alttd.ctf.game;
|
package com.alttd.ctf.game;
|
||||||
|
|
||||||
|
import com.alttd.ctf.Main;
|
||||||
import com.alttd.ctf.flag.Flag;
|
import com.alttd.ctf.flag.Flag;
|
||||||
import com.alttd.ctf.game.phases.ClassSelectionPhase;
|
import com.alttd.ctf.game.phases.ClassSelectionPhase;
|
||||||
import com.alttd.ctf.game.phases.CombatPhase;
|
import com.alttd.ctf.game.phases.CombatPhase;
|
||||||
import com.alttd.ctf.game.phases.EndedPhase;
|
import com.alttd.ctf.game.phases.EndedPhase;
|
||||||
import com.alttd.ctf.game.phases.GatheringPhase;
|
import com.alttd.ctf.game.phases.GatheringPhase;
|
||||||
import com.alttd.ctf.game_class.creation.FighterCreator;
|
import com.alttd.ctf.game_class.creation.FighterCreator;
|
||||||
|
import com.alttd.ctf.stats.PlayerStat;
|
||||||
import com.alttd.ctf.team.Team;
|
import com.alttd.ctf.team.Team;
|
||||||
import com.alttd.ctf.team.TeamPlayer;
|
import com.alttd.ctf.team.TeamPlayer;
|
||||||
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
|
import com.github.yannicklamprecht.worldborder.api.WorldBorderApi;
|
||||||
@@ -24,22 +26,26 @@ public class GameManager {
|
|||||||
private final HashMap<GamePhase, GamePhaseExecutor> phases;
|
private final HashMap<GamePhase, GamePhaseExecutor> phases;
|
||||||
private RunningGame runningGame;
|
private RunningGame runningGame;
|
||||||
private final HashMap<Integer, Team> teams = new HashMap<>();
|
private final HashMap<Integer, Team> teams = new HashMap<>();
|
||||||
|
private final HashMap<UUID, PlayerStat> playerStats = new HashMap<>();
|
||||||
|
|
||||||
public GameManager(WorldBorderApi worldBorderApi) {
|
public GameManager(Main main, WorldBorderApi worldBorderApi) {
|
||||||
phases = new HashMap<>();
|
phases = new HashMap<>();
|
||||||
phases.put(GamePhase.CLASS_SELECTION, new ClassSelectionPhase(this, FighterCreator::createFighter, worldBorderApi));
|
phases.put(GamePhase.CLASS_SELECTION, new ClassSelectionPhase(this, FighterCreator::createFighter, worldBorderApi));
|
||||||
phases.put(GamePhase.GATHERING, new GatheringPhase(this, worldBorderApi));
|
phases.put(GamePhase.GATHERING, new GatheringPhase(this, worldBorderApi));
|
||||||
phases.put(GamePhase.COMBAT, new CombatPhase());
|
phases.put(GamePhase.COMBAT, new CombatPhase());
|
||||||
phases.put(GamePhase.ENDED, new EndedPhase());
|
phases.put(GamePhase.ENDED, new EndedPhase(main, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<GamePhase> getGamePhase() {
|
public Optional<GamePhase> getGamePhase() {
|
||||||
return runningGame == null ? Optional.empty() : Optional.of(runningGame.getCurrentPhase());
|
return runningGame == null ? Optional.empty() : Optional.of(runningGame.getCurrentPhase());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPlayer(Team team, Player player) {
|
public TeamPlayer registerPlayer(Team team, Player player) {
|
||||||
unregisterPlayer(player);
|
unregisterPlayer(player);
|
||||||
teams.get(team.getId()).addPlayer(player);
|
UUID uuid = player.getUniqueId();
|
||||||
|
PlayerStat playerStat = playerStats
|
||||||
|
.computeIfAbsent(uuid, (ignored) -> new PlayerStat(uuid, player.getName()));
|
||||||
|
return teams.get(team.getId()).addPlayer(player, playerStat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterPlayer(Player player) {
|
public void unregisterPlayer(Player player) {
|
||||||
@@ -107,4 +113,20 @@ public class GameManager {
|
|||||||
}
|
}
|
||||||
return runningGame.skipCurrentPhase();
|
return runningGame.skipCurrentPhase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPlayerStats(List<PlayerStat> playerStats) {
|
||||||
|
this.playerStats.clear();
|
||||||
|
playerStats.forEach(playerStat -> this.playerStats.put(playerStat.getUuid(), playerStat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PlayerStat> getPlayerStats() {
|
||||||
|
return this.playerStats.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Duration> getRemainingTime() {
|
||||||
|
if (runningGame == null || runningGame.getCurrentPhase().equals(GamePhase.ENDED)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.of(runningGame.getRemainingTime());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.alttd.ctf.game;
|
|||||||
|
|
||||||
import com.alttd.ctf.config.GameConfig;
|
import com.alttd.ctf.config.GameConfig;
|
||||||
import com.alttd.ctf.flag.Flag;
|
import com.alttd.ctf.flag.Flag;
|
||||||
|
import com.alttd.ctf.team.TeamScoreboard;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
@@ -51,6 +52,7 @@ public class RunningGame implements Runnable {
|
|||||||
} else {
|
} else {
|
||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
}
|
}
|
||||||
|
TeamScoreboard.refreshScoreboard(gameManager);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Unexpected error in running game", e);
|
log.error("Unexpected error in running game", e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -73,7 +75,6 @@ public class RunningGame implements Runnable {
|
|||||||
private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) {
|
private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) {
|
||||||
//Remaining time for this phase
|
//Remaining time for this phase
|
||||||
Duration duration = phaseDurations.get(currentPhase).minus(Duration.between(phaseStartTime, Instant.now()));
|
Duration duration = phaseDurations.get(currentPhase).minus(Duration.between(phaseStartTime, Instant.now()));
|
||||||
log.debug(duration.toString());//TODO remove debug
|
|
||||||
if ((duration.toMinutes() > 1 && (duration.toMinutes() % 15 == 0 || duration.toMinutes() <= 5)) && duration.toSecondsPart() < 2) {
|
if ((duration.toMinutes() > 1 && (duration.toMinutes() % 15 == 0 || duration.toMinutes() <= 5)) && duration.toSecondsPart() < 2) {
|
||||||
if (lastMinuteBroadcast == duration.toMinutes()) {
|
if (lastMinuteBroadcast == duration.toMinutes()) {
|
||||||
return;
|
return;
|
||||||
@@ -115,4 +116,9 @@ public class RunningGame implements Runnable {
|
|||||||
//TODO say the phase ended early?
|
//TODO say the phase ended early?
|
||||||
nextPhaseActions(currentPhase, GamePhase.ENDED);
|
nextPhaseActions(currentPhase, GamePhase.ENDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Duration getRemainingTime() {
|
||||||
|
Duration duration = phaseDurations.get(currentPhase);
|
||||||
|
return duration.minus(Duration.between(phaseStartTime, Instant.now()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -62,7 +61,7 @@ public class ClassSelectionPhase implements GamePhaseExecutor {
|
|||||||
.filter(player -> gameManager.getTeamPlayer(player).isEmpty())
|
.filter(player -> gameManager.getTeamPlayer(player).isEmpty())
|
||||||
.forEach(player -> {
|
.forEach(player -> {
|
||||||
Team team = teamCircularIterator.next();
|
Team team = teamCircularIterator.next();
|
||||||
team.addPlayer(player);
|
gameManager.registerPlayer(team, player);
|
||||||
player.sendRichMessage("You joined <team>!", Placeholder.component("team", team.getName()));
|
player.sendRichMessage("You joined <team>!", Placeholder.component("team", team.getName()));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.alttd.ctf.game.phases;
|
package com.alttd.ctf.game.phases;
|
||||||
|
|
||||||
|
import com.alttd.ctf.Main;
|
||||||
import com.alttd.ctf.config.GameConfig;
|
import com.alttd.ctf.config.GameConfig;
|
||||||
import com.alttd.ctf.flag.Flag;
|
import com.alttd.ctf.flag.Flag;
|
||||||
|
import com.alttd.ctf.game.GameManager;
|
||||||
import com.alttd.ctf.game.GamePhase;
|
import com.alttd.ctf.game.GamePhase;
|
||||||
import com.alttd.ctf.game.GamePhaseExecutor;
|
import com.alttd.ctf.game.GamePhaseExecutor;
|
||||||
import com.alttd.ctf.team.Team;
|
import com.alttd.ctf.team.Team;
|
||||||
@@ -12,9 +14,11 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
|
|||||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.attribute.Attribute;
|
import org.bukkit.attribute.Attribute;
|
||||||
import org.bukkit.attribute.AttributeInstance;
|
import org.bukkit.attribute.AttributeInstance;
|
||||||
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -25,6 +29,13 @@ import java.util.Map;
|
|||||||
public class EndedPhase implements GamePhaseExecutor {
|
public class EndedPhase implements GamePhaseExecutor {
|
||||||
|
|
||||||
private final MiniMessage miniMessage = MiniMessage.miniMessage();
|
private final MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||||
|
private final Main main;
|
||||||
|
private final GameManager gameManager;
|
||||||
|
|
||||||
|
public EndedPhase(Main main, GameManager gameManager) {
|
||||||
|
this.main = main;
|
||||||
|
this.gameManager = gameManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Flag flag) {
|
public void start(Flag flag) {
|
||||||
@@ -51,8 +62,8 @@ public class EndedPhase implements GamePhaseExecutor {
|
|||||||
player.setHealth(20);
|
player.setHealth(20);
|
||||||
});
|
});
|
||||||
flag.resetAll();
|
flag.resetAll();
|
||||||
|
gameManager.getTeams().forEach(team -> Bukkit.getOnlinePlayers().forEach(team::removePlayer));
|
||||||
}).start();
|
}).start();
|
||||||
// TODO reset world (coreprotect) to prep for next round
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Component> getWinnerMessages(HashMap<Team, Integer> wins) {
|
private List<Component> getWinnerMessages(HashMap<Team, Integer> wins) {
|
||||||
@@ -71,18 +82,29 @@ public class EndedPhase implements GamePhaseExecutor {
|
|||||||
return messages;
|
return messages;
|
||||||
} else if (topTeams.size() > 1) { // Draw scenario, multiple teams have the same top score
|
} else if (topTeams.size() > 1) { // Draw scenario, multiple teams have the same top score
|
||||||
messages.add(miniMessage.deserialize("<yellow>It's a draw! Top teams:</yellow>"));
|
messages.add(miniMessage.deserialize("<yellow>It's a draw! Top teams:</yellow>"));
|
||||||
topTeams.forEach(team -> {
|
topTeams.forEach(team -> messages.add(
|
||||||
messages.add(miniMessage.deserialize("<team> had <score> captures.",
|
miniMessage.deserialize("<team> had <score> captures.",
|
||||||
Placeholder.component("team", team.getName()),
|
Placeholder.component("team", team.getName()),
|
||||||
Placeholder.parsed("score", String.valueOf(highestScore))));
|
Placeholder.parsed("score", String.valueOf(highestScore)))));
|
||||||
});
|
|
||||||
addOtherTeamsScore(wins, highestScore, messages);
|
addOtherTeamsScore(wins, highestScore, messages);
|
||||||
return messages;
|
return messages;
|
||||||
} else { // Single winner
|
} else { // Single winner
|
||||||
Team winner = topTeams.getFirst();
|
Team winner = topTeams.getFirst();
|
||||||
messages.add(miniMessage.deserialize("<green><team> has won with <score> captures!</green>",
|
messages.add(miniMessage.deserialize("<green><team> has won with <score> captures!</green>",
|
||||||
Placeholder.component("team", winner.getName()),
|
Placeholder.component("team", winner.getName()),
|
||||||
Placeholder.parsed("score", String.valueOf(highestScore))));
|
Placeholder.parsed("score", String.valueOf(highestScore))));
|
||||||
|
ConsoleCommandSender consoleSender = Bukkit.getConsoleSender();
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(main, () -> {
|
||||||
|
winner.getPlayers().forEach(teamPlayer -> {
|
||||||
|
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(teamPlayer.getUuid());
|
||||||
|
String name = offlinePlayer.getName();
|
||||||
|
if (name == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bukkit.dispatchCommand(consoleSender, String.format("lp user %s permission settemp ctf.victory.%s true 14d", name, winner.getId()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (wins.size() <= 1) {
|
if (wins.size() <= 1) {
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
@@ -97,8 +119,8 @@ public class EndedPhase implements GamePhaseExecutor {
|
|||||||
wins.entrySet().stream()
|
wins.entrySet().stream()
|
||||||
.filter(entry -> entry.getValue() < winningScore)
|
.filter(entry -> entry.getValue() < winningScore)
|
||||||
.forEach(entry -> messages.add(miniMessage.deserialize("<yellow><team> had <score> captures.</yellow>",
|
.forEach(entry -> messages.add(miniMessage.deserialize("<yellow><team> had <score> captures.</yellow>",
|
||||||
Placeholder.component("team", entry.getKey().getName()),
|
Placeholder.component("team", entry.getKey().getName()),
|
||||||
Placeholder.parsed("score", String.valueOf(entry.getValue())))));
|
Placeholder.parsed("score", String.valueOf(entry.getValue())))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -36,14 +36,13 @@ public class GatheringPhase implements GamePhaseExecutor {
|
|||||||
log.error("Unable to update world border due to missing Flag");
|
log.error("Unable to update world border due to missing Flag");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gameManager.getTeams().forEach(team -> {
|
gameManager.getTeams()
|
||||||
team.getPlayers().forEach(teamPlayer -> {
|
.forEach(team -> team.getPlayers().forEach(teamPlayer -> {
|
||||||
Player player = Bukkit.getPlayer(teamPlayer.getUuid());
|
Player player = Bukkit.getPlayer(teamPlayer.getUuid());
|
||||||
if (player == null || !player.isOnline()) {
|
if (player == null || !player.isOnline()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
teamPlayer.resetWorldBorder(player, worldBorderApi, nextPhase, flag.getFlagLocation());
|
teamPlayer.resetWorldBorder(player, worldBorderApi, nextPhase, flag.getFlagLocation());
|
||||||
});
|
}));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.alttd.ctf.game_class;
|
package com.alttd.ctf.game_class;
|
||||||
|
|
||||||
import com.alttd.ctf.game.GameManager;
|
import com.alttd.ctf.game.GameManager;
|
||||||
import com.alttd.ctf.game_class.creation.EngineerCreator;
|
import com.alttd.ctf.game_class.creation.*;
|
||||||
import com.alttd.ctf.game_class.creation.FighterCreator;
|
|
||||||
import com.alttd.ctf.game_class.creation.TankCreator;
|
|
||||||
import com.alttd.ctf.team.Team;
|
import com.alttd.ctf.team.Team;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -14,9 +12,7 @@ public class GameClassRetrieval {
|
|||||||
|
|
||||||
public static HashMap<Integer, List<GameClass>> getGameClassesForAllTeams(GameManager gameManager) {
|
public static HashMap<Integer, List<GameClass>> getGameClassesForAllTeams(GameManager gameManager) {
|
||||||
final HashMap<Integer, List<GameClass>> gameClasses = new HashMap<>();
|
final HashMap<Integer, List<GameClass>> gameClasses = new HashMap<>();
|
||||||
gameManager.getTeams().forEach(team -> {
|
gameManager.getTeams().forEach(team -> gameClasses.put(team.getId(), getGameClassesForTeam(team)));
|
||||||
gameClasses.put(team.getId(), getGameClassesForTeam(team));
|
|
||||||
});
|
|
||||||
return gameClasses;
|
return gameClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +20,9 @@ public class GameClassRetrieval {
|
|||||||
final List<GameClass> gameClasses = new ArrayList<>();
|
final List<GameClass> gameClasses = new ArrayList<>();
|
||||||
gameClasses.add(FighterCreator.createFighter(team.getColor()));
|
gameClasses.add(FighterCreator.createFighter(team.getColor()));
|
||||||
gameClasses.add(TankCreator.createTank(team.getColor()));
|
gameClasses.add(TankCreator.createTank(team.getColor()));
|
||||||
|
gameClasses.add(TrapperCreator.createTrapper(team.getColor()));
|
||||||
gameClasses.add(EngineerCreator.createEngineer(team.getColor()));
|
gameClasses.add(EngineerCreator.createEngineer(team.getColor()));
|
||||||
|
gameClasses.add(MageCreator.createMage(team.getColor()));
|
||||||
return gameClasses;
|
return gameClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.alttd.ctf.game_class.creation;
|
|||||||
|
|
||||||
import com.alttd.ctf.game_class.GameClass;
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
import com.alttd.ctf.game_class.implementations.Engineer;
|
import com.alttd.ctf.game_class.implementations.Engineer;
|
||||||
import com.alttd.ctf.game_class.implementations.Fighter;
|
|
||||||
import com.alttd.ctf.team.TeamColor;
|
import com.alttd.ctf.team.TeamColor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.alttd.ctf.game_class.creation;
|
||||||
|
|
||||||
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
|
import com.alttd.ctf.game_class.implementations.Mage;
|
||||||
|
import com.alttd.ctf.team.TeamColor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class MageCreator {
|
||||||
|
|
||||||
|
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||||
|
|
||||||
|
@Contract("_ -> new")
|
||||||
|
public static @NotNull GameClass createMage(@NotNull TeamColor teamColor) {
|
||||||
|
return new Mage(getArmor(), getTools(teamColor), getDisplayItem(teamColor),
|
||||||
|
20, 100, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(value = " -> new", pure = true)
|
||||||
|
private static @NotNull @Unmodifiable List<Material> getArmor() {
|
||||||
|
return (List.of(Material.CHAINMAIL_BOOTS, Material.AIR, Material.AIR, Material.LEATHER_HELMET));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract("_ -> new")
|
||||||
|
private static @NotNull @Unmodifiable List<ItemStack> getTools(@NotNull TeamColor teamColor) {
|
||||||
|
return (List.of(getShovel(teamColor)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NotNull ItemStack getShovel(@NotNull TeamColor teamColor) {
|
||||||
|
ItemStack shovel = new ItemStack(Material.WOODEN_SHOVEL);
|
||||||
|
ItemMeta meta = shovel.getItemMeta();
|
||||||
|
meta.itemName(miniMessage.deserialize(String.format("<color:%s>Snow shovel</color>", teamColor.hex())));
|
||||||
|
meta.setUnbreakable(true);
|
||||||
|
meta.addEnchant(Enchantment.EFFICIENCY, 1, false);
|
||||||
|
shovel.setItemMeta(meta);
|
||||||
|
return shovel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NotNull ItemStack getDisplayItem(@NotNull TeamColor teamColor) {
|
||||||
|
ItemStack itemStack = new ItemStack(Material.SNOWBALL);
|
||||||
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
|
itemMeta.displayName(miniMessage.deserialize(String.format("<color:%s>Mage</color>", teamColor.hex())));
|
||||||
|
itemMeta.lore(List.of(
|
||||||
|
miniMessage.deserialize("<gold>The Mage can throw many snowballs at once</gold>"),
|
||||||
|
miniMessage.deserialize("<gold>But it has a long cooldown.</gold>")
|
||||||
|
));
|
||||||
|
itemStack.setItemMeta(itemMeta);
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.alttd.ctf.game_class.creation;
|
package com.alttd.ctf.game_class.creation;
|
||||||
|
|
||||||
import com.alttd.ctf.game_class.GameClass;
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
import com.alttd.ctf.game_class.implementations.Fighter;
|
|
||||||
import com.alttd.ctf.game_class.implementations.Tank;
|
import com.alttd.ctf.game_class.implementations.Tank;
|
||||||
import com.alttd.ctf.team.TeamColor;
|
import com.alttd.ctf.team.TeamColor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -22,7 +21,7 @@ public class TankCreator {
|
|||||||
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
|
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||||
|
|
||||||
@Contract("_ -> new")
|
@Contract("_ -> new")
|
||||||
public static @NotNull GameClass createTank(@NotNull TeamColor teamColor) {//TODO add ability to become temp invulnerable (with some particle effects mayb?)
|
public static @NotNull GameClass createTank(@NotNull TeamColor teamColor) {
|
||||||
return new Tank(getArmor(), getTools(teamColor), getDisplayItem(teamColor),
|
return new Tank(getArmor(), getTools(teamColor), getDisplayItem(teamColor),
|
||||||
30, 7, 4);
|
30, 7, 4);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.alttd.ctf.game_class.creation;
|
||||||
|
|
||||||
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
|
import com.alttd.ctf.game_class.implementations.Trapper;
|
||||||
|
import com.alttd.ctf.team.TeamColor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class TrapperCreator {
|
||||||
|
|
||||||
|
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||||
|
|
||||||
|
@Contract("_ -> new")
|
||||||
|
public static @NotNull GameClass createTrapper(@NotNull TeamColor teamColor) {
|
||||||
|
return new Trapper(getArmor(), getTools(teamColor), getDisplayItem(teamColor),
|
||||||
|
20, 5, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(value = " -> new", pure = true)
|
||||||
|
private static @Unmodifiable List<Material> getArmor() {
|
||||||
|
return (List.of(Material.LEATHER_BOOTS, Material.LEATHER_LEGGINGS, Material.LEATHER_CHESTPLATE, Material.AIR));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract("_ -> new")
|
||||||
|
private static @NotNull @Unmodifiable List<ItemStack> getTools(TeamColor teamColor) {
|
||||||
|
List<ItemStack> itemStacks = new ArrayList<>(List.of(getShovel(teamColor)));
|
||||||
|
itemStacks.addAll(getPowderedSnow(teamColor));
|
||||||
|
return itemStacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NotNull List<ItemStack> getPowderedSnow(@NotNull TeamColor teamColor) {
|
||||||
|
ItemStack powderedSnow = new ItemStack(Material.POWDER_SNOW_BUCKET);
|
||||||
|
ItemMeta itemMeta = powderedSnow.getItemMeta();
|
||||||
|
itemMeta.itemName(MiniMessage.miniMessage().deserialize(
|
||||||
|
String.format("<color:%s>Snow Trap</color>", teamColor.hex())));
|
||||||
|
powderedSnow.setItemMeta(itemMeta);
|
||||||
|
List<ItemStack> snowBuckets = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
snowBuckets.add(powderedSnow.clone());
|
||||||
|
}
|
||||||
|
return snowBuckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NotNull ItemStack getShovel(@NotNull TeamColor teamColor) {
|
||||||
|
ItemStack shovel = new ItemStack(Material.WOODEN_SHOVEL);
|
||||||
|
ItemMeta meta = shovel.getItemMeta();
|
||||||
|
meta.setUnbreakable(true);
|
||||||
|
meta.itemName(miniMessage.deserialize(String.format("<color:%s>Snow shovel</color>", teamColor.hex())));
|
||||||
|
shovel.setItemMeta(meta);
|
||||||
|
return shovel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NotNull ItemStack getDisplayItem(@NotNull TeamColor teamColor) {
|
||||||
|
ItemStack itemStack = new ItemStack(Material.POWDER_SNOW_BUCKET);
|
||||||
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
|
itemMeta.displayName(miniMessage.deserialize(String.format("<color:%s>Trapper</color>", teamColor.hex())));
|
||||||
|
itemMeta.lore(List.of(
|
||||||
|
miniMessage.deserialize("<gold>The Trapper is a normal class, but it has a trick up it's sleeve</gold>"),
|
||||||
|
miniMessage.deserialize("<gold>They can place their powdered snow to trap the enemy team.</gold>")
|
||||||
|
));
|
||||||
|
itemStack.setItemMeta(itemMeta);
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
package com.alttd.ctf.game_class.implementations;
|
package com.alttd.ctf.game_class.implementations;
|
||||||
|
|
||||||
import com.alttd.ctf.game_class.GameClass;
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
import com.alttd.ctf.team.TeamColor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.alttd.ctf.game_class.implementations;
|
||||||
|
|
||||||
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.entity.Snowball;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class Mage extends GameClass {
|
||||||
|
public Mage(@NotNull List<Material> armor, @NotNull List<ItemStack> tools, @NotNull ItemStack displayItem,
|
||||||
|
double health, int throwTickSpeed, int damage) {
|
||||||
|
super(armor, tools, displayItem, health, throwTickSpeed, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void duplicateSnowBalls(Player shooter, Snowball snowball) {
|
||||||
|
Location location = snowball.getLocation();
|
||||||
|
PlayerInventory inventory = shooter.getInventory();
|
||||||
|
ItemStack itemStack = inventory.getItemInMainHand();
|
||||||
|
if (itemStack.getType() != Material.SNOWBALL) {
|
||||||
|
ItemStack itemInOffHand = inventory.getItemInOffHand();
|
||||||
|
if (itemInOffHand.getType() != Material.SNOWBALL) {
|
||||||
|
log.warn("Unable to find snowballs in main/off hand");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
itemStack = itemInOffHand;
|
||||||
|
}
|
||||||
|
if (itemStack.getAmount() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
duplicate(shooter, location, snowball.getVelocity(), itemStack.getAmount() - 1);
|
||||||
|
itemStack.setAmount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void duplicate(@NotNull Player shooter, @NotNull Location location, @NotNull Vector velocity, int count) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
double offsetX = (Math.random() - 0.5) * 2;
|
||||||
|
double offsetY = (Math.random() - 0.5) * 2;
|
||||||
|
double offsetZ = (Math.random() - 0.5) * 2;
|
||||||
|
|
||||||
|
Location newLocation = location.clone().add(offsetX, offsetY, offsetZ);
|
||||||
|
Snowball snowball = location.getWorld().spawn(newLocation, Snowball.class);
|
||||||
|
|
||||||
|
snowball.setShooter(shooter);
|
||||||
|
|
||||||
|
double velocityChangeX = (Math.random() - 0.5) * 0.5;
|
||||||
|
double velocityChangeY = (Math.random() - 0.5) * 0.5;
|
||||||
|
double velocityChangeZ = (Math.random() - 0.5) * 0.5;
|
||||||
|
|
||||||
|
Vector newVelocity = velocity.clone().add(new Vector(velocityChangeX, velocityChangeY, velocityChangeZ));
|
||||||
|
|
||||||
|
snowball.setVelocity(newVelocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.alttd.ctf.game_class.implementations;
|
||||||
|
|
||||||
|
import com.alttd.ctf.game_class.GameClass;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Trapper extends GameClass {
|
||||||
|
public Trapper(@NotNull List<Material> armor, @NotNull List<ItemStack> tools, @NotNull ItemStack displayItem,
|
||||||
|
double health, int throwTickSpeed, int damage) {
|
||||||
|
super(armor, tools, displayItem, health, throwTickSpeed, damage);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@ package com.alttd.ctf.gui;
|
|||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.Merchant;
|
|
||||||
import org.bukkit.inventory.MerchantInventory;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|||||||
@@ -1,16 +1,42 @@
|
|||||||
package com.alttd.ctf.stats;
|
package com.alttd.ctf.stats;
|
||||||
|
|
||||||
|
import com.alttd.ctf.Main;
|
||||||
|
import com.alttd.ctf.config.GameConfig;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@RequiredArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
public final class PlayerStat {
|
public final class PlayerStat {
|
||||||
|
@JsonIgnore
|
||||||
|
public static Main main;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
private boolean touched;
|
||||||
|
@JsonIgnore
|
||||||
private static final CommandSender commandSender = Bukkit.getConsoleSender();
|
private static final CommandSender commandSender = Bukkit.getConsoleSender();
|
||||||
private final UUID uuid;
|
@JsonIgnore
|
||||||
private final String inGameName;
|
private static boolean someoneDiedInPowderedSnow = false;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotNull
|
||||||
|
private UUID uuid;
|
||||||
|
@JsonProperty
|
||||||
|
@NotNull
|
||||||
|
private String inGameName;
|
||||||
|
|
||||||
private boolean completedGame = false;
|
private boolean completedGame = false;
|
||||||
private int flagsCaptured = 0;
|
private int flagsCaptured = 0;
|
||||||
@@ -23,16 +49,16 @@ public final class PlayerStat {
|
|||||||
private long timeSpendCapturingFlag = 0;
|
private long timeSpendCapturingFlag = 0;
|
||||||
private int deathsInPowderedSnow = 0;
|
private int deathsInPowderedSnow = 0;
|
||||||
|
|
||||||
public PlayerStat(UUID uuid, String inGameName) {
|
|
||||||
this.uuid = uuid;
|
|
||||||
this.inGameName = inGameName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void increaseStat(Stat stat) throws IllegalArgumentException {
|
public void increaseStat(Stat stat) throws IllegalArgumentException {
|
||||||
switch (stat) {
|
switch (stat) {
|
||||||
case COMPLETED_GAME -> {
|
case COMPLETED_GAME -> {
|
||||||
if (!completedGame) {
|
if (!completedGame) {
|
||||||
Bukkit.dispatchCommand(commandSender, String.format("lp user %s permission set ctf.game.completed", inGameName));
|
Bukkit.getScheduler().runTask(main, () -> {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(main, () -> {
|
||||||
|
Bukkit.dispatchCommand(commandSender, String.format("lp user %s permission settemp ctf.game.completed true 14d", inGameName));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
completedGame = true;
|
completedGame = true;
|
||||||
}
|
}
|
||||||
@@ -42,9 +68,30 @@ public final class PlayerStat {
|
|||||||
case BLOCKS_PLACED -> blocksPlaced++;
|
case BLOCKS_PLACED -> blocksPlaced++;
|
||||||
case SNOWBALLS_THROWN -> snowballsThrown++;
|
case SNOWBALLS_THROWN -> snowballsThrown++;
|
||||||
case TIME_SPEND_CAPTURING_FLAG -> timeSpendCapturingFlag++;
|
case TIME_SPEND_CAPTURING_FLAG -> timeSpendCapturingFlag++;
|
||||||
case DEATHS_IN_POWDERED_SNOW -> deathsInPowderedSnow++; //TODO announce if they are the first person to do this and save they are the first
|
case DEATHS_IN_POWDERED_SNOW -> {
|
||||||
|
if (someoneDiedInPowderedSnow) {
|
||||||
|
deathsInPowderedSnow++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
|
||||||
|
if (!offlinePlayer.isOnline()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Player player = offlinePlayer.getPlayer();
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bukkit.broadcast(MiniMessage.miniMessage().deserialize("<red><player> will receive a consolation prize for being the first to die in powdered snow.</red>",
|
||||||
|
Placeholder.component("player",player.displayName())));
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(main, () -> {
|
||||||
|
Bukkit.dispatchCommand(commandSender, String.format("lp user %s permission settemp ctf.game.first_powdered_snow_death true 14d", inGameName));
|
||||||
|
});
|
||||||
|
|
||||||
|
someoneDiedInPowderedSnow = true;
|
||||||
|
}
|
||||||
case DAMAGE_DONE, DAMAGE_HEALED -> throw new IllegalArgumentException(String.format("%s requires a number", stat.name()));
|
case DAMAGE_DONE, DAMAGE_HEALED -> throw new IllegalArgumentException(String.format("%s requires a number", stat.name()));
|
||||||
}
|
}
|
||||||
|
touched = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void increaseStat(Stat stat, double value) throws IllegalArgumentException {
|
public void increaseStat(Stat stat, double value) throws IllegalArgumentException {
|
||||||
@@ -53,6 +100,25 @@ public final class PlayerStat {
|
|||||||
case DAMAGE_HEALED -> damageHealed += value;
|
case DAMAGE_HEALED -> damageHealed += value;
|
||||||
default -> throw new IllegalArgumentException(String.format("%s cannot be passed with a number", stat.name()));
|
default -> throw new IllegalArgumentException(String.format("%s cannot be passed with a number", stat.name()));
|
||||||
}
|
}
|
||||||
|
touched = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUnTouched() {
|
||||||
|
touched = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getStat(Stat stat) {
|
||||||
|
return switch (stat) {
|
||||||
|
case COMPLETED_GAME -> completedGame ? 1 : 0;
|
||||||
|
case FLAGS_CAPTURED -> flagsCaptured;
|
||||||
|
case KILLS -> kills;
|
||||||
|
case DAMAGE_DONE -> damageDone;
|
||||||
|
case DAMAGE_HEALED -> damageHealed;
|
||||||
|
case SNOW_MINED -> snowMined;
|
||||||
|
case BLOCKS_PLACED -> blocksPlaced;
|
||||||
|
case SNOWBALLS_THROWN -> snowballsThrown;
|
||||||
|
case TIME_SPEND_CAPTURING_FLAG -> timeSpendCapturingFlag;
|
||||||
|
case DEATHS_IN_POWDERED_SNOW -> deathsInPowderedSnow;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.alttd.ctf.game.GameManager;
|
|||||||
import com.alttd.galaxy.discord.Bot;
|
import com.alttd.galaxy.discord.Bot;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.dv8tion.jda.api.JDA;
|
import net.dv8tion.jda.api.JDA;
|
||||||
import net.dv8tion.jda.api.Permission;
|
|
||||||
import net.dv8tion.jda.api.entities.*;
|
import net.dv8tion.jda.api.entities.*;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -56,9 +55,7 @@ public class DiscordTeam {
|
|||||||
}
|
}
|
||||||
Member nullableMember = guild.getMemberById(player.getDiscordID());
|
Member nullableMember = guild.getMemberById(player.getDiscordID());
|
||||||
if (nullableMember == null) {
|
if (nullableMember == null) {
|
||||||
guild.retrieveMemberById(player.getDiscordID()).queue(member -> {
|
guild.retrieveMemberById(player.getDiscordID()).queue(member -> consumer.apply(role, member));
|
||||||
consumer.apply(role, member);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
consumer.apply(role, nullableMember);
|
consumer.apply(role, nullableMember);
|
||||||
}
|
}
|
||||||
@@ -70,7 +67,7 @@ public class DiscordTeam {
|
|||||||
log.info("Unable to remove team role from server owner");
|
log.info("Unable to remove team role from server owner");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
member.getGuild().removeRoleFromMember(member, role).queue(ignored -> kickFromVoiceIfNeeded(member));
|
member.getGuild().removeRoleFromMember(member, role).queue();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,24 +80,8 @@ public class DiscordTeam {
|
|||||||
gameManager.getTeams().forEach(otherTeam ->
|
gameManager.getTeams().forEach(otherTeam ->
|
||||||
member.getRoles().stream()
|
member.getRoles().stream()
|
||||||
.filter(otherRole -> otherRole.getIdLong() == otherTeam.getDiscordRole())
|
.filter(otherRole -> otherRole.getIdLong() == otherTeam.getDiscordRole())
|
||||||
.forEach(otherRole -> {
|
.forEach(otherRole -> member.getGuild().removeRoleFromMember(member, otherRole).queue()));
|
||||||
member.getGuild().removeRoleFromMember(member, otherRole).queue();
|
member.getGuild().addRoleToMember(member, role).queue();
|
||||||
}));
|
|
||||||
member.getGuild().addRoleToMember(member, role).queue(ignored -> kickFromVoiceIfNeeded(member));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void kickFromVoiceIfNeeded(@NotNull Member member) {
|
|
||||||
GuildVoiceState voiceState = member.getVoiceState();
|
|
||||||
if (voiceState == null || !voiceState.inAudioChannel()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AudioChannel channel = voiceState.getChannel();
|
|
||||||
if (channel == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!member.hasPermission(channel, Permission.VOICE_CONNECT)) {
|
|
||||||
member.getGuild().kickVoiceMember(member).queue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.alttd.ctf.team;
|
package com.alttd.ctf.team;
|
||||||
|
|
||||||
import com.alttd.ctf.game.GameManager;
|
import com.alttd.ctf.game.GameManager;
|
||||||
|
import com.alttd.ctf.stats.PlayerStat;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -8,15 +9,9 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scoreboard.*;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -27,7 +22,7 @@ import java.util.*;
|
|||||||
public class Team {
|
public class Team {
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private final static Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
|
private final TeamScoreboard scoreboard = new TeamScoreboard(this);
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private final HashMap<UUID, TeamPlayer> players = new HashMap<>();
|
private final HashMap<UUID, TeamPlayer> players = new HashMap<>();
|
||||||
@JsonProperty("name")
|
@JsonProperty("name")
|
||||||
@@ -73,10 +68,10 @@ public class Team {
|
|||||||
discordTeam = new DiscordTeam(gameManager);
|
discordTeam = new DiscordTeam(gameManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TeamPlayer addPlayer(Player player) {
|
public TeamPlayer addPlayer(Player player, PlayerStat playerStat) {
|
||||||
removeFromScoreBoard(player);
|
removeFromScoreboard(player);
|
||||||
UUID uuid = player.getUniqueId();
|
UUID uuid = player.getUniqueId();
|
||||||
TeamPlayer teamPlayer = new TeamPlayer(player, this);
|
TeamPlayer teamPlayer = new TeamPlayer(player, this, playerStat);
|
||||||
players.put(uuid, teamPlayer);
|
players.put(uuid, teamPlayer);
|
||||||
addToScoreboard(player);
|
addToScoreboard(player);
|
||||||
if (discordTeam != null) {
|
if (discordTeam != null) {
|
||||||
@@ -100,7 +95,7 @@ public class Team {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removePlayer(@NotNull Player player) {
|
public void removePlayer(@NotNull Player player) {
|
||||||
removeFromScoreBoard(player);
|
removeFromScoreboard(player);
|
||||||
TeamPlayer remove = players.remove(player.getUniqueId());
|
TeamPlayer remove = players.remove(player.getUniqueId());
|
||||||
if (remove == null) {
|
if (remove == null) {
|
||||||
return;
|
return;
|
||||||
@@ -114,38 +109,15 @@ public class Team {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addToScoreboard(Player player) {
|
public void addToScoreboard(Player player) {
|
||||||
org.bukkit.scoreboard.Team team = scoreboard.getTeam("ctf_" + id);
|
scoreboard.addToScoreboard(player);
|
||||||
if (team == null) {
|
|
||||||
team = scoreboard.registerNewTeam("ctf_" + id);
|
|
||||||
team.displayName(name);
|
|
||||||
NamedTextColor namedTextColor = NamedTextColor.nearestTo(TextColor.color(color.r(), color.g(), color.b()));
|
|
||||||
team.color(namedTextColor);
|
|
||||||
}
|
|
||||||
team.addPlayer(player);
|
|
||||||
player.setScoreboard(scoreboard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFromScoreBoard(Player player) {
|
private void removeFromScoreboard(Player player) {
|
||||||
scoreboard.getTeams().stream()
|
scoreboard.removeFromScoreboard(player);
|
||||||
.filter(team -> team.getName().startsWith("ctf_"))
|
|
||||||
.filter(team -> team.hasPlayer(player))
|
|
||||||
.forEach(team -> team.removePlayer(player));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScore(int newScore) {
|
public void setScore(int newScore) {
|
||||||
Objective objective = getOrCreateObjective();
|
scoreboard.setScore(newScore);
|
||||||
Score score = objective.getScore(legacyTeamColor + PlainTextComponentSerializer.plainText().serialize(name));
|
|
||||||
score.setScore(newScore);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Objective getOrCreateObjective() {
|
|
||||||
Objective objective = scoreboard.getObjective("teamScores");
|
|
||||||
if (objective == null) {
|
|
||||||
objective = scoreboard.registerNewObjective("teamScores", Criteria.DUMMY,
|
|
||||||
MiniMessage.miniMessage().deserialize("<gold>CTF score</gold>"));
|
|
||||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
|
||||||
}
|
|
||||||
return objective;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ public class TeamPlayer {
|
|||||||
private GameClass gameClass;
|
private GameClass gameClass;
|
||||||
private boolean isDead = false;
|
private boolean isDead = false;
|
||||||
|
|
||||||
protected TeamPlayer(Player player, Team team) {
|
protected TeamPlayer(Player player, Team team, PlayerStat playerStat) {
|
||||||
this.uuid = player.getUniqueId();
|
this.uuid = player.getUniqueId();
|
||||||
this.team = team;
|
this.team = team;
|
||||||
this.playerStat = new PlayerStat(uuid, player.getName());
|
this.playerStat = playerStat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void respawn(@NotNull Player player, @NotNull WorldBorderApi worldBorderApi, @NotNull GamePhase gamePhase) {
|
public void respawn(@NotNull Player player, @NotNull WorldBorderApi worldBorderApi, @NotNull GamePhase gamePhase) {
|
||||||
@@ -60,8 +60,8 @@ public class TeamPlayer {
|
|||||||
isDead = true;
|
isDead = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetWorldBorder(@NotNull Player player, WorldBorderApi worldBorderApi, GamePhase gamePhase, Location worldBorderCenter) {
|
public void resetWorldBorder(Player player, WorldBorderApi worldBorderApi, GamePhase gamePhase, Location worldBorderCenter) {
|
||||||
if (!player.isOnline()) {
|
if (player == null || !player.isOnline()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WorldBorderSettings worldBorderSettings = GameConfig.WORLD_BORDER.getGAME_PHASE_WORLD_BORDER().get(gamePhase);
|
WorldBorderSettings worldBorderSettings = GameConfig.WORLD_BORDER.getGAME_PHASE_WORLD_BORDER().get(gamePhase);
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.alttd.ctf.team;
|
||||||
|
|
||||||
|
import com.alttd.ctf.game.GameManager;
|
||||||
|
import com.alttd.ctf.game.GamePhase;
|
||||||
|
import net.kyori.adventure.text.format.*;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scoreboard.*;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
public class TeamScoreboard {
|
||||||
|
|
||||||
|
private final static Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
|
||||||
|
private final Team team;
|
||||||
|
|
||||||
|
public TeamScoreboard(Team team) {
|
||||||
|
this.team = team;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToScoreboard(Player player) {
|
||||||
|
org.bukkit.scoreboard.Team scoreboardTeam = scoreboard.getTeam("ctf_" + team.getId());
|
||||||
|
if (scoreboardTeam == null) {
|
||||||
|
scoreboardTeam = scoreboard.registerNewTeam("ctf_" + team.getId());
|
||||||
|
scoreboardTeam.displayName(team.getName());
|
||||||
|
TeamColor color = team.getColor();
|
||||||
|
NamedTextColor namedTextColor = NamedTextColor.nearestTo(TextColor.color(color.r(), color.g(), color.b()));
|
||||||
|
scoreboardTeam.color(namedTextColor);
|
||||||
|
}
|
||||||
|
scoreboardTeam.addPlayer(player);
|
||||||
|
player.setScoreboard(scoreboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeFromScoreboard(Player player) {
|
||||||
|
scoreboard.getTeams().stream()
|
||||||
|
.filter(team -> team.getName().startsWith("ctf_"))
|
||||||
|
.filter(team -> team.hasPlayer(player))
|
||||||
|
.forEach(team -> team.removePlayer(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setScore(int newScore) {
|
||||||
|
Objective objective = getOrCreateObjective();
|
||||||
|
Score score = objective.getScore(team.getLegacyTeamColor() +
|
||||||
|
PlainTextComponentSerializer.plainText().serialize(team.getName()));
|
||||||
|
score.setScore(newScore);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Objective getOrCreateObjective() {
|
||||||
|
Objective objective = scoreboard.getObjective("teamScores");
|
||||||
|
if (objective == null) {
|
||||||
|
objective = scoreboard.registerNewObjective("teamScores", Criteria.DUMMY,
|
||||||
|
MiniMessage.miniMessage().deserialize("<gold>CTF score</gold>"));
|
||||||
|
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||||
|
}
|
||||||
|
return objective;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record PhaseScore(GamePhase gamePhase, Score score) {}
|
||||||
|
private static PhaseScore phaseScore = null;
|
||||||
|
private static void updateTime(GamePhase gamePhase, Duration duration) {
|
||||||
|
if (phaseScore == null) {
|
||||||
|
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective()
|
||||||
|
.getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName())));
|
||||||
|
} else if (phaseScore.gamePhase() != gamePhase) {
|
||||||
|
phaseScore.score.resetScore();
|
||||||
|
phaseScore = new PhaseScore(gamePhase, getOrCreateObjective()
|
||||||
|
.getScore(ChatColor.GREEN + PlainTextComponentSerializer.plainText().serialize(gamePhase.getDisplayName())));
|
||||||
|
}
|
||||||
|
phaseScore.score.setScore(duration.toMinutesPart() == 0 ? duration.toSecondsPart() : duration.toMinutesPart());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void refreshScoreboard(GameManager gameManager) {
|
||||||
|
gameManager.getGamePhase().ifPresent(gamePhase ->
|
||||||
|
gameManager.getRemainingTime().ifPresent(duration ->
|
||||||
|
updateTime(gamePhase, duration)));
|
||||||
|
// TODO if game is active show time + game phase
|
||||||
|
// if someone has flag show that
|
||||||
|
// show how many of each team in circle?
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
#Sun Feb 23 01:14:21 CET 2025
|
#Sun Mar 02 00:42:30 CET 2025
|
||||||
buildNumber=70
|
buildNumber=112
|
||||||
version=0.1
|
version=0.1
|
||||||
|
|||||||
Reference in New Issue
Block a user