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.
This commit is contained in:
parent
f5bb1564ae
commit
3c5842a92c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<UUID, LinkedList<Instant>> 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<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) {
|
||||
Optional<GamePhase> optionalGamePhase = gameManager.getGamePhase();
|
||||
if (optionalGamePhase.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -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<GamePhase> getGamePhase() {
|
||||
|
|
|
|||
|
|
@ -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<Component> getWinnerMessages(HashMap<Team, Integer> wins) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user