diff --git a/src/main/java/org/battleplugins/arena/ctf/ArenaCtf.java b/src/main/java/org/battleplugins/arena/ctf/ArenaCtf.java index 1fc6e21..8c4f3e7 100644 --- a/src/main/java/org/battleplugins/arena/ctf/ArenaCtf.java +++ b/src/main/java/org/battleplugins/arena/ctf/ArenaCtf.java @@ -8,6 +8,7 @@ import org.battleplugins.arena.ctf.arena.CtfArena; import org.battleplugins.arena.ctf.event.ArenaFlagCaptureEvent; import org.battleplugins.arena.ctf.event.ArenaFlagReturnEvent; +import org.battleplugins.arena.ctf.event.ArenaFlagTakeEvent; import org.battleplugins.arena.event.ArenaEventType; import org.battleplugins.arena.event.action.EventActionType; import org.battleplugins.arena.stat.ArenaStat; @@ -29,6 +30,7 @@ public class ArenaCtf extends JavaPlugin { public static final ArenaEventType FLAG_CAPTURE_EVENT = ArenaEventType.create("on-flag-capture", ArenaFlagCaptureEvent.class); public static final ArenaEventType FLAG_RETURN_EVENT = ArenaEventType.create("on-flag-return", ArenaFlagReturnEvent.class); + public static final ArenaEventType FLAG_TAKE_EVENT = ArenaEventType.create("on-flag-take", ArenaFlagTakeEvent.class); private static ArenaCtf instance; diff --git a/src/main/java/org/battleplugins/arena/ctf/arena/CtfCompetition.java b/src/main/java/org/battleplugins/arena/ctf/arena/CtfCompetition.java index 4bf3100..dee5936 100644 --- a/src/main/java/org/battleplugins/arena/ctf/arena/CtfCompetition.java +++ b/src/main/java/org/battleplugins/arena/ctf/arena/CtfCompetition.java @@ -9,6 +9,7 @@ import org.battleplugins.arena.ctf.CtfUtil; import org.battleplugins.arena.ctf.event.ArenaFlagCaptureEvent; import org.battleplugins.arena.ctf.event.ArenaFlagReturnEvent; +import org.battleplugins.arena.ctf.event.ArenaFlagTakeEvent; import org.battleplugins.arena.messages.Message; import org.battleplugins.arena.team.ArenaTeam; import org.battleplugins.arena.util.ItemColor; @@ -27,6 +28,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -128,8 +130,15 @@ public void tickFlags() { continue; } + if (!flag.placed) { + continue; + } + + boolean alreadyCapturing = this.isFlagBeingCaptured(flag); this.capturingFlags.put(arenaPlayer, new CaptureInfo(flag, System.currentTimeMillis())); - this.broadcast(CtfMessages.FLAG_BEING_TAKEN, flag.team.getFormattedName(), Component.text(arenaPlayer.getPlayer().getName())); + if (!alreadyCapturing) { + this.broadcast(CtfMessages.FLAG_BEING_TAKEN, flag.team.getFormattedName(), Component.text(arenaPlayer.getPlayer().getName())); + } } else if (!flag.team.equals(arenaPlayer.getTeam())) { // No longer in capture region - cancel this.capturingFlags.remove(arenaPlayer); @@ -138,19 +147,33 @@ public void tickFlags() { } Duration captureTime = ArenaCtf.getInstance().getMainConfig().getCaptureTime(); - for (Map.Entry entry : this.capturingFlags.entrySet()) { + Set flagsBeingCaptured = new HashSet<>(); + for (Map.Entry entry : List.copyOf(this.capturingFlags.entrySet())) { + if (!entry.getValue().flag.placed) { + this.capturingFlags.remove(entry.getKey()); + continue; + } + // Check if the player has been capturing the flag for the required time if (Duration.ofMillis(System.currentTimeMillis() - entry.getValue().startTime).compareTo(captureTime) >= 0) { this.stealFlag(entry.getKey(), entry.getValue().flag); - } else { - // Send animation - Component progressBar = CtfUtil.getProgressBar('■', entry.getValue().startTime(), captureTime); - Component component = CtfMessages.CAPTURE_PROGRESS.toComponent(progressBar); - entry.getKey().getPlayer().sendActionBar(component); + continue; + } + + // Send animation + Component progressBar = CtfUtil.getProgressBar('■', entry.getValue().startTime(), captureTime); + Component component = CtfMessages.CAPTURE_PROGRESS.toComponent(progressBar); + entry.getKey().getPlayer().sendActionBar(component); + + flagsBeingCaptured.add(entry.getValue().flag); + } - // Play flame particles at the flag - entry.getValue().flag.flagLocation.getWorld().spawnParticle(Particle.FLAME, entry.getValue().flag.flagLocation.toCenterLocation(), 5, 0.3, 0.75, 0.3, 0); + for (ActiveFlag flag : flagsBeingCaptured) { + if (!flag.placed) { + continue; } + + flag.flagLocation.getWorld().spawnParticle(Particle.FLAME, flag.flagLocation.toCenterLocation(), 5, 0.3, 0.75, 0.3, 0); } for (Map.Entry entry : this.capturedFlags.entrySet()) { @@ -159,8 +182,9 @@ public void tickFlags() { } private void stealFlag(ArenaPlayer player, ActiveFlag flag) { + this.cancelCapturesForFlag(flag); this.capturedFlags.put(player, flag); - this.capturingFlags.remove(player); + this.getArena().getEventManager().callEvent(new ArenaFlagTakeEvent(player)); this.broadcast(CtfMessages.FLAG_STOLEN, flag.team.getFormattedName(), Component.text(player.getPlayer().getName())); this.broadcastSounds(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.BLOCK_ANVIL_PLACE, 0.0f); @@ -172,6 +196,7 @@ private void pickUpFlag(ArenaPlayer player, ActiveFlag flag) { flag.dropTime = -1; this.capturedFlags.put(player, flag); + this.getArena().getEventManager().callEvent(new ArenaFlagTakeEvent(player)); this.broadcast(CtfMessages.FLAG_PICKED_UP, flag.team.getFormattedName(), Component.text(player.getPlayer().getName())); this.broadcastSounds(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.ENTITY_ALLAY_DEATH, 1.0f); @@ -207,6 +232,7 @@ private void captureFlag(ArenaPlayer player) { } private void returnFlag(ActiveFlag flag, @Nullable ArenaPlayer player) { + this.cancelCapturesForFlag(flag); if (player != null) { this.getArena().getEventManager().callEvent(new ArenaFlagReturnEvent(player)); @@ -334,8 +360,8 @@ public void dropFlag(Location location) { } public void updateLocation(Location location) { - int highestBlockY = location.getWorld().getHighestBlockYAt(location) + 1; - this.flagLocation = new Location(location.getWorld(), location.getX(), highestBlockY, location.getZ(), location.getYaw(), location.getPitch()); + Location blockLocation = location.toBlockLocation(); + this.flagLocation = new Location(location.getWorld(), blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ(), location.getYaw(), location.getPitch()); } public void playAnimation(Location location) { @@ -358,7 +384,21 @@ public void playAnimation(Location location, int count, int step, int steps) { } } } - + + private boolean isFlagBeingCaptured(ActiveFlag flag) { + for (CaptureInfo captureInfo : this.capturingFlags.values()) { + if (captureInfo.flag == flag) { + return true; + } + } + + return false; + } + + private void cancelCapturesForFlag(ActiveFlag flag) { + this.capturingFlags.entrySet().removeIf(entry -> entry.getValue().flag == flag); + } + public record CaptureInfo(ActiveFlag flag, long startTime) { } } diff --git a/src/main/java/org/battleplugins/arena/ctf/event/ArenaFlagTakeEvent.java b/src/main/java/org/battleplugins/arena/ctf/event/ArenaFlagTakeEvent.java new file mode 100644 index 0000000..01464d2 --- /dev/null +++ b/src/main/java/org/battleplugins/arena/ctf/event/ArenaFlagTakeEvent.java @@ -0,0 +1,26 @@ +package org.battleplugins.arena.ctf.event; + +import org.battleplugins.arena.ArenaPlayer; +import org.battleplugins.arena.event.EventTrigger; +import org.battleplugins.arena.event.player.BukkitArenaPlayerEvent; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +@EventTrigger("on-flag-take") +public class ArenaFlagTakeEvent extends BukkitArenaPlayerEvent { + private static final HandlerList HANDLERS = new HandlerList(); + + public ArenaFlagTakeEvent(@NotNull ArenaPlayer player) { + super(player.getArena(), player); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return HANDLERS; + } + + public static HandlerList getHandlerList() { + return HANDLERS; + } +}