Stage 13: Perks and Totems
This commit is contained in:
parent
d1f854fc79
commit
37e67ce97d
23 changed files with 2070 additions and 25 deletions
125
src/main/java/dev/loki/hatch/Hatch.java
Normal file
125
src/main/java/dev/loki/hatch/Hatch.java
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package dev.loki.hatch;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public class Hatch {
|
||||
private final Location location;
|
||||
private HatchState state;
|
||||
private Block hatchBlock;
|
||||
|
||||
public enum HatchState {
|
||||
HIDDEN,
|
||||
CLOSED,
|
||||
OPEN
|
||||
}
|
||||
|
||||
public Hatch(Location location) {
|
||||
this.location = location;
|
||||
this.state = HatchState.HIDDEN;
|
||||
this.hatchBlock = location.getBlock();
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public Location getJumpTarget() {
|
||||
return location.clone().add(0.5, -2, 0.5);
|
||||
}
|
||||
|
||||
public HatchState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return state == HatchState.HIDDEN;
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return state == HatchState.CLOSED;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return state == HatchState.OPEN;
|
||||
}
|
||||
|
||||
public void reveal() {
|
||||
if (state == HatchState.HIDDEN) {
|
||||
state = HatchState.CLOSED;
|
||||
updateVisuals();
|
||||
playRevealEffect();
|
||||
}
|
||||
}
|
||||
|
||||
public void open() {
|
||||
if (state == HatchState.CLOSED) {
|
||||
state = HatchState.OPEN;
|
||||
updateVisuals();
|
||||
playOpenEffect();
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
state = HatchState.HIDDEN;
|
||||
clearVisuals();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
state = HatchState.HIDDEN;
|
||||
clearVisuals();
|
||||
}
|
||||
|
||||
private void updateVisuals() {
|
||||
switch (state) {
|
||||
case CLOSED -> hatchBlock.setType(Material.IRON_TRAPDOOR);
|
||||
case OPEN -> hatchBlock.setType(Material.AIR);
|
||||
default -> hatchBlock.setType(Material.AIR);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearVisuals() {
|
||||
hatchBlock.setType(Material.AIR);
|
||||
}
|
||||
|
||||
public boolean isInRange(Location playerLoc, double radius) {
|
||||
return location.distance(playerLoc) <= radius;
|
||||
}
|
||||
|
||||
public boolean canEscape(Location playerLoc) {
|
||||
return isOpen() && isInRange(playerLoc, 1.5);
|
||||
}
|
||||
|
||||
private void playRevealEffect() {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return;
|
||||
|
||||
world.playSound(location, Sound.BLOCK_METAL_PLACE, 1.0f, 0.8f);
|
||||
world.spawnParticle(org.bukkit.Particle.SMOKE,
|
||||
location.clone().add(0.5, 0.5, 0.5),
|
||||
30, 0.3, 0.3, 0.3, 0.05);
|
||||
}
|
||||
|
||||
private void playOpenEffect() {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return;
|
||||
|
||||
world.playSound(location, Sound.BLOCK_IRON_TRAPDOOR_OPEN, 1.0f, 1.0f);
|
||||
world.spawnParticle(org.bukkit.Particle.END_ROD,
|
||||
location.clone().add(0.5, 0.5, 0.5),
|
||||
20, 0.2, 0.2, 0.2, 0.02);
|
||||
}
|
||||
|
||||
public void playEscapeEffect() {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return;
|
||||
|
||||
world.playSound(location, Sound.ENTITY_PLAYER_SPLASH, 1.0f, 1.0f);
|
||||
world.spawnParticle(org.bukkit.Particle.PORTAL,
|
||||
location.clone().add(0.5, 0, 0.5),
|
||||
100, 0.5, 0.5, 0.5, 0.5);
|
||||
}
|
||||
}
|
||||
76
src/main/java/dev/loki/hatch/HatchCondition.java
Normal file
76
src/main/java/dev/loki/hatch/HatchCondition.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package dev.loki.hatch;
|
||||
|
||||
import dev.loki.player.BasePlayer;
|
||||
import dev.loki.player.PlayerState;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class HatchCondition {
|
||||
private final int minSurvivorsForOpen;
|
||||
|
||||
public HatchCondition(int minSurvivorsForOpen) {
|
||||
this.minSurvivorsForOpen = minSurvivorsForOpen;
|
||||
}
|
||||
|
||||
public boolean shouldSpawn(Collection<BasePlayer> players, int repairedGenerators) {
|
||||
int aliveSurvivors = countAliveSurvivors(players);
|
||||
return aliveSurvivors <= repairedGenerators;
|
||||
}
|
||||
|
||||
public boolean shouldOpen(Hatch hatch, Collection<BasePlayer> players, int repairedGenerators) {
|
||||
if (hatch.isOpen()) return false;
|
||||
if (!hatch.isClosed() && !hatch.isHidden()) return false;
|
||||
|
||||
return shouldSpawn(players, repairedGenerators);
|
||||
}
|
||||
|
||||
public boolean canOpen(Hatch hatch, Collection<BasePlayer> players, int repairedGenerators) {
|
||||
if (!hatch.isHidden() && !hatch.isClosed()) return false;
|
||||
|
||||
int aliveSurvivors = countAliveSurvivors(players);
|
||||
int requiredGens = Math.max(minSurvivorsForOpen, aliveSurvivors);
|
||||
|
||||
return repairedGenerators >= requiredGens;
|
||||
}
|
||||
|
||||
public int countAliveSurvivors(Collection<BasePlayer> players) {
|
||||
return (int) players.stream()
|
||||
.filter(p -> !p.isKiller())
|
||||
.filter(this::isAlive)
|
||||
.count();
|
||||
}
|
||||
|
||||
private boolean isAlive(BasePlayer player) {
|
||||
PlayerState state = player.getState();
|
||||
return state != PlayerState.DEAD
|
||||
&& state != PlayerState.ESCAPED
|
||||
&& state != PlayerState.HOOKED;
|
||||
}
|
||||
|
||||
public int getRemainingAlive(Collection<BasePlayer> players) {
|
||||
return countAliveSurvivors(players);
|
||||
}
|
||||
|
||||
public boolean isLastSurvivor(Collection<BasePlayer> players) {
|
||||
return countAliveSurvivors(players) == 1;
|
||||
}
|
||||
|
||||
public boolean checkAndReveal(Hatch hatch, Collection<BasePlayer> players, int repairedGenerators) {
|
||||
if (hatch.isHidden() && shouldSpawn(players, repairedGenerators)) {
|
||||
hatch.reveal();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean checkAndOpen(Hatch hatch, Collection<BasePlayer> players, int repairedGenerators) {
|
||||
if (canOpen(hatch, players, repairedGenerators)) {
|
||||
if (hatch.isHidden()) {
|
||||
hatch.reveal();
|
||||
}
|
||||
hatch.open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
110
src/main/java/dev/loki/hatch/HatchEscape.java
Normal file
110
src/main/java/dev/loki/hatch/HatchEscape.java
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package dev.loki.hatch;
|
||||
|
||||
import dev.loki.player.PlayerState;
|
||||
import dev.loki.player.Survivor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class HatchEscape {
|
||||
private static final double ESCAPE_RADIUS = 1.5;
|
||||
|
||||
private final Hatch hatch;
|
||||
|
||||
public HatchEscape(Hatch hatch) {
|
||||
this.hatch = hatch;
|
||||
}
|
||||
|
||||
public boolean tryEscape(Survivor survivor) {
|
||||
if (!hatch.isOpen()) {
|
||||
return tryRevealAndCheck(survivor);
|
||||
}
|
||||
|
||||
Player player = survivor.getPlayer();
|
||||
if (player == null) return false;
|
||||
|
||||
if (!isAtHatch(player.getLocation())) {
|
||||
player.sendMessage("§cПодойдите ближе к люку!");
|
||||
return false;
|
||||
}
|
||||
|
||||
performEscape(survivor);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canEscape(Survivor survivor) {
|
||||
if (!hatch.isOpen()) return false;
|
||||
|
||||
Player player = survivor.getPlayer();
|
||||
if (player == null) return false;
|
||||
|
||||
return isAtHatch(player.getLocation());
|
||||
}
|
||||
|
||||
private boolean tryRevealAndCheck(Survivor survivor) {
|
||||
Player player = survivor.getPlayer();
|
||||
if (player == null) return false;
|
||||
|
||||
if (hatch.isHidden()) {
|
||||
player.sendMessage("§7Люк скрыт...");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hatch.isClosed()) {
|
||||
player.sendMessage("§cЛюк закрыт!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAtHatch(Location location) {
|
||||
return hatch.isInRange(location, ESCAPE_RADIUS);
|
||||
}
|
||||
|
||||
private void performEscape(Survivor survivor) {
|
||||
Player player = survivor.getPlayer();
|
||||
if (player == null) return;
|
||||
|
||||
player.teleport(hatch.getJumpTarget());
|
||||
hatch.playEscapeEffect();
|
||||
|
||||
player.getWorld().playSound(player.getLocation(),
|
||||
Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.0f);
|
||||
player.sendTitle("§a§lПОБЕГ!", "§7Вы сбежали через люк!", 10, 60, 10);
|
||||
|
||||
survivor.setState(PlayerState.ESCAPED);
|
||||
|
||||
giveEscapeReward(survivor);
|
||||
}
|
||||
|
||||
private void giveEscapeReward(Survivor survivor) {
|
||||
Player player = survivor.getPlayer();
|
||||
if (player == null) return;
|
||||
|
||||
player.sendMessage("§a+5000 Очков — Побег через люк!");
|
||||
}
|
||||
|
||||
public void forceOpenForEscape() {
|
||||
if (hatch.isHidden()) {
|
||||
hatch.reveal();
|
||||
}
|
||||
if (!hatch.isOpen()) {
|
||||
hatch.open();
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyNearbyPlayers() {
|
||||
Location hatchLoc = hatch.getLocation();
|
||||
World world = hatchLoc.getWorld();
|
||||
if (world == null) return;
|
||||
|
||||
for (Player player : world.getPlayers()) {
|
||||
if (player.getLocation().distance(hatchLoc) < 30) {
|
||||
player.sendMessage("§e§lЛюк открыт!");
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue