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