From 3c5842a92c11a8e922214e0219064254519a2682 Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Sat, 1 Mar 2025 19:29:46 +0100 Subject: [PATCH] Implement shield mechanics and enhance game end reset logic Added shield blocking, cooldown, and breaking mechanics with sound and particle effects. Improved game reset functionality to properly remove players from teams at the end. Updated capture material and refactored imports for cleaner structure. --- src/main/java/com/alttd/ctf/Main.java | 6 +- .../java/com/alttd/ctf/config/GameConfig.java | 2 +- .../com/alttd/ctf/events/OtherGameEvents.java | 2 + .../com/alttd/ctf/events/SnowballEvent.java | 71 ++++++++++++++++++- .../java/com/alttd/ctf/game/GameManager.java | 2 +- .../com/alttd/ctf/game/phases/EndedPhase.java | 8 ++- version.properties | 4 +- 7 files changed, 84 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/alttd/ctf/Main.java b/src/main/java/com/alttd/ctf/Main.java index 1b90e26..c204143 100644 --- a/src/main/java/com/alttd/ctf/Main.java +++ b/src/main/java/com/alttd/ctf/Main.java @@ -4,10 +4,7 @@ import com.alttd.ctf.commands.CommandManager; import com.alttd.ctf.config.Config; import com.alttd.ctf.config.GameConfig; import com.alttd.ctf.config.Messages; -import com.alttd.ctf.events.InventoryItemInteractionEvent; -import com.alttd.ctf.events.OnPlayerDeath; -import com.alttd.ctf.events.OnPlayerOnlineStatus; -import com.alttd.ctf.events.SnowballEvent; +import com.alttd.ctf.events.*; import com.alttd.ctf.flag.Flag; import com.alttd.ctf.flag.FlagTryCaptureEvent; import com.alttd.ctf.game.GameManager; @@ -94,6 +91,7 @@ public class Main extends JavaPlugin { private void registerEvents(Flag flag, WorldBorderApi worldBorderApi) { PluginManager pluginManager = getServer().getPluginManager(); pluginManager.registerEvents(new SnowballEvent(gameManager), this); + pluginManager.registerEvents(new OtherGameEvents(gameManager), this); pluginManager.registerEvents(new FlagTryCaptureEvent(flag), this); pluginManager.registerEvents(new OnPlayerDeath(gameManager, worldBorderApi, this, flag), this); pluginManager.registerEvents(new InventoryItemInteractionEvent(), this); diff --git a/src/main/java/com/alttd/ctf/config/GameConfig.java b/src/main/java/com/alttd/ctf/config/GameConfig.java index 8ffa691..ed4bc28 100644 --- a/src/main/java/com/alttd/ctf/config/GameConfig.java +++ b/src/main/java/com/alttd/ctf/config/GameConfig.java @@ -90,7 +90,7 @@ public class GameConfig extends AbstractConfig { public static double CAPTURE_RADIUS = 5; public static int CAPTURE_SCORE = 50; 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") private static void load() { diff --git a/src/main/java/com/alttd/ctf/events/OtherGameEvents.java b/src/main/java/com/alttd/ctf/events/OtherGameEvents.java index 0fc72f7..8d3306f 100644 --- a/src/main/java/com/alttd/ctf/events/OtherGameEvents.java +++ b/src/main/java/com/alttd/ctf/events/OtherGameEvents.java @@ -30,8 +30,10 @@ public class OtherGameEvents implements Listener { @EventHandler public void onBlockBreak(BlockBreakEvent event) { if (gameManager.getGamePhase().isEmpty()) { + log.info("no game phases"); return; } + log.info(event.getBlock().getType().toString()); if (!Tag.SNOW.isTagged(event.getBlock().getType())) { event.setCancelled(true); return; diff --git a/src/main/java/com/alttd/ctf/events/SnowballEvent.java b/src/main/java/com/alttd/ctf/events/SnowballEvent.java index affa31f..ea89f6b 100644 --- a/src/main/java/com/alttd/ctf/events/SnowballEvent.java +++ b/src/main/java/com/alttd/ctf/events/SnowballEvent.java @@ -9,6 +9,8 @@ import com.alttd.ctf.team.TeamPlayer; import lombok.extern.slf4j.Slf4j; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.Sound; import org.bukkit.entity.Snowball; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -18,7 +20,11 @@ import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import java.time.Instant; +import java.util.HashMap; +import java.util.LinkedList; import java.util.Optional; +import java.util.UUID; @Slf4j public class SnowballEvent implements Listener { @@ -42,7 +48,8 @@ public class SnowballEvent implements Listener { @EventHandler public void onSnowballHit(EntityDamageByEntityEvent event) { 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; } GameClass shooterClass = shooterTeamPlayer.getGameClass(); @@ -57,9 +64,26 @@ public class SnowballEvent implements Listener { } log.debug("{} health was set to {} because of a snowball thrown by {}", 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 public void onSnowballThrown(ProjectileLaunchEvent event) { handleSnowballThrown(event, (shooter, shooterTeamPlayer, snowball) -> { @@ -72,10 +96,22 @@ public class SnowballEvent implements Listener { }); } - private boolean blockedAttack(@NotNull Player hitPlayer, @NotNull Snowball snowball) { + private final HashMap> lastTankHits = new HashMap<>(); + + private boolean blockedAttack(@NotNull Player hitPlayer, @NotNull Player shooter, @NotNull Snowball snowball) { if (!hitPlayer.isBlocking()) { 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(); Vector playerFacing = playerLocation.getDirection().normalize(); Location snowballLocation = snowball.getLocation(); @@ -86,6 +122,37 @@ public class SnowballEvent implements Listener { 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 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) { Optional optionalGamePhase = gameManager.getGamePhase(); if (optionalGamePhase.isEmpty()) { diff --git a/src/main/java/com/alttd/ctf/game/GameManager.java b/src/main/java/com/alttd/ctf/game/GameManager.java index 48ebf76..7a4191c 100644 --- a/src/main/java/com/alttd/ctf/game/GameManager.java +++ b/src/main/java/com/alttd/ctf/game/GameManager.java @@ -32,7 +32,7 @@ public class GameManager { phases.put(GamePhase.CLASS_SELECTION, new ClassSelectionPhase(this, FighterCreator::createFighter, worldBorderApi)); phases.put(GamePhase.GATHERING, new GatheringPhase(this, worldBorderApi)); phases.put(GamePhase.COMBAT, new CombatPhase()); - phases.put(GamePhase.ENDED, new EndedPhase()); + phases.put(GamePhase.ENDED, new EndedPhase(this)); } public Optional getGamePhase() { diff --git a/src/main/java/com/alttd/ctf/game/phases/EndedPhase.java b/src/main/java/com/alttd/ctf/game/phases/EndedPhase.java index 7d5df38..be2fb07 100644 --- a/src/main/java/com/alttd/ctf/game/phases/EndedPhase.java +++ b/src/main/java/com/alttd/ctf/game/phases/EndedPhase.java @@ -2,6 +2,7 @@ package com.alttd.ctf.game.phases; import com.alttd.ctf.config.GameConfig; import com.alttd.ctf.flag.Flag; +import com.alttd.ctf.game.GameManager; import com.alttd.ctf.game.GamePhase; import com.alttd.ctf.game.GamePhaseExecutor; import com.alttd.ctf.team.Team; @@ -25,6 +26,11 @@ import java.util.Map; public class EndedPhase implements GamePhaseExecutor { private final MiniMessage miniMessage = MiniMessage.miniMessage(); + private final GameManager gameManager; + + public EndedPhase(GameManager gameManager) { + this.gameManager = gameManager; + } @Override public void start(Flag flag) { @@ -51,8 +57,8 @@ public class EndedPhase implements GamePhaseExecutor { player.setHealth(20); }); flag.resetAll(); + gameManager.getTeams().forEach(team -> Bukkit.getOnlinePlayers().forEach(team::removePlayer)); }).start(); - // TODO reset world (coreprotect) to prep for next round } private List getWinnerMessages(HashMap wins) { diff --git a/version.properties b/version.properties index 06fd47f..866d440 100644 --- a/version.properties +++ b/version.properties @@ -1,3 +1,3 @@ -#Sat Mar 01 01:12:24 CET 2025 -buildNumber=95 +#Sat Mar 01 19:29:28 CET 2025 +buildNumber=102 version=0.1