diff --git a/src/main/java/com/alttd/ctf/flag/Flag.java b/src/main/java/com/alttd/ctf/flag/Flag.java index d437af0..d2cebbb 100644 --- a/src/main/java/com/alttd/ctf/flag/Flag.java +++ b/src/main/java/com/alttd/ctf/flag/Flag.java @@ -96,12 +96,40 @@ public class Flag implements Runnable { Bukkit.getScheduler().runTask(main, () -> flagLocation.getBlock().setType(flagItem.getType())); } + private void spawnFlagParticleRing() { + Location center = flagLocation.clone(); + World world = center.getWorld(); + double radius = 0.7; + double gap = 0.2; + double circumference = 2 * Math.PI * radius; + int particleCount = (int) (circumference / gap); + + Particle particle = Particle.DUST; + TeamColor color = winningTeam.getColor(); + // Generate particle positions + for (double heightOffset = 0; heightOffset < 2; heightOffset += 0.5) { + center.setY(center.getY() + 0.5); + for (int i = 0; i < particleCount; i++) { + double angle = 2 * Math.PI * i / particleCount; + double x = center.getX() + radius * Math.cos(angle); + double z = center.getZ() + radius * Math.sin(angle); + double y = center.getY(); + + world.spawnParticle(particle, x, y, z, 1, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(color.r(), color.g(), color.b()), 1)); + } + } + } + @Override public void run() { if (flagCarrier != null) { checkFlagCarrier(); return; } + if (winningTeam != null) { + spawnFlagParticleRing(); + return; + } if (flagLocation == null) { log.warn("Tried to run Flag without a flag location, spawn it first"); return; diff --git a/src/main/java/com/alttd/ctf/game/GameManager.java b/src/main/java/com/alttd/ctf/game/GameManager.java index ba1c4c9..1d70922 100644 --- a/src/main/java/com/alttd/ctf/game/GameManager.java +++ b/src/main/java/com/alttd/ctf/game/GameManager.java @@ -77,7 +77,7 @@ public class GameManager { executorService.shutdown(); executorService = Executors.newSingleThreadScheduledExecutor(); } - runningGame = new RunningGame(this, duration, flag); + runningGame = new RunningGame(this, duration, flag, executorService); executorService.scheduleAtFixedRate(runningGame, 0, 1, TimeUnit.SECONDS); } diff --git a/src/main/java/com/alttd/ctf/game/RunningGame.java b/src/main/java/com/alttd/ctf/game/RunningGame.java index 4e13ad8..3b4ed49 100644 --- a/src/main/java/com/alttd/ctf/game/RunningGame.java +++ b/src/main/java/com/alttd/ctf/game/RunningGame.java @@ -13,6 +13,7 @@ import javax.annotation.Nullable; import java.time.Duration; import java.time.Instant; import java.util.HashMap; +import java.util.concurrent.ScheduledExecutorService; @Slf4j public class RunningGame implements Runnable { @@ -20,14 +21,16 @@ public class RunningGame implements Runnable { private final HashMap phaseDurations = GameConfig.PHASES.getGAME_PHASE_DURATION(); private final GameManager gameManager; private final Flag flag; + private final ScheduledExecutorService executorService; @Getter private GamePhase currentPhase = GamePhase.values()[0]; private Instant phaseStartTime = null; private int lastMinuteBroadcast = 0; - public RunningGame(GameManager gameManager, Duration gameDuration, Flag flag) { + public RunningGame(GameManager gameManager, Duration gameDuration, Flag flag, ScheduledExecutorService executorService) { this.gameManager = gameManager; this.flag = flag; + this.executorService = executorService; phaseDurations.put(GamePhase.COMBAT, gameDuration); } @@ -37,16 +40,16 @@ public class RunningGame implements Runnable { GamePhase nextPhase = (currentPhase.ordinal() + 1 < GamePhase.values().length) ? GamePhase.values()[currentPhase.ordinal() + 1] : null; if (phaseStartTime == null) { phaseStartTime = Instant.now(); - nextPhaseActions(null, currentPhase, nextPhase); + nextPhaseActions(null, currentPhase); } - if (Duration.between(phaseStartTime, Instant.now()).compareTo(phaseDurations.get(currentPhase)) >= 0) { - GamePhase previousPhase = currentPhase; - currentPhase = GamePhase.values()[currentPhase.ordinal() + 1]; //TODO fix this running out of bounds - nextPhaseActions(previousPhase, currentPhase, nextPhase); + if (nextPhase != null && Duration.between(phaseStartTime, Instant.now()).compareTo(phaseDurations.get(currentPhase)) >= 0) { + nextPhaseActions(currentPhase, nextPhase); phaseStartTime = Instant.now(); } else if (nextPhase != null) { broadcastNextPhaseStartTime(currentPhase, nextPhase); + } else { + executorService.shutdown(); } } catch (Exception e) { log.error("Unexpected error in running game", e); @@ -54,15 +57,13 @@ public class RunningGame implements Runnable { } } - private void nextPhaseActions(@Nullable GamePhase previousPhase, @NotNull GamePhase phase, @Nullable GamePhase nextPhase) { + private void nextPhaseActions(@Nullable GamePhase previousPhase, @NotNull GamePhase phase) { //TODO command to go to next phase + this.currentPhase = phase; if (previousPhase != null) { gameManager.getPhaseExecutor(previousPhase).end(phase); } gameManager.getPhaseExecutor(phase).start(flag); - if (nextPhase != null) { - broadcastNextPhaseStartTime(phase, nextPhase); - } } private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) {//TODO check how this works/what it should do @@ -86,9 +87,17 @@ public class RunningGame implements Runnable { } } + public void skipCurrentPhase() { + GamePhase nextPhase = (currentPhase.ordinal() + 1 < GamePhase.values().length) ? GamePhase.values()[currentPhase.ordinal() + 1] : null; + if (nextPhase == null) { + log.warn("Tried to skip phase {} but there is no next phase", currentPhase); + return; + } + nextPhaseActions(currentPhase, nextPhase); + } + public void end() { //TODO say the phase ended early? - currentPhase = GamePhase.ENDED; - nextPhaseActions(null, currentPhase, null); + nextPhaseActions(currentPhase, GamePhase.ENDED); } }