diff --git a/README.md b/README.md index 8a6a603..8a2b4c0 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ SupremeCore currently includes modular systems for: - `/landmarks` — list discovered landmarks / journal-related actions - `/vampire ` — manage vampirism state - `/realestate ` (`/re`) — list for-sale Towny plots and view one +- `/morality ` (`/moral`) — check alignment and manage morality --- @@ -57,6 +58,7 @@ SupremeCore currently includes modular systems for: - `landmarks.nearest` - `realestate.list` - `realestate.view` +- `morality.admin` --- diff --git a/src/main/java/net/supremesurvival/supremecore/SupremeCore.java b/src/main/java/net/supremesurvival/supremecore/SupremeCore.java index e0f6fb3..4c4a439 100644 --- a/src/main/java/net/supremesurvival/supremecore/SupremeCore.java +++ b/src/main/java/net/supremesurvival/supremecore/SupremeCore.java @@ -10,6 +10,7 @@ import net.supremesurvival.supremecore.landmarks.LandmarkManager; import net.supremesurvival.supremecore.landmarks.PlayerListeners; import net.supremesurvival.supremecore.morality.Morality; +import net.supremesurvival.supremecore.morality.MoralityCommand; import net.supremesurvival.supremecore.commonUtils.placeholder.SupremePlaceholder; import net.supremesurvival.supremecore.tomes.TomeManager; import net.supremesurvival.supremecore.tomes.TomesCommand; @@ -49,6 +50,8 @@ public void onEnable() { this.getCommand("Landmarks").setExecutor(new LandmarkCommand()); this.getCommand("Vampire").setExecutor(vampire); this.getCommand("RealEstate").setExecutor(new RealEstateCommand()); + this.getCommand("Morality").setExecutor(new MoralityCommand()); + this.getCommand("Morality").setTabCompleter(new MoralityCommand()); Morality.enable(); this.getServer().getPluginManager().registerEvents(new Morality(), this); this.getServer().getPluginManager().registerEvents(vampire, this); diff --git a/src/main/java/net/supremesurvival/supremecore/morality/Morality.java b/src/main/java/net/supremesurvival/supremecore/morality/Morality.java index 3e08724..2505435 100644 --- a/src/main/java/net/supremesurvival/supremecore/morality/Morality.java +++ b/src/main/java/net/supremesurvival/supremecore/morality/Morality.java @@ -1,11 +1,11 @@ package net.supremesurvival.supremecore.morality; -import com.palmergames.bukkit.towny.event.player.PlayerKilledPlayerEvent; -import net.supremesurvival.supremecore.commonUtils.fileHandler.ConfigUtility; import net.supremesurvival.supremecore.commonUtils.Logger; +import net.supremesurvival.supremecore.commonUtils.fileHandler.ConfigUtility; import net.supremesurvival.supremecore.commonUtils.fileHandler.FileHandler; -import net.supremesurvival.supremecore.morality.player.MoralPlayer; import net.supremesurvival.supremecore.commonUtils.placeholder.SupremePlaceholder; +import net.supremesurvival.supremecore.morality.player.MoralPlayer; +import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Entity; @@ -14,163 +14,336 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.raid.RaidFinishEvent; import org.bukkit.event.raid.RaidTriggerEvent; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; +import java.time.Instant; import java.util.*; -//Working - could do with cleaning up. public class Morality implements Listener { + private static final String HANDLE = "Morality"; + + private static final Map moralPlayers = new HashMap<>(); + private static final NavigableMap boundsMap = new TreeMap<>(); + private static final Map actionWeights = new HashMap<>(); + private static FileConfiguration moralityConfig; - private static HashMap moralManagerList; - private static final Map boundsMap = new LinkedHashMap<>(); private static File dataFile; - final static String handle = "Morality"; - public static void enable(){ + + private static int minMorality = -16000; + private static int maxMorality = 16000; + private static boolean decayEnabled = true; + private static int decayPointsPerDay = 25; + + public static void enable() { SupremePlaceholder.register(); moralityConfig = ConfigUtility.getModuleConfig("Morality"); - ConfigurationSection moralityBounds = moralityConfig.getConfigurationSection("moralitybounds"); - for (String key : moralityBounds.getKeys(false)) { - int value = moralityBounds.getInt(key); - boundsMap.put(key.toUpperCase(), value); - } - moralManagerList = new HashMap(); + + loadBounds(); + loadSettings(); + loadActionWeights(); + + moralPlayers.clear(); dataFile = FileHandler.getDataFile("/Morality/playerdata.txt"); - HashMap allData = new HashMap(); + loadData(); + + Logger.sendMessage("Morality enabled. Loaded " + moralPlayers.size() + " player records.", Logger.LogType.INFO, HANDLE); + } + + public static void disable() { + saveData(); + } + + public static void reload() { + saveData(); + enable(); + } + + private static void loadBounds() { + boundsMap.clear(); + + ConfigurationSection section = moralityConfig.getConfigurationSection("bounds"); + if (section == null) { + section = moralityConfig.getConfigurationSection("moralitybounds"); // Backward compat } - //currently overwrites whole file with online users. Need to correct this. Seems that reading back the whole file and overwriting the lines where uuid is contained in moralmanagerlist is the way to go. That or switch to json. - public static void disable(){ - HashMap allData = new HashMap(); - allData = FileHandler.loadAllMoralityData(dataFile, allData); - assert allData != null; - if(allData.isEmpty()){ + if (section == null) { + Logger.sendMessage("No morality bounds found in config. Falling back to NEUTRAL(0).", Logger.LogType.WARN, HANDLE); + boundsMap.put(0, "NEUTRAL"); return; } - for(UUID uuid : moralManagerList.keySet()){ - if(allData.containsKey(uuid)){ - allData.replace(uuid, moralManagerList.get(uuid)); - }else{allData.put(uuid, moralManagerList.get(uuid));} + + for (String key : section.getKeys(false)) { + int threshold = section.getInt(key); + boundsMap.put(threshold, key.toUpperCase(Locale.ROOT)); } - try (BufferedWriter writer = new BufferedWriter(new FileWriter(dataFile))){ - for (Map.Entry entry : allData.entrySet()){ - UUID playerID = entry.getKey(); - int morality = entry.getValue().getMorality(); - writer.write(playerID.toString() + ":" + morality); - writer.write("\n"); - Logger.sendMessage("Wrote playerdata for " + playerID + ": Morality = " + morality, Logger.LogType.INFO, handle); + + if (boundsMap.isEmpty()) { + boundsMap.put(0, "NEUTRAL"); } } - catch ( - IOException e) { - Logger.sendMessage(e.toString(), Logger.LogType.ERR, handle); - }} - @EventHandler - public void HeroEvent(RaidFinishEvent event){ - List players = event.getWinners(); - Iterator playersIterator = players.iterator(); - Logger.sendMessage("Raid Finished", Logger.LogType.INFO,handle); - while(playersIterator.hasNext()){ - Player player = playersIterator.next(); - Logger.sendMessage(player.getName() + "Participated in raid", Logger.LogType.INFO, handle); - MoralPlayer moralPlayer = moralManagerList.get(player.getUniqueId()); - moralPlayer.addMorality(1000); - moralityCheck(moralPlayer); + + private static void loadSettings() { + minMorality = moralityConfig.getInt("morality.min", -16000); + maxMorality = moralityConfig.getInt("morality.max", 16000); + + decayEnabled = moralityConfig.getBoolean("morality.decay.enabled", true); + decayPointsPerDay = moralityConfig.getInt("morality.decay.points-per-day", 25); + } + + private static void loadActionWeights() { + actionWeights.clear(); + + ConfigurationSection section = moralityConfig.getConfigurationSection("actions"); + if (section == null) { + actionWeights.put("raid-win", 1000); + actionWeights.put("raid-trigger", -250); + actionWeights.put("villager-kill", -50); + actionWeights.put("kill-good-player", -150); + actionWeights.put("kill-evil-player", 150); + return; + } + + for (String key : section.getKeys(false)) { + actionWeights.put(key.toLowerCase(Locale.ROOT), section.getInt(key)); + } + } + + private static void loadData() { + if (dataFile == null || !dataFile.exists()) { + return; + } + + try (BufferedReader reader = new BufferedReader(new FileReader(dataFile))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.isBlank()) continue; + + // Supported formats: + // uuid:morality + // uuid:morality:lastUpdatedEpochSeconds + String[] parts = line.split(":"); + if (parts.length < 2) continue; + + UUID uuid; + try { + uuid = UUID.fromString(parts[0]); + } catch (IllegalArgumentException ignored) { + continue; + } + + int morality; + try { + morality = Integer.parseInt(parts[1]); + } catch (NumberFormatException ignored) { + morality = 0; + } + + long lastUpdated = Instant.now().getEpochSecond(); + if (parts.length >= 3) { + try { + lastUpdated = Long.parseLong(parts[2]); + } catch (NumberFormatException ignored) { + // Keep now + } + } + + morality = clamp(morality); + String standing = resolveStanding(morality); + moralPlayers.put(uuid, new MoralPlayer(uuid, morality, standing, lastUpdated)); + } + } catch (IOException e) { + Logger.sendMessage("Failed to load morality data: " + e.getMessage(), Logger.LogType.ERR, HANDLE); + } + } + + private static void saveData() { + if (dataFile == null) return; + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(dataFile))) { + for (MoralPlayer moralPlayer : moralPlayers.values()) { + writer.write(moralPlayer.getUuid().toString()); + writer.write(":"); + writer.write(String.valueOf(moralPlayer.getMorality())); + writer.write(":"); + writer.write(String.valueOf(moralPlayer.getLastUpdatedEpochSeconds())); + writer.newLine(); + } + } catch (IOException e) { + Logger.sendMessage("Failed to save morality data: " + e.getMessage(), Logger.LogType.ERR, HANDLE); } } @EventHandler - public void BadOmenEvent(RaidTriggerEvent event){ + public void onJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - Logger.sendMessage("Raid started by " + player.getName(), Logger.LogType.INFO, handle); - MoralPlayer moralPlayer = moralManagerList.get(player.getUniqueId()); - moralPlayer.reduceMorality(250); - moralityCheck(moralPlayer); + MoralPlayer moralPlayer = getOrCreate(player.getUniqueId()); + applyDecay(moralPlayer); + updateStanding(moralPlayer, false); } @EventHandler - public void mobDeath(EntityDeathEvent event){ - Entity entity = event.getEntity(); - if(entity instanceof Villager){ - if(((Villager) entity).getKiller() != null){ - Player player = ((Villager) entity).getKiller(); - MoralPlayer moralPlayer = moralManagerList.get(player.getUniqueId()); - moralPlayer.reduceMorality(50); - moralityCheck(moralPlayer); - } + public void onRaidFinish(RaidFinishEvent event) { + int amount = actionWeights.getOrDefault("raid-win", 0); + for (Player winner : event.getWinners()) { + adjustMorality(winner.getUniqueId(), amount, "Raid victory", true); } } + @EventHandler - public void playerKill(PlayerKilledPlayerEvent event){ - Player killer = event.getKiller(); - Player victim = event.getVictim(); - MoralPlayer moralVictim = moralManagerList.get(victim.getUniqueId()); - MoralPlayer moralKiller = moralManagerList.get(killer.getUniqueId()); - if(moralVictim.getMorality()< -250){ - moralKiller.addMorality(150); - - }else if(moralVictim.getMorality()> 250){ - moralKiller.reduceMorality(150); - } + public void onRaidTrigger(RaidTriggerEvent event) { + int amount = actionWeights.getOrDefault("raid-trigger", 0); + adjustMorality(event.getPlayer().getUniqueId(), amount, "Triggered a raid", true); } @EventHandler - public void join(PlayerJoinEvent event){ - Player player = event.getPlayer(); - if(!player.hasPlayedBefore()){ - //addplayer data with 0 values to wherever it ends up stored also - moralManagerList.put(player.getUniqueId(),new MoralPlayer(player.getUniqueId(), 0)); - return; + public void onVillagerDeath(EntityDeathEvent event) { + Entity entity = event.getEntity(); + if (!(entity instanceof Villager villager)) return; + + Player killer = villager.getKiller(); + if (killer == null) return; + + int amount = actionWeights.getOrDefault("villager-kill", 0); + adjustMorality(killer.getUniqueId(), amount, "Killed a villager", true); + } + + @EventHandler + public void onPlayerKill(PlayerDeathEvent event) { + Player victim = event.getEntity(); + Player killer = victim.getKiller(); + if (killer == null) return; + + MoralPlayer victimData = getOrCreate(victim.getUniqueId()); + String victimStanding = victimData.getStanding(); + + int delta; + if (isEvilStanding(victimStanding)) { + delta = actionWeights.getOrDefault("kill-evil-player", 0); + } else { + delta = actionWeights.getOrDefault("kill-good-player", 0); } - if(moralManagerList.containsKey(player.getUniqueId())){ - //test - moralityCheck(moralManagerList.get(player.getUniqueId())); - return; + + adjustMorality(killer.getUniqueId(), delta, "Killed " + victim.getName(), true); + } + + private static boolean isEvilStanding(String standing) { + return standing.equalsIgnoreCase("CHAOTIC") + || standing.equalsIgnoreCase("CORRUPT") + || standing.equalsIgnoreCase("DISHONOURABLE") + || standing.equalsIgnoreCase("INFAMOUS") + || standing.equalsIgnoreCase("RUTHLESS") + || standing.equalsIgnoreCase("VILLAINOUS") + || standing.equalsIgnoreCase("MALEVOLENT") + || standing.equalsIgnoreCase("WRETCHED") + || standing.equalsIgnoreCase("DIABOLICAL") + || standing.equalsIgnoreCase("DEMONIC"); + } + + public static void adjustMorality(UUID uuid, int delta, String reason, boolean notifyPlayer) { + MoralPlayer moralPlayer = getOrCreate(uuid); + applyDecay(moralPlayer); + + int before = moralPlayer.getMorality(); + int after = clamp(before + delta); + moralPlayer.setMorality(after); + moralPlayer.setLastUpdatedEpochSeconds(Instant.now().getEpochSecond()); + + String previousStanding = moralPlayer.getStanding(); + updateStanding(moralPlayer, notifyPlayer); + + Player player = Bukkit.getPlayer(uuid); + if (notifyPlayer && player != null && player.isOnline() && delta != 0) { + String sign = delta > 0 ? "+" : ""; + player.sendMessage("§7[§6Morality§7] " + reason + " §8(§f" + sign + delta + "§8) §7=> §f" + after); + if (!previousStanding.equalsIgnoreCase(moralPlayer.getStanding())) { + player.sendMessage("§7[§6Morality§7] Alignment changed: §f" + pretty(previousStanding) + " §7-> §f" + pretty(moralPlayer.getStanding())); + } } - //load player data from wherever it is stored - HashMap moralManagerListTMP = FileHandler.loadMoralityData(event.getPlayer().getUniqueId(), moralManagerList, dataFile); - if (moralManagerListTMP == null){ - Logger.sendMessage("Player data for " + player.getName() + " not found, inserting default value", Logger.LogType.INFO, handle); - moralManagerList.put(player.getUniqueId(),new MoralPlayer(player.getUniqueId(),0)); - moralityCheck(moralManagerList.get(player.getUniqueId())); - return; + } + + private static void applyDecay(MoralPlayer moralPlayer) { + if (!decayEnabled || decayPointsPerDay <= 0) return; + + long now = Instant.now().getEpochSecond(); + long elapsedSeconds = now - moralPlayer.getLastUpdatedEpochSeconds(); + if (elapsedSeconds < 86400) return; + + long days = elapsedSeconds / 86400; + int decayAmount = (int) (days * decayPointsPerDay); + + int morality = moralPlayer.getMorality(); + if (morality > 0) { + morality = Math.max(0, morality - decayAmount); + } else if (morality < 0) { + morality = Math.min(0, morality + decayAmount); } - moralManagerList = moralManagerListTMP; - //test - moralityCheck(moralManagerList.get(player.getUniqueId())); + + moralPlayer.setMorality(clamp(morality)); + moralPlayer.setLastUpdatedEpochSeconds(now); + } + + public static MoralPlayer getOrCreate(UUID uuid) { + MoralPlayer moralPlayer = moralPlayers.get(uuid); + if (moralPlayer != null) return moralPlayer; + + moralPlayer = new MoralPlayer(uuid, 0, resolveStanding(0), Instant.now().getEpochSecond()); + moralPlayers.put(uuid, moralPlayer); + return moralPlayer; + } + + private static void updateStanding(MoralPlayer moralPlayer, boolean notifyPlayer) { + String previous = moralPlayer.getStanding(); + String resolved = resolveStanding(moralPlayer.getMorality()); + moralPlayer.setStanding(resolved); + + if (!notifyPlayer || previous.equalsIgnoreCase(resolved)) return; + + Player player = Bukkit.getPlayer(moralPlayer.getUuid()); + if (player != null && player.isOnline()) { + player.sendMessage("§7[§6Morality§7] You are now considered §f" + pretty(resolved)); } + } - //This class will check the players morality value against the configured morality bounds - public static void moralityCheck(MoralPlayer player){ - Player bukkitPlayer = player.getPlayer(); - String moralStanding = ""; - int morality = player.getMorality(); - for (Map.Entry entry : boundsMap.entrySet()) { - if (morality < 0){ - if(entry.getValue() > 0){continue;} - if(morality < entry.getValue()){moralStanding = entry.getKey(); - continue;} - if(morality > entry.getValue()){ - player.updateMoralStanding(MoralPlayer.MoralStanding.valueOf(moralStanding)); - break;} - } - if (morality >= entry.getValue()) { - moralStanding = entry.getKey(); - player.updateMoralStanding(MoralPlayer.MoralStanding.valueOf(moralStanding)); - break; - } + private static String resolveStanding(int morality) { + Map.Entry entry = boundsMap.floorEntry(morality); + if (entry == null) { + return boundsMap.firstEntry().getValue(); } - bukkitPlayer.sendMessage("Your morality is " + player.getMorality() + ":" + player.getStanding()); + return entry.getValue(); + } + + private static int clamp(int morality) { + return Math.max(minMorality, Math.min(maxMorality, morality)); } - public static String getMoralStanding(Player player){ - return moralManagerList.get(player.getUniqueId()).getStanding().toString(); + + private static String pretty(String raw) { + String lower = raw.toLowerCase(Locale.ROOT); + return lower.substring(0, 1).toUpperCase(Locale.ROOT) + lower.substring(1); + } + + public static String getMoralStanding(Player player) { + if (player == null) return "NEUTRAL"; + MoralPlayer data = getOrCreate(player.getUniqueId()); + applyDecay(data); + updateStanding(data, false); + return data.getStanding(); } - public static int getMorality(Player player){ - return moralManagerList.get(player.getUniqueId()).getMorality(); + + public static int getMorality(Player player) { + if (player == null) return 0; + MoralPlayer data = getOrCreate(player.getUniqueId()); + applyDecay(data); + return data.getMorality(); + } + + public static List top(int limit) { + List values = new ArrayList<>(moralPlayers.values()); + values.sort(Comparator.comparingInt(MoralPlayer::getMorality).reversed()); + if (values.size() <= limit) return values; + return values.subList(0, limit); } } diff --git a/src/main/java/net/supremesurvival/supremecore/morality/MoralityCommand.java b/src/main/java/net/supremesurvival/supremecore/morality/MoralityCommand.java new file mode 100644 index 0000000..8abb95a --- /dev/null +++ b/src/main/java/net/supremesurvival/supremecore/morality/MoralityCommand.java @@ -0,0 +1,137 @@ +package net.supremesurvival.supremecore.morality; + +import net.supremesurvival.supremecore.morality.player.MoralPlayer; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class MoralityCommand implements CommandExecutor, TabCompleter { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 0 || args[0].equalsIgnoreCase("status")) { + if (!(sender instanceof Player player)) { + sender.sendMessage("Usage: /morality status "); + return true; + } + + Player target = player; + if (args.length >= 2 && sender.hasPermission("morality.admin")) { + Player parsed = Bukkit.getPlayerExact(args[1]); + if (parsed != null) target = parsed; + } + + sender.sendMessage("§7[§6Morality§7] §f" + target.getName() + " §7=> §f" + + Morality.getMorality(target) + " §8(§f" + Morality.getMoralStanding(target) + "§8)"); + return true; + } + + if (args[0].equalsIgnoreCase("top")) { + int limit = 10; + if (args.length >= 2) { + try { + limit = Math.max(1, Math.min(25, Integer.parseInt(args[1]))); + } catch (NumberFormatException ignored) { + } + } + + List top = Morality.top(limit); + sender.sendMessage("§7[§6Morality§7] §fTop " + top.size() + " players:"); + int i = 1; + for (MoralPlayer moralPlayer : top) { + String name = Bukkit.getOfflinePlayer(moralPlayer.getUuid()).getName(); + if (name == null) name = moralPlayer.getUuid().toString(); + sender.sendMessage("§8" + i + ". §f" + name + " §7- §f" + moralPlayer.getMorality() + + " §8(§f" + moralPlayer.getStanding() + "§8)"); + i++; + } + return true; + } + + if (args[0].equalsIgnoreCase("reload")) { + if (!sender.hasPermission("morality.admin")) { + sender.sendMessage("§cYou do not have permission."); + return true; + } + Morality.reload(); + sender.sendMessage("§7[§6Morality§7] Reloaded morality config and data."); + return true; + } + + if (args[0].equalsIgnoreCase("add") || args[0].equalsIgnoreCase("set")) { + if (!sender.hasPermission("morality.admin")) { + sender.sendMessage("§cYou do not have permission."); + return true; + } + + if (args.length < 3) { + sender.sendMessage("Usage: /morality " + args[0] + " "); + return true; + } + + Player target = Bukkit.getPlayerExact(args[1]); + if (target == null) { + sender.sendMessage("§cPlayer not found online."); + return true; + } + + int amount; + try { + amount = Integer.parseInt(args[2]); + } catch (NumberFormatException ex) { + sender.sendMessage("§cAmount must be a number."); + return true; + } + + if (args[0].equalsIgnoreCase("set")) { + int current = Morality.getMorality(target); + Morality.adjustMorality(target.getUniqueId(), amount - current, "Admin set", true); + } else { + Morality.adjustMorality(target.getUniqueId(), amount, "Admin adjustment", true); + } + + sender.sendMessage("§7[§6Morality§7] Updated §f" + target.getName() + "§7."); + return true; + } + + sender.sendMessage("§7Usage: /morality "); + return true; + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + List completions = new ArrayList<>(); + + if (args.length == 1) { + completions.add("status"); + completions.add("top"); + if (sender.hasPermission("morality.admin")) { + completions.add("add"); + completions.add("set"); + completions.add("reload"); + } + return filter(completions, args[0]); + } + + if (args.length == 2 && (args[0].equalsIgnoreCase("status") || args[0].equalsIgnoreCase("add") || args[0].equalsIgnoreCase("set"))) { + for (Player p : Bukkit.getOnlinePlayers()) { + completions.add(p.getName()); + } + return filter(completions, args[1]); + } + + return completions; + } + + private List filter(List options, String query) { + String lower = query.toLowerCase(Locale.ROOT); + return options.stream().filter(s -> s.toLowerCase(Locale.ROOT).startsWith(lower)).toList(); + } +} diff --git a/src/main/java/net/supremesurvival/supremecore/morality/player/MoralPlayer.java b/src/main/java/net/supremesurvival/supremecore/morality/player/MoralPlayer.java index e8edc97..32a413d 100644 --- a/src/main/java/net/supremesurvival/supremecore/morality/player/MoralPlayer.java +++ b/src/main/java/net/supremesurvival/supremecore/morality/player/MoralPlayer.java @@ -1,69 +1,50 @@ package net.supremesurvival.supremecore.morality.player; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - import java.util.UUID; public class MoralPlayer { - final UUID uuid; - Integer morality; - MoralStanding moralStanding; + private final UUID uuid; + private int morality; + private String standing; + private long lastUpdatedEpochSeconds; - public MoralPlayer(UUID uuid, int morality){ + public MoralPlayer(UUID uuid, int morality, String standing, long lastUpdatedEpochSeconds) { this.uuid = uuid; this.morality = morality; + this.standing = standing; + this.lastUpdatedEpochSeconds = lastUpdatedEpochSeconds; + } + // Backward-compatible constructor used by legacy file handlers. + public MoralPlayer(UUID uuid, int morality) { + this(uuid, morality, "NEUTRAL", System.currentTimeMillis() / 1000L); } - public Player getPlayer(){ - return Bukkit.getPlayer(this.uuid); + + public UUID getUuid() { + return uuid; } - public int getMorality(){ - return this.morality; + + public int getMorality() { + return morality; } - public void setMorality(Integer morality){ + public void setMorality(int morality) { this.morality = morality; } - public void addMorality(Integer morality){ - this.morality = this.morality + morality; + public String getStanding() { + return standing; } - public void reduceMorality(Integer morality){ - this.morality = this.morality -morality; - } - public MoralStanding getStanding(){ - return moralStanding; + public void setStanding(String standing) { + this.standing = standing; } - public void updateMoralStanding(MoralStanding standing){ - this.moralStanding = standing; + public long getLastUpdatedEpochSeconds() { + return lastUpdatedEpochSeconds; } - public enum MoralStanding{ - DIVINE, - SAINT, - PURE, - HEROIC, - RIGHTEOUS, - VIRTUOUS, - NOBLE, - HONOURABLE, - LAWFUL, - RESPECTABLE, - NEUTRAL, - CHAOTIC, - CORRUPT, - DISHONOURABLE, - INFAMOUS, - RUTHLESS, - VILLAINOUS, - MALEVOLENT, - WRETCHED, - DIABOLICAL, - DEMONIC + public void setLastUpdatedEpochSeconds(long lastUpdatedEpochSeconds) { + this.lastUpdatedEpochSeconds = lastUpdatedEpochSeconds; } - } - diff --git a/src/main/resources/Morality/config.yml b/src/main/resources/Morality/config.yml index fd07952..a52670f 100644 --- a/src/main/resources/Morality/config.yml +++ b/src/main/resources/Morality/config.yml @@ -1,4 +1,20 @@ -moralitybounds: +morality: + min: -20000 + max: 20000 + decay: + enabled: true + points-per-day: 30 + +actions: + raid-win: 800 + raid-trigger: -180 + villager-kill: -120 + kill-good-player: -180 + kill-evil-player: 140 + +# Highest threshold <= player morality becomes their current standing. +# Keep this sorted highest-to-lowest for readability. +bounds: DIVINE: 16000 SAINT: 10000 PURE: 6000 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 2bc423b..3f7f338 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -46,6 +46,9 @@ permissions: realestate.bypasscooldown: description: bypass /realestate view cooldown checks default: op + morality.admin: + description: administer morality values and reload settings + default: op commands: HorseInfo: description: Your description @@ -69,3 +72,7 @@ commands: description: list and view Towny plots for sale usage: /realestate aliases: [re] + Morality: + description: view and manage morality alignment + usage: /morality + aliases: [moral]