commit acfaa82e2ba245800689c2e140d807c0917a3b32 Author: M_Viper Date: Sat Aug 23 13:18:05 2025 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1cfc2ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Maven target build folder +target/ + +# IDE configs (optional, falls Eclipse/IntelliJ/VSCode) +.idea/ +.vscode/ +*.iml + +# Betriebssystem-spezifisches +.DS_Store +Thumbs.db diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3c29812 --- /dev/null +++ b/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + me.viper + SurvivalMechanics + 1.0-SNAPSHOT + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot-api + 1.21.3-R0.1-SNAPSHOT + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + + + + + \ No newline at end of file diff --git a/src/main/java/me/viper/survivalmechanics/SurvivalMechanics.java b/src/main/java/me/viper/survivalmechanics/SurvivalMechanics.java new file mode 100644 index 0000000..67005f4 --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/SurvivalMechanics.java @@ -0,0 +1,350 @@ +package me.viper.survivalmechanics; + +import me.viper.survivalmechanics.mechanics.*; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerBedEnterEvent; +import org.bukkit.event.player.PlayerBedLeaveEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.ChatColor; +import org.bukkit.scoreboard.*; + +import java.io.File; +import java.io.IOException; +import java.util.UUID; + +public class SurvivalMechanics extends JavaPlugin implements Listener { + private HungerManager hungerManager; + private ThirstManager thirstManager; + private FatigueManager fatigueManager; + private TemperatureManager temperatureManager; + private StaminaManager staminaManager; + private VulnerabilityManager vulnerabilityManager; + private HygieneManager hygieneManager; + private FileConfiguration langConfig; + private FileConfiguration playerDataConfig; + private File playerDataFile; + + @Override + public void onEnable() { + saveDefaultConfig(); + saveResource("lang.yml", false); + saveResource("playerdata.yml", false); + loadLangConfig(); + loadPlayerDataConfig(); + hungerManager = new HungerManager(this); + thirstManager = new ThirstManager(this); + fatigueManager = new FatigueManager(this); + temperatureManager = new TemperatureManager(this); + staminaManager = new StaminaManager(this); + vulnerabilityManager = new VulnerabilityManager(this); + hygieneManager = new HygieneManager(this); + hungerManager.startHungerTask(); + thirstManager.startThirstTask(); + fatigueManager.startFatigueTask(); + temperatureManager.startTemperatureTask(); + staminaManager.startStaminaTask(); + vulnerabilityManager.startVulnerabilityTask(); + hygieneManager.startHygieneTask(); + startScoreboardDisplay(); + getServer().getPluginManager().registerEvents(this, this); + getLogger().info("SurvivalMechanics Plugin aktiviert!"); + } + + @Override + public void onDisable() { + savePlayerDataConfig(); + getLogger().info("SurvivalMechanics Plugin deaktiviert!"); + } + + private void loadLangConfig() { + File langFile = new File(getDataFolder(), "lang.yml"); + langConfig = YamlConfiguration.loadConfiguration(langFile); + } + + private void loadPlayerDataConfig() { + playerDataFile = new File(getDataFolder(), "playerdata.yml"); + playerDataConfig = YamlConfiguration.loadConfiguration(playerDataFile); + } + + private void savePlayerDataConfig() { + try { + playerDataConfig.save(playerDataFile); + } catch (IOException e) { + getLogger().severe("Fehler beim Speichern von playerdata.yml: " + e.getMessage()); + } + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + String path = "players." + playerId + "."; + if (playerDataConfig.contains(path)) { + hungerManager.loadHunger(playerId, playerDataConfig.getInt(path + "hunger", getConfig().getInt("hunger.initial", 80))); + thirstManager.loadThirst(playerId, playerDataConfig.getInt(path + "thirst", getConfig().getInt("thirst.initial", 80))); + fatigueManager.loadFatigue(playerId, playerDataConfig.getInt(path + "fatigue", getConfig().getInt("fatigue.initial", 100))); + temperatureManager.loadTemperature(playerId, playerDataConfig.getInt(path + "temperature", getConfig().getInt("temperature.initial", 50))); + staminaManager.loadStamina(playerId, playerDataConfig.getInt(path + "stamina", getConfig().getInt("stamina.initial", 80))); + vulnerabilityManager.loadVulnerability(playerId, playerDataConfig.getInt(path + "vulnerability", getConfig().getInt("vulnerability.initial", 0))); + hygieneManager.loadHygiene(playerId, playerDataConfig.getInt(path + "hygiene", getConfig().getInt("hygiene.initial", 80))); + } + setupPlayerScoreboard(player); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + String path = "players." + playerId + "."; + playerDataConfig.set(path + "hunger", hungerManager.getHunger(playerId)); + playerDataConfig.set(path + "thirst", thirstManager.getThirst(playerId)); + playerDataConfig.set(path + "fatigue", fatigueManager.getFatigue(playerId)); + playerDataConfig.set(path + "temperature", temperatureManager.getTemperature(playerId)); + playerDataConfig.set(path + "stamina", staminaManager.getStamina(playerId)); + playerDataConfig.set(path + "vulnerability", vulnerabilityManager.getVulnerability(playerId)); + playerDataConfig.set(path + "hygiene", hygieneManager.getHygiene(playerId)); + savePlayerDataConfig(); + player.setScoreboard(getServer().getScoreboardManager().getNewScoreboard()); + } + + @EventHandler + public void onPlayerBedEnter(PlayerBedEnterEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + event.setCancelled(false); // Erlaube Schlafen jederzeit + fatigueManager.loadFatigue(playerId, getConfig().getInt("fatigue.max", 100)); + staminaManager.loadStamina(playerId, getConfig().getInt("stamina.max", 100)); + int hunger = hungerManager.getHunger(playerId); + int thirst = thirstManager.getThirst(playerId); + int hungerReduction = getConfig().getInt("hunger.sleep-reduction", 50); + int thirstReduction = getConfig().getInt("thirst.sleep-reduction", 50); + hungerManager.loadHunger(playerId, Math.max(0, hunger - hungerReduction)); + thirstManager.loadThirst(playerId, Math.max(0, thirst - thirstReduction)); + if (canSendMessage(playerId, "fatigue")) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', langConfig.getString("fatigue.rested", "§aDu erwachst erfrischt und voller Energie!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId, "fatigue"); + } + } + + @EventHandler + public void onPlayerBedLeave(PlayerBedLeaveEvent event) { + Player player = event.getPlayer(); + player.getWorld().setTime(0); // Setze Tageszeit auf Morgen + } + + @EventHandler + public void onPlayerDeath(PlayerDeathEvent event) { + Player player = event.getEntity(); + UUID playerId = player.getUniqueId(); + String deathCause = null; + if (hungerManager.getHunger(playerId) == 0 && getConfig().getBoolean("hunger.death-enabled", true)) { + deathCause = langConfig.getString("hunger.death", "§4Du bist verhungert!"); + } else if (thirstManager.getThirst(playerId) == 0 && getConfig().getBoolean("thirst.death-enabled", true)) { + deathCause = langConfig.getString("thirst.death", "§4Du bist verdurstet!"); + } else if (fatigueManager.getFatigue(playerId) == 0 && getConfig().getBoolean("fatigue.death-enabled", true)) { + deathCause = langConfig.getString("fatigue.death", "§4Du bist vor Erschöpfung zusammengebrochen!"); + } else if (temperatureManager.getTemperature(playerId) == 0 && getConfig().getBoolean("temperature.death-enabled", true)) { + String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase(); + boolean isRaining = player.getWorld().hasStorm() && player.getLocation().getBlock().getLightFromSky() == 15; + deathCause = langConfig.getString(isRaining ? "temperature.death-rain" : (getConfig().getStringList("temperature.cold-biomes").contains(biome) ? "temperature.death-cold" : "temperature.death-hot"), "§4Deine Körpertemperatur hat dich umgebracht!"); + } else if (hygieneManager.getHygiene(playerId) == 0 && getConfig().getBoolean("hygiene.death-enabled", true)) { + deathCause = langConfig.getString("hygiene.death", "§4Eine Infektion hat dich dahingerafft!"); + } + if (deathCause != null) { + event.setDeathMessage(ChatColor.translateAlternateColorCodes('&', deathCause)); + player.getWorld().playSound(player.getLocation(), "entity.player.death", 1.0f, 1.0f); + } + } + + private void startScoreboardDisplay() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : getServer().getOnlinePlayers()) { + updatePlayerScoreboard(player); + } + } + }.runTaskTimer(this, 0L, getConfig().getLong("display.update-interval", 100)); // Alle 5 Sekunden + } + + private void setupPlayerScoreboard(Player player) { + ScoreboardManager manager = getServer().getScoreboardManager(); + Scoreboard scoreboard = manager.getNewScoreboard(); + Objective objective = scoreboard.registerNewObjective("survival", "dummy", ChatColor.translateAlternateColorCodes('&', langConfig.getString("scoreboard.title", "&6Survival"))); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + player.setScoreboard(scoreboard); + } + + private void updatePlayerScoreboard(Player player) { + UUID playerId = player.getUniqueId(); + Scoreboard scoreboard = player.getScoreboard(); + Objective objective = scoreboard.getObjective("survival"); + if (objective == null) { + setupPlayerScoreboard(player); + scoreboard = player.getScoreboard(); + objective = scoreboard.getObjective("survival"); + } + // Reset previous scores + for (String entry : scoreboard.getEntries()) { + scoreboard.resetScores(entry); + } + // Get player stats + int hunger = hungerManager.getHunger(playerId); + int thirst = thirstManager.getThirst(playerId); + int fatigue = fatigueManager.getFatigue(playerId); + int temperature = temperatureManager.getTemperature(playerId); + int stamina = staminaManager.getStamina(playerId); + int vulnerability = vulnerabilityManager.getVulnerability(playerId); + int hygiene = hygieneManager.getHygiene(playerId); + int barLength = getConfig().getInt("display.bar-length", 5); + String barFilled = getConfig().getString("display.bar-filled", "█"); + String barEmpty = getConfig().getString("display.bar-empty", "▒"); + String hungerColor = getConfig().getString("display.hunger-color", "§6"); + String thirstColor = getConfig().getString("display.thirst-color", "§b"); + String fatigueColor = getConfig().getString("display.fatigue-color", "§7"); + String temperatureColor = getConfig().getString("display.temperature-color", "§c"); + String staminaColor = getConfig().getString("display.stamina-color", "§a"); + String vulnerabilityColor = getConfig().getString("display.vulnerability-color", "§4"); + String hygieneColor = getConfig().getString("display.hygiene-color", "§9"); + int mildThreshold = getConfig().getInt("display.mild-threshold", 60); + int criticalThreshold = getConfig().getInt("vulnerability.critical-threshold", 80); // Use vulnerability-specific threshold + // Get status based on thresholds + String hungerStatus = getStatus("hunger", hunger, mildThreshold, getConfig().getInt("hunger.critical-threshold", 20)); + String thirstStatus = getStatus("thirst", thirst, mildThreshold, getConfig().getInt("thirst.critical-threshold", 20)); + String fatigueStatus = getStatus("fatigue", fatigue, mildThreshold, getConfig().getInt("fatigue.critical-threshold", 20)); + String temperatureStatus = getTemperatureStatus(temperature, mildThreshold, getConfig().getInt("temperature.critical-threshold", 20)); + String staminaStatus = getStatus("stamina", stamina, mildThreshold, getConfig().getInt("stamina.critical-threshold", 20)); + String vulnerabilityStatus = getVulnerabilityStatus(vulnerability, mildThreshold, criticalThreshold); + String hygieneStatus = getStatus("hygiene", hygiene, mildThreshold, getConfig().getInt("hygiene.critical-threshold", 20)); + // Set scores + String[] entries = new String[] { + "§r", // Leerzeile + hungerColor + langConfig.getString("scoreboard.hunger", "HP") + ": " + getProgressBar(hunger, 100, barLength, barFilled, barEmpty) + " " + hungerStatus, + thirstColor + langConfig.getString("scoreboard.thirst", "TH") + ": " + getProgressBar(thirst, 100, barLength, barFilled, barEmpty) + " " + thirstStatus, + "§r ", // Leerzeile + fatigueColor + langConfig.getString("scoreboard.fatigue", "FT") + ": " + getProgressBar(fatigue, 100, barLength, barFilled, barEmpty) + " " + fatigueStatus, + temperatureColor + langConfig.getString("scoreboard.temperature", "TP") + ": " + getProgressBar(temperature, 100, barLength, barFilled, barEmpty) + " " + temperatureStatus, + "§r ", // Leerzeile + staminaColor + langConfig.getString("scoreboard.stamina", "ST") + ": " + getProgressBar(stamina, 100, barLength, barFilled, barEmpty) + " " + staminaStatus, + vulnerabilityColor + langConfig.getString("scoreboard.vulnerability", "VL") + ": " + getProgressBar(vulnerability, 100, barLength, barFilled, barEmpty) + " " + vulnerabilityStatus, + hygieneColor + langConfig.getString("scoreboard.hygiene", "HY") + ": " + getProgressBar(hygiene, 100, barLength, barFilled, barEmpty) + " " + hygieneStatus + }; + for (int i = 0; i < entries.length; i++) { + String entry = ChatColor.translateAlternateColorCodes('&', entries[i]); + if (entry.length() > 40) { + entry = entry.substring(0, 40); // Scoreboard-Zeilen sind auf 40 Zeichen begrenzt + } + Score score = objective.getScore(entry); + score.setScore(entries.length - i); // Höhere Werte oben + } + } + + private String getProgressBar(int current, int max, int totalBars, String filled, String empty) { + int filledBars = (int) ((double) current / max * totalBars); + int emptyBars = totalBars - filledBars; + StringBuilder bar = new StringBuilder(); + for (int i = 0; i < filledBars; i++) { + bar.append(filled); + } + for (int i = 0; i < emptyBars; i++) { + bar.append(empty); + } + return bar.toString(); + } + + private String getStatus(String mechanic, int value, int mildThreshold, int criticalThreshold) { + String statusKey; + if (value >= mildThreshold) { + statusKey = mechanic + ".status.full"; + } else if (value > criticalThreshold) { + statusKey = mechanic + ".status.mild"; + } else if (value > 0) { + statusKey = mechanic + ".status." + (mechanic.equals("hygiene") ? "dirty" : "tired"); + } else { + statusKey = mechanic + ".status." + (mechanic.equals("hunger") ? "starving" : mechanic.equals("thirst") ? "dehydrated" : mechanic.equals("fatigue") ? "exhausted" : mechanic.equals("stamina") ? "exhausted" : "critical"); + } + return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, "")); + } + + private String getTemperatureStatus(int value, int mildThreshold, int criticalThreshold) { + String statusKey; + if (value >= 40 && value <= 60) { + statusKey = "temperature.status.full"; + } else if (value > 60) { + statusKey = value >= criticalThreshold + 60 ? "temperature.status.critical" : "temperature.status.hot"; + } else { + statusKey = value <= criticalThreshold ? "temperature.status.critical" : "temperature.status.cold"; + } + return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, "")); + } + + private String getVulnerabilityStatus(int value, int mildThreshold, int criticalThreshold) { + String statusKey; + if (value >= criticalThreshold) { + statusKey = "vulnerability.status.critical"; + } else if (value > mildThreshold) { + statusKey = "vulnerability.status.injured"; + } else if (value > getConfig().getInt("display.critical-threshold", 20)) { + statusKey = "vulnerability.status.mild"; + } else { + statusKey = "vulnerability.status.full"; + } + return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, "")); + } + + public boolean canSendMessage(UUID playerId, String mechanic) { + long currentTime = System.currentTimeMillis(); + long lastTime = langConfig.getLong("last-message." + mechanic + "." + playerId, 0L); + return (currentTime - lastTime) / 1000 >= getConfig().getInt(mechanic + ".message-cooldown", 60); + } + + public void setLastMessageTime(UUID playerId, String mechanic) { + langConfig.set("last-message." + mechanic + "." + playerId, System.currentTimeMillis()); + try { + langConfig.save(new File(getDataFolder(), "lang.yml")); + } catch (IOException e) { + getLogger().severe("Fehler beim Speichern von lang.yml: " + e.getMessage()); + } + } + + public HungerManager getHungerManager() { + return hungerManager; + } + + public ThirstManager getThirstManager() { + return thirstManager; + } + + public FatigueManager getFatigueManager() { + return fatigueManager; + } + + public TemperatureManager getTemperatureManager() { + return temperatureManager; + } + + public StaminaManager getStaminaManager() { + return staminaManager; + } + + public VulnerabilityManager getVulnerabilityManager() { + return vulnerabilityManager; + } + + public HygieneManager getHygieneManager() { + return hygieneManager; + } + + public FileConfiguration getLangConfig() { + return langConfig; + } +} \ No newline at end of file diff --git a/src/main/java/me/viper/survivalmechanics/mechanics/FatigueManager.java b/src/main/java/me/viper/survivalmechanics/mechanics/FatigueManager.java new file mode 100644 index 0000000..42a532b --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/mechanics/FatigueManager.java @@ -0,0 +1,147 @@ +package me.viper.survivalmechanics.mechanics; + +import me.viper.survivalmechanics.SurvivalMechanics; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.ChatColor; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class FatigueManager implements Listener { + private final JavaPlugin plugin; + private final Map fatigueLevels = new HashMap<>(); + private final Map deathTimers = new HashMap<>(); + private final int maxFatigue; + private final double decreaseRate; + private final double activityMultiplier; + private final double nightMultiplier; + private final double climbingMultiplier; + private final int climbingHeightThreshold; + private final double climbingHeightScaling; + private final int slownessDuration; + private final int slownessAmplifier; + private final int blurDuration; + private final int blurAmplifier; + private final double staminaPenalty; + private final int criticalThreshold; + private final boolean deathEnabled; + private final int deathDelay; + private final int messageCooldown; + private final boolean criticalMessageOnly; + + public FatigueManager(JavaPlugin plugin) { + this.plugin = plugin; + this.maxFatigue = plugin.getConfig().getInt("fatigue.max", 100); + this.decreaseRate = plugin.getConfig().getDouble("fatigue.decrease-rate", 0.5); + this.activityMultiplier = plugin.getConfig().getDouble("fatigue.activity-multiplier", 2); + this.nightMultiplier = plugin.getConfig().getDouble("fatigue.night-multiplier", 2); + this.climbingMultiplier = plugin.getConfig().getDouble("fatigue.climbing-multiplier", 2); + this.climbingHeightThreshold = plugin.getConfig().getInt("fatigue.climbing-height-threshold", 100); + this.climbingHeightScaling = plugin.getConfig().getDouble("fatigue.climbing-height-scaling", 0.01); + this.slownessDuration = plugin.getConfig().getInt("fatigue.slowness-duration", 200); + this.slownessAmplifier = plugin.getConfig().getInt("fatigue.slowness-amplifier", 1); + this.blurDuration = plugin.getConfig().getInt("fatigue.blur-duration", 100); + this.blurAmplifier = plugin.getConfig().getInt("fatigue.blur-amplifier", 1); + this.staminaPenalty = plugin.getConfig().getDouble("fatigue.stamina-penalty", 1.5); + this.criticalThreshold = plugin.getConfig().getInt("fatigue.critical-threshold", 20); + this.deathEnabled = plugin.getConfig().getBoolean("fatigue.death-enabled", true); + this.deathDelay = plugin.getConfig().getInt("fatigue.death-delay", 60); + this.messageCooldown = plugin.getConfig().getInt("fatigue.message-cooldown", 60); + this.criticalMessageOnly = plugin.getConfig().getBoolean("fatigue.critical-message-only", true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void startFatigueTask() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + UUID playerId = player.getUniqueId(); + int fatigue = fatigueLevels.getOrDefault(playerId, maxFatigue); + double decrease = decreaseRate; + long time = player.getWorld().getTime(); + boolean isNight = time >= 12000 && time < 24000; + if (isNight) { + decrease *= nightMultiplier; + } + if (player.isSprinting() || player.isSwimming()) { + decrease *= activityMultiplier; + } + fatigue = Math.max(0, fatigue - (int) decrease); + fatigueLevels.put(playerId, fatigue); + + if (fatigue <= criticalThreshold && fatigue > 0) { + player.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, slownessDuration, slownessAmplifier)); + player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, blurDuration, blurAmplifier)); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("fatigue.critical", "§7Du kannst dich kaum wach halten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (fatigue == 0 && deathEnabled && !deathTimers.containsKey(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("fatigue.warning", "§4Deine Erschöpfung wird dich umbringen!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + deathTimers.put(playerId, new BukkitRunnable() { + @Override + public void run() { + if (fatigueLevels.getOrDefault(playerId, maxFatigue) == 0) { + player.setHealth(0); + } + deathTimers.remove(playerId); + } + }.runTaskLater(plugin, 20L * deathDelay)); + } else if (fatigue >= maxFatigue && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("fatigue.rested", "§aDu erwachst erholt und voller Kraft!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + }.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + int fatigue = fatigueLevels.getOrDefault(playerId, maxFatigue); + if (player.isClimbing() && player.getLocation().getY() > climbingHeightThreshold) { + double heightFactor = 1 + ((player.getLocation().getY() - climbingHeightThreshold) * climbingHeightScaling); + fatigue = Math.max(0, fatigue - (int) (decreaseRate * climbingMultiplier * heightFactor)); + fatigueLevels.put(playerId, fatigue); + if (fatigue <= criticalThreshold && fatigue > 0 && canSendMessage(playerId)) { + player.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, slownessDuration, slownessAmplifier)); + player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, blurDuration, blurAmplifier)); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("fatigue.critical", "§7Du kannst dich kaum wach halten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + ((SurvivalMechanics) plugin).getStaminaManager().applyFatiguePenalty(playerId, staminaPenalty); + } + + private boolean canSendMessage(UUID playerId) { + return ((SurvivalMechanics) plugin).canSendMessage(playerId, "fatigue"); + } + + private void setLastMessageTime(UUID playerId) { + ((SurvivalMechanics) plugin).setLastMessageTime(playerId, "fatigue"); + } + + public int getFatigue(UUID playerId) { + return fatigueLevels.getOrDefault(playerId, maxFatigue); + } + + public void loadFatigue(UUID playerId, int fatigue) { + fatigueLevels.put(playerId, fatigue); + } +} diff --git a/src/main/java/me/viper/survivalmechanics/mechanics/HungerManager.java b/src/main/java/me/viper/survivalmechanics/mechanics/HungerManager.java new file mode 100644 index 0000000..4ce67b9 --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/mechanics/HungerManager.java @@ -0,0 +1,185 @@ +package me.viper.survivalmechanics.mechanics; + +import me.viper.survivalmechanics.SurvivalMechanics; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerToggleSprintEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.Material; +import org.bukkit.ChatColor; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.List; + +public class HungerManager implements Listener { + private final JavaPlugin plugin; + private final Map hungerLevels = new HashMap<>(); + private final Map deathTimers = new HashMap<>(); + private final int maxHunger; + private final double decreaseRate; + private final double sprintMultiplier; + private final double combatMultiplier; + private final double nightMultiplier; + private final int sleepReduction; + private final double damage; + private final int criticalThreshold; + private final boolean deathEnabled; + private final int deathDelay; + private final List foodItems; + private final int foodRecoveryRate; + private final boolean particleEffect; + private final int messageCooldown; + private final boolean criticalMessageOnly; + + public HungerManager(JavaPlugin plugin) { + this.plugin = plugin; + this.maxHunger = plugin.getConfig().getInt("hunger.max", 100); + this.decreaseRate = plugin.getConfig().getDouble("hunger.decrease-rate", 0.5); + this.sprintMultiplier = plugin.getConfig().getDouble("hunger.sprint-multiplier", 2); + this.combatMultiplier = plugin.getConfig().getDouble("hunger.combat-multiplier", 3); + this.nightMultiplier = plugin.getConfig().getDouble("hunger.night-multiplier", 1.5); + this.sleepReduction = plugin.getConfig().getInt("hunger.sleep-reduction", 50); + this.damage = plugin.getConfig().getDouble("hunger.damage", 0.5); + this.criticalThreshold = plugin.getConfig().getInt("hunger.critical-threshold", 20); + this.deathEnabled = plugin.getConfig().getBoolean("hunger.death-enabled", true); + this.deathDelay = plugin.getConfig().getInt("hunger.death-delay", 60); + this.foodItems = plugin.getConfig().getStringList("hunger.food-items"); + this.foodRecoveryRate = plugin.getConfig().getInt("hunger.food-recovery-rate", 20); + this.particleEffect = plugin.getConfig().getBoolean("hunger.particle-effect", true); + this.messageCooldown = plugin.getConfig().getInt("hunger.message-cooldown", 60); + this.criticalMessageOnly = plugin.getConfig().getBoolean("hunger.critical-message-only", true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void startHungerTask() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + UUID playerId = player.getUniqueId(); + int hunger = hungerLevels.getOrDefault(playerId, maxHunger); + double decrease = decreaseRate; + long time = player.getWorld().getTime(); + boolean isNight = time >= 12000 && time < 24000; + if (isNight) { + decrease *= nightMultiplier; + } + hunger = Math.max(0, hunger - (int) decrease); + hungerLevels.put(playerId, hunger); + + if (hunger <= criticalThreshold && hunger > 0) { + player.damage(damage); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hunger.critical", "§4Dein Körper schwächt durch Hunger!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (hunger == 0 && deathEnabled && !deathTimers.containsKey(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hunger.warning", "§4Du bist dem Verhungern nahe!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + deathTimers.put(playerId, new BukkitRunnable() { + @Override + public void run() { + if (hungerLevels.getOrDefault(playerId, maxHunger) == 0) { + player.setHealth(0); + } + deathTimers.remove(playerId); + } + }.runTaskLater(plugin, 20L * deathDelay)); + } else if (hunger >= maxHunger && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hunger.fed", "§aDu fühlst dich satt und gestärkt!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + }.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + if (event.hasItem() && foodItems.contains(event.getItem().getType().toString())) { + int hunger = hungerLevels.getOrDefault(playerId, maxHunger); + hunger = Math.min(maxHunger, hunger + foodRecoveryRate); + hungerLevels.put(playerId, hunger); + event.getItem().setAmount(event.getItem().getAmount() - 1); + if (particleEffect) { + player.getWorld().spawnParticle(org.bukkit.Particle.HEART, player.getLocation().add(0, 1, 0), 5); + } + if (canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hunger.fed", "§aDu fühlst dich satt und gestärkt!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + if (deathTimers.containsKey(playerId)) { + deathTimers.get(playerId).cancel(); + deathTimers.remove(playerId); + } + } + } + + @EventHandler + public void onPlayerToggleSprint(PlayerToggleSprintEvent event) { + if (event.isSprinting()) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + int hunger = hungerLevels.getOrDefault(playerId, maxHunger); + hunger = Math.max(0, hunger - (int) (decreaseRate * sprintMultiplier)); + hungerLevels.put(playerId, hunger); + if (hunger <= criticalThreshold && hunger > 0 && canSendMessage(playerId)) { + player.damage(damage); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hunger.critical", "§4Dein Körper schwächt durch Hunger!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + + @EventHandler + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + UUID playerId = player.getUniqueId(); + int hunger = hungerLevels.getOrDefault(playerId, maxHunger); + hunger = Math.max(0, hunger - (int) (decreaseRate * combatMultiplier)); + hungerLevels.put(playerId, hunger); + if (hunger <= criticalThreshold && hunger > 0 && canSendMessage(playerId)) { + player.damage(damage); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hunger.critical", "§4Dein Körper schwächt durch Hunger!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + + private boolean canSendMessage(UUID playerId) { + return ((SurvivalMechanics) plugin).canSendMessage(playerId, "hunger"); + } + + private void setLastMessageTime(UUID playerId) { + ((SurvivalMechanics) plugin).setLastMessageTime(playerId, "hunger"); + } + + public int getHunger(UUID playerId) { + return hungerLevels.getOrDefault(playerId, maxHunger); + } + + public void loadHunger(UUID playerId, int hunger) { + hungerLevels.put(playerId, hunger); + } + + public List getFoodItems() { + return foodItems; + } +} \ No newline at end of file diff --git a/src/main/java/me/viper/survivalmechanics/mechanics/HygieneManager.java b/src/main/java/me/viper/survivalmechanics/mechanics/HygieneManager.java new file mode 100644 index 0000000..f9c5545 --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/mechanics/HygieneManager.java @@ -0,0 +1,179 @@ +package me.viper.survivalmechanics.mechanics; + +import me.viper.survivalmechanics.SurvivalMechanics; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.Material; +import org.bukkit.ChatColor; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.List; + +public class HygieneManager implements Listener { + private final JavaPlugin plugin; + private final Map hygieneLevels = new HashMap<>(); + private final Map deathTimers = new HashMap<>(); + private final int maxHygiene; + private final double decreaseRate; + private final List dirtyBiomes; + private final double diggingMultiplier; + private final double climbingMultiplier; + private final int climbingHeightThreshold; + private final double climbingHeightScaling; + private final double vulnerabilityExhaustionMultiplier; + private final double recoveryRate; + private final double waterRecoveryRate; + private final int weaknessDuration; + private final int weaknessAmplifier; + private final int criticalThreshold; + private final boolean deathEnabled; + private final int deathDelay; + private final int messageCooldown; + private final boolean criticalMessageOnly; + + public HygieneManager(JavaPlugin plugin) { + this.plugin = plugin; + this.maxHygiene = plugin.getConfig().getInt("hygiene.max", 100); + this.decreaseRate = plugin.getConfig().getDouble("hygiene.decrease-rate", 0.5); + this.dirtyBiomes = plugin.getConfig().getStringList("hygiene.dirty-biomes"); + this.diggingMultiplier = plugin.getConfig().getDouble("hygiene.digging-multiplier", 3); + this.climbingMultiplier = plugin.getConfig().getDouble("hygiene.climbing-multiplier", 2); + this.climbingHeightThreshold = plugin.getConfig().getInt("hygiene.climbing-height-threshold", 100); + this.climbingHeightScaling = plugin.getConfig().getDouble("hygiene.climbing-height-scaling", 0.01); + this.vulnerabilityExhaustionMultiplier = plugin.getConfig().getDouble("hygiene.vulnerability-exhaustion-multiplier", 2); + this.recoveryRate = plugin.getConfig().getDouble("hygiene.recovery-rate", 1); + this.waterRecoveryRate = plugin.getConfig().getDouble("hygiene.water-recovery-rate", 5); + this.weaknessDuration = plugin.getConfig().getInt("hygiene.weakness-duration", 200); + this.weaknessAmplifier = plugin.getConfig().getInt("hygiene.weakness-amplifier", 1); + this.criticalThreshold = plugin.getConfig().getInt("hygiene.critical-threshold", 20); + this.deathEnabled = plugin.getConfig().getBoolean("hygiene.death-enabled", true); + this.deathDelay = plugin.getConfig().getInt("hygiene.death-delay", 60); + this.messageCooldown = plugin.getConfig().getInt("hygiene.message-cooldown", 60); + this.criticalMessageOnly = plugin.getConfig().getBoolean("hygiene.critical-message-only", true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void startHygieneTask() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + UUID playerId = player.getUniqueId(); + int hygiene = hygieneLevels.getOrDefault(playerId, maxHygiene); + int vulnerability = ((SurvivalMechanics) plugin).getVulnerabilityManager().getVulnerability(playerId); + String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase(); + + double decrease = decreaseRate; + if (dirtyBiomes.contains(biome)) { + decrease *= 2; + } + if (vulnerability > plugin.getConfig().getInt("vulnerability.critical-threshold", 80)) { + decrease *= vulnerabilityExhaustionMultiplier; + } + hygiene = Math.max(0, hygiene - (int) decrease); + hygieneLevels.put(playerId, hygiene); + + if (hygiene <= criticalThreshold && hygiene > 0) { + player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, weaknessDuration, weaknessAmplifier)); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hygiene.critical", "§4Schmutz und Gestank machen dich krank!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (hygiene == 0 && deathEnabled && !deathTimers.containsKey(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hygiene.warning", "§4Eine Infektion droht dich zu töten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + deathTimers.put(playerId, new BukkitRunnable() { + @Override + public void run() { + if (hygieneLevels.getOrDefault(playerId, maxHygiene) == 0) { + player.setHealth(0); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hygiene.death", "§4Eine Infektion hat dein Leben beendet!"))); + } + deathTimers.remove(playerId); + } + }.runTaskLater(plugin, 20L * deathDelay)); + } else if (hygiene >= maxHygiene && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hygiene.clean", "§aDu fühlst dich sauber und wohl!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + }.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + Material blockType = event.getBlock().getType(); + if (blockType == Material.DIRT || blockType == Material.GRASS_BLOCK) { + int hygiene = hygieneLevels.getOrDefault(playerId, maxHygiene); + hygiene = Math.max(0, hygiene - (int) (decreaseRate * diggingMultiplier)); + hygieneLevels.put(playerId, hygiene); + if (hygiene <= criticalThreshold && hygiene > 0 && canSendMessage(playerId)) { + player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, weaknessDuration, weaknessAmplifier)); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hygiene.critical", "§4Schmutz und Gestank machen dich krank!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + int hygiene = hygieneLevels.getOrDefault(playerId, maxHygiene); + if (player.getLocation().getBlock().isLiquid()) { + hygiene = Math.min(maxHygiene, hygiene + (int) waterRecoveryRate); + hygieneLevels.put(playerId, hygiene); + if (hygiene >= maxHygiene && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hygiene.clean", "§aDu fühlst dich sauber und wohl!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + if (deathTimers.containsKey(playerId)) { + deathTimers.get(playerId).cancel(); + deathTimers.remove(playerId); + } + } else if (player.isClimbing() && player.getLocation().getY() > climbingHeightThreshold) { + double heightFactor = 1 + ((player.getLocation().getY() - climbingHeightThreshold) * climbingHeightScaling); + hygiene = Math.max(0, hygiene - (int) (decreaseRate * climbingMultiplier * heightFactor)); + hygieneLevels.put(playerId, hygiene); + if (hygiene <= criticalThreshold && hygiene > 0 && canSendMessage(playerId)) { + player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, weaknessDuration, weaknessAmplifier)); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("hygiene.critical", "§4Schmutz und Gestank machen dich krank!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + + private boolean canSendMessage(UUID playerId) { + return ((SurvivalMechanics) plugin).canSendMessage(playerId, "hygiene"); + } + + private void setLastMessageTime(UUID playerId) { + ((SurvivalMechanics) plugin).setLastMessageTime(playerId, "hygiene"); + } + + public int getHygiene(UUID playerId) { + return hygieneLevels.getOrDefault(playerId, maxHygiene); + } + + public void loadHygiene(UUID playerId, int hygiene) { + hygieneLevels.put(playerId, hygiene); + } +} \ No newline at end of file diff --git a/src/main/java/me/viper/survivalmechanics/mechanics/StaminaManager.java b/src/main/java/me/viper/survivalmechanics/mechanics/StaminaManager.java new file mode 100644 index 0000000..bb12649 --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/mechanics/StaminaManager.java @@ -0,0 +1,182 @@ +package me.viper.survivalmechanics.mechanics; + +import me.viper.survivalmechanics.SurvivalMechanics; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerToggleSprintEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.ChatColor; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class StaminaManager implements Listener { + private final JavaPlugin plugin; + private final Map staminaLevels = new HashMap<>(); + private final int maxStamina; + private final double decreaseRate; + private final double sprintMultiplier; + private final double jumpMultiplier; + private final double combatMultiplier; + private final double climbingMultiplier; + private final int climbingHeightThreshold; + private final double climbingHeightScaling; + private final double regenRate; + private final double hungerThirstPenalty; + private final double fatiguePenalty; + private final double vulnerabilityStaminaPenalty; + private final double staminaVulnerabilityIncrease; + private final int criticalThreshold; + private final int minToSprint; + private final int messageCooldown; + private final boolean criticalMessageOnly; + + public StaminaManager(JavaPlugin plugin) { + this.plugin = plugin; + this.maxStamina = plugin.getConfig().getInt("stamina.max", 100); + this.decreaseRate = plugin.getConfig().getDouble("stamina.decrease-rate", 1); + this.sprintMultiplier = plugin.getConfig().getDouble("stamina.sprint-multiplier", 3); + this.jumpMultiplier = plugin.getConfig().getDouble("stamina.jump-multiplier", 2); + this.combatMultiplier = plugin.getConfig().getDouble("stamina.combat-multiplier", 4); + this.climbingMultiplier = plugin.getConfig().getDouble("stamina.climbing-multiplier", 2); + this.climbingHeightThreshold = plugin.getConfig().getInt("stamina.climbing-height-threshold", 100); + this.climbingHeightScaling = plugin.getConfig().getDouble("stamina.climbing-height-scaling", 0.01); + this.regenRate = plugin.getConfig().getDouble("stamina.regen-rate", 2); + this.hungerThirstPenalty = plugin.getConfig().getDouble("stamina.hunger-thirst-penalty", 0.5); + this.fatiguePenalty = plugin.getConfig().getDouble("stamina.fatigue-penalty", 0.5); + this.vulnerabilityStaminaPenalty = plugin.getConfig().getDouble("stamina.vulnerability-stamina-penalty", 0.7); + this.staminaVulnerabilityIncrease = plugin.getConfig().getDouble("stamina.stamina-vulnerability-increase", 2); + this.criticalThreshold = plugin.getConfig().getInt("stamina.critical-threshold", 20); + this.minToSprint = plugin.getConfig().getInt("stamina.min-to-sprint", 20); + this.messageCooldown = plugin.getConfig().getInt("stamina.message-cooldown", 60); + this.criticalMessageOnly = plugin.getConfig().getBoolean("stamina.critical-message-only", true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void startStaminaTask() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + UUID playerId = player.getUniqueId(); + int stamina = staminaLevels.getOrDefault(playerId, maxStamina); + int hunger = ((SurvivalMechanics) plugin).getHungerManager().getHunger(playerId); + int thirst = ((SurvivalMechanics) plugin).getThirstManager().getThirst(playerId); + int fatigue = ((SurvivalMechanics) plugin).getFatigueManager().getFatigue(playerId); + double regen = regenRate; + if (hunger < criticalThreshold || thirst < criticalThreshold) { + regen *= hungerThirstPenalty; + } + if (fatigue < criticalThreshold) { + regen *= fatiguePenalty; + } + stamina = Math.min(maxStamina, stamina + (int) regen); + staminaLevels.put(playerId, stamina); + + if (stamina <= criticalThreshold && canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("stamina.critical-sprint", "§4Du bist zu schwach, um zu sprinten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + }.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden + } + + @EventHandler + public void onPlayerToggleSprint(PlayerToggleSprintEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + int stamina = staminaLevels.getOrDefault(playerId, maxStamina); + if (event.isSprinting() && stamina < minToSprint) { + event.setCancelled(true); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("stamina.critical-sprint", "§4Du bist zu schwach, um zu sprinten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (event.isSprinting()) { + stamina = Math.max(0, stamina - (int) (decreaseRate * sprintMultiplier)); + staminaLevels.put(playerId, stamina); + applyVulnerabilityIncrease(playerId); + } + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + int stamina = staminaLevels.getOrDefault(playerId, maxStamina); + if (player.getVelocity().getY() > 0 && !player.isOnGround()) { + stamina = Math.max(0, stamina - (int) (decreaseRate * jumpMultiplier)); + staminaLevels.put(playerId, stamina); + if (stamina <= criticalThreshold && canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("stamina.critical-jump", "§4Du bist zu schwach, um zu springen!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + applyVulnerabilityIncrease(playerId); + } else if (player.isClimbing() && player.getLocation().getY() > climbingHeightThreshold) { + double heightFactor = 1 + ((player.getLocation().getY() - climbingHeightThreshold) * climbingHeightScaling); + stamina = Math.max(0, stamina - (int) (decreaseRate * climbingMultiplier * heightFactor)); + staminaLevels.put(playerId, stamina); + if (stamina <= criticalThreshold && canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("climbing.critical", "§4Das Klettern zehrt an deinen Kräften!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + applyVulnerabilityIncrease(playerId); + } + } + + @EventHandler + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + UUID playerId = player.getUniqueId(); + int stamina = staminaLevels.getOrDefault(playerId, maxStamina); + stamina = Math.max(0, stamina - (int) (decreaseRate * combatMultiplier)); + staminaLevels.put(playerId, stamina); + if (stamina <= criticalThreshold && canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("stamina.critical-combat", "§4Du bist zu schwach, um zu kämpfen!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + applyVulnerabilityIncrease(playerId); + } + } + + public void applyFatiguePenalty(UUID playerId, double penalty) { + int stamina = staminaLevels.getOrDefault(playerId, maxStamina); + stamina = Math.max(0, stamina - (int) (decreaseRate * penalty)); + staminaLevels.put(playerId, stamina); + } + + private void applyVulnerabilityIncrease(UUID playerId) { + int stamina = staminaLevels.getOrDefault(playerId, maxStamina); + if (stamina <= criticalThreshold) { + ((SurvivalMechanics) plugin).getVulnerabilityManager().increaseVulnerability(playerId, (int) staminaVulnerabilityIncrease); + } + } + + private boolean canSendMessage(UUID playerId) { + return ((SurvivalMechanics) plugin).canSendMessage(playerId, "stamina"); + } + + private void setLastMessageTime(UUID playerId) { + ((SurvivalMechanics) plugin).setLastMessageTime(playerId, "stamina"); + } + + public int getStamina(UUID playerId) { + return staminaLevels.getOrDefault(playerId, maxStamina); + } + + public void loadStamina(UUID playerId, int stamina) { + staminaLevels.put(playerId, stamina); + } +} \ No newline at end of file diff --git a/src/main/java/me/viper/survivalmechanics/mechanics/TemperatureManager.java b/src/main/java/me/viper/survivalmechanics/mechanics/TemperatureManager.java new file mode 100644 index 0000000..125d8b9 --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/mechanics/TemperatureManager.java @@ -0,0 +1,196 @@ +package me.viper.survivalmechanics.mechanics; + +import me.viper.survivalmechanics.SurvivalMechanics; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.ChatColor; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.List; + +public class TemperatureManager implements Listener { + private final JavaPlugin plugin; + private final Map temperatureLevels = new HashMap<>(); + private final Map deathTimers = new HashMap<>(); + private final int maxTemperature; + private final double decreaseRate; + private final List coldBiomes; + private final List hotBiomes; + private final double coldDamage; + private final double hotDamage; + private final int warmthRadius; + private final double rainCoolRate; + private final double rainMultiplier; + private final double nightColdMultiplier; + private final int criticalThreshold; + private final boolean deathEnabled; + private final int deathDelay; + private final int messageCooldown; + private final boolean criticalMessageOnly; + + public TemperatureManager(JavaPlugin plugin) { + this.plugin = plugin; + this.maxTemperature = plugin.getConfig().getInt("temperature.max", 100); + this.decreaseRate = plugin.getConfig().getDouble("temperature.decrease-rate", 1); + this.coldBiomes = plugin.getConfig().getStringList("temperature.cold-biomes"); + this.hotBiomes = plugin.getConfig().getStringList("temperature.hot-biomes"); + this.coldDamage = plugin.getConfig().getDouble("temperature.cold-damage", 0.5); + this.hotDamage = plugin.getConfig().getDouble("temperature.hot-damage", 0.5); + this.warmthRadius = plugin.getConfig().getInt("temperature.warmth-radius", 5); + this.rainCoolRate = plugin.getConfig().getDouble("temperature.rain-cool-rate", 2); + this.rainMultiplier = plugin.getConfig().getDouble("temperature.rain-multiplier", 1.5); + this.nightColdMultiplier = plugin.getConfig().getDouble("temperature.night-cold-multiplier", 1.5); + this.criticalThreshold = plugin.getConfig().getInt("temperature.critical-threshold", 20); + this.deathEnabled = plugin.getConfig().getBoolean("temperature.death-enabled", true); + this.deathDelay = plugin.getConfig().getInt("temperature.death-delay", 60); + this.messageCooldown = plugin.getConfig().getInt("temperature.message-cooldown", 60); + this.criticalMessageOnly = plugin.getConfig().getBoolean("temperature.critical-message-only", true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void startTemperatureTask() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + UUID playerId = player.getUniqueId(); + int temperature = temperatureLevels.getOrDefault(playerId, maxTemperature); + int hygiene = ((SurvivalMechanics) plugin).getHygieneManager().getHygiene(playerId); + double decrease = decreaseRate; + String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase(); + long time = player.getWorld().getTime(); + boolean isNight = time >= 12000 && time < 24000; + boolean isRaining = player.getWorld().hasStorm() && player.getLocation().getBlock().getLightFromSky() == 15; + + if (hotBiomes.contains(biome)) { + temperature = Math.min(maxTemperature, temperature + (int) decrease); + if (temperature <= criticalThreshold && temperature > 0) { + player.damage(hotDamage); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.critical-hot", "§4Die Hitze überwältigt dich!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (temperature == 0 && deathEnabled && !deathTimers.containsKey(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.warning-hot", "§4Die Hitze wird dich bald töten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + deathTimers.put(playerId, new BukkitRunnable() { + @Override + public void run() { + if (temperatureLevels.getOrDefault(playerId, maxTemperature) == 0) { + player.setHealth(0); + } + deathTimers.remove(playerId); + } + }.runTaskLater(plugin, 20L * deathDelay)); + } + } else if (coldBiomes.contains(biome)) { + decrease *= isNight ? nightColdMultiplier : 1; + temperature = Math.max(0, temperature - (int) decrease); + if (temperature <= criticalThreshold && temperature > 0) { + player.damage(coldDamage); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.critical-cold", "§4Du zitterst unkontrollierbar!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (temperature == 0 && deathEnabled && !deathTimers.containsKey(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.warning-cold", "§4Die Kälte wird dich bald töten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + deathTimers.put(playerId, new BukkitRunnable() { + @Override + public void run() { + if (temperatureLevels.getOrDefault(playerId, maxTemperature) == 0) { + player.setHealth(0); + } + deathTimers.remove(playerId); + } + }.runTaskLater(plugin, 20L * deathDelay)); + } + } else if (isRaining) { + decrease *= rainMultiplier; + temperature = Math.max(0, temperature - (int) (decrease + rainCoolRate)); + if (temperature <= criticalThreshold && temperature > 0) { + player.damage(coldDamage); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.rain", "§4Der Regen lässt dich erfrieren!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (temperature == 0 && deathEnabled && !deathTimers.containsKey(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.warning-rain", "§4Der Regen wird dich unterkühlen!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + deathTimers.put(playerId, new BukkitRunnable() { + @Override + public void run() { + if (temperatureLevels.getOrDefault(playerId, maxTemperature) == 0) { + player.setHealth(0); + } + deathTimers.remove(playerId); + } + }.runTaskLater(plugin, 20L * deathDelay)); + } + } else { + int recovery = hygiene < ((SurvivalMechanics) plugin).getConfig().getInt("hygiene.critical-threshold", 20) ? 1 : 2; + if (temperature > maxTemperature / 2) { + temperature = Math.max(maxTemperature / 2, temperature - recovery); + } else if (temperature < maxTemperature / 2) { + temperature = Math.min(maxTemperature / 2, temperature + recovery); + } + } + temperatureLevels.put(playerId, temperature); + + if (temperature >= maxTemperature && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.comfortable", "§aDeine Körpertemperatur fühlt sich gut an!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + }.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + int temperature = temperatureLevels.getOrDefault(playerId, maxTemperature); + boolean isRaining = player.getWorld().hasStorm() && player.getLocation().getBlock().getLightFromSky() == 15; + + if (isRaining) { + temperature = Math.max(0, temperature - (int) (decreaseRate * rainMultiplier + rainCoolRate)); + temperatureLevels.put(playerId, temperature); + if (temperature <= criticalThreshold && temperature > 0 && canSendMessage(playerId)) { + player.damage(coldDamage); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("temperature.rain", "§4Der Regen lässt dich erfrieren!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + + private boolean canSendMessage(UUID playerId) { + return ((SurvivalMechanics) plugin).canSendMessage(playerId, "temperature"); + } + + private void setLastMessageTime(UUID playerId) { + ((SurvivalMechanics) plugin).setLastMessageTime(playerId, "temperature"); + } + + public int getTemperature(UUID playerId) { + return temperatureLevels.getOrDefault(playerId, maxTemperature); + } + + public void loadTemperature(UUID playerId, int temperature) { + temperatureLevels.put(playerId, temperature); + } +} \ No newline at end of file diff --git a/src/main/java/me/viper/survivalmechanics/mechanics/ThirstManager.java b/src/main/java/me/viper/survivalmechanics/mechanics/ThirstManager.java new file mode 100644 index 0000000..38fbc64 --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/mechanics/ThirstManager.java @@ -0,0 +1,141 @@ +package me.viper.survivalmechanics.mechanics; + +import me.viper.survivalmechanics.SurvivalMechanics; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.Material; +import org.bukkit.ChatColor; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.List; + +public class ThirstManager implements Listener { + private final JavaPlugin plugin; + private final Map thirstLevels = new HashMap<>(); + private final Map deathTimers = new HashMap<>(); + private final int maxThirst; + private final double decreaseRate; + private final List hotBiomes; + private final double hotBiomeMultiplier; + private final int rainRegenRate; + private final int waterRegenRate; + private final int sleepReduction; + private final double damage; + private final int criticalThreshold; + private final boolean deathEnabled; + private final int deathDelay; + private final int messageCooldown; + private final boolean criticalMessageOnly; + + public ThirstManager(JavaPlugin plugin) { + this.plugin = plugin; + this.maxThirst = plugin.getConfig().getInt("thirst.max", 100); + this.decreaseRate = plugin.getConfig().getDouble("thirst.decrease-rate", 1); + this.hotBiomes = plugin.getConfig().getStringList("thirst.hot-biomes"); + this.hotBiomeMultiplier = plugin.getConfig().getDouble("thirst.hot-biome-multiplier", 2); + this.rainRegenRate = plugin.getConfig().getInt("thirst.rain-regen-rate", 1); + this.waterRegenRate = plugin.getConfig().getInt("thirst.water-regen-rate", 5); + this.sleepReduction = plugin.getConfig().getInt("thirst.sleep-reduction", 50); + this.damage = plugin.getConfig().getDouble("thirst.damage", 0.5); + this.criticalThreshold = plugin.getConfig().getInt("thirst.critical-threshold", 20); + this.deathEnabled = plugin.getConfig().getBoolean("thirst.death-enabled", true); + this.deathDelay = plugin.getConfig().getInt("thirst.death-delay", 60); + this.messageCooldown = plugin.getConfig().getInt("thirst.message-cooldown", 60); + this.criticalMessageOnly = plugin.getConfig().getBoolean("thirst.critical-message-only", true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void startThirstTask() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + UUID playerId = player.getUniqueId(); + int thirst = thirstLevels.getOrDefault(playerId, maxThirst); + double decrease = decreaseRate; + String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase(); + boolean isRaining = player.getWorld().hasStorm() && player.getLocation().getBlock().getLightFromSky() == 15; + + if (hotBiomes.contains(biome)) { + decrease *= hotBiomeMultiplier; + } + if (isRaining) { + thirst = Math.min(maxThirst, thirst + rainRegenRate); + } else { + thirst = Math.max(0, thirst - (int) decrease); + } + thirstLevels.put(playerId, thirst); + + if (thirst <= criticalThreshold && thirst > 0) { + player.damage(damage); + if (canSendMessage(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("thirst.critical", "§4Deine Kehle brennt vor Durst!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } else if (thirst == 0 && deathEnabled && !deathTimers.containsKey(playerId)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("thirst.warning", "§4Dehydration droht dich zu töten!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + deathTimers.put(playerId, new BukkitRunnable() { + @Override + public void run() { + if (thirstLevels.getOrDefault(playerId, maxThirst) == 0) { + player.setHealth(0); + } + deathTimers.remove(playerId); + } + }.runTaskLater(plugin, 20L * deathDelay)); + } else if (thirst >= maxThirst && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("thirst.hydrated", "§aDu fühlst dich erfrischt!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + }.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + if (event.hasItem() && event.getItem().getType() == Material.POTION) { + int thirst = thirstLevels.getOrDefault(playerId, maxThirst); + thirst = Math.min(maxThirst, thirst + waterRegenRate); + thirstLevels.put(playerId, thirst); + event.getItem().setAmount(event.getItem().getAmount() - 1); + if (canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("thirst.hydrated", "§aDu fühlst dich erfrischt!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + if (deathTimers.containsKey(playerId)) { + deathTimers.get(playerId).cancel(); + deathTimers.remove(playerId); + } + } + } + + private boolean canSendMessage(UUID playerId) { + return ((SurvivalMechanics) plugin).canSendMessage(playerId, "thirst"); + } + + private void setLastMessageTime(UUID playerId) { + ((SurvivalMechanics) plugin).setLastMessageTime(playerId, "thirst"); + } + + public int getThirst(UUID playerId) { + return thirstLevels.getOrDefault(playerId, maxThirst); + } + + public void loadThirst(UUID playerId, int thirst) { + thirstLevels.put(playerId, thirst); + } +} \ No newline at end of file diff --git a/src/main/java/me/viper/survivalmechanics/mechanics/VulnerabilityManager.java b/src/main/java/me/viper/survivalmechanics/mechanics/VulnerabilityManager.java new file mode 100644 index 0000000..a58d16a --- /dev/null +++ b/src/main/java/me/viper/survivalmechanics/mechanics/VulnerabilityManager.java @@ -0,0 +1,151 @@ +package me.viper.survivalmechanics.mechanics; + +import me.viper.survivalmechanics.SurvivalMechanics; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.ChatColor; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.List; + +public class VulnerabilityManager implements Listener { + private final JavaPlugin plugin; + private final Map vulnerabilityLevels = new HashMap<>(); + private final int maxVulnerability; + private final double increaseRate; + private final double criticalHitMultiplier; + private final double heavyArmorMultiplier; + private final double hungerExhaustionMultiplier; + private final double recoveryRate; + private final double foodRecoveryRate; + private final int weaknessDuration; + private final int weaknessAmplifier; + private final int criticalThreshold; + private final int messageCooldown; + private final boolean criticalMessageOnly; + + public VulnerabilityManager(JavaPlugin plugin) { + this.plugin = plugin; + this.maxVulnerability = plugin.getConfig().getInt("vulnerability.max", 100); + this.increaseRate = plugin.getConfig().getDouble("vulnerability.increase-rate", 5); + this.criticalHitMultiplier = plugin.getConfig().getDouble("vulnerability.critical-hit-multiplier", 2); + this.heavyArmorMultiplier = plugin.getConfig().getDouble("vulnerability.heavy-armor-multiplier", 2); + this.hungerExhaustionMultiplier = plugin.getConfig().getDouble("vulnerability.hunger-exhaustion-multiplier", 2); + this.recoveryRate = plugin.getConfig().getDouble("vulnerability.recovery-rate", 2); + this.foodRecoveryRate = plugin.getConfig().getDouble("vulnerability.food-recovery-rate", 3); + this.weaknessDuration = plugin.getConfig().getInt("vulnerability.weakness-duration", 200); + this.weaknessAmplifier = plugin.getConfig().getInt("vulnerability.weakness-amplifier", 1); + this.criticalThreshold = plugin.getConfig().getInt("vulnerability.critical-threshold", 80); + this.messageCooldown = plugin.getConfig().getInt("vulnerability.message-cooldown", 60); + this.criticalMessageOnly = plugin.getConfig().getBoolean("vulnerability.critical-message-only", true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void startVulnerabilityTask() { + new BukkitRunnable() { + @Override + public void run() { + for (Player player : plugin.getServer().getOnlinePlayers()) { + UUID playerId = player.getUniqueId(); + int vulnerability = vulnerabilityLevels.getOrDefault(playerId, 0); + int hunger = ((SurvivalMechanics) plugin).getHungerManager().getHunger(playerId); + int thirst = ((SurvivalMechanics) plugin).getThirstManager().getThirst(playerId); + double recovery = recoveryRate; + if (hunger < ((SurvivalMechanics) plugin).getConfig().getInt("hunger.critical-threshold", 20) || + thirst < ((SurvivalMechanics) plugin).getConfig().getInt("thirst.critical-threshold", 20)) { + vulnerability = Math.min(maxVulnerability, vulnerability + (int) (increaseRate * hungerExhaustionMultiplier)); + } else { + vulnerability = Math.max(0, vulnerability - (int) recovery); + } + vulnerabilityLevels.put(playerId, vulnerability); + + if (vulnerability >= criticalThreshold && canSendMessage(playerId)) { + player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, weaknessDuration, weaknessAmplifier)); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("vulnerability.critical", "§4Deine Verletzungen machen dich schwach!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } else if (vulnerability == 0 && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("vulnerability.healed", "§aDu bist wieder vollständig geheilt!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + }.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden + } + + @EventHandler + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + UUID playerId = player.getUniqueId(); + int vulnerability = vulnerabilityLevels.getOrDefault(playerId, 0); + vulnerability = Math.min(maxVulnerability, vulnerability + (int) increaseRate); + vulnerabilityLevels.put(playerId, vulnerability); + if (vulnerability >= criticalThreshold) { + event.setDamage(event.getDamage() * criticalHitMultiplier); + } + for (ItemStack armor : player.getInventory().getArmorContents()) { + if (armor != null && (armor.getType().toString().contains("DIAMOND") || armor.getType().toString().contains("NETHERITE"))) { + vulnerability = Math.min(maxVulnerability, vulnerability + (int) (increaseRate * heavyArmorMultiplier)); + vulnerabilityLevels.put(playerId, vulnerability); + } + } + if (vulnerability >= criticalThreshold && canSendMessage(playerId)) { + player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, weaknessDuration, weaknessAmplifier)); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("vulnerability.critical", "§4Deine Verletzungen machen dich schwach!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + UUID playerId = player.getUniqueId(); + if (event.hasItem() && ((SurvivalMechanics) plugin).getHungerManager().getFoodItems().contains(event.getItem().getType().toString())) { + int vulnerability = vulnerabilityLevels.getOrDefault(playerId, 0); + vulnerability = Math.max(0, vulnerability - (int) foodRecoveryRate); + vulnerabilityLevels.put(playerId, vulnerability); + if (vulnerability == 0 && canSendMessage(playerId) && !criticalMessageOnly) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', ((SurvivalMechanics) plugin).getLangConfig().getString("vulnerability.healed", "§aDu bist wieder vollständig geheilt!"))); + player.getWorld().playSound(player.getLocation(), "entity.player.levelup", 1.0f, 1.0f); + setLastMessageTime(playerId); + } + } + } + + public void increaseVulnerability(UUID playerId, int amount) { + int vulnerability = vulnerabilityLevels.getOrDefault(playerId, 0); + vulnerability = Math.min(maxVulnerability, vulnerability + amount); + vulnerabilityLevels.put(playerId, vulnerability); + } + + private boolean canSendMessage(UUID playerId) { + return ((SurvivalMechanics) plugin).canSendMessage(playerId, "vulnerability"); + } + + private void setLastMessageTime(UUID playerId) { + ((SurvivalMechanics) plugin).setLastMessageTime(playerId, "vulnerability"); + } + + public int getVulnerability(UUID playerId) { + return vulnerabilityLevels.getOrDefault(playerId, 0); + } + + public void loadVulnerability(UUID playerId, int vulnerability) { + vulnerabilityLevels.put(playerId, vulnerability); + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..2679cc4 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,174 @@ +# Konfiguration für Hunger +hunger: + max: 100 # Maximaler Hungerwert (0-100). Bestimmt die Obergrenze für den Hunger. + initial: 80 # Startwert für Hunger beim Betreten des Servers (0-100). 100 = Satt, 0 = Verhungert. + decrease-rate: 0.5 # Wie viel Hunger pro Intervall abnimmt (z. B. 0.5 pro 20 Sekunden). Höhere Werte = schnellerer Hungerabbau. + decrement-interval: 20 # Intervall in Sekunden, in dem Hunger, Durst, etc. aktualisiert werden (z. B. 20 = alle 20 Sekunden). + sprint-multiplier: 1.5 # Multiplikator für Hungerabbau beim Sprinten (z. B. 1.5 = 50% schnellerer Abbau). Werte > 1 erhöhen den Verbrauch. + combat-multiplier: 2 # Multiplikator für Hungerabbau im Kampf (z. B. 2 = doppelter Abbau). Werte > 1 erhöhen den Verbrauch. + night-multiplier: 1.2 # Multiplikator für Hungerabbau nachts (z. B. 1.2 = 20% schnellerer Abbau). Werte > 1 erhöhen den Verbrauch. + sleep-reduction: 40 # Wie viel Hunger durch Schlafen regeneriert wird (z. B. 40 = +40 Hunger). Werte 0-100. + damage: 0.5 # Schaden pro Sekunde, wenn Hunger = 0 (z. B. 0.5 = halbes Herz pro Sekunde). Werte > 0 aktivieren Schaden. + critical-threshold: 20 # Schwellenwert für kritischen Hunger (z. B. 20 = bei ≤20 wird "Verhungert" angezeigt und Effekte starten). + death-enabled: true # Ob Spieler bei Hunger = 0 nach Verzögerung sterben (true/false). + death-delay: 60 # Verzögerung in Sekunden, bevor Spieler bei Hunger = 0 stirbt (z. B. 60 = 1 Minute). + food-items: # Liste der Nahrungsmittel, die Hunger regenerieren. + - BREAD # Brot + - APPLE # Apfel + - COOKED_BEEF # Gekochtes Rindfleisch + - COOKED_CHICKEN # Gekochtes Hühnchen + food-recovery-rate: 34 # Wie viel Hunger ein Nahrungsmittel regeneriert (z. B. 34 = +34 Hunger pro Item, 3 Brote/Fleisch füllen von 0 auf 100). Werte 0-100. + particle-effect: true # Ob Partikeleffekte bei kritischem Hunger angezeigt werden (true/false). + message-cooldown: 60 # Abklingzeit in Sekunden für Hungermeldungen (z. B. 60 = Meldung alle 60 Sekunden). + critical-message-only: true # Ob nur kritische Meldungen (bei ≤20) gesendet werden (true = nur kritische, false = auch andere). + +# Konfiguration für Durst +thirst: + max: 100 # Maximaler Durstwert (0-100). Bestimmt die Obergrenze für Durst. + initial: 80 # Startwert für Durst beim Betreten des Servers (0-100). 100 = Erfrischt, 0 = Dehydriert. + decrease-rate: 0.8 # Wie viel Durst pro Intervall abnimmt (z. B. 0.8 pro 20 Sekunden). Höhere Werte = schnellerer Durstabbau. + decrement-interval: 20 # Intervall in Sekunden, in dem Durst aktualisiert wird (z. B. 20 = alle 20 Sekunden). + hot-biomes: # Biome, in denen Durst schneller abnimmt (heiße Biome). + - DESERT # Wüste + - SAVANNA # Savanne + - BADLANDS # Tafelberge + hot-biome-multiplier: 1.5 # Multiplikator für Durstabbau in heißen Biomen (z. B. 1.5 = 50% schneller). Werte > 1 erhöhen den Verbrauch. + rain-regen-rate: 2 # Wie viel Durst im Regen regeneriert wird pro Intervall (z. B. 2 = +2 Durst). Werte 0-100. + water-regen-rate: 50 # Wie viel Durst durch Trinken von Wasser regeneriert wird (z. B. 50 = +50 Durst, 2 Wasser füllen von 0 auf 100). Werte 0-100. + sleep-reduction: 40 # Wie viel Durst durch Schlafen regeneriert wird (z. B. 40 = +40 Durst). Werte 0-100. + damage: 0.5 # Schaden pro Sekunde, wenn Durst = 0 (z. B. 0.5 = halbes Herz pro Sekunde). Werte > 0 aktivieren Schaden. + critical-threshold: 20 # Schwellenwert für kritischen Durst (z. B. 20 = bei ≤20 wird "Dehydriert" angezeigt und Effekte starten). + death-enabled: true # Ob Spieler bei Durst = 0 nach Verzögerung sterben (true/false). + death-delay: 60 # Verzögerung in Sekunden, bevor Spieler bei Durst = 0 stirbt (z. B. 60 = 1 Minute). + message-cooldown: 60 # Abklingzeit in Sekunden für Durstmeldungen (z. B. 60 = Meldung alle 60 Sekunden). + critical-message-only: true # Ob nur kritische Meldungen (bei ≤20) gesendet werden (true = nur kritische, false = auch andere). + +# Konfiguration für Müdigkeit +fatigue: + max: 100 # Maximaler Müdigkeitswert (0-100). Bestimmt die Obergrenze für Müdigkeit. + initial: 100 # Startwert für Müdigkeit beim Betreten des Servers (0-100). 100 = Erholt, 0 = Erschöpft. + decrease-rate: 1.0 # Wie viel Müdigkeit pro Intervall abnimmt (z. B. 1.0 pro 30 Sekunden). Höhere Werte = schnellerer Abbau. + decrement-interval: 40 # Intervall in Sekunden, in dem Müdigkeit aktualisiert wird (z. B. 30 = alle 30 Sekunden). + activity-multiplier: 1.0 # Multiplikator für Müdigkeitsabbau bei Aktivitäten wie Sprinten/Schwimmen (z. B. 1.5 = 50% schneller). Werte > 1 erhöhen den Verbrauch. + night-multiplier: 2.0 # Multiplikator für Müdigkeitsabbau nachts (z. B. 2.0 = 2x schneller). Werte > 1 erhöhen den Verbrauch. + climbing-multiplier: 1.5 # Multiplikator für Müdigkeitsabbau beim Klettern (z. B. 1.5 = 50% schneller). Werte > 1 erhöhen den Verbrauch. + climbing-height-threshold: 100 # Höhe (Y-Koordinate), ab der Klettern Müdigkeit beeinflusst (z. B. 100 = ab Y=100). + climbing-height-scaling: 0.01 # Skalierungsfaktor für Müdigkeitsabbau basierend auf Kletterhöhe (z. B. 0.01 = 1% mehr pro Block über Schwelle). + slowness-duration: 200 # Dauer des Langsamkeitseffekts bei kritischer Müdigkeit in Ticks (z. B. 200 = 10 Sekunden). 20 Ticks = 1 Sekunde. + slowness-amplifier: 1 # Stärke des Langsamkeitseffekts (z. B. 1 = Langsamkeit I). Werte 0-255. + blur-duration: 100 # Dauer des Blindheitseffekts bei kritischer Müdigkeit in Ticks (z. B. 100 = 5 Sekunden). 20 Ticks = 1 Sekunde. + blur-amplifier: 1 # Stärke des Blindheitseffekts (z. B. 1 = Blindheit I). Werte 0-255. + stamina-penalty: 1.0 # Multiplikator für Ausdauerabbau bei kritischer Müdigkeit (z. B. 1.0 = kein zusätzlicher Abbau). Werte < 1 verringern, > 1 erhöhen. + critical-threshold: 20 # Schwellenwert für kritische Müdigkeit (z. B. 20 = bei ≤20 werden Effekte und Meldungen ausgelöst). + death-enabled: true # Ob Spieler bei Müdigkeit = 0 nach Verzögerung sterben (true/false). + death-delay: 60 # Verzögerung in Sekunden, bevor Spieler bei Müdigkeit = 0 stirbt (z. B. 60 = 1 Minute). + message-cooldown: 60 # Abklingzeit in Sekunden für Müdigkeitsmeldungen (z. B. 60 = Meldung alle 60 Sekunden). + critical-message-only: true # Ob nur kritische Meldungen (bei ≤20) gesendet werden (true = nur kritische, false = auch andere). + +# Konfiguration für Temperatur +temperature: + max: 50 # Maximaler Temperaturwert (0-100). 50 = Angenehm, 0 = Unterkühlt, 100 = Überhitzt. + initial: 50 # Startwert für Temperatur beim Betreten des Servers (0-100). 50 = Angenehm. + decrease-rate: 0.6 # Wie viel Temperatur in kalten Biomen pro Intervall abnimmt (z. B. 0.6 pro 20 Sekunden). Höhere Werte = schnellerer Abfall. + increase-rate: 0.6 # Wie viel Temperatur in heißen Biomen pro Intervall steigt (z. B. 0.6 pro 20 Sekunden). Höhere Werte = schnellerer Anstieg. + decrement-interval: 20 # Intervall in Sekunden, in dem Temperatur aktualisiert wird (z. B. 20 = alle 20 Sekunden). + cold-biomes: # Biome, in denen Temperatur abnimmt (kalte Biome). + - SNOWY_TAIGA # Verschneite Taiga + - SNOWY_TUNDRA # Verschneite Tundra + - ICE_SPIKES # Eisspitzen + hot-biomes: # Biome, in denen Temperatur steigt (heiße Biome). + - DESERT # Wüste + - SAVANNA # Savanne + - BADLANDS # Tafelberge + cold-damage: 0.5 # Schaden pro Sekunde bei kritischer Unterkühlung (z. B. 0.5 = halbes Herz pro Sekunde). Werte > 0 aktivieren Schaden. + hot-damage: 0.5 # Schaden pro Sekunde bei kritischer Überhitzung (z. B. 0.5 = halbes Herz pro Sekunde). Werte > 0 aktivieren Schaden. + warmth-radius: 5 # Radius in Blöcken, in dem Wärmequellen (z. B. Lagerfeuer) die Temperatur erhöhen (z. B. 5 = 5 Blöcke). + rain-cool-rate: 1 # Wie viel Temperatur im Regen pro Intervall abnimmt (z. B. 1 = -1 Temperatur). Werte > 0 kühlen ab. + rain-multiplier: 1.2 # Multiplikator für Temperaturabbau im Regen (z. B. 1.2 = 20% schneller). Werte > 1 erhöhen den Abfall. + night-cold-multiplier: 1.2 # Multiplikator für Temperaturabbau nachts in kalten Biomen (z. B. 1.2 = 20% schneller). Werte > 1 erhöhen den Abfall. + critical-threshold: 20 # Schwellenwert für kritische Temperatur (z. B. 20 = bei ≤20 oder ≥80 werden Effekte und Meldungen ausgelöst). + death-enabled: true # Ob Spieler bei kritischer Temperatur nach Verzögerung sterben (true/false). + death-delay: 60 # Verzögerung in Sekunden, bevor Spieler bei kritischer Temperatur stirbt (z. B. 60 = 1 Minute). + message-cooldown: 60 # Abklingzeit in Sekunden für Temperaturmeldungen (z. B. 60 = Meldung alle 60 Sekunden). + critical-message-only: true # Ob nur kritische Meldungen (bei ≤20 oder ≥80) gesendet werden (true = nur kritische, false = auch andere). + +# Konfiguration für Ausdauer +stamina: + max: 100 # Maximaler Ausdauerwert (0-100). Bestimmt die Obergrenze für Ausdauer. + initial: 100 # Startwert für Ausdauer beim Betreten des Servers (0-100). 100 = Energiegeladen, 0 = Ausgelaugt. + decrease-rate: 0.5 # Wie viel Ausdauer pro Intervall abnimmt (z. B. 1.0 pro 20 Sekunden). Höhere Werte = schnellerer Abbau. + decrement-interval: 20 # Intervall in Sekunden, in dem Ausdauer aktualisiert wird (z. B. 20 = alle 20 Sekunden). + sprint-multiplier: 0.5 # Multiplikator für Ausdauerabbau beim Sprinten (z. B. 5 = 3x schneller). Werte > 1 erhöhen den Verbrauch. + jump-multiplier: 1.0 # Multiplikator für Ausdauerabbau beim Springen (z. B. 1.5 = 50% schneller). Werte > 1 erhöhen den Verbrauch. + combat-multiplier: 2 # Multiplikator für Ausdauerabbau im Kampf (z. B. 2 = 2x schneller). Werte > 1 erhöhen den Verbrauch. + climbing-multiplier: 1.5 # Multiplikator für Ausdauerabbau beim Klettern (z. B. 1.5 = 50% schneller). Werte > 1 erhöhen den Verbrauch. + climbing-height-threshold: 100 # Höhe (Y-Koordinate), ab der Klettern Ausdauer beeinflusst (z. B. 100 = ab Y=100). + climbing-height-scaling: 0.01 # Skalierungsfaktor für Ausdauerabbau basierend auf Kletterhöhe (z. B. 0.01 = 1% mehr pro Block über Schwelle). + regen-rate: 3 # Wie viel Ausdauer pro Intervall regeneriert wird, wenn der Spieler ruht (z. B. 3 = +3 Ausdauer). Werte 0-100. + hunger-thirst-penalty: 0.5 # Multiplikator für Ausdauerabbau bei kritischem Hunger/Durst (z. B. 0.5 = 50% langsamer). Werte < 1 verringern, > 1 erhöhen. + fatigue-penalty: 0.5 # Multiplikator für Ausdauerabbau bei kritischer Müdigkeit (z. B. 0.5 = 50% langsamer). Werte < 1 verringern, > 1 erhöhen. + vulnerability-stamina-penalty: 0.7 # Multiplikator für Ausdauerabbau bei kritischer Verletzlichkeit (z. B. 0.7 = 30% langsamer). Werte < 1 verringern, > 1 erhöhen. + stamina-vulnerability-increase: 2 # Wie viel Verletzlichkeit durch niedrige Ausdauer steigt (z. B. 2 = +2 Verletzlichkeit). Werte 0-100. + critical-threshold: 20 # Schwellenwert für kritische Ausdauer (z. B. 20 = bei ≤20 werden Effekte und Meldungen ausgelöst). + min-to-sprint: 20 # Mindest-Ausdauerwert, um sprinten zu können (z. B. 20 = Sprinten bei ≤20 nicht möglich). + message-cooldown: 60 # Abklingzeit in Sekunden für Ausdauermeldungen (z. B. 60 = Meldung alle 60 Sekunden). + critical-message-only: true # Ob nur kritische Meldungen (bei ≤20) gesendet werden (true = nur kritische, false = auch andere). + +# Konfiguration für Verletztbarkeit +vulnerability: + max: 100 # Maximale Verletzlichkeit (0-100). 0 = Gesund, 100 = Schwer verletzt. + initial: 0 # Startwert für Verletzlichkeit beim Betreten des Servers (0-100). 0 = Gesund, 100 = Schwer verletzt. + increase-rate: 3 # Wie viel Verletzlichkeit pro Intervall steigt (z. B. 3 pro 20 Sekunden bei Schaden). Höhere Werte = schnellerer Anstieg. + decrement-interval: 20 # Intervall in Sekunden, in dem Verletzlichkeit aktualisiert wird (z. B. 20 = alle 20 Sekunden). + critical-hit-multiplier: 1.5 # Multiplikator für Verletzlichkeitsanstieg bei kritischen Treffern (z. B. 1.5 = 50% mehr). Werte > 1 erhöhen den Anstieg. + heavy-armor-multiplier: 1.5 # Multiplikator für Verletzlichkeitsanstieg bei schwerer Rüstung (z. B. 1.5 = 50% mehr). Werte > 1 erhöhen den Anstieg. + hunger-exhaustion-multiplier: 1.5 # Multiplikator für Verletzlichkeitsanstieg bei kritischem Hunger/Müdigkeit (z. B. 1.5 = 50% mehr). Werte > 1 erhöhen den Anstieg. + recovery-rate: 3 # Wie viel Verletzlichkeit pro Intervall sinkt, wenn der Spieler ruht (z. B. 3 = -3 Verletzlichkeit). Werte 0-100. + food-recovery-rate: 34 # Wie viel Verletzlichkeit durch Essen sinkt (z. B. 34 = -34 Verletzlichkeit pro Nahrung, 3 Brote/Fleisch setzen von 100 auf 0). Werte 0-100. + weakness-duration: 200 # Dauer des Schwächeeffekts bei kritischer Verletzlichkeit in Ticks (z. B. 200 = 10 Sekunden). 20 Ticks = 1 Sekunde. + weakness-amplifier: 1 # Stärke des Schwächeeffekts (z. B. 1 = Schwäche I). Werte 0-255. + critical-threshold: 80 # Schwellenwert für kritische Verletzlichkeit (z. B. 80 = bei ≥80 wird "Schwer verletzt" angezeigt und Effekte starten). + message-cooldown: 60 # Abklingzeit in Sekunden für Verletzlichkeitsmeldungen (z. B. 60 = Meldung alle 60 Sekunden). + critical-message-only: true # Ob nur kritische Meldungen (bei ≥80) gesendet werden (true = nur kritische, false = auch andere). + +# Konfiguration für Hygiene +hygiene: + max: 100 # Maximaler Hygienewert (0-100). Bestimmt die Obergrenze für Hygiene. + initial: 80 # Startwert für Hygiene beim Betreten des Servers (0-100). 100 = Sauber, 0 = Verwahrlost. + decrease-rate: 0.5 # Wie viel Hygiene pro Intervall abnimmt (z. B. 0.5 pro 20 Sekunden). Höhere Werte = schnellerer Abbau. + decrement-interval: 20 # Intervall in Sekunden, in dem Hygiene aktualisiert wird (z. B. 20 = alle 20 Sekunden). + dirty-biomes: # Biome, in denen Hygiene schneller abnimmt (schmutzige Biome). + - SWAMP # Sumpf + - MUDDY_SWAMP # Schlammiger Sumpf + digging-multiplier: 2 # Multiplikator für Hygieneabbau beim Graben (z. B. 2 = doppelt so schnell). Werte > 1 erhöhen den Verbrauch. + climbing-multiplier: 1.5 # Multiplikator für Hygieneabbau beim Klettern (z. B. 1.5 = 50% schneller). Werte > 1 erhöhen den Verbrauch. + climbing-height-threshold: 100 # Höhe (Y-Koordinate), ab der Klettern Hygiene beeinflusst (z. B. 100 = ab Y=100). + climbing-height-scaling: 0.01 # Skalierungsfaktor für Hygieneabbau basierend auf Kletterhöhe (z. B. 0.01 = 1% mehr pro Block über Schwelle). + vulnerability-exhaustion-multiplier: 2 # Multiplikator für Verletzlichkeitsanstieg bei kritischer Hygiene (z. B. 2 = doppelt so viel). Werte > 1 erhöhen den Anstieg. + recovery-rate: 2 # Wie viel Hygiene pro Intervall regeneriert wird, wenn der Spieler ruht (z. B. 2 = +2 Hygiene). Werte 0-100. + water-recovery-rate: 6 # Wie viel Hygiene durch Wasser (z. B. Schwimmen) regeneriert wird (z. B. 6 = +6 Hygiene). Werte 0-100. + weakness-duration: 200 # Dauer des Schwächeeffekts bei kritischer Hygiene in Ticks (z. B. 200 = 10 Sekunden). 20 Ticks = 1 Sekunde. + weakness-amplifier: 1 # Stärke des Schwächeeffekts (z. B. 1 = Schwäche I). Werte 0-255. + critical-threshold: 20 # Schwellenwert für kritische Hygiene (z. B. 20 = bei ≤20 wird "Verwahrlost" angezeigt und Effekte starten). + death-enabled: true # Ob Spieler bei kritischer Hygiene nach Verzögerung sterben (true/false). + death-delay: 60 # Verzögerung in Sekunden, bevor Spieler bei kritischer Hygiene stirbt (z. B. 60 = 1 Minute). + message-cooldown: 60 # Abklingzeit in Sekunden für Hygienemeldungen (z. B. 60 = Meldung alle 60 Sekunden). + critical-message-only: true # Ob nur kritische Meldungen (bei ≤20) gesendet werden (true = nur kritische, false = auch andere). + +# Konfiguration für die ActionBar-Anzeige +display: + bar-length: 5 # Länge der Balken im Scoreboard (z. B. 5 = █████ bei vollem Wert). Werte 1-10, kürzere Balken = weniger gequetscht. + bar-filled: "█" # Zeichen für gefüllte Balken im Scoreboard (z. B. █). Beliebiges Zeichen möglich. + bar-empty: "▒" # Zeichen für leere Balken im Scoreboard (z. B. ▒). Beliebiges Zeichen möglich. + update-interval: 100 # Intervall in Ticks, in dem das Scoreboard aktualisiert wird (z. B. 100 = 5 Sekunden). 20 Ticks = 1 Sekunde. + critical-display-threshold: 60 # Schwellenwert für Statusanzeige im Scoreboard (z. B. 60 = Status wie "Mild" ab ≤60). Werte 0-100. + rotation-interval: 80 # Intervall in Ticks, in dem die ActionBar rotiert (z. B. 80 = 4 Sekunden). 20 Ticks = 1 Sekunde. + hunger-color: "§6" # Farbcode für Hunger im Scoreboard (z. B. §6 = Gold). Minecraft-Farbcodes (§0-§f). + thirst-color: "§b" # Farbcode für Durst im Scoreboard (z. B. §b = Hellblau). Minecraft-Farbcodes (§0-§f). + fatigue-color: "§7" # Farbcode für Müdigkeit im Scoreboard (z. B. §7 = Grau). Minecraft-Farbcodes (§0-§f). + temperature-color: "§c" # Farbcode für Temperatur im Scoreboard (z. B. §c = Rot). Minecraft-Farbcodes (§0-§f). + stamina-color: "§a" # Farbcode für Ausdauer im Scoreboard (z. B. §a = Grün). Minecraft-Farbcodes (§0-§f). + vulnerability-color: "§4" # Farbcode für Verletzlichkeit im Scoreboard (z. B. §4 = Dunkelrot). Minecraft-Farbcodes (§0-§f). + hygiene-color: "§9" # Farbcode für Hygiene im Scoreboard (z. B. §9 = Dunkelblau). Minecraft-Farbcodes (§0-§f). + mild-threshold: 60 # Schwellenwert für "Mild"-Status im Scoreboard (z. B. 60 = "Mild" bei ≤60 für Hunger, Durst, etc.). Werte 0-100. + critical-threshold: 20 # Schwellenwert für kritischen Status im Scoreboard (z. B. 20 = "Verhungert" bei ≤20 für Hunger). Werte 0-100. \ No newline at end of file diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml new file mode 100644 index 0000000..0a23832 --- /dev/null +++ b/src/main/resources/lang.yml @@ -0,0 +1,95 @@ +scoreboard: + title: "&6Survival" + hunger: "HP" + thirst: "TH" + fatigue: "FT" + temperature: "TP" + stamina: "ST" + vulnerability: "VL" + hygiene: "HY" + +hunger: + critical: "&4Dein Körper schwächt durch Hunger!" + warning: "&4Du bist dem Verhungern nahe!" + fed: "&aDu fühlst dich satt und gestärkt!" + death: "&4Dein Körper gibt dem Hunger nach!" + status: + full: "&aSatt" + mild: "&eHungrig" + hungry: "&cSehr hungrig" + starving: "&4Verhungert" + +thirst: + critical: "&4Deine Kehle brennt vor Durst!" + warning: "&4Dehydration droht dich zu töten!" + hydrated: "&aDu fühlst dich erfrischt!" + death: "&4Dein Körper verdurstet elendig!" + status: + full: "&aErfrischt" + mild: "&eDurstig" + thirsty: "&cSehr durstig" + dehydrated: "&4Dehydriert" + +fatigue: + critical: "&7Du kannst dich kaum wach halten!" + warning: "&4Deine Erschöpfung wird dich umbringen!" + rested: "&aDu erwachst erholt und voller Kraft!" + death: "&4Dein Körper bricht vor Erschöpfung zusammen!" + status: + full: "&aErholt" + mild: "&eMüde" + tired: "&cSehr müde" + exhausted: "&4Erschöpft" + +temperature: + critical-cold: "&4Du zitterst unkontrollierbar!" + critical-hot: "&4Die Hitze überwältigt dich!" + rain: "&4Der Regen lässt dich erfrieren!" + warning-cold: "&4Die Kälte wird dich bald töten!" + warning-hot: "&4Die Hitze wird dich bald töten!" + warning-rain: "&4Der Regen wird dich unterkühlen!" + comfortable: "&aDeine Körpertemperatur fühlt sich gut an!" + death-cold: "&4Dein Körper gibt der Kälte nach!" + death-hot: "&4Die Hitze raubt dir das Leben!" + death-rain: "&4Der Regen hat dich unterkühlt!" + status: + full: "&aAngenehm" + mild: "&eUnwohl" + extreme: "&cKalt/Hot" + critical: "&4Unterkühlt/Überhitzt" + +stamina: + critical-sprint: "&4Du bist zu schwach, um zu sprinten!" + critical-jump: "&4Du bist zu schwach, um zu springen!" + critical-combat: "&4Du bist zu schwach, um zu kämpfen!" + full: "&aDu sprühst vor Energie!" + vulnerability: "&4Deine Schwäche macht dich anfälliger!" + status: + full: "&aEnergiegeladen" + mild: "&eErmüdet" + tired: "&cSehr erschöpft" + exhausted: "&4Völlig erschöpft" + +vulnerability: + critical: "&4Deine Verletzungen machen dich schwach!" + healed: "&aDu bist wieder vollständig geheilt!" + food-heal: "&eNahrung lindert deine Wunden!" + status: + full: "&aGesund" + mild: "&eVerletzt" + injured: "&cSchwer verletzt" + critical: "&4Kritisch" + +hygiene: + critical: "&4Schmutz und Gestank machen dich krank!" + warning: "&4Eine Infektion droht dich zu töten!" + clean: "&aDu fühlst dich sauber und wohl!" + death: "&4Eine Infektion hat dein Leben beendet!" + status: + full: "&aSauber" + mild: "&eSchmutzig" + dirty: "&cSehr schmutzig" + filthy: "&4Verseucht" + +climbing: + critical: "&4Das Klettern zehrt an deinen Kräften!" \ No newline at end of file diff --git a/src/main/resources/playerdata.yml b/src/main/resources/playerdata.yml new file mode 100644 index 0000000..0dd313d --- /dev/null +++ b/src/main/resources/playerdata.yml @@ -0,0 +1,2 @@ +# Wird dynamisch generiert +players: {} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..7a3c506 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,5 @@ +name: SurvivalMechanics +main: me.viper.survivalmechanics.SurvivalMechanics +version: 1.0-SNAPSHOT +api-version: 1.21 +author: M_Viper \ No newline at end of file