diff --git a/TwosideKeeper.jar b/TwosideKeeper.jar index c26935f..10d5ca5 100644 Binary files a/TwosideKeeper.jar and b/TwosideKeeper.jar differ diff --git a/src/sig/plugin/TwosideKeeper/BossMonster.java b/src/sig/plugin/TwosideKeeper/BossMonster.java index 8c385d1..07dc738 100644 --- a/src/sig/plugin/TwosideKeeper/BossMonster.java +++ b/src/sig/plugin/TwosideKeeper/BossMonster.java @@ -18,6 +18,7 @@ import org.bukkit.potion.PotionEffect; import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions; +@Deprecated public class BossMonster { private String name; private double maxhp; diff --git a/src/sig/plugin/TwosideKeeper/CustomDamage.java b/src/sig/plugin/TwosideKeeper/CustomDamage.java index fc8a38e..f9dc06a 100644 --- a/src/sig/plugin/TwosideKeeper/CustomDamage.java +++ b/src/sig/plugin/TwosideKeeper/CustomDamage.java @@ -2980,7 +2980,17 @@ public class CustomDamage { dmg += ItemSet.TotalBaseAmountBasedOnSetBonusCount((Player)shooter, ItemSet.OLIVE, 3, 3); if (ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.PANROS, 5) || ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.DAWNTRACKER, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.LUCI, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.WINDRY, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.SHARD, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.TOXIN, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.PROTECTOR, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.SUSTENANCE, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.LEGION, 5) || + ItemSet.HasSetBonusBasedOnSetBonusCount((Player)shooter, ItemSet.PRIDE, 5) || (ItemSet.meetsSlayerSwordConditions(ItemSet.LORASYS, 9, 1, (Player)shooter)) || + (ItemSet.meetsSlayerSwordConditions(ItemSet.ASSASSIN, 9, 1, (Player)shooter)) || + (ItemSet.meetsSlayerSwordConditions(ItemSet.STEALTH, 9, 1, (Player)shooter)) || GenericFunctions.HasFullRangerSet((Player)shooter)) { dmg += 15; } @@ -3448,8 +3458,38 @@ public class CustomDamage { if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.DAWNTRACKER, 5)) { finaldmg += dmg*0.5; } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.WINDRY, 5)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.LUCI, 5)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.SHARD, 5)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.TOXIN, 5)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.PROTECTOR, 5)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.SUSTENANCE, 5)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.LEGION, 5)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.HasSetBonusBasedOnSetBonusCount(p, ItemSet.PRIDE, 5)) { + finaldmg += dmg*0.5; + } else if (ItemSet.meetsSlayerSwordConditions(ItemSet.LORASYS, 9, 1, p)) { finaldmg += dmg*0.5; + } else + if (ItemSet.meetsSlayerSwordConditions(ItemSet.ASSASSIN, 9, 1, p)) { + finaldmg += dmg*0.5; + } else + if (ItemSet.meetsSlayerSwordConditions(ItemSet.STEALTH, 9, 1, p)) { + finaldmg += dmg*0.5; } finaldmg += dmg*aPlugin.API.getPlayerBonuses(p).getBonusArmorPenetration(); if (Buff.hasBuff(p, "WINDCHARGE") && diff --git a/src/sig/plugin/TwosideKeeper/CustomMonster.java b/src/sig/plugin/TwosideKeeper/CustomMonster.java index ee39f35..11a3eb4 100644 --- a/src/sig/plugin/TwosideKeeper/CustomMonster.java +++ b/src/sig/plugin/TwosideKeeper/CustomMonster.java @@ -99,4 +99,14 @@ public class CustomMonster { public void bloodPoolSpawnedEvent(LivingEntity target) { } + + public void AnnounceDPSBreakdown() { + } + + /** + * 0.0 means cannot be moved, 1.0 means normal knockback. + */ + public double getKnockbackMult() { + return 1.0; + } } diff --git a/src/sig/plugin/TwosideKeeper/GlobalLoot.java b/src/sig/plugin/TwosideKeeper/GlobalLoot.java new file mode 100644 index 0000000..2bbb1d7 --- /dev/null +++ b/src/sig/plugin/TwosideKeeper/GlobalLoot.java @@ -0,0 +1,99 @@ +package sig.plugin.TwosideKeeper; + +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions; + +public class GlobalLoot { + Item item; + String lootname; + UUID item_uuid; + HashMap drop_inventories = new HashMap(); + HashMap last_opened_loot = new HashMap(); + + GlobalLoot(Location spawnLoc, String lootName) { + item = (Item)spawnLoc.getWorld().dropItemNaturally(spawnLoc, new ItemStack(Material.CHEST)); + item_uuid = item.getUniqueId(); + item.setCustomName(lootName); + item.setCustomNameVisible(true); + item.setPickupDelay(Integer.MAX_VALUE); + item.setInvulnerable(true); + this.lootname = lootName; + } + + public void runInventoryCloseEvent(InventoryCloseEvent ev) { + Player p = (Player)ev.getPlayer(); + if (drop_inventories.containsKey(p.getUniqueId()) && + ev.getInventory().getTitle()!=null && + ev.getInventory().getTitle().equalsIgnoreCase(lootname)) { + last_opened_loot.put(p.getUniqueId(), TwosideKeeper.getServerTickTime()); + } + } + + public boolean runTick() { + if ((item!=null && item.isValid())) { + List players = GenericFunctions.getNearbyPlayers(item.getLocation(), 1); + for (Player p : players) { + if (p.getOpenInventory().getType()==InventoryType.CRAFTING && + drop_inventories.containsKey(p.getUniqueId())) { + if (!last_opened_loot.containsKey(p.getUniqueId()) || + last_opened_loot.get(p.getUniqueId())+100<=TwosideKeeper.getServerTickTime()) { + last_opened_loot.put(p.getUniqueId(), TwosideKeeper.getServerTickTime()); + p.openInventory(drop_inventories.get(p.getUniqueId())); + } + } + } + return true; + } else { + return false; + } + } + + public Item getItem() { + return item; + } + + public UUID getItemUniqueID() { + return item_uuid; + } + + public void addNewDropInventory(Player p, ItemStack...lootitems) { + if (drop_inventories.containsKey(p.getUniqueId())) { + Inventory inv = drop_inventories.get(p.getUniqueId()); + inv.addItem(lootitems); + } else { + Inventory newinv = Bukkit.createInventory(p, ((((lootitems.length-1)/9)+1)*9),this.lootname); + newinv.addItem(lootitems); + drop_inventories.put(p.getUniqueId(), newinv); + } + } + + public void openDropInventory(Player p) { + if (drop_inventories.containsKey(p.getUniqueId())) { + p.openInventory(drop_inventories.get(p.getUniqueId())); + } else { + TwosideKeeper.log("WARNING! Drop Inventory for Player with UUID <"+p.getUniqueId()+"> does not have an associated inventory with Global Loot <"+item.getUniqueId()+">. THIS SHOULD NOT BE HAPPENING!!", 1); + p.sendMessage(ChatColor.RED+"Something terrible has happened! "+ChatColor.RESET+"Please let the server administrator know about this."); + } + } + + public static GlobalLoot spawnGlobalLoot(Location loc, String lootName) { + GlobalLoot loot = new GlobalLoot(loc,lootName); + TwosideKeeper.globalloot.put(loot.getItem().getUniqueId(), loot); + return loot; + } +} diff --git a/src/sig/plugin/TwosideKeeper/HelperStructures/ArtifactItem.java b/src/sig/plugin/TwosideKeeper/HelperStructures/ArtifactItem.java index 3daf339..60b79ce 100644 --- a/src/sig/plugin/TwosideKeeper/HelperStructures/ArtifactItem.java +++ b/src/sig/plugin/TwosideKeeper/HelperStructures/ArtifactItem.java @@ -15,5 +15,5 @@ public enum ArtifactItem { DIVINE_CORE, DIVINE_BASE, MALLEABLE_BASE, - ARTIFACT_RECIPE + ARTIFACT_RECIPE; } diff --git a/src/sig/plugin/TwosideKeeper/HelperStructures/Common/GenericFunctions.java b/src/sig/plugin/TwosideKeeper/HelperStructures/Common/GenericFunctions.java index 135f75d..6ec6766 100644 --- a/src/sig/plugin/TwosideKeeper/HelperStructures/Common/GenericFunctions.java +++ b/src/sig/plugin/TwosideKeeper/HelperStructures/Common/GenericFunctions.java @@ -2615,7 +2615,9 @@ public class GenericFunctions { return ItemSet.hasFullSet(p, ItemSet.ALIKAHN) || ItemSet.hasFullSet(p, ItemSet.DARNYS) || ItemSet.hasFullSet(p, ItemSet.JAMDAK) || - ItemSet.hasFullSet(p, ItemSet.LORASAADI); + ItemSet.hasFullSet(p, ItemSet.LORASAADI) || + ItemSet.hasFullSet(p, ItemSet.TOXIN) || + ItemSet.hasFullSet(p, ItemSet.SHARD); /*int rangerarmort1 = 0; //Count the number of each tier of sets. //LEGACY CODE. int rangerarmort2 = 0; int rangerarmort3 = 0; diff --git a/src/sig/plugin/TwosideKeeper/HelperStructures/CustomItem.java b/src/sig/plugin/TwosideKeeper/HelperStructures/CustomItem.java index bf55ca1..78201d3 100644 --- a/src/sig/plugin/TwosideKeeper/HelperStructures/CustomItem.java +++ b/src/sig/plugin/TwosideKeeper/HelperStructures/CustomItem.java @@ -154,6 +154,48 @@ public class CustomItem { return item_VacuumCube.clone(); } + public static ItemStack IronMaterialKit() { + ItemStack kit = new ItemStack(Material.IRON_BLOCK); + ItemUtils.setDisplayName(kit, ChatColor.translateAlternateColorCodes('§', "§7§lIron Material Kit")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7Converts an item's base material")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7to §rIron§7 and hardens it.")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§eIncreases Breaks Remaining.")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7Right-click an item on a pedestal to use.")); + kit.addUnsafeEnchantment(Enchantment.DURABILITY, 1); + ItemUtils.addFlag(kit, ItemFlag.HIDE_ENCHANTS); + return kit.clone(); + } + + public static ItemStack DiamondMaterialKit() { + ItemStack kit = new ItemStack(Material.DIAMOND_BLOCK); + ItemUtils.setDisplayName(kit, ChatColor.translateAlternateColorCodes('§', "§b§lDiamond Material Kit")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7Converts an item's base material")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7to §bDiamond§7.")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§aApplies Unbreaking and Mending.")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7Right-click an item on a pedestal to use.")); + kit.addUnsafeEnchantment(Enchantment.DURABILITY, 1); + ItemUtils.addFlag(kit, ItemFlag.HIDE_ENCHANTS); + return kit.clone(); + } + + public static ItemStack GoldMaterialKit() { + ItemStack kit = new ItemStack(Material.GOLD_BLOCK); + ItemUtils.setDisplayName(kit, ChatColor.translateAlternateColorCodes('§', "§e§lGold Material Kit")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7Converts an item's base material")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7to §eGold§7.")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§cMay degrade the item.")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "")); + ItemUtils.addLore(kit, ChatColor.translateAlternateColorCodes('§', "§7Right-click an item on a pedestal to use.")); + kit.addUnsafeEnchantment(Enchantment.DURABILITY, 1); + ItemUtils.addFlag(kit, ItemFlag.HIDE_ENCHANTS); + return kit.clone(); + } + private static ShapelessRecipe VacuumCubeRecipe() { ItemStack item_VacuumCube = VacuumCube(); diff --git a/src/sig/plugin/TwosideKeeper/HelperStructures/ItemSet.java b/src/sig/plugin/TwosideKeeper/HelperStructures/ItemSet.java index e27e8de..08f2636 100644 --- a/src/sig/plugin/TwosideKeeper/HelperStructures/ItemSet.java +++ b/src/sig/plugin/TwosideKeeper/HelperStructures/ItemSet.java @@ -821,6 +821,9 @@ public enum ItemSet { lore.add(ChatColor.GRAY+" with Wind Slash and gain "+(tier)+" Absorption Health."); lore.add(ChatColor.GRAY+" "); lore.add(ChatColor.GRAY+" (5 second cooldown)"); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); break; case ASSASSIN: lore.add(ChatColor.GOLD+""+ChatColor.ITALIC+"Increases in power based on "+ChatColor.BOLD+"Total Tier Amount"); @@ -829,6 +832,9 @@ public enum ItemSet { lore.add(ChatColor.WHITE+" Assassinate enables you to jump to target blocks."); lore.add(ChatColor.WHITE+" Cooldown of Assassinate decreases by 70% when"); lore.add(ChatColor.WHITE+" jumping to blocks."); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); if (tier>=2) { lore.add(ChatColor.DARK_AQUA+" T18 - "); lore.add(ChatColor.WHITE+" Decreases cooldown of Assassinate by 50% when"); @@ -857,6 +863,9 @@ public enum ItemSet { lore.add(ChatColor.GRAY+" going below 1 for "+(tier+6)+" seconds."); lore.add(ChatColor.GRAY+" "); lore.add(ChatColor.GRAY+" (120s Cooldown)"); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); lore.add(ChatColor.DARK_AQUA+" 6 - "+ChatColor.WHITE+""); lore.add(ChatColor.WHITE+" +"+(tier*10)+"% Lifesteal"); lore.add(ChatColor.WHITE+" +"+(tier*10)+"% Health Regeneration"); @@ -877,6 +886,9 @@ public enum ItemSet { lore.add(ChatColor.GRAY+" Dodge performed."); lore.add(ChatColor.GRAY+" "); lore.add(ChatColor.GRAY+" (120s Cooldown)"); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); break; case PRIDE: lore.add(ChatColor.GOLD+""+ChatColor.ITALIC+"Set Bonus:"); @@ -888,6 +900,9 @@ public enum ItemSet { lore.add(" "+ChatColor.WHITE+" Poison "+ItemSet.GetBaseAmount(set, tier, 4)+" to everything it hits for 15 seconds."); lore.add(ChatColor.DARK_AQUA+" 5 - "+ChatColor.WHITE+" "+ABILITY_LABEL+"Sweep Up"+ABILITY_LABEL_END+" (Shift+Right-Click) heals"); lore.add(" "+ChatColor.WHITE+" half the health it deals as HP directly."); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); lore.add(ChatColor.DARK_AQUA+" 6 - "+ChatColor.WHITE+""); lore.add(ChatColor.WHITE+" +"+(tier*10)+"% Lifesteal"); lore.add(ChatColor.WHITE+" +"+(tier*10)+"% Health Regeneration"); @@ -907,6 +922,9 @@ public enum ItemSet { lore.add(ChatColor.GRAY+" seconds on all party members."); lore.add(ChatColor.GRAY+" "); lore.add(ChatColor.GRAY+" (150 second cooldown)"); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); break; case SHARD: lore.add(ChatColor.GOLD+""+ChatColor.ITALIC+"Set Bonus:"); @@ -918,6 +936,9 @@ public enum ItemSet { lore.add(ChatColor.GRAY+" into shrapnel, dealing damage to all nearby targets"); lore.add(ChatColor.GRAY+" and dealing ticks of additional fire damage for 10"); lore.add(ChatColor.GRAY+" seconds. Shrapnel stacks infinitely on a target."); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); break; case STEALTH: lore.add(ChatColor.GOLD+""+ChatColor.ITALIC+"Increases in power based on "+ChatColor.BOLD+"Total Tier Amount"); @@ -925,6 +946,9 @@ public enum ItemSet { lore.add(ChatColor.DARK_AQUA+" T9 - "); lore.add(ChatColor.WHITE+" Stealth does not cause durability to decrease."); lore.add(ChatColor.WHITE+" Stealth does not get removed when getting hit."); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); if (tier>=2) { lore.add(ChatColor.DARK_AQUA+" T18 - "); lore.add(ChatColor.WHITE+" Going from Visible to Stealth will remove"); @@ -953,6 +977,9 @@ public enum ItemSet { lore.add(ChatColor.DARK_AQUA+" 5 - "+ABILITY_LABEL+" Share the Life"+ABILITY_LABEL_END); lore.add(ChatColor.GRAY+" Increases the Regeneration Pool for other party"); lore.add(ChatColor.GRAY+" members by "+(tier)+" whenever you get hit."); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); break; case TOXIN: lore.add(ChatColor.GOLD+""+ChatColor.ITALIC+"Set Bonus:"); @@ -970,6 +997,9 @@ public enum ItemSet { lore.add(ChatColor.GRAY+" is created around it, applying stacking Burn to all"); lore.add(ChatColor.GRAY+" enemy targets in the fire pool. (Burn deals more damage"); lore.add(ChatColor.GRAY+" as the number of stacks increase.)"); + lore.add(ChatColor.GRAY+" "); + lore.add(ChatColor.WHITE+" +50% Armor Penetration"); + lore.add(ChatColor.WHITE+" +20 Damage"); break; } return lore; diff --git a/src/sig/plugin/TwosideKeeper/HelperStructures/Loot.java b/src/sig/plugin/TwosideKeeper/HelperStructures/Loot.java index c506262..a24c08d 100644 --- a/src/sig/plugin/TwosideKeeper/HelperStructures/Loot.java +++ b/src/sig/plugin/TwosideKeeper/HelperStructures/Loot.java @@ -561,7 +561,9 @@ public class Loot { boolean allowed=true; //Setting this to false will not convert it to a set piece. prefix = (hardened)?(ChatColor.LIGHT_PURPLE+""+ChatColor.BOLD+"Hardened Mega "):(ChatColor.AQUA+""+ChatColor.BOLD+"Mega "); switch (set) { - case PANROS:{ + case PANROS: + case WINDRY: + case LUCI:{ if (item.getType().toString().contains("SWORD")) { } else @@ -570,9 +572,11 @@ public class Loot { allowed = false; } tierbonus = (custom)?tierbonus:modifyTierBonus(item,tierbonus); - set_name = prefix+"Panros Striker "+GenericFunctions.UserFriendlyMaterialName(item.getType()); //Striker set. + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Striker "+GenericFunctions.UserFriendlyMaterialName(item.getType()); //Striker set. }break; - case SONGSTEEL:{ + case SONGSTEEL: + case PROTECTOR: + case SUSTENANCE:{ if (item.getType().toString().contains("SWORD")) { item.setType(Material.SHIELD); tierbonus/=(custom)?1:2; @@ -582,9 +586,11 @@ public class Loot { allowed = false; } tierbonus = (custom)?tierbonus:modifyTierBonus(item,tierbonus); - set_name = prefix+"Songsteel Defender "+GenericFunctions.UserFriendlyMaterialName(item.getType()); //Defender set. + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Defender "+GenericFunctions.UserFriendlyMaterialName(item.getType()); //Defender set. }break; - case DAWNTRACKER:{ + case DAWNTRACKER: + case LEGION: + case PRIDE:{ if (item.getType().toString().contains("SWORD")) { item.setType(Material.valueOf(item.getType().toString().replace("SWORD","")+"AXE")); } else @@ -593,50 +599,39 @@ public class Loot { allowed = false; } tierbonus = (custom)?tierbonus:modifyTierBonus(item,tierbonus); - set_name = prefix+"Dawntracker Barbarian "+GenericFunctions.UserFriendlyMaterialName(item.getType()); + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Barbarian "+GenericFunctions.UserFriendlyMaterialName(item.getType()); }break; - case LORASYS:{ + case LORASYS: + case ASSASSIN: + case STEALTH:{ if (!item.getType().toString().contains("SWORD")) { allowed = false; } tierbonus = (custom)?tierbonus:modifyTierBonus(item,tierbonus); - set_name = prefix+"Lorasys Slayer "+GenericFunctions.UserFriendlyMaterialName(item.getType()); - }break; - case JAMDAK:{ - if (item.getType().toString().contains("SWORD")) { - item.setType(Material.BOW); - } else - if (!item.getType().name().contains("LEATHER") && !item.getType().name().contains("BOW")) { - allowed = false; - } - set_name = prefix+"Jamdak Ranger "+GenericFunctions.UserFriendlyMaterialName(item.getType()); - }break; - case DARNYS:{ - if (item.getType().toString().contains("SWORD")) { - item.setType(Material.BOW); - } else - if (!item.getType().toString().contains("LEATHER") && !item.getType().name().contains("BOW")) { - allowed = false; - } - set_name = prefix+"Darnys Ranger "+GenericFunctions.UserFriendlyMaterialName(item.getType()); - }break; - case ALIKAHN:{ - if (item.getType().toString().contains("SWORD")) { - item.setType(Material.BOW); - } else - if (!item.getType().toString().contains("LEATHER") && !item.getType().name().contains("BOW")) { - allowed = false; - } - set_name = prefix+"Alikahn Ranger "+GenericFunctions.UserFriendlyMaterialName(item.getType()); + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Slayer "+GenericFunctions.UserFriendlyMaterialName(item.getType()); }break; + case JAMDAK: + case SHARD: + case TOXIN: + case DARNYS: + case ALIKAHN: case LORASAADI:{ if (item.getType().toString().contains("SWORD")) { item.setType(Material.BOW); } else - if (!item.getType().toString().contains("LEATHER") && !item.getType().name().contains("BOW")) { + if (item.getType().toString().contains("_HELMET") || + item.getType().toString().contains("_LEGGINGS") || + item.getType().toString().contains("_CHESTPLATE") || + item.getType().toString().contains("_BOOTS")) { + String itemstr = item.getType().toString(); + String[] split = itemstr.split("_"); + String newstr = "LEATHER_"+split[1]; + item.setType(Material.valueOf(newstr)); + } else + if (!item.getType().name().contains("LEATHER") && !item.getType().name().contains("BOW")) { allowed = false; } - set_name = prefix+"Lorasaadi Ranger "+GenericFunctions.UserFriendlyMaterialName(item.getType()); + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Ranger "+GenericFunctions.UserFriendlyMaterialName(item.getType()); }break; case GLADOMAIN:{ //item.setType(Material.SKULL_ITEM); else @@ -648,7 +643,7 @@ public class Loot { ItemMeta m = item.getItemMeta(); m.addItemFlags(ItemFlag.HIDE_ENCHANTS); item.setItemMeta(m); - set_name = prefix+"Gladomain Slayer Amulet"; + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Slayer Amulet"; }break; case MOONSHADOW:{ if (!item.getType().toString().contains("SKULL_ITEM")) { @@ -660,7 +655,7 @@ public class Loot { ItemMeta m = item.getItemMeta(); m.addItemFlags(ItemFlag.HIDE_ENCHANTS); item.setItemMeta(m); - set_name = prefix+"Moonshadow Slayer Trinket"; + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Slayer Trinket"; }break; case WOLFSBANE:{ if (!item.getType().toString().contains("SKULL_ITEM")) { @@ -672,7 +667,7 @@ public class Loot { ItemMeta m = item.getItemMeta(); m.addItemFlags(ItemFlag.HIDE_ENCHANTS); item.setItemMeta(m); - set_name = prefix+"Wolfsbane Slayer Ornament"; + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Slayer Ornament"; }break; case ALUSTINE:{ if (!item.getType().toString().contains("SKULL_ITEM")) { @@ -684,7 +679,7 @@ public class Loot { ItemMeta m = item.getItemMeta(); m.addItemFlags(ItemFlag.HIDE_ENCHANTS); item.setItemMeta(m); - set_name = prefix+"Alustine Slayer Charm"; + set_name = prefix+GenericFunctions.CapitalizeFirstLetters(set.name())+" Slayer Charm"; }break; case BLITZEN: case COMET: diff --git a/src/sig/plugin/TwosideKeeper/HelperStructures/PlayerMode.java b/src/sig/plugin/TwosideKeeper/HelperStructures/PlayerMode.java index c1a2ff8..968ad46 100644 --- a/src/sig/plugin/TwosideKeeper/HelperStructures/PlayerMode.java +++ b/src/sig/plugin/TwosideKeeper/HelperStructures/PlayerMode.java @@ -97,8 +97,8 @@ public enum PlayerMode { + ChatColor.WHITE+"->Whenever a Slayer critically strikes, it suppresses a target for 0.75 seconds. Suppression prevents movement, attacking, teleporting, and exploding. Suppressed targets glow Black.\n" + ChatColor.GRAY+"->Slayers thrive in 1vs1 situations. If a target is completely alone, they will glow white to the Slayer. Isolated targets take 50% more damage from the Slayer. Slayer's Dodge Chance increases by 40% against isolated targets.\n" + ChatColor.WHITE+"->Slayers can use the Assassination ability. Press the Drop key while looking at an enemy to perform an assassination: You jump directly behind the enemy, gaining 0.5 seconds of invulnerability. If the next hit after Assassination is performed kills the target, you gain a speed and strength buff. These buffs cap at Speed V and Strength X respectively and last 10 seconds. Assassination cooldown is reset whenever a target is instantly killed in this manner, and you get immediately put back into stealth, preventing further detection from other monsters.\n"), - SUMMONER(ChatColor.DARK_PURPLE,"SM","Summoner", - ChatColor.DARK_PURPLE+""+ChatColor.BOLD+"Summoner mode Perks: "+ChatColor.RESET+"\n"), + /*SUMMONER(ChatColor.DARK_PURPLE,"SM","Summoner", + ChatColor.DARK_PURPLE+""+ChatColor.BOLD+"Summoner mode Perks: "+ChatColor.RESET+"\n"),*/ NORMAL(ChatColor.WHITE,"A","Adventurer", ChatColor.WHITE+""+ChatColor.BOLD+"Adventurer mode Perks: "+ChatColor.RESET+"\n" + ChatColor.WHITE+"->Players are identified as 'Adventurers' by default.\n" diff --git a/src/sig/plugin/TwosideKeeper/Monster/GenericBoss.java b/src/sig/plugin/TwosideKeeper/Monster/GenericBoss.java new file mode 100644 index 0000000..45f6820 --- /dev/null +++ b/src/sig/plugin/TwosideKeeper/Monster/GenericBoss.java @@ -0,0 +1,353 @@ +package sig.plugin.TwosideKeeper.Monster; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BossBar; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; + +import sig.plugin.TwosideKeeper.ChargeZombie; +import sig.plugin.TwosideKeeper.CustomMonster; +import sig.plugin.TwosideKeeper.LivingEntityStructure; +import sig.plugin.TwosideKeeper.TwosideKeeper; +import sig.plugin.TwosideKeeper.HelperStructures.Channel; +import sig.plugin.TwosideKeeper.HelperStructures.PlayerMode; +import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions; +import sig.plugin.TwosideKeeper.HelperStructures.Utils.SoundUtils; + +public class GenericBoss extends CustomMonster{ + + protected List participantlist = new ArrayList(); + protected HashMap dpslist = new HashMap(); + protected HashMap> modelist = new HashMap>(); + BossBar healthbar; + protected String arrow = "->"; + int scroll=0; + boolean startedfight=false; + private Location lastLoc = null; + private long stuckTimer=0; + long lasthit; + + public GenericBoss(LivingEntity m) { + super(m); + } + + public List getParticipants() { + return participantlist; + } + + public void runTick() { + updateHealthbarForNearbyPlayers(); + updateTargetIfLost(); + regenerateHealthAndResetBossIfIdle(); + keepHealthbarUpdated(); + unstuckIfStuck(); + increaseBarTextScroll(); + } + + protected void increaseBarTextScroll() { + scroll++; + switch (scroll%22) { + case 11:{ + arrow=" -"; + }break; + case 12:{ + arrow=" "; + }break; + case 13:{ + arrow="> "; + }break; + case 14:{ + arrow="->"; + }break; + } + } + + private void unstuckIfStuck() { + if (!startedfight) { + ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); + } else + if (startedfight) { + lastLoc = m.getLocation().clone(); + if (lastLoc!=null && lastLoc.distance(m.getLocation())<=0.4) { + stuckTimer++; + //TwosideKeeper.log("Stuck. "+stuckTimer, 0); + ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); + } else { + stuckTimer=0; + } + if (!Channel.isChanneling(m) && stuckTimer>5) { + //Teleport randomly. + double numb = Math.random(); + if (numb<=0.33) { + Location newloc = m.getLocation().add(Math.random()*10-5,0,0); + if (!newloc.getBlock().getType().isSolid() && + !newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { + SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); + m.teleport(newloc); + } + } else + if (numb<=0.5) { + Location newloc = m.getLocation().add(0,0,Math.random()*10-5); + if (!newloc.getBlock().getType().isSolid() && + !newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { + SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); + m.teleport(newloc); + } + } + stuckTimer=0; + } + } + } + + private void keepHealthbarUpdated() { + healthbar.setProgress(m.getHealth()/m.getMaxHealth()); + Monster me = (Monster)m; + String healthbarfooter = ((me.getTarget()!=null && (me.getTarget() instanceof Player))?(ChatColor.DARK_AQUA+" "+arrow+" "+ChatColor.YELLOW+((Player)me.getTarget()).getName()):""); + if (Channel.isChanneling(m)) { + healthbar.setTitle(LivingEntityStructure.getChannelingBar(m)+healthbarfooter); + } else { + healthbar.setTitle(GenericFunctions.getDisplayName(m)+healthbarfooter); + } + } + + private void regenerateHealthAndResetBossIfIdle() { + if (lasthit+20*15<=TwosideKeeper.getServerTickTime()) { + GenericFunctions.HealEntity(m, m.getMaxHealth()*0.01); + if (startedfight) { + healthbar.setColor(BarColor.GREEN); + } + } else { + if (startedfight) { + healthbar.setColor(BarColor.BLUE); + } + } + if (participantlist.size()==0 && startedfight) { + startedfight=false; + m.setAI(false); + m.setHealth(m.getMaxHealth()); + announceFailedTakedown(); + } + } + + public void announceFailedTakedown() { + if (dpslist.size()>0 && !m.isDead()) { + Bukkit.getServer().broadcastMessage(GenericFunctions.getDisplayName(m)+" Takedown Failed..."); + Bukkit.getServer().broadcastMessage(ChatColor.YELLOW+"DPS Breakdown:"); + Bukkit.getServer().broadcastMessage(generateDPSReport()); + aPlugin.API.discordSendRaw(GenericFunctions.getDisplayName(m)+" Takedown Failed...\n\n"+ChatColor.YELLOW+"DPS Breakdown:"+"\n```\n"+generateDPSReport()+"\n```"); + dpslist.clear(); + healthbar.setColor(BarColor.WHITE); + } + } + + private void updateTargetIfLost() { + Monster mm = (Monster)m; + LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); + if (mm.getTarget()==null || !mm.getTarget().isValid() || + les.GetTarget()==null || !mm.getTarget().isValid() || + ((mm.getTarget().getLocation().distanceSquared(mm.getLocation())>2500 || + les.GetTarget().getLocation().distanceSquared(mm.getLocation())>2500 + ))) { + //See if there's another participant in the list. Choose randomly. + while (participantlist.size()>0) { + Player p = participantlist.get((int)(Math.random()*participantlist.size())); + if (p!=null && p.isValid() && !p.isDead() && + (p.getLocation().distanceSquared(mm.getLocation())<=2500)) { + mm.setTarget(p); + les.SetTarget(p); + break; + } else { + participantlist.remove(p); + } + } + if (participantlist.size()==0 && startedfight) { + //This fight has failed. + announceFailedTakedown(); + startedfight=false; + } + } + } + + private void updateHealthbarForNearbyPlayers() { + for (Player p : healthbar.getPlayers()) { + if (p.getWorld().equals(m.getWorld()) && p.getLocation().distanceSquared(m.getLocation())>2500) { + healthbar.removePlayer(p); + } + } + for (Entity e : m.getNearbyEntities(50, 50, 50)) { + if (e instanceof Player) { + Player p = (Player)e; + healthbar.addPlayer(p); + } + } + } + + public String generateDPSReport() { + //Sorts a list of players by DPS contribution. + List sorted_dmg = new ArrayList(); + List sorted_pl = new ArrayList(); + double totaldmg = 0; + for (String pl : dpslist.keySet()) { + double dmg = dpslist.get(pl); + int slot = 0; + totaldmg+=dmg; + for (int i=0;isorted_dmg.get(i)) { + break; + } else { + slot++; + } + } + sorted_pl.add(slot,pl); + sorted_dmg.add(slot,dmg); + } + StringBuilder finalstr = new StringBuilder(); + DecimalFormat df = new DecimalFormat("0.00"); + for (int i=0;i participants = getParticipants(); + StringBuilder participants_list = new StringBuilder(); + for (int i=0;i{ + m.setVelocity(m.getVelocity().multiply(getKnockbackMult())); + }, 1); + healthbar.setProgress(m.getHealth()/m.getMaxHealth()); + lasthit=TwosideKeeper.getServerTickTime(); + if (!startedfight) { + startedfight=true; + healthbar.setColor(BarColor.BLUE); + } + m.setAI(true); + } + + private void addTarget(LivingEntity damager, double dmg) { + if (damager instanceof Player) { + Player p = (Player)damager; + addParticipant(p); + if (!dpslist.containsKey(p.getName())) { + dpslist.put(p.getName(), dmg); + } else { + dpslist.put(p.getName(), dpslist.get(p.getName())+dmg); + } + if (!modelist.containsKey(p.getName())) { + HashMap modestruct = new HashMap(); + modestruct.put(PlayerMode.getPlayerMode(p).name(), 1); + modelist.put(p.getName(), modestruct); + } else { + HashMap modestruct = modelist.get(p.getName()); + if (modestruct.containsKey(PlayerMode.getPlayerMode(p).name())) { + Integer amt = modestruct.get(PlayerMode.getPlayerMode(p).name()); + modestruct.put(PlayerMode.getPlayerMode(p).name(), ++amt); + } else { + modestruct.put(PlayerMode.getPlayerMode(p).name(), 1); + } + } + } + } + + public PlayerMode getMostUsedPlayerMode(Player p) { + int highestamt = 0; + PlayerMode highestmode = null; + if (modelist.containsKey(p.getName())) { + HashMap modestruct = modelist.get(p.getName()); + for (String s : modestruct.keySet()) { + PlayerMode pm = PlayerMode.valueOf(s); + int amt = modestruct.get(s); + if (highestamt participantlist = new ArrayList(); - protected HashMap dpslist = new HashMap(); - BossBar healthbar; BossBar shieldbar; - long lasthit; - boolean startedfight=false; boolean isFlying=false; - private long stuckTimer=0; - int scroll=0; - private Location lastLoc = null; Location lastlandedloc = null; final static double[] SHIELD_AMT = new double[]{1800,4700,16000}; Location targetloc = null; @@ -93,7 +97,7 @@ public class Knight extends CustomMonster{ final static int[] GRANDSLAM_COOLDOWN = new int[]{900,700,600}; MixedDamage[] GRANDSLAM_DAMAGE = new MixedDamage[]{MixedDamage.v(450),MixedDamage.v(700),MixedDamage.v(700, 0.55)}; final Spell DARKREVERIE = new Spell("Dark Reverie",new int[]{60,40,40},new int[]{600,600,600}); - final Spell PHASEII = new Spell("Phase II",new int[]{200,200,200},new int[]{0,0,0}); + final Spell PHASEII = new Spell("Phase II",new int[]{80,80,80},new int[]{0,0,0}); final Spell LIGHTNINGBOLT = new Spell("Lightning Bolt",new int[]{80,60,40},new int[]{400,300,200},new MixedDamage[]{MixedDamage.v(100,0.02),MixedDamage.v(250,0.05),MixedDamage.v(400, 0.1)}); final Spell DARKLIGHT = new Spell("The Dark Light",new int[]{60,60,60},new int[]{500,500,500},new MixedDamage[]{MixedDamage.v(200,0.05),MixedDamage.v(300,0.10),MixedDamage.v(400, 0.15)}); final Spell MINDFIELD = new Spell("Mind Field",new int[]{120,80,80},new int[]{1200,1000,800},new MixedDamage[]{MixedDamage.v(0,0.04),MixedDamage.v(0,0.07),MixedDamage.v(0, 0.15)}); @@ -137,16 +141,11 @@ public class Knight extends CustomMonster{ } public void runTick() { - updateHealthbarForNearbyPlayers(); + super.runTick(); relinkToSpider(); displayDarkSwordParticles(); - updateTargetIfLost(); - regenerateHealthAndResetBossIfIdle(); - keepHealthbarUpdated(); keepSpiderPetNearby(); - unstuckIfStuck(); preventTargetFromBeingTheSameAsSpider(); - increaseBarTextScroll(); performSpells(); performSilverfishNotification(); removeDebuffs(); @@ -449,12 +448,6 @@ public class Knight extends CustomMonster{ return currentloc.getBlockY(); } - private void announceMessageToParticipants(String msg) { - for (Player p : participantlist) { - p.sendMessage(msg); - } - } - private void removeAllBuffsFromPlayers() { for (Player p : participantlist) { for (PotionEffect pe : p.getActivePotionEffects()) { @@ -784,43 +777,6 @@ public class Knight extends CustomMonster{ spider_pet.GetMonster().isValid(); } - private void unstuckIfStuck() { - if (!startedfight) { - ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); - } else - if (startedfight) { - lastLoc = m.getLocation().clone(); - if (lastLoc!=null && lastLoc.distance(m.getLocation())<=0.4) { - stuckTimer++; - //TwosideKeeper.log("Stuck. "+stuckTimer, 0); - ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); - } else { - stuckTimer=0; - } - if (!Channel.isChanneling(m) && stuckTimer>5) { - //Teleport randomly. - double numb = Math.random(); - if (numb<=0.33) { - Location newloc = m.getLocation().add(Math.random()*10-5,0,0); - if (!newloc.getBlock().getType().isSolid() && - !newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { - SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); - m.teleport(newloc); - } - } else - if (numb<=0.5) { - Location newloc = m.getLocation().add(0,0,Math.random()*10-5); - if (!newloc.getBlock().getType().isSolid() && - !newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { - SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); - m.teleport(newloc); - } - } - stuckTimer=0; - } - } - } - private void keepSpiderPetNearby() { if (isValidSpiderPet()) { LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(spider_pet.GetMonster()); @@ -831,81 +787,12 @@ public class Knight extends CustomMonster{ } } - private void keepHealthbarUpdated() { - healthbar.setProgress(m.getHealth()/m.getMaxHealth()); - Monster me = (Monster)m; - String healthbarfooter = ((me.getTarget()!=null && (me.getTarget() instanceof Player))?(ChatColor.DARK_AQUA+" "+arrow+" "+ChatColor.YELLOW+((Player)me.getTarget()).getName()):""); - if (Channel.isChanneling(m)) { - healthbar.setTitle(LivingEntityStructure.getChannelingBar(m)+healthbarfooter); - } else { - healthbar.setTitle(GenericFunctions.getDisplayName(m)+healthbarfooter); - } - if (isValidSpiderPet()) { - spider_pet.GetMonster().setHealth(spider_pet.GetMonster().getMaxHealth()); - } - if (shieldbar!=null) { - shieldbar.setProgress(Math.min(CustomDamage.getAbsorptionHearts(m)/SHIELD_AMT[getDifficultySlot()],1)); - } - } - - private void regenerateHealthAndResetBossIfIdle() { - if (lasthit+20*15<=TwosideKeeper.getServerTickTime()) { - GenericFunctions.HealEntity(m, m.getMaxHealth()*0.01); - if (startedfight) { - healthbar.setColor(BarColor.GREEN); - } - } else { - if (startedfight) { - healthbar.setColor(BarColor.BLUE); - } - } - if (participantlist.size()==0 && startedfight) { - startedfight=false; - m.setAI(false); - m.setHealth(m.getMaxHealth()); - announceFailedTakedown(); - } - } - - private void updateTargetIfLost() { - Monster mm = (Monster)m; - LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); - if (mm.getTarget()==null || !mm.getTarget().isValid() || - les.GetTarget()==null || !mm.getTarget().isValid() || - (!isFlying && (mm.getTarget().getLocation().distanceSquared(mm.getLocation())>2500 || - les.GetTarget().getLocation().distanceSquared(mm.getLocation())>2500 - ))) { - //See if there's another participant in the list. Choose randomly. - while (participantlist.size()>0) { - Player p = participantlist.get((int)(Math.random()*participantlist.size())); - if (p!=null && p.isValid() && !p.isDead() && - (isFlying || p.getLocation().distanceSquared(mm.getLocation())<=2500)) { - mm.setTarget(p); - les.SetTarget(p); - break; - } else { - participantlist.remove(p); - } - } - if (participantlist.size()==0 && startedfight) { - //This fight has failed. - announceFailedTakedown(); - startedfight=false; - } - } - } - public void announceFailedTakedown() { + super.announceFailedTakedown(); if (dpslist.size()>0 && !m.isDead()) { phaseii=false; - Bukkit.getServer().broadcastMessage(GenericFunctions.getDisplayName(m)+" Takedown Failed..."); - Bukkit.getServer().broadcastMessage(ChatColor.YELLOW+"DPS Breakdown:"); - Bukkit.getServer().broadcastMessage(generateDPSReport()); - aPlugin.API.discordSendRaw(GenericFunctions.getDisplayName(m)+" Takedown Failed...\n\n"+ChatColor.YELLOW+"DPS Breakdown:"+"\n```\n"+generateDPSReport()+"\n```"); - dpslist.clear(); PerformSpiderCleanup(); PerformSilverfishAndEndermiteCleanup(); - healthbar.setColor(BarColor.WHITE); } } @@ -929,36 +816,6 @@ public class Knight extends CustomMonster{ spider_pet.cleanup(); } } - - public String generateDPSReport() { - //Sorts a list of players by DPS contribution. - List sorted_dmg = new ArrayList(); - List sorted_pl = new ArrayList(); - double totaldmg = 0; - for (String pl : dpslist.keySet()) { - double dmg = dpslist.get(pl); - int slot = 0; - totaldmg+=dmg; - for (int i=0;isorted_dmg.get(i)) { - break; - } else { - slot++; - } - } - sorted_pl.add(slot,pl); - sorted_dmg.add(slot,dmg); - } - StringBuilder finalstr = new StringBuilder(); - DecimalFormat df = new DecimalFormat("0.00"); - for (int i=0;i{ - m.setVelocity(m.getVelocity().multiply(0.1)); - }, 1); - healthbar.setProgress(m.getHealth()/m.getMaxHealth()); - lasthit=TwosideKeeper.getServerTickTime(); - if (!startedfight) { - startedfight=true; - healthbar.setColor(BarColor.BLUE); - } - m.setAI(true); - } - - private void addTarget(LivingEntity damager, double dmg) { - if (damager instanceof Player) { - Player p = (Player)damager; - addParticipant(p); - if (!dpslist.containsKey(p.getName())) { - dpslist.put(p.getName(), dmg); - } else { - dpslist.put(p.getName(), dpslist.get(p.getName())+dmg); - } - } - } - - public void addParticipant(Player p) { - if (!participantlist.contains(p)) { - participantlist.add(p); - } + public double getKnockbackMult() { + return 0.1; } + private void displayDarkSwordParticles() { Location sparkleloc = m.getEyeLocation().add(0,-0.25,0); sparkleloc.setDirection(m.getLocation().getDirection().multiply(3)); @@ -1041,40 +871,6 @@ public class Knight extends CustomMonster{ return false; } - private void updateHealthbarForNearbyPlayers() { - for (Player p : healthbar.getPlayers()) { - if (p.getLocation().distanceSquared(m.getLocation())>2500) { - healthbar.removePlayer(p); - if (shieldbar!=null) { - shieldbar.removePlayer(p); - } - } - } - for (Entity e : m.getNearbyEntities(50, 50, 50)) { - if (e instanceof Player) { - Player p = (Player)e; - healthbar.addPlayer(p); - if (shieldbar!=null) { - shieldbar.addPlayer(p); - } - } - } - if (shieldbar==null && CustomDamage.getAbsorptionHearts(m)>0) { - shieldbar = Bukkit.getServer().createBossBar(GenericFunctions.getDisplayName(m)+"'s Shield", BarColor.WHITE, BarStyle.SEGMENTED_6, BarFlag.CREATE_FOG); - GenericFunctions.logAndApplyPotionEffectToEntity(PotionEffectType.INVISIBILITY, DARKCLEANSE.getCastTimes()[getDifficultySlot()], 1, m, true); - shieldbar.setProgress(Math.min(CustomDamage.getAbsorptionHearts(m)/SHIELD_AMT[getDifficultySlot()],1)); - for (Player p : healthbar.getPlayers()) { - shieldbar.addPlayer(p); - } - } - if (shieldbar!=null && m.hasPotionEffect(PotionEffectType.INVISIBILITY) && - CustomDamage.getAbsorptionHearts(m)<=0) { - GenericFunctions.logAndRemovePotionEffectFromEntity(PotionEffectType.INVISIBILITY, m); - shieldbar.removeAll(); - shieldbar=null; - } - } - private void SetupSpiderPet(LivingEntity m) { if (!TwosideKeeper.custommonsters.containsKey(m)) { TwosideKeeper.custommonsters.put(m.getUniqueId(),new DarkSpider((LivingEntity)m)); @@ -1130,7 +926,7 @@ public class Knight extends CustomMonster{ } public void cleanup() { - healthbar.removeAll(); + super.cleanup(); if (shieldbar!=null) { shieldbar.removeAll(); } @@ -1157,32 +953,239 @@ public class Knight extends CustomMonster{ endermites.clear(); } - protected void increaseBarTextScroll() { - scroll++; - switch (scroll%22) { - case 11:{ - arrow=" -"; - }break; - case 12:{ - arrow=" "; - }break; - case 13:{ - arrow="> "; - }break; - case 14:{ - arrow="->"; - }break; + public void setupBonusLoot() { + LivingEntityDifficulty diff = MonsterController.getLivingEntityDifficulty(m); + LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); + GlobalLoot gl = GlobalLoot.spawnGlobalLoot(m.getLocation(), ChatColor.AQUA+""+ChatColor.BOLD+les.getDifficultyAndMonsterName()+ChatColor.AQUA+""+ChatColor.BOLD+" Miniboss Loot"); + double lootrate=1.0; + for (Player p : participantlist) { + PlayerMode mode = getMostUsedPlayerMode(p); + switch (diff) { + case T2_MINIBOSS:{ + lootrate+=0.5; + }break; + case T3_MINIBOSS:{ + lootrate+=1.0; + }break; + } + double lootamt = lootrate; + while (lootamt>0) { + if ((lootamt-1)>=0 || + Math.random()<=lootamt) { + gl.addNewDropInventory(p,GetSetPiece(diff,mode)); //Guaranteed Loot Piece. + } + lootamt--; + } + AttemptRoll(gl, 0.33*lootrate, p, GetSetPiece(diff,PlayerMode.values()[(int)(Math.random()*PlayerMode.values().length)])); + AttemptRoll(gl, 0.33*lootrate, p, GetSetPiece(diff,PlayerMode.values()[(int)(Math.random()*PlayerMode.values().length)])); + + AttemptRoll(gl, 0.75*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MYSTERIOUS_ESSENCE, (int)(Math.random()*3)+1)); + switch (diff) { + case T1_MINIBOSS:{ + AttemptRoll(gl, 0.5*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.25*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_CORE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.125*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MALLEABLE_BASE, 1)); + }break; + case T2_MINIBOSS:{ + AttemptRoll(gl, 0.5*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ANCIENT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.25*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.125*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MALLEABLE_BASE, 1)); + }break; + case T3_MINIBOSS:{ + AttemptRoll(gl, 0.5*lootrate, p, Artifact.createArtifactItem(ArtifactItem.LOST_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.25*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.125*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MALLEABLE_BASE, 1)); + }break; + } + //Artifact.createRecipe(5, ArtifactItemType.SHOVEL) + AttemptRoll(gl, 0.08*lootrate, p, GetArtifactRecipe(diff)); + AttemptRoll(gl, 0.02*lootrate, p, GetMaterialKit(diff)); + AttemptRoll(gl, 0.5*lootrate, p, new DropRandomFood((int)(Math.random()*10)+1,0,0.5,100).getItemStack()); + AttemptRoll(gl, 0.33*lootrate, p, new DropRandomFood((int)(Math.random()*10)+1,0,0.5,500).getItemStack()); + AttemptRoll(gl, 0.1*lootrate, p, new DropRandomFood((int)(Math.random()*10)+1,0,0.5,1000).getItemStack()); + AttemptRoll(gl, 0.5*lootrate, p, new DropRandomEnchantedBook(0,2).getItemStack()); + AttemptRoll(gl, 0.33*lootrate, p, new DropRandomEnchantedBook(0,4).getItemStack()); + AttemptRoll(gl, 0.1*lootrate, p, new DropRandomEnchantedBook(0,6).getItemStack()); + AttemptRoll(gl, 0.15*lootrate, p, TwosideKeeper.HUNTERS_COMPASS.getItemStack()); + AttemptRoll(gl, 0.05*lootrate, p, getVial(diff)); } } - - public void onDeathEvent() { - Bukkit.getServer().broadcastMessage(ChatColor.YELLOW+"DPS Breakdown:"); - Bukkit.getServer().broadcastMessage(generateDPSReport()); - aPlugin.API.discordSendRaw(ChatColor.YELLOW+"DPS Breakdown:"+"\n```\n"+generateDPSReport()+"\n```"); - cleanup(); + + private ItemStack getVial(LivingEntityDifficulty diff) { + switch (diff) { + case T1_MINIBOSS:{ + return TwosideKeeper.STRENGTHENING_VIAL.getItemStack(); + } + case T2_MINIBOSS:{ + return TwosideKeeper.LIFE_VIAL.getItemStack(); + } + case T3_MINIBOSS:{ + return TwosideKeeper.HARDENING_VIAL.getItemStack(); + } + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating material kit. Diff: "+diff, 1); + DebugUtils.showStackTrace(); + return null; + } + + private ItemStack GetMaterialKit(LivingEntityDifficulty diff) { + switch (diff) { + case T1_MINIBOSS:{ + return CustomItem.IronMaterialKit(); + } + case T2_MINIBOSS:{ + if (Math.random()<=0.5) { + return CustomItem.DiamondMaterialKit(); + } else { + return CustomItem.IronMaterialKit(); + } + } + case T3_MINIBOSS:{ + if (Math.random()<=0.33) { + return CustomItem.IronMaterialKit(); + } else + if (Math.random()<=0.5){ + return CustomItem.DiamondMaterialKit(); + } else { + return CustomItem.GoldMaterialKit(); + } + } + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating material kit. Diff: "+diff, 1); + DebugUtils.showStackTrace(); + return null; } - public List getParticipants() { - return participantlist; + private ItemStack GetArtifactRecipe(LivingEntityDifficulty diff) { + ArtifactItemType type = ArtifactItemType.values()[(int)(Math.random()*ArtifactItemType.values().length)]; + switch (diff) { + case T1_MINIBOSS:{ + return Artifact.createRecipe(4, type); + } + case T2_MINIBOSS:{ + return Artifact.createRecipe(5, type); + } + case T3_MINIBOSS:{ + if (Math.random()<=0.1) { + return Artifact.createRecipe(8, type); + } else { + return Artifact.createRecipe(7, type); + } + } + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating artifact recipe. Diff: "+diff, 1); + DebugUtils.showStackTrace(); + return null; + } + + private void AttemptRoll(GlobalLoot loot, double chance, Player p, + ItemStack item) { + double lootamt = chance; + if (Math.random()<=lootamt) { + loot.addNewDropInventory(p,item); //Guaranteed Loot Piece. + } + } + + private ItemStack GetSetPiece(LivingEntityDifficulty diff, PlayerMode mode) { + switch (diff) { + case T1_MINIBOSS:{ + if (mode!=PlayerMode.SLAYER) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_BOOTS, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } else { + if (Math.random()<=0.4) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } else { + return TwosideKeeperAPI.generateSetPiece(Material.SKULL_ITEM, ItemSet.WOLFSBANE, (Math.random()<=0.1)?true:false, 3); + } + } + } + case T2_MINIBOSS:{ + if (Math.random()<=0.05) { + //Weapon roll. + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } else { + if (mode!=PlayerMode.SLAYER) { + if (Math.random()<=0.5) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_HELMET, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } else { + return TwosideKeeperAPI.generateSetPiece(Material.DIAMOND_BOOTS, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } + } else { + if (Math.random()<=0.4) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } else { + ItemSet[] baublesets = new ItemSet[]{ItemSet.WOLFSBANE,ItemSet.ALUSTINE}; + return TwosideKeeperAPI.generateSetPiece(Material.SKULL_ITEM, baublesets[(int)(Math.random()*baublesets.length)], (Math.random()<=0.2)?true:false, 3); + } + } + } + } + case T3_MINIBOSS:{ + if (Math.random()<=0.10) { + //Weapon roll. + switch ((int)(Math.random()*4)) { + case 0: + case 3:{ + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 3); + } + case 1:{ + return TwosideKeeperAPI.generateSetPiece(Material.DIAMOND_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } + case 2:{ + return TwosideKeeperAPI.generateSetPiece(Material.GOLD_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } + } + } else { + if (mode!=PlayerMode.SLAYER) { + switch ((int)(Math.random()*4)) { + case 0: + case 3:{ + Material[] armor = new Material[]{Material.IRON_HELMET,Material.IRON_CHESTPLATE,Material.IRON_LEGGINGS,Material.IRON_BOOTS,}; + return TwosideKeeperAPI.generateSetPiece(armor[(int)(Math.random()*armor.length)], getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 3); + } + case 1:{ + Material[] armor = new Material[]{Material.DIAMOND_HELMET,Material.DIAMOND_CHESTPLATE,Material.DIAMOND_LEGGINGS,Material.DIAMOND_BOOTS,}; + return TwosideKeeperAPI.generateSetPiece(armor[(int)(Math.random()*armor.length)], getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } + case 2:{ + Material[] armor = new Material[]{Material.GOLD_HELMET,Material.GOLD_CHESTPLATE,Material.GOLD_LEGGINGS,Material.GOLD_BOOTS,}; + return TwosideKeeperAPI.generateSetPiece(armor[(int)(Math.random()*armor.length)], getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } + } + } else { + if (Math.random()<=0.4) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 3); + } else { + ItemSet[] baublesets = new ItemSet[]{ItemSet.WOLFSBANE,ItemSet.ALUSTINE,ItemSet.MOONSHADOW,ItemSet.GLADOMAIN}; + return TwosideKeeperAPI.generateSetPiece(Material.SKULL_ITEM, baublesets[(int)(Math.random()*baublesets.length)], true, 3); + } + } + } + }break; + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating set piece. Diff: "+diff+", Mode: "+mode, 1); + DebugUtils.showStackTrace(); + return null; + } + + public static ItemSet getModeSpecificSet(PlayerMode mode) { + ItemSet[] allsets = new ItemSet[]{ItemSet.WINDRY,ItemSet.SHARD,ItemSet.PROTECTOR,ItemSet.LEGION,ItemSet.ASSASSIN,}; + switch (mode) { + case BARBARIAN: + return ItemSet.LEGION; + case DEFENDER: + return ItemSet.PROTECTOR; + case NORMAL: + return allsets[(int)(Math.random()*allsets.length)]; + case RANGER: + return ItemSet.SHARD; + case SLAYER: + return ItemSet.ASSASSIN; + case STRIKER: + return ItemSet.WINDRY; + default: + TwosideKeeper.log("WARNING! Could not find loot entry for mode "+mode+". This should not be happening!!", 1); + return allsets[(int)(Math.random()*allsets.length)]; + } } } diff --git a/src/sig/plugin/TwosideKeeper/Monster/SniperSkeleton.java b/src/sig/plugin/TwosideKeeper/Monster/SniperSkeleton.java index e0a06d7..0f34206 100644 --- a/src/sig/plugin/TwosideKeeper/Monster/SniperSkeleton.java +++ b/src/sig/plugin/TwosideKeeper/Monster/SniperSkeleton.java @@ -39,37 +39,39 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; import org.inventivetalent.glow.GlowAPI.Color; +import aPlugin.DropRandomEnchantedBook; +import aPlugin.DropRandomFood; +import sig.plugin.TwosideKeeper.Artifact; import sig.plugin.TwosideKeeper.Buff; import sig.plugin.TwosideKeeper.ChargeZombie; import sig.plugin.TwosideKeeper.CustomDamage; import sig.plugin.TwosideKeeper.CustomMonster; +import sig.plugin.TwosideKeeper.GlobalLoot; import sig.plugin.TwosideKeeper.LivingEntityStructure; import sig.plugin.TwosideKeeper.MonsterController; import sig.plugin.TwosideKeeper.TwosideKeeper; +import sig.plugin.TwosideKeeper.TwosideKeeperAPI; import sig.plugin.TwosideKeeper.Events.EntityChannelCastEvent; +import sig.plugin.TwosideKeeper.HelperStructures.ArtifactItem; +import sig.plugin.TwosideKeeper.HelperStructures.ArtifactItemType; import sig.plugin.TwosideKeeper.HelperStructures.BuffTemplate; import sig.plugin.TwosideKeeper.HelperStructures.Channel; +import sig.plugin.TwosideKeeper.HelperStructures.CustomItem; +import sig.plugin.TwosideKeeper.HelperStructures.ItemSet; import sig.plugin.TwosideKeeper.HelperStructures.LivingEntityDifficulty; +import sig.plugin.TwosideKeeper.HelperStructures.PlayerMode; import sig.plugin.TwosideKeeper.HelperStructures.Spell; import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions; import sig.plugin.TwosideKeeper.HelperStructures.Effects.HighlightCircle; +import sig.plugin.TwosideKeeper.HelperStructures.Utils.DebugUtils; import sig.plugin.TwosideKeeper.HelperStructures.Utils.EntityUtils; import sig.plugin.TwosideKeeper.HelperStructures.Utils.MovementUtils; import sig.plugin.TwosideKeeper.HelperStructures.Utils.SoundUtils; import sig.plugin.TwosideKeeper.HelperStructures.Utils.Classes.ColoredParticle; import sig.plugin.TwosideKeeper.HelperStructures.Utils.Classes.MixedDamage; -public class SniperSkeleton extends CustomMonster{ +public class SniperSkeleton extends GenericBoss{ - BossBar healthbar; - protected String arrow = "->"; - int scroll=0; - protected List participantlist = new ArrayList(); - protected HashMap dpslist = new HashMap(); - long lasthit; - boolean startedfight=false; - private long stuckTimer=0; - private Location lastLoc = null; MixedDamage[] BASIC_ATTACK_DAMAGE = new MixedDamage[]{MixedDamage.v(30),MixedDamage.v(50),MixedDamage.v(130, 0.02)}; final Spell PIERCING_ARROW = new Spell("Piercing Arrow",new int[]{40,20,20},new int[]{240,200,160},new MixedDamage[]{MixedDamage.v(100,0.02),MixedDamage.v(140,0.04),MixedDamage.v(200,0.08)}); final Spell BURNING_PLUME = new Spell("Burning Plume",new int[]{50,40,30},new int[]{300,240,200},new MixedDamage[]{MixedDamage.v(200,0.06),MixedDamage.v(300,0.08),MixedDamage.v(500,0.15)}); @@ -133,12 +135,7 @@ public class SniperSkeleton extends CustomMonster{ } public void runTick() { - updateHealthbarForNearbyPlayers(); - updateTargetIfLost(); - regenerateHealthAndResetBossIfIdle(); - keepHealthbarUpdated(); - unstuckIfStuck(); - increaseBarTextScroll(); + super.runTick(); performSpells(); updateAI(); removeIfTooOld(); @@ -357,12 +354,6 @@ public class SniperSkeleton extends CustomMonster{ bloodmites.add(bloodmite); } - private void announceMessageToParticipants(String msg) { - for (Player p : participantlist) { - p.sendMessage(msg); - } - } - protected boolean attemptSpellCast(Spell spell) { if (cooldownIsAvailable(spell.getLastCastedTime(),spell)) { //Face target. @@ -374,7 +365,7 @@ public class SniperSkeleton extends CustomMonster{ } public void cleanup() { - healthbar.removeAll(); + super.cleanup(); for (LivingEntity ent : bloodmites) { if (ent!=null && ent.isValid()) { ent.remove(); @@ -456,6 +447,19 @@ public class SniperSkeleton extends CustomMonster{ } } } + + public void announceFailedTakedown() { + super.announceFailedTakedown(); + if (dpslist.size()>0 && !m.isDead()) { + phaseii=false; + + for (LivingEntity ent : bloodmites) { + if (ent!=null && ent.isValid()) { + ent.remove(); + } + } + } + } private void runArrowRain() { new HighlightCircle(m.getLocation(),8,20,ARROW_RAIN.getCastTimes()[getDifficultySlot()]); @@ -601,119 +605,6 @@ public class SniperSkeleton extends CustomMonster{ return Math.random()<=1/8d && !Buff.hasBuff(m, "SILENCE") && startedfight && !Channel.isChanneling(m) && !m.hasPotionEffect(PotionEffectType.INVISIBILITY); } - private void unstuckIfStuck() { - if (!startedfight) { - ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); - } else - if (startedfight) { - lastLoc = m.getLocation().clone(); - if (lastLoc!=null && lastLoc.distance(m.getLocation())<=0.4) { - stuckTimer++; - //TwosideKeeper.log("Stuck. "+stuckTimer, 0); - ChargeZombie.BreakBlocksAroundArea((Monster)m, 1); - } else { - stuckTimer=0; - } - if (!Channel.isChanneling(m) && stuckTimer>5) { - //Teleport randomly. - double numb = Math.random(); - if (numb<=0.33) { - Location newloc = m.getLocation().add(Math.random()*10-5,0,0); - if (!newloc.getBlock().getType().isSolid() && - !newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { - SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); - m.teleport(newloc); - } - } else - if (numb<=0.5) { - Location newloc = m.getLocation().add(0,0,Math.random()*10-5); - if (!newloc.getBlock().getType().isSolid() && - !newloc.getBlock().getRelative(0,1,0).getType().isSolid()) { - SoundUtils.playGlobalSound(m.getLocation(), Sound.ENTITY_ENDERMEN_TELEPORT, 0.4f, 0.95f); - m.teleport(newloc); - } - } - stuckTimer=0; - } - } - } - - private void keepHealthbarUpdated() { - healthbar.setProgress(m.getHealth()/m.getMaxHealth()); - Monster me = (Monster)m; - String healthbarfooter = ((me.getTarget()!=null && (me.getTarget() instanceof Player))?(ChatColor.DARK_AQUA+" "+arrow+" "+ChatColor.YELLOW+((Player)me.getTarget()).getName()):""); - if (Channel.isChanneling(m)) { - healthbar.setTitle(LivingEntityStructure.getChannelingBar(m)+healthbarfooter); - } else { - healthbar.setTitle(GenericFunctions.getDisplayName(m)+healthbarfooter); - } - } - - private void regenerateHealthAndResetBossIfIdle() { - if (lasthit+20*15<=TwosideKeeper.getServerTickTime()) { - GenericFunctions.HealEntity(m, m.getMaxHealth()*0.01); - if (startedfight) { - healthbar.setColor(BarColor.GREEN); - } - } else { - if (startedfight) { - healthbar.setColor(BarColor.BLUE); - } - } - if (participantlist.size()==0 && startedfight) { - startedfight=false; - m.setAI(false); - m.setHealth(m.getMaxHealth()); - announceFailedTakedown(); - } - } - - private void updateTargetIfLost() { - Monster mm = (Monster)m; - LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); - if (mm.getTarget()==null || !mm.getTarget().isValid() || - les.GetTarget()==null || !mm.getTarget().isValid() || - ((mm.getTarget().getLocation().distanceSquared(mm.getLocation())>2500 || - les.GetTarget().getLocation().distanceSquared(mm.getLocation())>2500 - ))) { - //See if there's another participant in the list. Choose randomly. - while (participantlist.size()>0) { - Player p = participantlist.get((int)(Math.random()*participantlist.size())); - if (p!=null && p.isValid() && !p.isDead() && - (p.getLocation().distanceSquared(mm.getLocation())<=2500)) { - mm.setTarget(p); - les.SetTarget(p); - break; - } else { - participantlist.remove(p); - } - } - if (participantlist.size()==0 && startedfight) { - //This fight has failed. - announceFailedTakedown(); - startedfight=false; - } - } - } - - public void announceFailedTakedown() { - if (dpslist.size()>0 && !m.isDead()) { - phaseii=false; - Bukkit.getServer().broadcastMessage(GenericFunctions.getDisplayName(m)+" Takedown Failed..."); - Bukkit.getServer().broadcastMessage(ChatColor.YELLOW+"DPS Breakdown:"); - Bukkit.getServer().broadcastMessage(generateDPSReport()); - aPlugin.API.discordSendRaw(GenericFunctions.getDisplayName(m)+" Takedown Failed...\n\n"+ChatColor.YELLOW+"DPS Breakdown:"+"\n```\n"+generateDPSReport()+"\n```"); - dpslist.clear(); - healthbar.setColor(BarColor.WHITE); - - for (LivingEntity ent : bloodmites) { - if (ent!=null && ent.isValid()) { - ent.remove(); - } - } - } - } - public void announceSuccessfulTakedown() { if (dpslist.size()>0 && !m.isDead()) { phaseii=false; @@ -732,80 +623,8 @@ public class SniperSkeleton extends CustomMonster{ } } - public String generateDPSReport() { - //Sorts a list of players by DPS contribution. - List sorted_dmg = new ArrayList(); - List sorted_pl = new ArrayList(); - double totaldmg = 0; - for (String pl : dpslist.keySet()) { - double dmg = dpslist.get(pl); - int slot = 0; - totaldmg+=dmg; - for (int i=0;isorted_dmg.get(i)) { - break; - } else { - slot++; - } - } - sorted_pl.add(slot,pl); - sorted_dmg.add(slot,dmg); - } - StringBuilder finalstr = new StringBuilder(); - DecimalFormat df = new DecimalFormat("0.00"); - for (int i=0;i{ - m.setVelocity(m.getVelocity().multiply(0.33)); - }, 1); - healthbar.setProgress(m.getHealth()/m.getMaxHealth()); - lasthit=TwosideKeeper.getServerTickTime(); - if (!startedfight) { - startedfight=true; - healthbar.setColor(BarColor.BLUE); - } - m.setAI(true); - } - - private void addTarget(LivingEntity damager, double dmg) { - if (damager instanceof Player) { - Player p = (Player)damager; - addParticipant(p); - if (!dpslist.containsKey(p.getName())) { - dpslist.put(p.getName(), dmg); - } else { - dpslist.put(p.getName(), dpslist.get(p.getName())+dmg); - } - } - } - - public void addParticipant(Player p) { - if (!participantlist.contains(p)) { - participantlist.add(p); - } - } - - private void updateHealthbarForNearbyPlayers() { - for (Player p : healthbar.getPlayers()) { - if (p.getWorld().equals(m.getWorld()) && p.getLocation().distanceSquared(m.getLocation())>2500) { - healthbar.removePlayer(p); - } - } - for (Entity e : m.getNearbyEntities(50, 50, 50)) { - if (e instanceof Player) { - Player p = (Player)e; - healthbar.addPlayer(p); - } - } + public double getKnockbackMult() { + return 0.33; } public static boolean randomlyConvertAsSniperSkeleton(LivingEntity m, boolean force) { @@ -842,28 +661,248 @@ public class SniperSkeleton extends CustomMonster{ MonsterController.getLivingEntityDifficulty(m)==LivingEntityDifficulty.T3_MINIBOSS ); } - - protected void increaseBarTextScroll() { - scroll++; - switch (scroll%22) { - case 11:{ - arrow=" -"; - }break; - case 12:{ - arrow=" "; - }break; - case 13:{ - arrow="> "; - }break; - case 14:{ - arrow="->"; - }break; - } - } enum ShotMode { NORMAL, POISON, BLEED } + + + + public void setupBonusLoot() { + LivingEntityDifficulty diff = MonsterController.getLivingEntityDifficulty(m); + LivingEntityStructure les = LivingEntityStructure.GetLivingEntityStructure(m); + GlobalLoot gl = GlobalLoot.spawnGlobalLoot(m.getLocation(), ChatColor.AQUA+""+ChatColor.BOLD+les.getDifficultyAndMonsterName()+ChatColor.AQUA+""+ChatColor.BOLD+" Miniboss Loot"); + double lootrate=1.0; + for (Player p : participantlist) { + PlayerMode mode = getMostUsedPlayerMode(p); + switch (diff) { + case T2_MINIBOSS:{ + lootrate+=0.5; + }break; + case T3_MINIBOSS:{ + lootrate+=1.0; + }break; + } + double lootamt = lootrate; + while (lootamt>0) { + if ((lootamt-1)>=0 || + Math.random()<=lootamt) { + gl.addNewDropInventory(p,GetSetPiece(diff,mode)); //Guaranteed Loot Piece. + } + lootamt--; + } + AttemptRoll(gl, 0.33*lootrate, p, GetSetPiece(diff,PlayerMode.values()[(int)(Math.random()*PlayerMode.values().length)])); + AttemptRoll(gl, 0.33*lootrate, p, GetSetPiece(diff,PlayerMode.values()[(int)(Math.random()*PlayerMode.values().length)])); + + AttemptRoll(gl, 0.75*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MYSTERIOUS_ESSENCE, (int)(Math.random()*3)+1)); + switch (diff) { + case T1_MINIBOSS:{ + AttemptRoll(gl, 0.5*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.25*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_CORE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.125*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MALLEABLE_BASE, 1)); + }break; + case T2_MINIBOSS:{ + AttemptRoll(gl, 0.5*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ANCIENT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.25*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.125*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MALLEABLE_BASE, 1)); + }break; + case T3_MINIBOSS:{ + AttemptRoll(gl, 0.5*lootrate, p, Artifact.createArtifactItem(ArtifactItem.LOST_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.25*lootrate, p, Artifact.createArtifactItem(ArtifactItem.ARTIFACT_ESSENCE, (int)(Math.random()*3)+1)); + AttemptRoll(gl, 0.125*lootrate, p, Artifact.createArtifactItem(ArtifactItem.MALLEABLE_BASE, 1)); + }break; + } + //Artifact.createRecipe(5, ArtifactItemType.SHOVEL) + AttemptRoll(gl, 0.08*lootrate, p, GetArtifactRecipe(diff)); + AttemptRoll(gl, 0.02*lootrate, p, GetMaterialKit(diff)); + AttemptRoll(gl, 0.5*lootrate, p, new DropRandomFood((int)(Math.random()*10)+1,0,0.5,100).getItemStack()); + AttemptRoll(gl, 0.33*lootrate, p, new DropRandomFood((int)(Math.random()*10)+1,0,0.5,500).getItemStack()); + AttemptRoll(gl, 0.1*lootrate, p, new DropRandomFood((int)(Math.random()*10)+1,0,0.5,1000).getItemStack()); + AttemptRoll(gl, 0.5*lootrate, p, new DropRandomEnchantedBook(0,2).getItemStack()); + AttemptRoll(gl, 0.33*lootrate, p, new DropRandomEnchantedBook(0,4).getItemStack()); + AttemptRoll(gl, 0.1*lootrate, p, new DropRandomEnchantedBook(0,6).getItemStack()); + AttemptRoll(gl, 0.15*lootrate, p, TwosideKeeper.HUNTERS_COMPASS.getItemStack()); + AttemptRoll(gl, 0.05*lootrate, p, getVial(diff)); + } + } + + private ItemStack getVial(LivingEntityDifficulty diff) { + switch (diff) { + case T1_MINIBOSS:{ + return TwosideKeeper.STRENGTHENING_VIAL.getItemStack(); + } + case T2_MINIBOSS:{ + return TwosideKeeper.LIFE_VIAL.getItemStack(); + } + case T3_MINIBOSS:{ + return TwosideKeeper.HARDENING_VIAL.getItemStack(); + } + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating material kit. Diff: "+diff, 1); + DebugUtils.showStackTrace(); + return null; + } + + private ItemStack GetMaterialKit(LivingEntityDifficulty diff) { + switch (diff) { + case T1_MINIBOSS:{ + return CustomItem.IronMaterialKit(); + } + case T2_MINIBOSS:{ + if (Math.random()<=0.5) { + return CustomItem.DiamondMaterialKit(); + } else { + return CustomItem.IronMaterialKit(); + } + } + case T3_MINIBOSS:{ + if (Math.random()<=0.33) { + return CustomItem.IronMaterialKit(); + } else + if (Math.random()<=0.5){ + return CustomItem.DiamondMaterialKit(); + } else { + return CustomItem.GoldMaterialKit(); + } + } + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating material kit. Diff: "+diff, 1); + DebugUtils.showStackTrace(); + return null; + } + + private ItemStack GetArtifactRecipe(LivingEntityDifficulty diff) { + ArtifactItemType type = ArtifactItemType.values()[(int)(Math.random()*ArtifactItemType.values().length)]; + switch (diff) { + case T1_MINIBOSS:{ + return Artifact.createRecipe(4, type); + } + case T2_MINIBOSS:{ + return Artifact.createRecipe(5, type); + } + case T3_MINIBOSS:{ + if (Math.random()<=0.1) { + return Artifact.createRecipe(8, type); + } else { + return Artifact.createRecipe(7, type); + } + } + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating artifact recipe. Diff: "+diff, 1); + DebugUtils.showStackTrace(); + return null; + } + + private void AttemptRoll(GlobalLoot loot, double chance, Player p, + ItemStack item) { + double lootamt = chance; + if (Math.random()<=lootamt) { + loot.addNewDropInventory(p,item); //Guaranteed Loot Piece. + } + } + + private ItemStack GetSetPiece(LivingEntityDifficulty diff, PlayerMode mode) { + switch (diff) { + case T1_MINIBOSS:{ + if (mode!=PlayerMode.SLAYER) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_BOOTS, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } else { + if (Math.random()<=0.4) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } else { + return TwosideKeeperAPI.generateSetPiece(Material.SKULL_ITEM, ItemSet.WOLFSBANE, (Math.random()<=0.1)?true:false, 3); + } + } + } + case T2_MINIBOSS:{ + if (Math.random()<=0.05) { + //Weapon roll. + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } else { + if (mode!=PlayerMode.SLAYER) { + if (Math.random()<=0.5) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_HELMET, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } else { + return TwosideKeeperAPI.generateSetPiece(Material.DIAMOND_BOOTS, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } + } else { + if (Math.random()<=0.4) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } else { + ItemSet[] baublesets = new ItemSet[]{ItemSet.WOLFSBANE,ItemSet.ALUSTINE}; + return TwosideKeeperAPI.generateSetPiece(Material.SKULL_ITEM, baublesets[(int)(Math.random()*baublesets.length)], (Math.random()<=0.2)?true:false, 3); + } + } + } + } + case T3_MINIBOSS:{ + if (Math.random()<=0.10) { + //Weapon roll. + switch ((int)(Math.random()*4)) { + case 0: + case 3:{ + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 3); + } + case 1:{ + return TwosideKeeperAPI.generateSetPiece(Material.DIAMOND_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } + case 2:{ + return TwosideKeeperAPI.generateSetPiece(Material.GOLD_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } + } + } else { + if (mode!=PlayerMode.SLAYER) { + switch ((int)(Math.random()*4)) { + case 0: + case 3:{ + Material[] armor = new Material[]{Material.IRON_HELMET,Material.IRON_CHESTPLATE,Material.IRON_LEGGINGS,Material.IRON_BOOTS,}; + return TwosideKeeperAPI.generateSetPiece(armor[(int)(Math.random()*armor.length)], getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 3); + } + case 1:{ + Material[] armor = new Material[]{Material.DIAMOND_HELMET,Material.DIAMOND_CHESTPLATE,Material.DIAMOND_LEGGINGS,Material.DIAMOND_BOOTS,}; + return TwosideKeeperAPI.generateSetPiece(armor[(int)(Math.random()*armor.length)], getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 2); + } + case 2:{ + Material[] armor = new Material[]{Material.GOLD_HELMET,Material.GOLD_CHESTPLATE,Material.GOLD_LEGGINGS,Material.GOLD_BOOTS,}; + return TwosideKeeperAPI.generateSetPiece(armor[(int)(Math.random()*armor.length)], getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 1); + } + } + } else { + if (Math.random()<=0.4) { + return TwosideKeeperAPI.generateSetPiece(Material.IRON_SWORD, getModeSpecificSet(mode), (Math.random()<=0.1)?true:false, 3); + } else { + ItemSet[] baublesets = new ItemSet[]{ItemSet.WOLFSBANE,ItemSet.ALUSTINE,ItemSet.MOONSHADOW,ItemSet.GLADOMAIN}; + return TwosideKeeperAPI.generateSetPiece(Material.SKULL_ITEM, baublesets[(int)(Math.random()*baublesets.length)], true, 3); + } + } + } + }break; + } + TwosideKeeper.log("WARNING! Something went terribly wrong while generating set piece. Diff: "+diff+", Mode: "+mode, 1); + DebugUtils.showStackTrace(); + return null; + } + + public static ItemSet getModeSpecificSet(PlayerMode mode) { + ItemSet[] allsets = new ItemSet[]{ItemSet.LUCI,ItemSet.TOXIN,ItemSet.SUSTENANCE,ItemSet.PRIDE,ItemSet.STEALTH,}; + switch (mode) { + case BARBARIAN: + return ItemSet.PRIDE; + case DEFENDER: + return ItemSet.SUSTENANCE; + case NORMAL: + return allsets[(int)(Math.random()*allsets.length)]; + case RANGER: + return ItemSet.TOXIN; + case SLAYER: + return ItemSet.STEALTH; + case STRIKER: + return ItemSet.LUCI; + default: + TwosideKeeper.log("WARNING! Could not find loot entry for mode "+mode+". This should not be happening!!", 1); + return allsets[(int)(Math.random()*allsets.length)]; + } + } } diff --git a/src/sig/plugin/TwosideKeeper/TwosideKeeper.java b/src/sig/plugin/TwosideKeeper/TwosideKeeper.java index 6566329..199d8f7 100644 --- a/src/sig/plugin/TwosideKeeper/TwosideKeeper.java +++ b/src/sig/plugin/TwosideKeeper/TwosideKeeper.java @@ -273,6 +273,7 @@ import sig.plugin.TwosideKeeper.Logging.BowModeLogger; import sig.plugin.TwosideKeeper.Logging.LootLogger; import sig.plugin.TwosideKeeper.Logging.MysteriousEssenceLogger; import sig.plugin.TwosideKeeper.Monster.Dummy; +import sig.plugin.TwosideKeeper.Monster.GenericBoss; import sig.plugin.TwosideKeeper.Monster.HellfireGhast; import sig.plugin.TwosideKeeper.Monster.Knight; import sig.plugin.TwosideKeeper.Monster.MonsterTemplate; @@ -481,6 +482,7 @@ public class TwosideKeeper extends JavaPlugin implements Listener { public static final int TIMINGS_DEBUG = 5; public static double worldShopDistanceSquared = 1000000; public static double worldShopPriceMult = 2.0; //How much higher the price increases for every increment of worlsShopDistanceSquared. + public static Inventory testinv = null; public static String lastActionBarMessage=""; public static long last_snow_golem = 0; @@ -532,6 +534,7 @@ public class TwosideKeeper extends JavaPlugin implements Listener { public List colors_used = new ArrayList(); public static HashMap chargezombies = new HashMap(); public static HashMap custommonsters = new HashMap(); + public static HashMap globalloot = new HashMap(); public static List elitemonsters = new ArrayList(); public static RecyclingCenter TwosideRecyclingCenter; @@ -1582,8 +1585,10 @@ public class TwosideKeeper extends JavaPlugin implements Listener { w.setHealth(10); }break; case "ELITE":{ - Guardian m = (Guardian)MonsterController.convertLivingEntity((LivingEntity)p.getWorld().spawnEntity(p.getLocation(),EntityType.GUARDIAN), LivingEntityDifficulty.ELITE); - m.setElder(true); + LivingEntity m = MonsterController.convertMonster((Monster)p.getWorld().spawnEntity(p.getLocation(),EntityType.ZOMBIE), MonsterDifficulty.ELITE); + m.setHealth(1); + //Guardian m = (Guardian)MonsterController.convertLivingEntity((LivingEntity)p.getWorld().spawnEntity(p.getLocation(),EntityType.GUARDIAN), LivingEntityDifficulty.ELITE); + //m.setElder(true); }break; case "VACUUM":{ ItemStack[] remaining = InventoryUtils.insertItemsInVacuumCube(p, new ItemStack(Material.ENDER_PEARL,16), new ItemStack(Material.IRON_PICKAXE,1), new ItemStack(Material.GOLDEN_APPLE,64)); @@ -2042,9 +2047,6 @@ public class TwosideKeeper extends JavaPlugin implements Listener { LivingEntityDifficulty.T1_MINIBOSS); SniperSkeleton.randomlyConvertAsSniperSkeleton(m,true); TwosideKeeper.custommonsters.put(m.getUniqueId(),new SniperSkeleton(m)); - Bukkit.getScheduler().runTaskLater(TwosideKeeper.plugin, ()->{ - m.setHealth(m.getMaxHealth()*0.3); - }, 20); }break; case "DAMAGETEST":{ LivingEntity m = MonsterController.convertLivingEntity((Skeleton)p.getWorld().spawnEntity(p.getLocation(),EntityType.SKELETON), @@ -2100,6 +2102,34 @@ public class TwosideKeeper extends JavaPlugin implements Listener { case "EFFECTPOOL":{ new EffectPool(p.getLocation(),2,20*10,Color.fromRGB(255, 255, 0)); }break; + case "KIT":{ + ItemStack giveitem = null; + switch (Integer.parseInt(args[1])) { + case 0:{ + giveitem = CustomItem.IronMaterialKit(); + }break; + case 1:{ + giveitem = CustomItem.DiamondMaterialKit(); + }break; + case 2:{ + giveitem = CustomItem.GoldMaterialKit(); + }break; + } + GenericFunctions.giveItem(p, giveitem); + } + case "INV":{ + switch (Integer.parseInt(args[1])) { + case 0:{ + GlobalLoot gl = GlobalLoot.spawnGlobalLoot(p.getLocation(), "Test Loot"); + gl.addNewDropInventory(p, new ItemStack[]{CustomItem.IronMaterialKit(),CustomItem.DiamondMaterialKit(),CustomItem.GoldMaterialKit()}); + }break; + } + }break; + case "SHARD":{ + ItemStack shard = TwosideKeeper.UPGRADE_SHARD.getItemStack(); + TwosideKeeperAPI.setUpgradeShardTier(shard, Integer.parseInt(args[1])); + GenericFunctions.giveItem(p, shard); + } } } //LivingEntity m = MonsterController.convertMonster((Monster)p.getWorld().spawnEntity(p.getLocation(),EntityType.ZOMBIE), MonsterDifficulty.ELITE); @@ -5482,6 +5512,10 @@ public class TwosideKeeper extends JavaPlugin implements Listener { public void onInventoryClose(InventoryCloseEvent ev) { if (ev.getPlayer() instanceof Player) { Player p = (Player)ev.getPlayer(); + for (UUID id : globalloot.keySet()) { + GlobalLoot loot = globalloot.get(id); + loot.runInventoryCloseEvent(ev); + } //log("Location of inventory: "+ev.getInventory().getLocation().toString(),2); if (DeathManager.deathStructureExists(p) && ev.getInventory().getTitle().contains("Death Loot")) { Location deathloc = DeathManager.getDeathStructure(p).deathloc; @@ -6485,6 +6519,7 @@ public class TwosideKeeper extends JavaPlugin implements Listener { } } } + List removalEntities = new ArrayList(); for (Entity e : ev.getChunk().getEntities()) { if (e instanceof LivingEntity) { LivingEntity l = (LivingEntity)e; @@ -6493,6 +6528,14 @@ public class TwosideKeeper extends JavaPlugin implements Listener { l.setCustomName(les.getUnloadedName()); } } + if (e instanceof Item) { + if (TwosideKeeper.globalloot.containsKey(e.getUniqueId())) { + removalEntities.add(e); + } + } + } + for (Entity e : removalEntities) { + e.remove(); } } @@ -7843,52 +7886,11 @@ public class TwosideKeeper extends JavaPlugin implements Listener { if (custommonsters.containsKey(m.getUniqueId())) { CustomMonster cm = custommonsters.get(m.getUniqueId()); - if (cm instanceof Knight) { - Knight k = (Knight)cm; - List participants = k.getParticipants(); - StringBuilder participants_list = new StringBuilder(); - for (int i=0;i participants = em.getParticipantList(); StringBuilder participants_list = new StringBuilder(); + GlobalLoot gl = GlobalLoot.spawnGlobalLoot(m.getLocation(), ChatColor.LIGHT_PURPLE+""+ChatColor.BOLD+"Elite Loot"); for (int i=0;i participants = ss.getParticipants(); + StringBuilder participants_list = new StringBuilder(); + for (int i=0;i50) { @@ -360,6 +363,15 @@ final class runServerHeartbeat implements Runnable { TwosideKeeper.HeartbeatLogger.AddEntry(ChatColor.LIGHT_PURPLE+"Total Server Heartbeat", (int)(System.nanoTime()-totaltime));totaltime=System.nanoTime(); } + private void PerformGlobalLootManagement() { + for (UUID id : TwosideKeeper.globalloot.keySet()) { + GlobalLoot gl = TwosideKeeper.globalloot.get(id); + if (!gl.runTick()) { + TwosideKeeper.ScheduleRemoval(TwosideKeeper.globalloot, gl.getItemUniqueID()); + } + } + } + private void PerformHighlightCircleEffects() { for (HighlightCircle hc : TwosideKeeper.circles) { if (!hc.runTick()) {