diff --git a/Changelog.txt b/Changelog.txt index 51446e190..afc9384f4 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -8,6 +8,7 @@ Key: - Removal Version 1.4.06-dev + + Added health display for mobs during combat. + Added new API method to McMMOPlayerLevelUpEvent to set levels gained + Added new permission node for /ptp; mcmmo.commands.ptp.send (enabled by default) = Fixed displaying partial names when trying to use /ptp diff --git a/src/main/java/com/gmail/nossr50/commands/MobhealthCommand.java b/src/main/java/com/gmail/nossr50/commands/MobhealthCommand.java new file mode 100644 index 000000000..d6313d3ad --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/MobhealthCommand.java @@ -0,0 +1,39 @@ +package com.gmail.nossr50.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +import com.gmail.nossr50.datatypes.MobHealthbarType; +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.util.commands.CommandUtils; +import com.gmail.nossr50.util.player.UserManager; + +public class MobhealthCommand implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (CommandUtils.noConsoleUsage(sender)) { + return true; + } + + switch (args.length) { + case 1: + PlayerProfile playerProfile = UserManager.getPlayer(sender.getName()).getProfile(); + + try { + MobHealthbarType type = MobHealthbarType.valueOf(args[0].toUpperCase().trim()); + playerProfile.setMobHealthbarType(type); + sender.sendMessage("Display type changed to: " + type); //TODO: Localize + return true; + } + catch (IllegalArgumentException ex) { + sender.sendMessage("Invalid type!"); //TODO: Localize + return true; + } + + default: + return false; + } + } +} diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index 767779b12..59fd89285 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -6,6 +6,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.EntityType; +import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.skills.AbilityType; import com.gmail.nossr50.datatypes.skills.SkillType; import com.gmail.nossr50.util.StringUtils; @@ -48,6 +49,18 @@ public class Config extends AutoUpdateConfigLoader { public boolean getPartyDisplayNames() { return config.getBoolean("Commands.p.Use_Display_Names", true); } public boolean getAdminDisplayNames() { return config.getBoolean("Commands.a.Use_Display_Names", true); } + /* Mob Healthbar */ + public MobHealthbarType getMobHealthbarDefault() { + try { + return MobHealthbarType.valueOf(config.getString("Mob_Healthbar.Display_Type", "HEARTS").toUpperCase().trim()); + } + catch (IllegalArgumentException ex) { + return MobHealthbarType.HEARTS; + } + } + + public int getMobHealthbarTime() { return config.getInt("Mob_Healthbar.Display_Time", 3); } + /* Database Purging */ public int getPurgeInterval() { return config.getInt("Database_Purging.Purge_Interval", -1); } public int getOldUsersCutoff() { return config.getInt("Database_Purging.Old_User_Cutoff", 6); } diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 20be2db89..01725e485 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -96,6 +96,7 @@ public final class DatabaseManager { write("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "huds` (" + "`user_id` int(10) unsigned NOT NULL," + "`hudtype` varchar(50) NOT NULL DEFAULT 'STANDARD'," + + "`mobhealthbar` varchar(50) NOT NULL DEFAULT 'HEARTS'," + "PRIMARY KEY (`user_id`)," + "FOREIGN KEY (`user_id`) REFERENCES `" + tablePrefix + "users` (`id`) " + "ON DELETE CASCADE) ENGINE=MyISAM DEFAULT CHARSET=latin1;"); @@ -153,6 +154,7 @@ public final class DatabaseManager { checkDatabaseStructure(DatabaseUpdateType.BLAST_MINING); checkDatabaseStructure(DatabaseUpdateType.CASCADE_DELETE); checkDatabaseStructure(DatabaseUpdateType.INDEX); + checkDatabaseStructure(DatabaseUpdateType.MOB_HEALTHBARS); } /** @@ -574,6 +576,10 @@ public final class DatabaseManager { } break; + case MOB_HEALTHBARS: + sql = "SELECT * FROM `" + tablePrefix + "huds` ORDER BY `" + tablePrefix + "huds`.`mobhealthbar` ASC LIMIT 0 , 30"; + break; + default: break; } @@ -610,6 +616,11 @@ public final class DatabaseManager { write("ALTER TABLE `"+tablePrefix + "experience` ADD `fishing` int(10) NOT NULL DEFAULT '0' ;"); break; + case MOB_HEALTHBARS: + mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars..."); + write("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT 'HEARTS' ;"); + break; + default: break; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/MobHealthbarType.java b/src/main/java/com/gmail/nossr50/datatypes/MobHealthbarType.java new file mode 100644 index 000000000..3c67df798 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/MobHealthbarType.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.datatypes; + +public enum MobHealthbarType { + HEARTS, + BAR, + DISABLED; +} \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseUpdateType.java b/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseUpdateType.java index e173443c7..135748e33 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseUpdateType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseUpdateType.java @@ -4,5 +4,6 @@ public enum DatabaseUpdateType { FISHING, BLAST_MINING, CASCADE_DELETE, - INDEX; + INDEX, + MOB_HEALTHBARS; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 0828faa17..4c1395c99 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -13,6 +13,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.spout.SpoutConfig; import com.gmail.nossr50.database.DatabaseManager; +import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.skills.AbilityType; import com.gmail.nossr50.datatypes.skills.SkillType; import com.gmail.nossr50.datatypes.spout.huds.HudType; @@ -27,6 +28,7 @@ public class PlayerProfile { // HUD private McMMOHud spoutHud; private HudType hudType; + private MobHealthbarType mobHealthbarType; // mySQL Stuff private int userId; @@ -41,6 +43,7 @@ public class PlayerProfile { public PlayerProfile(String playerName, boolean addNew) { this.playerName = playerName; + mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); if (mcMMO.spoutEnabled) { hudType = SpoutConfig.getInstance().defaultHudType; @@ -98,6 +101,8 @@ public class PlayerProfile { } } + mobHealthbarType = MobHealthbarType.valueOf(DatabaseManager.read("SELECT mobhealthbar FROM " + tablePrefix + "huds WHERE user_id = " + userId).get(1).get(0)); + HashMap> cooldowns = DatabaseManager.read("SELECT mining, woodcutting, unarmed, herbalism, excavation, swords, axes, blast_mining FROM " + tablePrefix + "cooldowns WHERE user_id = " + userId); ArrayList cooldownValues = cooldowns.get(1); @@ -326,6 +331,10 @@ public class PlayerProfile { skillsDATS.put(AbilityType.BLAST_MINING, Integer.valueOf(character[36])); } + if (character.length > 38) { + mobHealthbarType = MobHealthbarType.valueOf(character[38]); + } + loaded = true; in.close(); @@ -348,6 +357,7 @@ public class PlayerProfile { String tablePrefix = Config.getInstance().getMySQLTablePrefix(); DatabaseManager.write("UPDATE " + tablePrefix + "huds SET hudtype = '" + hudType.toString() + "' WHERE user_id = " + userId); + DatabaseManager.write("UPDATE " + tablePrefix + "huds SET mobhealthbar = '" + mobHealthbarType.toString() + "' WHERE user_id = " + userId); DatabaseManager.write("UPDATE " + tablePrefix + "users SET lastlogin = " + ((int) (timestamp / Misc.TIME_CONVERSION_FACTOR)) + " WHERE id = " + userId); DatabaseManager.write("UPDATE " + tablePrefix + "cooldowns SET " + " mining = " + skillsDATS.get(AbilityType.SUPER_BREAKER) @@ -443,6 +453,7 @@ public class PlayerProfile { writer.append(skillsXp.get(SkillType.FISHING)).append(":"); writer.append(skillsDATS.get(AbilityType.BLAST_MINING)).append(":"); writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":"); + writer.append(mobHealthbarType.toString()).append(":"); writer.append("\r\n"); } } @@ -506,6 +517,7 @@ public class PlayerProfile { out.append("0:"); // FishingXp out.append("0:"); // Blast Mining out.append(String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)).append(":"); // LastLogin + out.append(mobHealthbarType.toString()).append(":"); // Mob Healthbar HUD // Add more in the same format as the line above @@ -549,6 +561,18 @@ public class PlayerProfile { this.hudType = hudType; } + /* + * Mob Healthbars + */ + + public MobHealthbarType getMobHealthbarType() { + return mobHealthbarType; + } + + public void setMobHealthbarType(MobHealthbarType mobHealthbarType) { + this.mobHealthbarType = mobHealthbarType; + } + /* * Cooldowns */ diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 6a39b9e54..1d9aaeabe 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -91,6 +91,8 @@ public class mcMMO extends JavaPlugin { public final static String blockMetadataKey = "mcMMO: Piston Tracking"; public final static String furnaceMetadataKey = "mcMMO: Tracked Furnace"; public final static String tntMetadataKey = "mcMMO: Tracked TNT"; + public final static String customNameKey = "mcMMO: Custom Name"; + public final static String customVisibleKey = "mcMMO: Name Visibility"; public static FixedMetadataValue metadataValue; @@ -355,6 +357,7 @@ public class mcMMO extends JavaPlugin { CommandRegistrationManager.registerHardcoreCommand(); CommandRegistrationManager.registerVampirismCommand(); CommandRegistrationManager.registerMcnotifyCommand(); + CommandRegistrationManager.registerMobhealthCommand(); // Spout commands CommandRegistrationManager.registerXplockCommand(); diff --git a/src/main/java/com/gmail/nossr50/runnables/MobHealthDisplayUpdaterTask.java b/src/main/java/com/gmail/nossr50/runnables/MobHealthDisplayUpdaterTask.java new file mode 100644 index 000000000..f5ae2444b --- /dev/null +++ b/src/main/java/com/gmail/nossr50/runnables/MobHealthDisplayUpdaterTask.java @@ -0,0 +1,24 @@ +package com.gmail.nossr50.runnables; + +import org.bukkit.entity.LivingEntity; +import org.bukkit.scheduler.BukkitRunnable; + +import com.gmail.nossr50.mcMMO; + +public class MobHealthDisplayUpdaterTask extends BukkitRunnable { + private LivingEntity target; + private String oldName; + private boolean oldNameVisible; + + public MobHealthDisplayUpdaterTask(LivingEntity target) { + this.target = target; + this.oldName = target.getMetadata(mcMMO.customNameKey).get(0).asString(); + this.oldNameVisible = target.getMetadata(mcMMO.customVisibleKey).get(0).asBoolean(); + } + + @Override + public void run() { + target.setCustomNameVisible(oldNameVisible); + target.setCustomName(oldName); + } +} diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 164559b0d..f2ca5c25f 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -20,6 +20,7 @@ public final class Permissions { */ public static boolean motd(Permissible permissible) { return permissible.hasPermission("mcmmo.motd"); } + public static boolean mobHealthDisplay(Permissible permissible) { return permissible.hasPermission("mcmmo.mobhealthdisplay"); } public static boolean updateNotifications(Permissible permissible) {return permissible.hasPermission("mcmmo.tools.updatecheck"); } public static boolean chimaeraWing(Permissible permissible) { return permissible.hasPermission("mcmmo.item.chimaerawing"); } diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 6b72df770..0a4f8ee39 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -11,6 +11,7 @@ import com.gmail.nossr50.commands.McgodCommand; import com.gmail.nossr50.commands.McmmoCommand; import com.gmail.nossr50.commands.McnotifyCommand; import com.gmail.nossr50.commands.McrefreshCommand; +import com.gmail.nossr50.commands.MobhealthCommand; import com.gmail.nossr50.commands.XprateCommand; import com.gmail.nossr50.commands.chat.AdminChatCommand; import com.gmail.nossr50.commands.chat.PartyChatCommand; @@ -366,4 +367,13 @@ public final class CommandRegistrationManager { command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcnotify")); command.setExecutor(new McnotifyCommand()); } + + public static void registerMobhealthCommand() { + PluginCommand command = mcMMO.p.getCommand("mobhealth"); + command.setDescription("Change the style of the mob healthbar"); //TODO: Localize + command.setPermission("mcmmo.commands.mobhealth"); + command.setPermissionMessage(permissionsMessage); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mobhealth", "")); + command.setExecutor(new MobhealthCommand()); + } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index d97a381b4..8cad04087 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.util.skills; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.AnimalTamer; import org.bukkit.entity.Animals; @@ -17,15 +18,19 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.player.PlayerAnimationEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.SkillType; import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent; import com.gmail.nossr50.events.fake.FakeEntityDamageEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.runnables.MobHealthDisplayUpdaterTask; import com.gmail.nossr50.runnables.skills.AwardCombatXpTask; import com.gmail.nossr50.runnables.skills.BleedTimerTask; import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; @@ -284,6 +289,34 @@ public final class CombatUtils { } } } + else if (attacker instanceof Player) { + Player player = (Player) attacker; + PlayerProfile profile = UserManager.getPlayer(player).getProfile(); + + if (Permissions.mobHealthDisplay(player) && profile.getMobHealthbarType() != MobHealthbarType.DISABLED) { + String oldName = target.getCustomName(); + boolean oldNameVisible = target.isCustomNameVisible(); + String newName = createHealthDisplay(profile, target, event.getDamage()); + + target.setCustomName(newName); + target.setCustomNameVisible(true); + + int displayTime = Config.getInstance().getMobHealthbarTime(); + + if (displayTime != -1) { + if (oldName == null) { + oldName = ""; + } + + if (!ChatColor.stripColor(oldName).equalsIgnoreCase(ChatColor.stripColor(newName))) { + target.setMetadata(mcMMO.customNameKey, new FixedMetadataValue(mcMMO.p, oldName)); + target.setMetadata(mcMMO.customVisibleKey, new FixedMetadataValue(mcMMO.p, oldNameVisible)); + } + + new MobHealthDisplayUpdaterTask(target).runTaskLater(mcMMO.p, displayTime * 20); // Clear health display after 3 seconds + } + } + } } /** @@ -583,4 +616,67 @@ public final class CombatUtils { return process; } + + private static String createHealthDisplay(PlayerProfile profile, LivingEntity entity, int damage) { + int maxHealth = entity.getMaxHealth(); + int currentHealth = Math.max(entity.getHealth() - damage, 0); + double healthPercentage = (currentHealth / (double) maxHealth) * 100.0D; + + int fullDisplay = 0; + ChatColor color = ChatColor.BLACK; + String symbol = ""; + + switch (profile.getMobHealthbarType()) { + case HEARTS: + fullDisplay = Math.min(maxHealth / 2, 10); + color = ChatColor.DARK_RED; + symbol = "❤"; + break; + + case BAR: + fullDisplay = 10; + + if (healthPercentage >= 85) { + color = ChatColor.DARK_GREEN; + } + else if (healthPercentage >= 70) { + color = ChatColor.GREEN; + } + else if (healthPercentage >= 55) { + color = ChatColor.GOLD; + } + else if (healthPercentage >= 40) { + color = ChatColor.YELLOW; + } + else if (healthPercentage >= 25) { + color = ChatColor.RED; + } + else if (healthPercentage >= 0) { + color = ChatColor.DARK_RED; + } + + symbol = "■"; + break; + + default: + return null; + } + + int coloredDisplay = (int) (fullDisplay * (healthPercentage / 100.0D)); + int grayDisplay = fullDisplay - coloredDisplay; + + String healthbar = color + ""; + + for (int i = 0; i < coloredDisplay; i++) { + healthbar += symbol; + } + + healthbar += ChatColor.GRAY; + + for (int i = 0; i < grayDisplay; i++) { + healthbar += symbol; + } + + return healthbar; + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 9c05df729..6d1f67c11 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -27,6 +27,12 @@ General: # Should mcMMO over-write configs to update, or make new ones ending in .new? Config_Update_Overwrite: true +Mob_Healthbar + # Default display for mob health bars - HEARTS, BAR, or DISABLED + Display_Type: HEARTS + # Amount of time (in seconds) to display. To display permanently, set to -1 + Display_Time: 3 + Database_Purging: # Amount of time (in hours) to wait between database purging # To only run at server start, set to 0 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index fa835aed3..d0ccd63b5 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -104,6 +104,9 @@ commands: mcnotify: aliases: [notify] description: Toggle mcMMO abilities chat display notifications on/off + mobhealth: + aliases: [mcmobhealth] + description: Change the style of the mob healthbar permissions: mcmmo.*: default: false @@ -659,6 +662,7 @@ permissions: mcmmo.commands.mcstats: true mcmmo.commands.mctop.all: true mcmmo.commands.mining: true + mcmmo.commands.mobhealth: true mcmmo.commands.party.all: true mcmmo.commands.ptp: true mcmmo.commands.ptp.accept: true @@ -875,6 +879,9 @@ permissions: mcmmo.commands.mmoupdate: default: false description: Allows access to the mmoupdate command + mcmmo.commands.mobhealth: + default: true + description: Allows access to the mobhealth command mcmmo.commands.party.*: default: false description: Implies access to all mcmmo.commands.party permissions. @@ -1179,6 +1186,7 @@ permissions: children: mcmmo.chat.partychat: true mcmmo.commands.defaults: true + mcmmo.mobhealthdisplay: true mcmmo.motd: true mcmmo.skills.all: true mcmmo.defaultsop: @@ -1200,6 +1208,8 @@ permissions: mcmmo.item.chimaerawing: true mcmmo.item.chimaerawing: description: Allows use of Chimaera Wing item + mcmmo.mobhealthdisplay: + description: Allows viewing of mob health display during combat mcmmo.motd: description: Allows access to the motd mcmmo.party.*: