Stage 2-3: Player states and Killer system
This commit is contained in:
parent
5a53620b3a
commit
d1f854fc79
14 changed files with 1095 additions and 0 deletions
79
src/main/java/dev/loki/perk/BasePerk.java
Normal file
79
src/main/java/dev/loki/perk/BasePerk.java
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
package dev.loki.perk;
|
||||
|
||||
import dev.loki.player.BasePlayer;
|
||||
import dev.loki.mdbd;
|
||||
|
||||
public abstract class BasePerk implements IPerk {
|
||||
protected final mdbd plugin;
|
||||
protected final String id;
|
||||
protected final String name;
|
||||
protected final String description;
|
||||
protected final PerkType type;
|
||||
protected final boolean passive;
|
||||
protected final int cooldownSeconds;
|
||||
protected long cooldownEndTime = 0;
|
||||
|
||||
protected BasePerk(mdbd plugin, String id, String name, String description,
|
||||
PerkType type, boolean passive, int cooldownSeconds) {
|
||||
this.plugin = plugin;
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.type = type;
|
||||
this.passive = passive;
|
||||
this.cooldownSeconds = cooldownSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PerkType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPassive() {
|
||||
return passive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCooldownSeconds() {
|
||||
return cooldownSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnCooldown() {
|
||||
return System.currentTimeMillis() < cooldownEndTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startCooldown() {
|
||||
if (cooldownSeconds > 0) {
|
||||
cooldownEndTime = System.currentTimeMillis() + (cooldownSeconds * 1000L);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetCooldown() {
|
||||
cooldownEndTime = 0;
|
||||
}
|
||||
|
||||
protected void sendPerkMessage(BasePlayer player, String message) {
|
||||
if (player.getPlayer() != null) {
|
||||
player.getPlayer().sendMessage("§6[" + name + "] §7" + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/main/java/dev/loki/perk/PerkRegistry.java
Normal file
60
src/main/java/dev/loki/perk/PerkRegistry.java
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package dev.loki.perk;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.killer.BBQChiliPerk;
|
||||
import dev.loki.perk.killer.CorruptInterventionPerk;
|
||||
import dev.loki.perk.killer.HexRuinPerk;
|
||||
import dev.loki.perk.survivor.BorrowedTimePerk;
|
||||
import dev.loki.perk.survivor.DeadHardPerk;
|
||||
import dev.loki.perk.survivor.SelfCarePerk;
|
||||
import dev.loki.perk.survivor.SprintBurstPerk;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PerkRegistry {
|
||||
private final Map<String, IPerk> perks = new HashMap<>();
|
||||
private final mdbd plugin;
|
||||
|
||||
public PerkRegistry(mdbd plugin) {
|
||||
this.plugin = plugin;
|
||||
registerDefaultPerks();
|
||||
}
|
||||
|
||||
private void registerDefaultPerks() {
|
||||
register(new SelfCarePerk(plugin));
|
||||
register(new DeadHardPerk(plugin));
|
||||
register(new SprintBurstPerk(plugin));
|
||||
register(new BorrowedTimePerk(plugin));
|
||||
register(new HexRuinPerk(plugin));
|
||||
register(new CorruptInterventionPerk(plugin));
|
||||
register(new BBQChiliPerk(plugin));
|
||||
}
|
||||
|
||||
public void register(IPerk perk) {
|
||||
perks.put(perk.getId().toLowerCase(), perk);
|
||||
plugin.getLogger().info("Registered perk: " + perk.getName());
|
||||
}
|
||||
|
||||
public IPerk getPerk(String id) {
|
||||
return perks.get(id.toLowerCase());
|
||||
}
|
||||
|
||||
public Map<String, IPerk> getAllPerks() {
|
||||
return new HashMap<>(perks);
|
||||
}
|
||||
|
||||
public Map<String, IPerk> getPerksByType(PerkType type) {
|
||||
Map<String, IPerk> result = new HashMap<>();
|
||||
for (Map.Entry<String, IPerk> entry : perks.entrySet()) {
|
||||
if (entry.getValue().getType() == type) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean hasPerk(String id) {
|
||||
return perks.containsKey(id.toLowerCase());
|
||||
}
|
||||
}
|
||||
105
src/main/java/dev/loki/perk/killer/BBQChiliPerk.java
Normal file
105
src/main/java/dev/loki/perk/killer/BBQChiliPerk.java
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package dev.loki.perk.killer;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.BasePerk;
|
||||
import dev.loki.perk.PerkTrigger;
|
||||
import dev.loki.perk.PerkType;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import dev.loki.player.Survivor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BBQChiliPerk extends BasePerk {
|
||||
private static final int REVEAL_DURATION_SECONDS = 4;
|
||||
private static final int AURA_RANGE = 100;
|
||||
private static final int BONUS_STACKS = 4;
|
||||
private final Map<UUID, Integer> hookedPlayers = new HashMap<>();
|
||||
private int currentStacks = 0;
|
||||
|
||||
public BBQChiliPerk(mdbd plugin) {
|
||||
super(plugin, "bbq_chili", "Барбекю и Чили",
|
||||
"После подвешивания видите ауру всех выживших на 4 секунды",
|
||||
PerkType.KILLER, true, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(BasePlayer player) {
|
||||
currentStacks = 0;
|
||||
sendPerkMessage(player, "Активировано: ауры видны после подвешивания");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(BasePlayer player, PerkTrigger trigger, Object context) {
|
||||
if (trigger == PerkTrigger.ON_KILLER_HOOK) {
|
||||
if (context instanceof Survivor survivor) {
|
||||
revealSurvivorAuras(player, survivor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void revealSurvivorAuras(BasePlayer killer, Survivor hookedSurvivor) {
|
||||
Player killerPlayer = killer.getPlayer();
|
||||
if (killerPlayer == null) return;
|
||||
|
||||
currentStacks = Math.min(currentStacks + 1, BONUS_STACKS);
|
||||
hookedPlayers.put(hookedSurvivor.getUuid(), currentStacks);
|
||||
|
||||
Collection<? extends Player> allPlayers = Bukkit.getOnlinePlayers();
|
||||
for (Player player : allPlayers) {
|
||||
if (player.equals(killerPlayer)) continue;
|
||||
if (player.getLocation().distance(killerPlayer.getLocation()) > AURA_RANGE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
revealAura(killerPlayer, player);
|
||||
}
|
||||
|
||||
sendPerkMessage(killer, "§cАуры выживших видны! (x" + currentStacks + " стаков)");
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
sendPerkMessage(killer, "§7Эффект ауры закончился");
|
||||
}
|
||||
}.runTaskLater(plugin, REVEAL_DURATION_SECONDS * 20L);
|
||||
}
|
||||
|
||||
private void revealAura(Player killer, Player survivor) {
|
||||
Location survivorLoc = survivor.getLocation();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Location particleLoc = survivorLoc.clone().add(0, i * 0.5, 0);
|
||||
killer.spawnParticle(Particle.GLOW, particleLoc, 5, 0.3, 0.5, 0.3, 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BasePlayer player) {
|
||||
currentStacks = 0;
|
||||
hookedPlayers.clear();
|
||||
sendPerkMessage(player, "Перк деактивирован");
|
||||
}
|
||||
|
||||
public int getStacks() {
|
||||
return currentStacks;
|
||||
}
|
||||
|
||||
public static int getRevealDuration() {
|
||||
return REVEAL_DURATION_SECONDS;
|
||||
}
|
||||
|
||||
public static int getAuraRange() {
|
||||
return AURA_RANGE;
|
||||
}
|
||||
|
||||
public static int getMaxStacks() {
|
||||
return BONUS_STACKS;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package dev.loki.perk.killer;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.BasePerk;
|
||||
import dev.loki.perk.PerkTrigger;
|
||||
import dev.loki.perk.PerkType;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class CorruptInterventionPerk extends BasePerk {
|
||||
private static final int BLOCK_DURATION_SECONDS = 120;
|
||||
private static final int FARTHEST_GENERATORS = 3;
|
||||
private final Set<UUID> blockedGenerators = new HashSet<>();
|
||||
private boolean effectActive = false;
|
||||
|
||||
public CorruptInterventionPerk(mdbd plugin) {
|
||||
super(plugin, "corrupt_intervention", "Вмешательство Порчи",
|
||||
"3 самых дальних генератора от киллера заблокированы на 120 секунд",
|
||||
PerkType.KILLER, true, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(BasePlayer player) {
|
||||
effectActive = true;
|
||||
sendPerkMessage(player, "§cВмешательство активировано! Дальние генераторы заблокированы");
|
||||
startEffectTimer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(BasePlayer player, PerkTrigger trigger, Object context) {
|
||||
if (trigger == PerkTrigger.ON_GENERATOR_START && effectActive) {
|
||||
if (context instanceof UUID genId) {
|
||||
if (blockedGenerators.contains(genId)) {
|
||||
preventRepair(player, genId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void preventRepair(BasePlayer player, UUID genId) {
|
||||
Player bukkitPlayer = player.getPlayer();
|
||||
if (bukkitPlayer == null) return;
|
||||
bukkitPlayer.sendMessage("§cЭтот генератор заблокирован Порчей!");
|
||||
spawnBlockEffect(bukkitPlayer);
|
||||
}
|
||||
|
||||
private void spawnBlockEffect(Player player) {
|
||||
Location loc = player.getLocation();
|
||||
player.getWorld().spawnParticle(Particle.BARRIER, loc.add(0, 1, 0), 5, 0.5, 0.5, 0.5, 0);
|
||||
}
|
||||
|
||||
private void startEffectTimer() {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
effectActive = false;
|
||||
blockedGenerators.clear();
|
||||
}
|
||||
}.runTaskLater(plugin, BLOCK_DURATION_SECONDS * 20L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BasePlayer player) {
|
||||
effectActive = false;
|
||||
blockedGenerators.clear();
|
||||
sendPerkMessage(player, "Перк деактивирован");
|
||||
}
|
||||
|
||||
public void blockGenerator(UUID generatorId) {
|
||||
if (blockedGenerators.size() < FARTHEST_GENERATORS) {
|
||||
blockedGenerators.add(generatorId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isGeneratorBlocked(UUID generatorId) {
|
||||
return effectActive && blockedGenerators.contains(generatorId);
|
||||
}
|
||||
|
||||
public boolean isEffectActive() {
|
||||
return effectActive;
|
||||
}
|
||||
|
||||
public static int getBlockDuration() {
|
||||
return BLOCK_DURATION_SECONDS;
|
||||
}
|
||||
|
||||
public static int getFarthestGeneratorCount() {
|
||||
return FARTHEST_GENERATORS;
|
||||
}
|
||||
}
|
||||
94
src/main/java/dev/loki/perk/killer/HexRuinPerk.java
Normal file
94
src/main/java/dev/loki/perk/killer/HexRuinPerk.java
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package dev.loki.perk.killer;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.BasePerk;
|
||||
import dev.loki.perk.PerkTrigger;
|
||||
import dev.loki.perk.PerkType;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class HexRuinPerk extends BasePerk {
|
||||
private static final double REGRESSION_RATE = 0.25;
|
||||
private static final double KICK_REGRESSION = 2.5;
|
||||
private final Map<UUID, Double> affectedGenerators = new HashMap<>();
|
||||
private boolean hexActive = true;
|
||||
|
||||
public HexRuinPerk(mdbd plugin) {
|
||||
super(plugin, "hex_ruin", "Порча: Губительность",
|
||||
"Генераторы автоматически теряют прогресс когда не чинятся",
|
||||
PerkType.KILLER, true, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(BasePlayer player) {
|
||||
hexActive = true;
|
||||
sendPerkMessage(player, "§cПорча активирована! Генераторы регрессируют");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(BasePlayer player, PerkTrigger trigger, Object context) {
|
||||
switch (trigger) {
|
||||
case ON_GENERATOR_START -> handleGeneratorStart(player, context);
|
||||
case ON_GENERATOR_COMPLETE -> handleGeneratorComplete(player, context);
|
||||
case ON_TOTEM_CLEANSED -> handleTotemCleansed(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleGeneratorStart(BasePlayer player, Object context) {
|
||||
if (!hexActive) return;
|
||||
if (context instanceof UUID genId) {
|
||||
affectedGenerators.put(genId, 0.0);
|
||||
spawnHexParticles(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleGeneratorComplete(BasePlayer player, Object context) {
|
||||
if (context instanceof UUID genId) {
|
||||
affectedGenerators.remove(genId);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTotemCleansed(BasePlayer player) {
|
||||
hexActive = false;
|
||||
affectedGenerators.clear();
|
||||
sendPerkMessage(player, "§cПорча очищена! Губительность деактивирована");
|
||||
}
|
||||
|
||||
private void spawnHexParticles(BasePlayer player) {
|
||||
Player bukkitPlayer = player.getPlayer();
|
||||
if (bukkitPlayer == null) return;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Location loc = bukkitPlayer.getLocation().add(
|
||||
Math.random() * 4 - 2,
|
||||
Math.random() * 2,
|
||||
Math.random() * 4 - 2
|
||||
);
|
||||
bukkitPlayer.getWorld().spawnParticle(Particle.SOUL_FIRE_FLAME, loc, 3, 0.2, 0.2, 0.2, 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BasePlayer player) {
|
||||
hexActive = false;
|
||||
affectedGenerators.clear();
|
||||
sendPerkMessage(player, "Перк деактивирован");
|
||||
}
|
||||
|
||||
public static double getRegressionRate() {
|
||||
return REGRESSION_RATE;
|
||||
}
|
||||
|
||||
public static double getKickRegression() {
|
||||
return KICK_REGRESSION;
|
||||
}
|
||||
|
||||
public boolean isHexActive() {
|
||||
return hexActive;
|
||||
}
|
||||
}
|
||||
76
src/main/java/dev/loki/perk/survivor/BorrowedTimePerk.java
Normal file
76
src/main/java/dev/loki/perk/survivor/BorrowedTimePerk.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package dev.loki.perk.survivor;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.BasePerk;
|
||||
import dev.loki.perk.PerkTrigger;
|
||||
import dev.loki.perk.PerkType;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public class BorrowedTimePerk extends BasePerk {
|
||||
private static final int ENDURANCE_DURATION_SECONDS = 15;
|
||||
private static final int SPEED_BOOST_SECONDS = 2;
|
||||
private static final int SPEED_AMPLIFIER = 1;
|
||||
|
||||
public BorrowedTimePerk(mdbd plugin) {
|
||||
super(plugin, "borrowed_time", "Заемное Время",
|
||||
"После снятия с крюка получите 15 сек неуязвимости и рывок скорости",
|
||||
PerkType.SURVIVOR, true, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(BasePlayer player) {
|
||||
sendPerkMessage(player, "Активировано: защита после спасения");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(BasePlayer player, PerkTrigger trigger, Object context) {
|
||||
if (trigger == PerkTrigger.ON_UNHOOKED) {
|
||||
applyEndurance(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyEndurance(BasePlayer player) {
|
||||
Player bukkitPlayer = player.getPlayer();
|
||||
if (bukkitPlayer == null) return;
|
||||
|
||||
bukkitPlayer.addPotionEffect(new PotionEffect(
|
||||
PotionEffectType.DAMAGE_RESISTANCE,
|
||||
ENDURANCE_DURATION_SECONDS * 20,
|
||||
4,
|
||||
false, false, true));
|
||||
|
||||
bukkitPlayer.addPotionEffect(new PotionEffect(
|
||||
PotionEffectType.SPEED,
|
||||
SPEED_BOOST_SECONDS * 20,
|
||||
SPEED_AMPLIFIER,
|
||||
false, false, true));
|
||||
|
||||
sendPerkMessage(player, "§aЗаемное Время активировано! 15 сек защиты");
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (player.getPlayer() != null) {
|
||||
player.getPlayer().sendMessage("§cЗаемное Время закончилось");
|
||||
}
|
||||
}
|
||||
}.runTaskLater(plugin, ENDURANCE_DURATION_SECONDS * 20L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BasePlayer player) {
|
||||
Player bukkitPlayer = player.getPlayer();
|
||||
if (bukkitPlayer != null) {
|
||||
bukkitPlayer.removePotionEffect(PotionEffectType.DAMAGE_RESISTANCE);
|
||||
}
|
||||
sendPerkMessage(player, "Перк деактивирован");
|
||||
}
|
||||
|
||||
public static int getEnduranceDuration() {
|
||||
return ENDURANCE_DURATION_SECONDS;
|
||||
}
|
||||
}
|
||||
76
src/main/java/dev/loki/perk/survivor/DeadHardPerk.java
Normal file
76
src/main/java/dev/loki/perk/survivor/DeadHardPerk.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package dev.loki.perk.survivor;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.BasePerk;
|
||||
import dev.loki.perk.PerkTrigger;
|
||||
import dev.loki.perk.PerkType;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import dev.loki.player.PlayerState;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class DeadHardPerk extends BasePerk {
|
||||
private static final int DASH_DISTANCE = 4;
|
||||
private static final int INVULNERABILITY_TICKS = 20;
|
||||
private static final int EXHAUSTION_SECONDS = 60;
|
||||
|
||||
public DeadHardPerk(mdbd plugin) {
|
||||
super(plugin, "dead_hard", "Тяжелый Рывок",
|
||||
"При ранении активируйте для рывка и неуязвимости",
|
||||
PerkType.SURVIVOR, false, EXHAUSTION_SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(BasePlayer player) {
|
||||
sendPerkMessage(player, "Готов к использованию");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(BasePlayer player, PerkTrigger trigger, Object context) {
|
||||
if (trigger == PerkTrigger.ON_KILLER_HIT && !isOnCooldown()) {
|
||||
if (shouldActivate(player)) {
|
||||
performDash(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldActivate(BasePlayer player) {
|
||||
return player.getState() == PlayerState.INJURED;
|
||||
}
|
||||
|
||||
private void performDash(BasePlayer player) {
|
||||
Player bukkitPlayer = player.getPlayer();
|
||||
if (bukkitPlayer == null) return;
|
||||
|
||||
Vector direction = bukkitPlayer.getLocation().getDirection();
|
||||
direction.setY(0).normalize().multiply(DASH_DISTANCE);
|
||||
|
||||
Location target = bukkitPlayer.getLocation().add(direction);
|
||||
bukkitPlayer.teleport(target);
|
||||
bukkitPlayer.getWorld().spawnParticle(Particle.CLOUD, bukkitPlayer.getLocation(), 10);
|
||||
|
||||
startCooldown();
|
||||
sendPerkMessage(player, "Рывок выполнен!");
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (player.getPlayer() != null) {
|
||||
player.getPlayer().sendMessage("§aТяжелый Рывок готов к использованию!");
|
||||
}
|
||||
}
|
||||
}.runTaskLater(plugin, cooldownSeconds * 20L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BasePlayer player) {
|
||||
sendPerkMessage(player, "Перк деактивирован");
|
||||
}
|
||||
|
||||
public static int getInvulnerabilityTicks() {
|
||||
return INVULNERABILITY_TICKS;
|
||||
}
|
||||
}
|
||||
53
src/main/java/dev/loki/perk/survivor/SelfCarePerk.java
Normal file
53
src/main/java/dev/loki/perk/survivor/SelfCarePerk.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package dev.loki.perk.survivor;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.BasePerk;
|
||||
import dev.loki.perk.PerkTrigger;
|
||||
import dev.loki.perk.PerkType;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import dev.loki.player.PlayerState;
|
||||
|
||||
public class SelfCarePerk extends BasePerk {
|
||||
private static final double HEAL_RATE = 0.5;
|
||||
private static final int SELF_HEAL_TIME = 24;
|
||||
|
||||
public SelfCarePerk(mdbd plugin) {
|
||||
super(plugin, "self_care", "Самолечение",
|
||||
"Позволяет лечить себя без аптечки на 50% скорости",
|
||||
PerkType.SURVIVOR, true, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(BasePlayer player) {
|
||||
sendPerkMessage(player, "Активировано: вы можете лечить себя без аптечки");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(BasePlayer player, PerkTrigger trigger, Object context) {
|
||||
if (trigger == PerkTrigger.ON_HEAL_START) {
|
||||
handleSelfHeal(player, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSelfHeal(BasePlayer player, Object context) {
|
||||
if (player.getState() != PlayerState.INJURED) {
|
||||
return;
|
||||
}
|
||||
if (context instanceof Boolean && (Boolean) context) {
|
||||
sendPerkMessage(player, "Вы начали лечить себя...");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BasePlayer player) {
|
||||
sendPerkMessage(player, "Перк деактивирован");
|
||||
}
|
||||
|
||||
public static double getHealRate() {
|
||||
return HEAL_RATE;
|
||||
}
|
||||
|
||||
public static int getSelfHealTime() {
|
||||
return SELF_HEAL_TIME;
|
||||
}
|
||||
}
|
||||
80
src/main/java/dev/loki/perk/survivor/SprintBurstPerk.java
Normal file
80
src/main/java/dev/loki/perk/survivor/SprintBurstPerk.java
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package dev.loki.perk.survivor;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.perk.BasePerk;
|
||||
import dev.loki.perk.PerkTrigger;
|
||||
import dev.loki.perk.PerkType;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public class SprintBurstPerk extends BasePerk {
|
||||
private static final int SPRINT_DURATION_SECONDS = 3;
|
||||
private static final int EXHAUSTION_SECONDS = 40;
|
||||
private static final int SPEED_AMPLIFIER = 2;
|
||||
|
||||
public SprintBurstPerk(mdbd plugin) {
|
||||
super(plugin, "sprint_burst", "Рывок Скорости",
|
||||
"При старте бега получите 150% скорости на 3 секунды",
|
||||
PerkType.SURVIVOR, false, EXHAUSTION_SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(BasePlayer player) {
|
||||
sendPerkMessage(player, "Готов к использованию");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(BasePlayer player, PerkTrigger trigger, Object context) {
|
||||
if (trigger == PerkTrigger.ON_SPRINT_START && !isOnCooldown()) {
|
||||
activateSprint(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void activateSprint(BasePlayer player) {
|
||||
Player bukkitPlayer = player.getPlayer();
|
||||
if (bukkitPlayer == null) return;
|
||||
|
||||
bukkitPlayer.addPotionEffect(new PotionEffect(
|
||||
PotionEffectType.SPEED,
|
||||
SPRINT_DURATION_SECONDS * 20,
|
||||
SPEED_AMPLIFIER,
|
||||
false, false, true));
|
||||
|
||||
startCooldown();
|
||||
sendPerkMessage(player, "§aРывок активирован!");
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (player.getPlayer() != null) {
|
||||
player.getPlayer().sendMessage("§cИзнурение... Рывок на перезарядке");
|
||||
}
|
||||
}
|
||||
}.runTaskLater(plugin, SPRINT_DURATION_SECONDS * 20L);
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (player.getPlayer() != null) {
|
||||
player.getPlayer().sendMessage("§aРывок Скорости снова готов!");
|
||||
}
|
||||
}
|
||||
}.runTaskLater(plugin, cooldownSeconds * 20L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BasePlayer player) {
|
||||
Player bukkitPlayer = player.getPlayer();
|
||||
if (bukkitPlayer != null) {
|
||||
bukkitPlayer.removePotionEffect(PotionEffectType.SPEED);
|
||||
}
|
||||
sendPerkMessage(player, "Перк деактивирован");
|
||||
}
|
||||
|
||||
public static int getSprintDuration() {
|
||||
return SPRINT_DURATION_SECONDS;
|
||||
}
|
||||
}
|
||||
52
src/main/java/dev/loki/totem/DullTotem.java
Normal file
52
src/main/java/dev/loki/totem/DullTotem.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package dev.loki.totem;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class DullTotem extends Totem {
|
||||
private static final String TOTEM_SKULL_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTBiNzE5ZTNlODUwMTRlMDEyZGM1ZTMxNTU2OGIwZjI0N2Y1ZDhkZjE5YjcyOWEyNTEwYmNjY2ViYzdhNmIifX19";
|
||||
|
||||
public DullTotem(Location location) {
|
||||
super(location);
|
||||
this.state = TotemState.DULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateVisuals() {
|
||||
if (display == null || display.isDead()) return;
|
||||
display.setCustomName(state.getColorCode() + state.getDisplayName());
|
||||
display.getEquipment().setHelmet(createTotemItem());
|
||||
}
|
||||
|
||||
private ItemStack createTotemItem() {
|
||||
ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
|
||||
SkullMeta meta = (SkullMeta) skull.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(state.getDisplayName());
|
||||
skull.setItemMeta(meta);
|
||||
}
|
||||
return skull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(UUID playerId) {
|
||||
if (state == TotemState.DULL) {
|
||||
setState(TotemState.CLEANSED);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canBecomeHex() {
|
||||
return state == TotemState.DULL;
|
||||
}
|
||||
|
||||
public void convertToHex(UUID hexPerkId) {
|
||||
if (canBecomeHex()) {
|
||||
setState(TotemState.HEX);
|
||||
setLinkedPerkId(hexPerkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
src/main/java/dev/loki/totem/HexTotem.java
Normal file
86
src/main/java/dev/loki/totem/HexTotem.java
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package dev.loki.totem;
|
||||
|
||||
import dev.loki.perk.killer.HexRuinPerk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class HexTotem extends Totem {
|
||||
private final String hexName;
|
||||
private boolean active;
|
||||
|
||||
public HexTotem(Location location, String hexName) {
|
||||
super(location);
|
||||
this.state = TotemState.HEX;
|
||||
this.hexName = hexName;
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawn() {
|
||||
super.spawn();
|
||||
startParticleEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateVisuals() {
|
||||
if (display == null || display.isDead()) return;
|
||||
String name = state.getColorCode() + "Порча: " + hexName;
|
||||
display.setCustomName(name);
|
||||
display.getEquipment().setHelmet(createHexItem());
|
||||
}
|
||||
|
||||
private ItemStack createHexItem() {
|
||||
ItemStack skull = new ItemStack(Material.WITHER_SKELETON_SKULL);
|
||||
SkullMeta meta = (SkullMeta) skull.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName("§cHex Totem");
|
||||
skull.setItemMeta(meta);
|
||||
}
|
||||
return skull;
|
||||
}
|
||||
|
||||
private void startParticleEffect() {
|
||||
if (location.getWorld() == null) return;
|
||||
location.getWorld().spawnParticle(Particle.SOUL_FIRE_FLAME,
|
||||
location.clone().add(0, 1.5, 0),
|
||||
2, 0.3, 0.5, 0.3, 0.01);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(UUID playerId) {
|
||||
if (state == TotemState.HEX && active) {
|
||||
cleanse(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanse(UUID playerId) {
|
||||
active = false;
|
||||
setState(TotemState.CLEANSED);
|
||||
spawnCleanseEffect();
|
||||
}
|
||||
|
||||
private void spawnCleanseEffect() {
|
||||
if (location.getWorld() == null) return;
|
||||
location.getWorld().spawnParticle(Particle.END_ROD,
|
||||
location.clone().add(0, 1, 0),
|
||||
20, 0.5, 0.5, 0.5, 0.1);
|
||||
location.getWorld().playSound(location, org.bukkit.Sound.BLOCK_BEACON_DEACTIVATE, 1.0f, 0.5f);
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public String getHexName() {
|
||||
return hexName;
|
||||
}
|
||||
|
||||
public Class<?> getHexType() {
|
||||
return HexRuinPerk.class;
|
||||
}
|
||||
}
|
||||
86
src/main/java/dev/loki/totem/Totem.java
Normal file
86
src/main/java/dev/loki/totem/Totem.java
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package dev.loki.totem;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class Totem {
|
||||
protected final UUID id;
|
||||
protected final Location location;
|
||||
protected ArmorStand display;
|
||||
protected TotemState state;
|
||||
protected UUID linkedPerkId;
|
||||
|
||||
public Totem(Location location) {
|
||||
this.id = UUID.randomUUID();
|
||||
this.location = location;
|
||||
this.state = TotemState.DULL;
|
||||
this.linkedPerkId = null;
|
||||
}
|
||||
|
||||
public void spawn() {
|
||||
if (display != null && !display.isDead()) {
|
||||
return;
|
||||
}
|
||||
display = (ArmorStand) location.getWorld().spawnEntity(location, EntityType.ARMOR_STAND);
|
||||
display.setVisible(false);
|
||||
display.setGravity(false);
|
||||
display.setSmall(true);
|
||||
display.setMarker(true);
|
||||
display.setCustomNameVisible(true);
|
||||
updateVisuals();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (display != null && !display.isDead()) {
|
||||
display.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void updateVisuals();
|
||||
|
||||
public abstract void onInteract(UUID playerId);
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public TotemState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(TotemState state) {
|
||||
this.state = state;
|
||||
updateVisuals();
|
||||
}
|
||||
|
||||
public UUID getLinkedPerkId() {
|
||||
return linkedPerkId;
|
||||
}
|
||||
|
||||
public void setLinkedPerkId(UUID linkedPerkId) {
|
||||
this.linkedPerkId = linkedPerkId;
|
||||
}
|
||||
|
||||
public boolean isHexTotem() {
|
||||
return state == TotemState.HEX;
|
||||
}
|
||||
|
||||
public boolean isBlessedTotem() {
|
||||
return state == TotemState.BLESSED;
|
||||
}
|
||||
|
||||
public boolean isCleansed() {
|
||||
return state == TotemState.CLEANSED;
|
||||
}
|
||||
|
||||
public double distanceTo(Location other) {
|
||||
return location.distance(other);
|
||||
}
|
||||
}
|
||||
127
src/main/java/dev/loki/totem/TotemManager.java
Normal file
127
src/main/java/dev/loki/totem/TotemManager.java
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package dev.loki.totem;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class TotemManager {
|
||||
private static final int DEFAULT_TOTEM_COUNT = 5;
|
||||
private final List<Totem> totems = new ArrayList<>();
|
||||
private final Map<UUID, Totem> totemById = new HashMap<>();
|
||||
|
||||
public void initializeTotems(List<Location> locations) {
|
||||
clearTotems();
|
||||
int count = Math.min(locations.size(), DEFAULT_TOTEM_COUNT);
|
||||
for (int i = 0; i < count; i++) {
|
||||
DullTotem totem = new DullTotem(locations.get(i));
|
||||
addTotem(totem);
|
||||
totem.spawn();
|
||||
}
|
||||
}
|
||||
|
||||
public void addTotem(Totem totem) {
|
||||
totems.add(totem);
|
||||
totemById.put(totem.getId(), totem);
|
||||
}
|
||||
|
||||
public void removeTotem(UUID id) {
|
||||
Totem totem = totemById.remove(id);
|
||||
if (totem != null) {
|
||||
totem.remove();
|
||||
totems.remove(totem);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearTotems() {
|
||||
for (Totem totem : totems) {
|
||||
totem.remove();
|
||||
}
|
||||
totems.clear();
|
||||
totemById.clear();
|
||||
}
|
||||
|
||||
public Totem getTotem(UUID id) {
|
||||
return totemById.get(id);
|
||||
}
|
||||
|
||||
public Totem getNearestTotem(Location location) {
|
||||
Totem nearest = null;
|
||||
double minDist = Double.MAX_VALUE;
|
||||
for (Totem totem : totems) {
|
||||
double dist = totem.distanceTo(location);
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
nearest = totem;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
public Totem getNearestDullTotem(Location location) {
|
||||
Totem nearest = null;
|
||||
double minDist = Double.MAX_VALUE;
|
||||
for (Totem totem : totems) {
|
||||
if (totem.getState() != TotemState.DULL) continue;
|
||||
double dist = totem.distanceTo(location);
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
nearest = totem;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
public List<Totem> getAllTotems() {
|
||||
return new ArrayList<>(totems);
|
||||
}
|
||||
|
||||
public List<Totem> getHexTotems() {
|
||||
List<Totem> hexTotems = new ArrayList<>();
|
||||
for (Totem totem : totems) {
|
||||
if (totem.isHexTotem()) {
|
||||
hexTotems.add(totem);
|
||||
}
|
||||
}
|
||||
return hexTotems;
|
||||
}
|
||||
|
||||
public List<Totem> getCleansedTotems() {
|
||||
List<Totem> cleansed = new ArrayList<>();
|
||||
for (Totem totem : totems) {
|
||||
if (totem.isCleansed()) {
|
||||
cleansed.add(totem);
|
||||
}
|
||||
}
|
||||
return cleansed;
|
||||
}
|
||||
|
||||
public int getActiveHexCount() {
|
||||
int count = 0;
|
||||
for (Totem totem : totems) {
|
||||
if (totem.isHexTotem() && totem instanceof HexTotem hex && hex.isActive()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public boolean hasActiveHexes() {
|
||||
return getActiveHexCount() > 0;
|
||||
}
|
||||
|
||||
public void convertToHex(UUID totemId, String hexName) {
|
||||
Totem totem = totemById.get(totemId);
|
||||
if (totem instanceof DullTotem dull && dull.canBecomeHex()) {
|
||||
Location loc = totem.getLocation();
|
||||
removeTotem(totemId);
|
||||
HexTotem hexTotem = new HexTotem(loc, hexName);
|
||||
hexTotem.setLinkedPerkId(totemId);
|
||||
addTotem(hexTotem);
|
||||
hexTotem.spawn();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDefaultTotemCount() {
|
||||
return DEFAULT_TOTEM_COUNT;
|
||||
}
|
||||
}
|
||||
24
src/main/java/dev/loki/totem/TotemState.java
Normal file
24
src/main/java/dev/loki/totem/TotemState.java
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package dev.loki.totem;
|
||||
|
||||
public enum TotemState {
|
||||
DULL("Тусклый тотем", "§7"),
|
||||
HEX("§cПроклятый тотем", "§c"),
|
||||
BLESSED("§dБлагословенный тотем", "§d"),
|
||||
CLEANSED("Очищенный тотем", "§a");
|
||||
|
||||
private final String displayName;
|
||||
private final String colorCode;
|
||||
|
||||
TotemState(String displayName, String colorCode) {
|
||||
this.displayName = displayName;
|
||||
this.colorCode = colorCode;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getColorCode() {
|
||||
return colorCode;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue