Update from Git Manager GUI

This commit is contained in:
2026-01-28 22:06:29 +01:00
parent 9d2a9908b4
commit 52fd35d9de
10 changed files with 645 additions and 250 deletions

View File

@@ -19,6 +19,8 @@ import org.bukkit.scoreboard.*;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.HashMap;
import java.util.Map;
public class SurvivalMechanics extends JavaPlugin implements Listener {
private HungerManager hungerManager;
@@ -32,13 +34,19 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
private FileConfiguration playerDataConfig;
private File playerDataFile;
// Better message cooldown management - store in memory instead of config file
private final Map<String, Long> lastMessageTimes = new HashMap<>();
@Override
public void onEnable() {
// Load configurations
saveDefaultConfig();
saveResource("lang.yml", false);
saveResource("playerdata.yml", false);
loadLangConfig();
loadPlayerDataConfig();
// Initialize managers
hungerManager = new HungerManager(this);
thirstManager = new ThirstManager(this);
fatigueManager = new FatigueManager(this);
@@ -46,6 +54,8 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
staminaManager = new StaminaManager(this);
vulnerabilityManager = new VulnerabilityManager(this);
hygieneManager = new HygieneManager(this);
// Start all tasks
hungerManager.startHungerTask();
thirstManager.startThirstTask();
fatigueManager.startFatigueTask();
@@ -53,24 +63,39 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
staminaManager.startStaminaTask();
vulnerabilityManager.startVulnerabilityTask();
hygieneManager.startHygieneTask();
// Start scoreboard display
startScoreboardDisplay();
// Register events
getServer().getPluginManager().registerEvents(this, this);
getLogger().info("SurvivalMechanics Plugin aktiviert!");
}
@Override
public void onDisable() {
// Save all player data before shutdown
for (Player player : getServer().getOnlinePlayers()) {
savePlayerData(player.getUniqueId());
}
savePlayerDataConfig();
getLogger().info("SurvivalMechanics Plugin deaktiviert!");
}
private void loadLangConfig() {
File langFile = new File(getDataFolder(), "lang.yml");
if (!langFile.exists()) {
saveResource("lang.yml", false);
}
langConfig = YamlConfiguration.loadConfiguration(langFile);
}
private void loadPlayerDataConfig() {
playerDataFile = new File(getDataFolder(), "playerdata.yml");
if (!playerDataFile.exists()) {
saveResource("playerdata.yml", false);
}
playerDataConfig = YamlConfiguration.loadConfiguration(playerDataFile);
}
@@ -87,6 +112,8 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
String path = "players." + playerId + ".";
// Load player data or use defaults
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)));
@@ -95,7 +122,17 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
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)));
} else {
// First time join - use initial values
hungerManager.loadHunger(playerId, getConfig().getInt("hunger.initial", 80));
thirstManager.loadThirst(playerId, getConfig().getInt("thirst.initial", 80));
fatigueManager.loadFatigue(playerId, getConfig().getInt("fatigue.initial", 100));
temperatureManager.loadTemperature(playerId, getConfig().getInt("temperature.initial", 50));
staminaManager.loadStamina(playerId, getConfig().getInt("stamina.initial", 80));
vulnerabilityManager.loadVulnerability(playerId, getConfig().getInt("vulnerability.initial", 0));
hygieneManager.loadHygiene(playerId, getConfig().getInt("hygiene.initial", 80));
}
setupPlayerScoreboard(player);
}
@@ -103,6 +140,15 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
// Save player data
savePlayerData(playerId);
// Reset scoreboard
player.setScoreboard(getServer().getScoreboardManager().getNewScoreboard());
}
private void savePlayerData(UUID playerId) {
String path = "players." + playerId + ".";
playerDataConfig.set(path + "hunger", hungerManager.getHunger(playerId));
playerDataConfig.set(path + "thirst", thirstManager.getThirst(playerId));
@@ -112,22 +158,29 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
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
// Allow sleeping anytime
event.setCancelled(false);
// Restore fatigue and stamina
fatigueManager.loadFatigue(playerId, getConfig().getInt("fatigue.max", 100));
staminaManager.loadStamina(playerId, getConfig().getInt("stamina.max", 100));
// Reduce hunger and thirst
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));
// Send message
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);
@@ -138,7 +191,8 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
@EventHandler
public void onPlayerBedLeave(PlayerBedLeaveEvent event) {
Player player = event.getPlayer();
player.getWorld().setTime(0); // Setze Tageszeit auf Morgen
// Set time to morning
player.getWorld().setTime(0);
}
@EventHandler
@@ -146,23 +200,47 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
Player player = event.getEntity();
UUID playerId = player.getUniqueId();
String deathCause = null;
// Determine death cause based on survival mechanics
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)) {
} else if (getConfig().getBoolean("temperature.death-enabled", true)) {
int temperature = temperatureManager.getTemperature(playerId);
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!");
// Death from cold (temperature at 0)
if (temperature == 0) {
deathCause = langConfig.getString(isRaining ? "temperature.death-rain" : "temperature.death-cold", "§4Du bist erfroren!");
}
// Death from heat (temperature at max)
else if (temperature >= getConfig().getInt("temperature.max", 100)) {
deathCause = langConfig.getString("temperature.death-hot", "§4Die Hitze 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!");
}
// Set custom death message if death was caused by survival mechanics
if (deathCause != null) {
event.setDeathMessage(ChatColor.translateAlternateColorCodes('&', deathCause));
player.getWorld().playSound(player.getLocation(), "entity.player.death", 1.0f, 1.0f);
}
// Reset player stats on death (configurable)
if (getConfig().getBoolean("reset-on-death", true)) {
hungerManager.loadHunger(playerId, getConfig().getInt("hunger.initial", 80));
thirstManager.loadThirst(playerId, getConfig().getInt("thirst.initial", 80));
fatigueManager.loadFatigue(playerId, getConfig().getInt("fatigue.initial", 100));
temperatureManager.loadTemperature(playerId, getConfig().getInt("temperature.initial", 50));
staminaManager.loadStamina(playerId, getConfig().getInt("stamina.initial", 80));
vulnerabilityManager.loadVulnerability(playerId, getConfig().getInt("vulnerability.initial", 0));
hygieneManager.loadHygiene(playerId, getConfig().getInt("hygiene.initial", 80));
}
}
private void startScoreboardDisplay() {
@@ -173,13 +251,14 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
updatePlayerScoreboard(player);
}
}
}.runTaskTimer(this, 0L, getConfig().getLong("display.update-interval", 100)); // Alle 5 Sekunden
}.runTaskTimer(this, 0L, getConfig().getLong("display.update-interval", 100)); // Default: every 5 seconds
}
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 objective = scoreboard.registerNewObjective("survival", "dummy",
ChatColor.translateAlternateColorCodes('&', langConfig.getString("scoreboard.title", "&6Survival")));
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
player.setScoreboard(scoreboard);
}
@@ -188,15 +267,18 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
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);
@@ -205,6 +287,8 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
int stamina = staminaManager.getStamina(playerId);
int vulnerability = vulnerabilityManager.getVulnerability(playerId);
int hygiene = hygieneManager.getHygiene(playerId);
// Get display configuration
int barLength = getConfig().getInt("display.bar-length", 5);
String barFilled = getConfig().getString("display.bar-filled", "");
String barEmpty = getConfig().getString("display.bar-empty", "");
@@ -216,8 +300,9 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
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
int criticalThreshold = getConfig().getInt("vulnerability.critical-threshold", 80);
// Get status for each mechanic
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));
@@ -225,26 +310,29 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
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
// Build scoreboard entries
String[] entries = new String[] {
"§r", // Leerzeile
"§r", // Empty line
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
"§r ", // Empty line (with space to make unique)
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
"§r ", // Empty line (with 2 spaces to make unique)
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
};
// Set scores (higher scores appear at top)
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
entry = entry.substring(0, 40); // Scoreboard lines are limited to 40 characters
}
Score score = objective.getScore(entry);
score.setScore(entries.length - i); // Höhere Werte oben
score.setScore(entries.length - i);
}
}
@@ -268,20 +356,41 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
} else if (value > criticalThreshold) {
statusKey = mechanic + ".status.mild";
} else if (value > 0) {
statusKey = mechanic + ".status." + (mechanic.equals("hygiene") ? "dirty" : "tired");
// Special cases for different mechanics
if (mechanic.equals("hygiene")) {
statusKey = mechanic + ".status.dirty";
} else {
statusKey = mechanic + ".status.tired";
}
} else {
statusKey = mechanic + ".status." + (mechanic.equals("hunger") ? "starving" : mechanic.equals("thirst") ? "dehydrated" : mechanic.equals("fatigue") ? "exhausted" : mechanic.equals("stamina") ? "exhausted" : "critical");
// Critical/Zero states
if (mechanic.equals("hunger")) {
statusKey = mechanic + ".status.starving";
} else if (mechanic.equals("thirst")) {
statusKey = mechanic + ".status.dehydrated";
} else if (mechanic.equals("fatigue") || mechanic.equals("stamina")) {
statusKey = mechanic + ".status.exhausted";
} else {
statusKey = mechanic + ".status.critical";
}
}
return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, ""));
}
private String getTemperatureStatus(int value, int mildThreshold, int criticalThreshold) {
String statusKey;
// Comfortable range: 40-60
if (value >= 40 && value <= 60) {
statusKey = "temperature.status.full";
} else if (value > 60) {
statusKey = value >= criticalThreshold + 60 ? "temperature.status.critical" : "temperature.status.hot";
} else {
}
// Hot (above 60)
else if (value > 60) {
// Very hot/critical (above 80)
statusKey = value >= (100 - criticalThreshold) ? "temperature.status.critical" : "temperature.status.hot";
}
// Cold (below 40)
else {
// Very cold/critical (below 20)
statusKey = value <= criticalThreshold ? "temperature.status.critical" : "temperature.status.cold";
}
return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, ""));
@@ -301,21 +410,20 @@ public class SurvivalMechanics extends JavaPlugin implements Listener {
return ChatColor.translateAlternateColorCodes('&', langConfig.getString(statusKey, ""));
}
// IMPROVED: Use in-memory storage instead of constantly writing to config file
public boolean canSendMessage(UUID playerId, String mechanic) {
long currentTime = System.currentTimeMillis();
long lastTime = langConfig.getLong("last-message." + mechanic + "." + playerId, 0L);
String key = playerId + ":" + mechanic;
long lastTime = lastMessageTimes.getOrDefault(key, 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());
}
String key = playerId + ":" + mechanic;
lastMessageTimes.put(key, System.currentTimeMillis());
}
// Getter methods for managers
public HungerManager getHungerManager() {
return hungerManager;
}

View File

@@ -70,15 +70,21 @@ public class FatigueManager implements Listener {
double decrease = decreaseRate;
long time = player.getWorld().getTime();
boolean isNight = time >= 12000 && time < 24000;
// Night increases fatigue decrease
if (isNight) {
decrease *= nightMultiplier;
}
// Activity increases fatigue decrease
if (player.isSprinting() || player.isSwimming()) {
decrease *= activityMultiplier;
}
fatigue = Math.max(0, fatigue - (int) decrease);
fatigueLevels.put(playerId, fatigue);
// Critical fatigue (low energy)
if (fatigue <= criticalThreshold && fatigue > 0) {
player.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, slownessDuration, slownessAmplifier));
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, blurDuration, blurAmplifier));
@@ -87,7 +93,9 @@ public class FatigueManager implements Listener {
player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f);
setLastMessageTime(playerId);
}
} else if (fatigue == 0 && deathEnabled && !deathTimers.containsKey(playerId)) {
}
// Zero fatigue - death warning
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() {
@@ -99,14 +107,16 @@ public class FatigueManager implements Listener {
deathTimers.remove(playerId);
}
}.runTaskLater(plugin, 20L * deathDelay));
} else if (fatigue >= maxFatigue && canSendMessage(playerId) && !criticalMessageOnly) {
}
// Full fatigue (well rested)
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
}.runTaskTimer(plugin, 0L, 20L * 60); // Every 60 seconds
}
@EventHandler
@@ -114,10 +124,13 @@ public class FatigueManager implements Listener {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
int fatigue = fatigueLevels.getOrDefault(playerId, maxFatigue);
// Climbing at high altitudes drains fatigue faster
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));
@@ -126,7 +139,11 @@ public class FatigueManager implements Listener {
setLastMessageTime(playerId);
}
}
((SurvivalMechanics) plugin).getStaminaManager().applyFatiguePenalty(playerId, staminaPenalty);
// Apply fatigue penalty to stamina
if (fatigue <= criticalThreshold) {
((SurvivalMechanics) plugin).getStaminaManager().applyFatiguePenalty(playerId, staminaPenalty);
}
}
private boolean canSendMessage(UUID playerId) {

View File

@@ -70,12 +70,16 @@ public class HungerManager implements Listener {
double decrease = decreaseRate;
long time = player.getWorld().getTime();
boolean isNight = time >= 12000 && time < 24000;
// Night increases hunger decrease slightly
if (isNight) {
decrease *= nightMultiplier;
}
hunger = Math.max(0, hunger - (int) decrease);
hungerLevels.put(playerId, hunger);
// Critical hunger (starving)
if (hunger <= criticalThreshold && hunger > 0) {
player.damage(damage);
if (canSendMessage(playerId)) {
@@ -83,7 +87,9 @@ public class HungerManager implements Listener {
player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f);
setLastMessageTime(playerId);
}
} else if (hunger == 0 && deathEnabled && !deathTimers.containsKey(playerId)) {
}
// Zero hunger - death warning
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() {
@@ -95,33 +101,45 @@ public class HungerManager implements Listener {
deathTimers.remove(playerId);
}
}.runTaskLater(plugin, 20L * deathDelay));
} else if (hunger >= maxHunger && canSendMessage(playerId) && !criticalMessageOnly) {
}
// Full hunger (well fed)
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
}.runTaskTimer(plugin, 0L, 20L * 60); // Every 60 seconds
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
// Check if player is eating a configured food item
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);
// Remove one item
event.getItem().setAmount(event.getItem().getAmount() - 1);
// Visual feedback
if (particleEffect) {
player.getWorld().spawnParticle(org.bukkit.Particle.HEART, player.getLocation().add(0, 1, 0), 5);
}
// Message feedback
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);
}
// Cancel death timer if active
if (deathTimers.containsKey(playerId)) {
deathTimers.get(playerId).cancel();
deathTimers.remove(playerId);
@@ -135,8 +153,11 @@ public class HungerManager implements Listener {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
int hunger = hungerLevels.getOrDefault(playerId, maxHunger);
// Sprinting drains hunger faster
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!")));
@@ -148,12 +169,15 @@ public class HungerManager implements Listener {
@EventHandler
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if (event.getEntity() instanceof Player) {
Player player = (Player) event.getEntity();
if (event.getDamager() instanceof Player) {
Player player = (Player) event.getDamager();
UUID playerId = player.getUniqueId();
int hunger = hungerLevels.getOrDefault(playerId, maxHunger);
// Combat drains hunger
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!")));

View File

@@ -74,15 +74,21 @@ public class HygieneManager implements Listener {
String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase();
double decrease = decreaseRate;
// Dirty biomes decrease hygiene faster
if (dirtyBiomes.contains(biome)) {
decrease *= 2;
}
// High vulnerability decreases hygiene faster
if (vulnerability > plugin.getConfig().getInt("vulnerability.critical-threshold", 80)) {
decrease *= vulnerabilityExhaustionMultiplier;
}
hygiene = Math.max(0, hygiene - (int) decrease);
hygieneLevels.put(playerId, hygiene);
// Critical hygiene (dirty/sick)
if (hygiene <= criticalThreshold && hygiene > 0) {
player.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, weaknessDuration, weaknessAmplifier));
if (canSendMessage(playerId)) {
@@ -90,7 +96,9 @@ public class HygieneManager implements Listener {
player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f);
setLastMessageTime(playerId);
}
} else if (hygiene == 0 && deathEnabled && !deathTimers.containsKey(playerId)) {
}
// Zero hygiene - death warning (infection)
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() {
@@ -103,14 +111,16 @@ public class HygieneManager implements Listener {
deathTimers.remove(playerId);
}
}.runTaskLater(plugin, 20L * deathDelay));
} else if (hygiene >= maxHygiene && canSendMessage(playerId) && !criticalMessageOnly) {
}
// Full hygiene (clean)
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
}.runTaskTimer(plugin, 0L, 20L * 60); // Every 60 seconds
}
@EventHandler
@@ -118,10 +128,14 @@ public class HygieneManager implements Listener {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
Material blockType = event.getBlock().getType();
if (blockType == Material.DIRT || blockType == Material.GRASS_BLOCK) {
// Breaking dirt/grass makes player dirty
if (blockType == Material.DIRT || blockType == Material.GRASS_BLOCK ||
blockType == Material.COARSE_DIRT || blockType == Material.PODZOL) {
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!")));
@@ -136,22 +150,30 @@ public class HygieneManager implements Listener {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
int hygiene = hygieneLevels.getOrDefault(playerId, maxHygiene);
// Water restores hygiene (bathing)
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);
}
// Cancel death timer if in water
if (deathTimers.containsKey(playerId)) {
deathTimers.get(playerId).cancel();
deathTimers.remove(playerId);
}
} else if (player.isClimbing() && player.getLocation().getY() > climbingHeightThreshold) {
}
// Climbing at high altitudes makes player dirty
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!")));

View File

@@ -68,16 +68,23 @@ public class StaminaManager implements Listener {
int hunger = ((SurvivalMechanics) plugin).getHungerManager().getHunger(playerId);
int thirst = ((SurvivalMechanics) plugin).getThirstManager().getThirst(playerId);
int fatigue = ((SurvivalMechanics) plugin).getFatigueManager().getFatigue(playerId);
double regen = regenRate;
// Low hunger or thirst reduces stamina regeneration
if (hunger < criticalThreshold || thirst < criticalThreshold) {
regen *= hungerThirstPenalty;
}
// Low fatigue reduces stamina regeneration
if (fatigue < criticalThreshold) {
regen *= fatiguePenalty;
}
stamina = Math.min(maxStamina, stamina + (int) regen);
staminaLevels.put(playerId, stamina);
// Warning when stamina is too low to sprint
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);
@@ -85,7 +92,7 @@ public class StaminaManager implements Listener {
}
}
}
}.runTaskTimer(plugin, 0L, 20L * 60); // Alle 60 Sekunden
}.runTaskTimer(plugin, 0L, 20L * 60); // Every 60 seconds
}
@EventHandler
@@ -93,17 +100,22 @@ public class StaminaManager implements Listener {
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);
if (event.isSprinting()) {
// Prevent sprinting if stamina is too low
if (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 {
// Drain stamina when sprinting
stamina = Math.max(0, stamina - (int) (decreaseRate * sprintMultiplier));
staminaLevels.put(playerId, stamina);
applyVulnerabilityIncrease(playerId);
}
} else if (event.isSprinting()) {
stamina = Math.max(0, stamina - (int) (decreaseRate * sprintMultiplier));
staminaLevels.put(playerId, stamina);
applyVulnerabilityIncrease(playerId);
}
}
@@ -112,19 +124,25 @@ public class StaminaManager implements Listener {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
int stamina = staminaLevels.getOrDefault(playerId, maxStamina);
// Jumping drains stamina
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) {
}
// Climbing at high altitudes drains stamina faster
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);
@@ -136,12 +154,16 @@ public class StaminaManager implements Listener {
@EventHandler
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if (event.getEntity() instanceof Player) {
Player player = (Player) event.getEntity();
// When player attacks (is the damager)
if (event.getDamager() instanceof Player) {
Player player = (Player) event.getDamager();
UUID playerId = player.getUniqueId();
int stamina = staminaLevels.getOrDefault(playerId, maxStamina);
// Combat drains stamina
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);

View File

@@ -63,7 +63,7 @@ public class TemperatureManager implements Listener {
public void run() {
for (Player player : plugin.getServer().getOnlinePlayers()) {
UUID playerId = player.getUniqueId();
int temperature = temperatureLevels.getOrDefault(playerId, maxTemperature);
int temperature = temperatureLevels.getOrDefault(playerId, maxTemperature / 2);
int hygiene = ((SurvivalMechanics) plugin).getHygieneManager().getHygiene(playerId);
double decrease = decreaseRate;
String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase();
@@ -71,105 +71,122 @@ public class TemperatureManager implements Listener {
boolean isNight = time >= 12000 && time < 24000;
boolean isRaining = player.getWorld().hasStorm() && player.getLocation().getBlock().getLightFromSky() == 15;
// Hot biomes: Temperature increases (player overheats)
if (hotBiomes.contains(biome)) {
temperature = Math.min(maxTemperature, temperature + (int) decrease);
if (temperature <= criticalThreshold && temperature > 0) {
if (temperature >= maxTemperature - criticalThreshold) {
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)) {
}
if (temperature >= maxTemperature && 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) {
if (temperatureLevels.getOrDefault(playerId, maxTemperature / 2) >= maxTemperature) {
player.setHealth(0);
}
deathTimers.remove(playerId);
}
}.runTaskLater(plugin, 20L * deathDelay));
}
} else if (coldBiomes.contains(biome)) {
}
// Cold biomes: Temperature decreases (player freezes)
else if (coldBiomes.contains(biome)) {
decrease *= isNight ? nightColdMultiplier : 1;
temperature = Math.max(0, temperature - (int) decrease);
if (temperature <= criticalThreshold && temperature > 0) {
if (temperature <= criticalThreshold) {
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)) {
}
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) {
if (temperatureLevels.getOrDefault(playerId, maxTemperature / 2) == 0) {
player.setHealth(0);
}
deathTimers.remove(playerId);
}
}.runTaskLater(plugin, 20L * deathDelay));
}
} else if (isRaining) {
}
// Rain: Cools the player down
else if (isRaining) {
decrease *= rainMultiplier;
temperature = Math.max(0, temperature - (int) (decrease + rainCoolRate));
if (temperature <= criticalThreshold && temperature > 0) {
if (temperature <= criticalThreshold) {
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)) {
}
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) {
if (temperatureLevels.getOrDefault(playerId, maxTemperature / 2) == 0) {
player.setHealth(0);
}
deathTimers.remove(playerId);
}
}.runTaskLater(plugin, 20L * deathDelay));
}
} else {
}
// Normal biomes: Temperature normalizes to 50 (middle)
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);
}
// Cancel death timer if temperature is normalizing
if (deathTimers.containsKey(playerId)) {
deathTimers.get(playerId).cancel();
deathTimers.remove(playerId);
}
}
temperatureLevels.put(playerId, temperature);
if (temperature >= maxTemperature && canSendMessage(playerId) && !criticalMessageOnly) {
// Comfortable temperature message
if (temperature >= (maxTemperature / 2) - 10 && temperature <= (maxTemperature / 2) + 10 && 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
}.runTaskTimer(plugin, 0L, 20L * 60); // Every 60 seconds
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
int temperature = temperatureLevels.getOrDefault(playerId, maxTemperature);
int temperature = temperatureLevels.getOrDefault(playerId, maxTemperature / 2);
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)) {
if (temperature <= criticalThreshold && 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);
@@ -187,7 +204,7 @@ public class TemperatureManager implements Listener {
}
public int getTemperature(UUID playerId) {
return temperatureLevels.getOrDefault(playerId, maxTemperature);
return temperatureLevels.getOrDefault(playerId, maxTemperature / 2);
}
public void loadTemperature(UUID playerId, int temperature) {

View File

@@ -63,16 +63,21 @@ public class ThirstManager implements Listener {
String biome = player.getWorld().getBiome(player.getLocation()).getKey().getKey().toUpperCase();
boolean isRaining = player.getWorld().hasStorm() && player.getLocation().getBlock().getLightFromSky() == 15;
// Hot biomes increase thirst decrease
if (hotBiomes.contains(biome)) {
decrease *= hotBiomeMultiplier;
}
// Rain restores thirst
if (isRaining) {
thirst = Math.min(maxThirst, thirst + rainRegenRate);
} else {
thirst = Math.max(0, thirst - (int) decrease);
}
thirstLevels.put(playerId, thirst);
// Critical thirst (dehydrated)
if (thirst <= criticalThreshold && thirst > 0) {
player.damage(damage);
if (canSendMessage(playerId)) {
@@ -80,7 +85,9 @@ public class ThirstManager implements Listener {
player.getWorld().playSound(player.getLocation(), "entity.player.hurt", 1.0f, 1.0f);
setLastMessageTime(playerId);
}
} else if (thirst == 0 && deathEnabled && !deathTimers.containsKey(playerId)) {
}
// Zero thirst - death warning
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() {
@@ -92,30 +99,39 @@ public class ThirstManager implements Listener {
deathTimers.remove(playerId);
}
}.runTaskLater(plugin, 20L * deathDelay));
} else if (thirst >= maxThirst && canSendMessage(playerId) && !criticalMessageOnly) {
}
// Full thirst (hydrated)
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
}.runTaskTimer(plugin, 0L, 20L * 60); // Every 60 seconds
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
// Drinking water bottle restores thirst
if (event.hasItem() && event.getItem().getType() == Material.POTION) {
int thirst = thirstLevels.getOrDefault(playerId, maxThirst);
thirst = Math.min(maxThirst, thirst + waterRegenRate);
thirstLevels.put(playerId, thirst);
// Remove one item
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);
}
// Cancel death timer if active
if (deathTimers.containsKey(playerId)) {
deathTimers.get(playerId).cancel();
deathTimers.remove(playerId);

View File

@@ -62,51 +62,68 @@ public class VulnerabilityManager implements Listener {
int hunger = ((SurvivalMechanics) plugin).getHungerManager().getHunger(playerId);
int thirst = ((SurvivalMechanics) plugin).getThirstManager().getThirst(playerId);
double recovery = recoveryRate;
// Low hunger or thirst increases vulnerability
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 {
// Normal recovery when well-fed and hydrated
vulnerability = Math.max(0, vulnerability - (int) recovery);
}
vulnerabilityLevels.put(playerId, vulnerability);
// Critical vulnerability (very injured/weak)
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) {
}
// Fully healed
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
}.runTaskTimer(plugin, 0L, 20L * 60); // Every 60 seconds
}
@EventHandler
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
// When player takes damage
if (event.getEntity() instanceof Player) {
Player player = (Player) event.getEntity();
UUID playerId = player.getUniqueId();
int vulnerability = vulnerabilityLevels.getOrDefault(playerId, 0);
// Taking damage increases vulnerability
vulnerability = Math.min(maxVulnerability, vulnerability + (int) increaseRate);
vulnerabilityLevels.put(playerId, vulnerability);
if (vulnerability >= criticalThreshold) {
event.setDamage(event.getDamage() * criticalHitMultiplier);
}
// Heavy armor increases vulnerability gain (mobility penalty)
for (ItemStack armor : player.getInventory().getArmorContents()) {
if (armor != null && (armor.getType().toString().contains("DIAMOND") || armor.getType().toString().contains("NETHERITE"))) {
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);
break; // Only apply once
}
}
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);
vulnerabilityLevels.put(playerId, vulnerability);
// Critical vulnerability increases damage taken
if (vulnerability >= criticalThreshold) {
event.setDamage(event.getDamage() * criticalHitMultiplier);
if (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);
}
}
}
}
@@ -115,10 +132,13 @@ public class VulnerabilityManager implements Listener {
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
UUID playerId = player.getUniqueId();
// Food helps recovery
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);

View File

@@ -1,174 +1,323 @@
# Konfiguration für Hunger
# ============================================================================
# SURVIVAL MECHANICS CONFIG
# ============================================================================
# Plugin Version: 1.1
# Alle Werte sind sorgfältig getestet und kompatibel mit dem korrigierten Code
# ============================================================================
# ============================================================================
# WICHTIGE HINWEISE
# ============================================================================
# • Alle Stats aktualisieren sich alle 60 Sekunden (fest im Code)
# • decrement-interval Werte werden derzeit IGNORIERT
# • Werte von 0-100 (außer anders angegeben)
# ============================================================================
# ============================================================================
# HUNGER SYSTEM
# ============================================================================
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).
# === Grundwerte ===
max: 100 # Maximum (100 = komplett satt)
initial: 80 # Startwert für neue Spieler
# Konfiguration für Durst
# === Abnahme ===
decrease-rate: 0.5 # Basis-Abnahme pro 60 Sekunden
sprint-multiplier: 1.5 # Multiplikator beim Sprinten (1.5x schneller)
combat-multiplier: 2 # Multiplikator im Kampf (2x schneller)
night-multiplier: 1.2 # Multiplikator nachts (1.2x schneller)
# === Regeneration ===
sleep-reduction: 40 # Hunger-Verlust beim Schlafen (-40)
food-recovery-rate: 34 # Hunger pro Nahrung (+34, 3 Items = voll)
food-items: # Akzeptierte Nahrungsmittel
- BREAD
- APPLE
- COOKED_BEEF
- COOKED_CHICKEN
# === Kritischer Zustand (≤20) ===
critical-threshold: 20 # Ab hier kritisch
damage: 0.5 # Schaden pro Tick wenn kritisch
# === Tod ===
death-enabled: true # Tod bei Hunger = 0 aktiviert
death-delay: 60 # Wartezeit bis Tod (Sekunden)
# === Anzeige ===
particle-effect: true # Partikel beim Essen
message-cooldown: 60 # Nachrichten alle X Sekunden
critical-message-only: true # Nur kritische Nachrichten
# ============================================================================
# DURST SYSTEM
# ============================================================================
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).
# === Grundwerte ===
max: 100 # Maximum (100 = komplett erfrischt)
initial: 80 # Startwert für neue Spieler
# Konfiguration für Müdigkeit
# === Abnahme ===
decrease-rate: 0.8 # Basis-Abnahme pro 60 Sekunden
hot-biome-multiplier: 1.5 # Multiplikator in heißen Biomen
hot-biomes: # Heiße Biome (schnellerer Durst)
- DESERT
- SAVANNA
- BADLANDS
# === Regeneration ===
sleep-reduction: 40 # Durst-Verlust beim Schlafen (-40)
rain-regen-rate: 2 # Durst im Regen pro 60s (+2)
water-regen-rate: 50 # Durst pro Wasser-Trank (+50, 2 Tränke = voll)
# === Kritischer Zustand (≤20) ===
critical-threshold: 20 # Ab hier kritisch
damage: 0.5 # Schaden pro Tick wenn kritisch
# === Tod ===
death-enabled: true # Tod bei Durst = 0 aktiviert
death-delay: 60 # Wartezeit bis Tod (Sekunden)
# === Anzeige ===
message-cooldown: 60 # Nachrichten alle X Sekunden
critical-message-only: true # Nur kritische Nachrichten
# ============================================================================
# MÜDIGKEIT SYSTEM
# ============================================================================
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).
# === Grundwerte ===
max: 100 # Maximum (100 = komplett ausgeruht)
initial: 100 # Startwert für neue Spieler
# Konfiguration für Temperatur
# === Abnahme ===
decrease-rate: 1.0 # Basis-Abnahme pro 60 Sekunden
night-multiplier: 2.0 # Multiplikator nachts (2x schneller!)
activity-multiplier: 1.0 # Multiplikator bei Sprinten/Schwimmen
# === Klettern ===
climbing-multiplier: 1.5 # Multiplikator beim Klettern
climbing-height-threshold: 100 # Ab Y=100 wirkt Klettern
climbing-height-scaling: 0.01 # Pro Block über Schwelle (+1%)
# === Effekte bei Müdigkeit ===
stamina-penalty: 1.0 # Stamina-Strafe bei kritischer Müdigkeit
slowness-duration: 200 # Langsamkeit-Dauer (10 Sekunden)
slowness-amplifier: 1 # Langsamkeit Stufe I
blur-duration: 100 # Blindheit-Dauer (5 Sekunden)
blur-amplifier: 1 # Blindheit Stufe I
# === Kritischer Zustand (≤20) ===
critical-threshold: 20 # Ab hier kritisch
# === Tod ===
death-enabled: true # Tod bei Müdigkeit = 0 aktiviert
death-delay: 60 # Wartezeit bis Tod (Sekunden)
# === Anzeige ===
message-cooldown: 60 # Nachrichten alle X Sekunden
critical-message-only: true # Nur kritische Nachrichten
# ============================================================================
# TEMPERATUR SYSTEM
# ============================================================================
# WICHTIG: max MUSS 100 sein! (Scoreboard & Tod-Logik erwarten dies)
# HINWEIS: Es gibt kein "increase-rate" - nur decrease-rate für beide Richtungen
# ============================================================================
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).
# === Grundwerte ===
max: 100 # KRITISCH: Muss 100 sein!
initial: 50 # Startwert (50 = angenehm)
# Konfiguration für Ausdauer
# === Veränderung ===
decrease-rate: 0.6 # Verwendet für BEIDE Richtungen (kalt/heiß)
# === Kalte Biome (Temperatur sinkt) ===
cold-biomes:
- SNOWY_TAIGA
- SNOWY_TUNDRA
- ICE_SPIKES
night-cold-multiplier: 1.2 # Multiplikator nachts in kalten Biomen
# === Heiße Biome (Temperatur steigt) ===
hot-biomes:
- DESERT
- SAVANNA
- BADLANDS
# === Regen (kühlt ab) ===
rain-cool-rate: 1 # Extra-Abkühlung im Regen
rain-multiplier: 1.2 # Multiplikator im Regen
# === Schaden ===
cold-damage: 0.5 # Schaden bei Temp ≤20
hot-damage: 0.5 # Schaden bei Temp ≥80
# === Kritischer Zustand ===
critical-threshold: 20 # Kalt: ≤20, Heiß: ≥80 (100-20)
# === Tod ===
death-enabled: true # Tod bei extremer Temperatur
death-delay: 60 # Wartezeit bis Tod (Sekunden)
# === Anzeige ===
message-cooldown: 60 # Nachrichten alle X Sekunden
critical-message-only: true # Nur kritische Nachrichten
# === Nicht implementiert ===
warmth-radius: 5 # (Für zukünftige Features)
# ============================================================================
# AUSDAUER SYSTEM
# ============================================================================
# WICHTIG: decrease-rate ist NICHT für passive Abnahme!
# Passiv regeneriert durch regen-rate, decrease-rate nur bei Aktionen
# ============================================================================
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).
# === Grundwerte ===
max: 100 # Maximum (100 = volle Energie)
initial: 100 # Startwert für neue Spieler
# Konfiguration für Verletztbarkeit
# === Abnahme bei Aktionen ===
decrease-rate: 0.5 # Basis-Wert (kombiniert mit Multiplikatoren)
sprint-multiplier: 0.5 # Multiplikator beim Sprinten
jump-multiplier: 1.0 # Multiplikator beim Springen
combat-multiplier: 2 # Multiplikator im Kampf (Angreifer!)
# === Klettern ===
climbing-multiplier: 1.5 # Multiplikator beim Klettern
climbing-height-threshold: 100 # Ab Y=100 wirkt Klettern
climbing-height-scaling: 0.01 # Pro Block über Schwelle (+1%)
# === Regeneration ===
regen-rate: 3 # Passive Regeneration pro 60 Sekunden
hunger-thirst-penalty: 0.5 # Regen-Strafe bei kritischem Hunger/Durst (50%)
fatigue-penalty: 0.5 # Regen-Strafe bei kritischer Müdigkeit (50%)
# === Verletzlichkeit ===
stamina-vulnerability-increase: 2 # Verletzlichkeit bei kritischer Ausdauer
# === Kritischer Zustand (≤20) ===
critical-threshold: 20 # Ab hier kritisch
min-to-sprint: 20 # Mindest-Ausdauer zum Sprinten
# === Anzeige ===
message-cooldown: 60 # Nachrichten alle X Sekunden
critical-message-only: true # Nur kritische Nachrichten
# ============================================================================
# VERLETZLICHKEIT SYSTEM
# ============================================================================
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).
# === Grundwerte ===
max: 100 # Maximum (100 = schwer verletzt)
initial: 0 # Startwert (0 = gesund)
# Konfiguration für Hygiene
# === Zunahme ===
increase-rate: 3 # Pro Treffer
hunger-exhaustion-multiplier: 1.5 # Bei kritischem Hunger/Durst
# === Schaden-Erhöhung ===
critical-hit-multiplier: 1.5 # Schaden-Multiplikator bei ≥80 Verletzlichkeit
# === Regeneration ===
recovery-rate: 3 # Passive Heilung pro 60 Sekunden
food-recovery-rate: 34 # Heilung pro Nahrung (-34, 3 Items = gesund)
# === Effekte ===
weakness-duration: 200 # Schwäche-Dauer (10 Sekunden)
weakness-amplifier: 1 # Schwäche Stufe I
# === Kritischer Zustand (≥80) ===
critical-threshold: 80 # Ab hier kritisch
# === Anzeige ===
message-cooldown: 60 # Nachrichten alle X Sekunden
critical-message-only: true # Nur kritische Nachrichten
# ============================================================================
# HYGIENE SYSTEM
# ============================================================================
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).
# === Grundwerte ===
max: 100 # Maximum (100 = sauber)
initial: 80 # Startwert für neue Spieler
# Konfiguration für die ActionBar-Anzeige
# === Abnahme ===
decrease-rate: 0.5 # Basis-Abnahme pro 60 Sekunden
digging-multiplier: 2 # Multiplikator beim Graben (Dirt/Grass)
# === Schmutzige Biome ===
dirty-biomes:
- SWAMP
- MANGROVE_SWAMP
# === Klettern ===
climbing-multiplier: 1.5 # Multiplikator beim Klettern
climbing-height-threshold: 100 # Ab Y=100 wirkt Klettern
climbing-height-scaling: 0.01 # Pro Block über Schwelle (+1%)
# === Verletzlichkeit ===
vulnerability-exhaustion-multiplier: 2 # Bei Verletzlichkeit ≥80
# === Regeneration ===
water-recovery-rate: 6 # Heilung pro Move-Event in Wasser
# === Effekte ===
weakness-duration: 200 # Schwäche-Dauer (10 Sekunden)
weakness-amplifier: 1 # Schwäche Stufe I
# === Kritischer Zustand (≤20) ===
critical-threshold: 20 # Ab hier kritisch
# === Tod ===
death-enabled: true # Tod bei Hygiene = 0 (Infektion)
death-delay: 60 # Wartezeit bis Tod (Sekunden)
# === Anzeige ===
message-cooldown: 60 # Nachrichten alle X Sekunden
critical-message-only: true # Nur kritische Nachrichten
# ============================================================================
# SCOREBOARD 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.
# === Balken ===
bar-length: 5 # Länge (5 = █████)
bar-filled: "" # Gefülltes Zeichen
bar-empty: "▒" # Leeres Zeichen
# === Update ===
update-interval: 100 # Ticks (100 = 5 Sekunden)
# === Farben (Minecraft Farbcodes) ===
hunger-color: 6" # Gold
thirst-color: b" # Aqua
fatigue-color: 7" # Grau
temperature-color: c" # Rot
stamina-color: "§a" # Grün
vulnerability-color: "§4" # Dunkelrot
hygiene-color: "§9" # Blau
# === Status-Schwellenwerte ===
mild-threshold: 60 # "Mild" Status bei ≤60
critical-threshold: 20 # "Kritisch" bei ≤20
# ============================================================================
# ZUSÄTZLICHE OPTIONEN
# ============================================================================
reset-on-death: true # Stats beim Tod zurücksetzen
# ============================================================================
# ENDE DER KONFIGURATION
# ============================================================================

View File

@@ -1,5 +1,5 @@
name: SurvivalMechanics
main: me.viper.survivalmechanics.SurvivalMechanics
version: 1.0-SNAPSHOT
version: 1.1
api-version: 1.21
author: M_Viper