diff --git a/pom.xml b/pom.xml index 4528e129..40b6caab 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ strife - 3.4.4 + 3.4.5 jar strife @@ -109,7 +109,7 @@ LibsDisguises LibsDisguises - 10.0.16-SNAPSHOT + 10.0.26-SNAPSHOT provided diff --git a/src/main/java/land/face/strife/StrifePlugin.java b/src/main/java/land/face/strife/StrifePlugin.java index abc9c132..605ee98f 100644 --- a/src/main/java/land/face/strife/StrifePlugin.java +++ b/src/main/java/land/face/strife/StrifePlugin.java @@ -16,6 +16,13 @@ The MIT License Copyright (c) 2015 Teal Cube Games */ package land.face.strife; +import static com.comphenix.protocol.PacketType.Play.Server.ENTITY_METADATA; + +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.wrappers.WrappedWatchableObject; import com.comphenix.xp.lookup.LevelingRate; import com.tealcube.minecraft.bukkit.facecore.logging.PluginLogger; import com.tealcube.minecraft.bukkit.facecore.plugin.FacePlugin; @@ -51,6 +58,7 @@ The MIT License Copyright (c) 2015 Teal Cube Games import land.face.strife.data.UniqueEntity; import land.face.strife.data.ability.Ability; import land.face.strife.data.champion.LifeSkillType; +import land.face.strife.data.effects.Riptide; import land.face.strife.data.effects.ShootBlock; import land.face.strife.data.effects.TriggerLoreAbility; import land.face.strife.hooks.SnazzyPartiesHook; @@ -153,8 +161,11 @@ The MIT License Copyright (c) 2015 Teal Cube Games import org.bukkit.Material; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; +import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitTask; public class StrifePlugin extends FacePlugin { @@ -537,6 +548,37 @@ public void enable() { DamageUtil.refresh(); + Riptide.buildNMSEnum(this); + Riptide.startTask(this); + + ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(this, ENTITY_METADATA) { + public void onPacketSending(PacketEvent event) { + try { + int entityId = event.getPacket().getIntegers().read(0); + if (entityId < 0) { + return; + } + Entity entity = event.getPacket() + .getEntityModifier(event.getPlayer().getWorld()).read(0); + if (entity instanceof LivingEntity && Riptide + .isRiptideAnimationPlaying((LivingEntity) entity)) { + StructureModifier> watcher = event.getPacket() + .getWatchableCollectionModifier(); + for (WrappedWatchableObject watch : watcher.read(0)) { + if (watch.getIndex() == 6) { + watch.setValue(Riptide.RIPTIDE_POSE_ENUM); + } + if (watch.getIndex() == 7) { + watch.setValue((byte) 4); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + LogUtil.printInfo("Loaded " + uniqueEntityManager.getLoadedUniquesMap().size() + " mobs"); LogUtil.printInfo("Loaded " + effectManager.getLoadedEffects().size() + " effects"); LogUtil.printInfo("Loaded " + abilityManager.getLoadedAbilities().size() + " abilities"); @@ -552,6 +594,7 @@ public void disable() { entityHider.close(); HandlerList.unregisterAll(this); Bukkit.getScheduler().cancelTasks(this); + ProtocolLibrary.getProtocolManager().removePacketListeners(this); strifeMobManager.despawnAllTempEntities(); bossBarManager.clearBars(); @@ -579,6 +622,18 @@ public void disable() { LogUtil.printInfo("Successfully disabled Strife-v" + getDescription().getVersion()); } + public static Class getNMSClass(String name, Plugin plugin) { + String version = plugin.getServer().getClass().getPackage().getName().split("\\.")[3]; + try { + return Class.forName("net.minecraft.server." + version + "." + name); + } + + catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + } + private VersionedSmartYamlConfiguration defaultSettingsLoad(String name) { return new VersionedSmartYamlConfiguration(new File(getDataFolder(), name), getResource(name), VersionedConfiguration.VersionUpdateType.BACKUP_AND_UPDATE); diff --git a/src/main/java/land/face/strife/data/champion/Champion.java b/src/main/java/land/face/strife/data/champion/Champion.java index 83512497..48722bd4 100644 --- a/src/main/java/land/face/strife/data/champion/Champion.java +++ b/src/main/java/land/face/strife/data/champion/Champion.java @@ -24,12 +24,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import java.util.stream.IntStream; import land.face.strife.StrifePlugin; import land.face.strife.data.CombatDetailsContainer; import land.face.strife.managers.StatUpdateManager; import land.face.strife.stats.StrifeStat; import land.face.strife.stats.StrifeTrait; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; public class Champion { @@ -116,10 +118,10 @@ public int getPendingLevel(StrifeAttribute stat) { } public void buildAttributeHeatmap() { - float red = 0; - float yellow = 0; - float green = 0; - float blue = 0; + int red = 0; + int yellow = 0; + int green = 0; + int blue = 0; for (StrifeAttribute attribute : getLevelMap().keySet()) { switch (attribute.getKey()) { case "str": @@ -136,15 +138,27 @@ public void buildAttributeHeatmap() { break; } } - float total = red + yellow + green + blue; - red = red / total; - yellow = yellow / total; - green = green / total; - blue = blue / total; - attributeHeatmap = IntStream.range(0, (int) (red * 8)).mapToObj(i -> "⬤").toString() + - IntStream.range(0, (int) (yellow * 8)).mapToObj(i -> "⬤") + - IntStream.range(0, (int) (green * 8)).mapToObj(i -> "⬤") + - IntStream.range(0, (int) (blue * 8)).mapToObj(i -> "⬤"); + float total = Math.max(1, red + yellow + green + blue); + int segments = 40 - player.getName().length(); + + int redSegments = (int) Math.ceil((float) segments * (float) red / total); + total -= red; + segments -= redSegments; + + int yellowSegments = (int) Math.floor((float) segments * (float) yellow / total); + total -= yellow; + segments -= yellowSegments; + + int greenSegments = (int) Math.ceil((float) segments * (float) green / total); + segments -= greenSegments; + + int blueSegments = segments; + + attributeHeatmap = + ChatColor.RED + IntStream.range(0, redSegments).mapToObj(i -> "▌").collect(Collectors.joining()) + + ChatColor.YELLOW + IntStream.range(0, yellowSegments).mapToObj(i -> "▌").collect(Collectors.joining()) + + ChatColor.GREEN + IntStream.range(0, greenSegments).mapToObj(i -> "▌").collect(Collectors.joining()) + + ChatColor.BLUE + IntStream.range(0, blueSegments).mapToObj(i -> "▌").collect(Collectors.joining()); } public String getAttributeHeatmap() { @@ -181,7 +195,6 @@ public int getUnusedStatPoints() { public void setUnusedStatPoints(int unusedStatPoints) { saveData.setUnusedStatPoints(unusedStatPoints); - buildAttributeHeatmap(); } public int getPendingUnusedStatPoints() { diff --git a/src/main/java/land/face/strife/data/champion/LifeSkillType.java b/src/main/java/land/face/strife/data/champion/LifeSkillType.java index 80657446..31adff5d 100644 --- a/src/main/java/land/face/strife/data/champion/LifeSkillType.java +++ b/src/main/java/land/face/strife/data/champion/LifeSkillType.java @@ -6,7 +6,7 @@ public enum LifeSkillType { CRAFTING("Crafting", "crafting", ChatColor.YELLOW), - ENCHANTING("Enchanting", "enchant", ChatColor.of(new Color(128, 93, 255))), + ENCHANTING("Enchanting", "enchant", ChatColor.of(new Color(113, 79, 236))), FISHING("Fishing", "fishing", ChatColor.AQUA), MINING("Mining", "mining", ChatColor.DARK_GREEN), FARMING("Gathering", "farming", ChatColor.of(new Color(255, 192, 87))), @@ -15,6 +15,7 @@ public enum LifeSkillType { SNEAK("Sneak", "sneak", ChatColor.GRAY), AGILITY("Agility", "agility", ChatColor.DARK_AQUA), TRADING("Trading", "trading", ChatColor.DARK_GREEN), + FLYING("Flying", "flying", ChatColor.of(new Color(114, 187, 255))), SWORDSMANSHIP("Swordsmanship", "sword", ChatColor.RED, true), DAGGER_MASTERY("Dagger Mastery", "dagger", ChatColor.of(new Color(204, 246, 102)), true), AXE_MASTERY("Axe Mastery", "axe", ChatColor.RED, true), @@ -61,7 +62,7 @@ public ChatColor getColor() { return color; } - public boolean isComnbat() { + public boolean isCombat() { return combat; } } diff --git a/src/main/java/land/face/strife/data/conditions/Condition.java b/src/main/java/land/face/strife/data/conditions/Condition.java index d3017aa9..2e3f5b13 100644 --- a/src/main/java/land/face/strife/data/conditions/Condition.java +++ b/src/main/java/land/face/strife/data/conditions/Condition.java @@ -121,6 +121,7 @@ public enum ConditionType { ENTITY_TYPE, UNIQUE_ID, FACTION_MEMBER, + FLYING, VELOCITY, GROUNDED, BLEEDING, diff --git a/src/main/java/land/face/strife/data/conditions/FlyingCondition.java b/src/main/java/land/face/strife/data/conditions/FlyingCondition.java new file mode 100644 index 00000000..dec0c905 --- /dev/null +++ b/src/main/java/land/face/strife/data/conditions/FlyingCondition.java @@ -0,0 +1,13 @@ +package land.face.strife.data.conditions; + +import land.face.strife.data.StrifeMob; + +public class FlyingCondition extends Condition { + + public boolean isMet(StrifeMob attacker, StrifeMob target) { + if (getCompareTarget() == CompareTarget.SELF) { + target = attacker; + } + return target.getEntity().isGliding(); + } +} diff --git a/src/main/java/land/face/strife/data/effects/Damage.java b/src/main/java/land/face/strife/data/effects/Damage.java index 4e3fe9f7..e2425f43 100644 --- a/src/main/java/land/face/strife/data/effects/Damage.java +++ b/src/main/java/land/face/strife/data/effects/Damage.java @@ -58,7 +58,7 @@ public void apply(StrifeMob caster, StrifeMob target) { mods.setApplyOnHitEffects(applyOnHitEffects); mods.setShowPopoffs(showPopoffs); mods.setBypassBarrier(bypassBarrier); - mods.setScaleChancesWithAttack(true); + mods.setScaleChancesWithAttack(false); if (canSneakAttack && caster.getEntity() instanceof Player && getPlugin().getStealthManager() .canSneakAttack((Player) caster.getEntity())) { mods.setSneakAttack(true); diff --git a/src/main/java/land/face/strife/data/effects/Effect.java b/src/main/java/land/face/strife/data/effects/Effect.java index 3cc15ba2..17f90726 100644 --- a/src/main/java/land/face/strife/data/effects/Effect.java +++ b/src/main/java/land/face/strife/data/effects/Effect.java @@ -119,6 +119,7 @@ public enum EffectType { RESTORE_ENERGY, INCREASE_RAGE, PROJECTILE, + RIPTIDE, EQUIPMENT_SWAP, EVOKER_FANGS, FALLING_BLOCK, diff --git a/src/main/java/land/face/strife/data/effects/Push.java b/src/main/java/land/face/strife/data/effects/Push.java index 5e5e8322..c084c909 100644 --- a/src/main/java/land/face/strife/data/effects/Push.java +++ b/src/main/java/land/face/strife/data/effects/Push.java @@ -1,8 +1,9 @@ package land.face.strife.data.effects; +import com.tealcube.minecraft.bukkit.shade.apache.commons.lang3.StringUtils; import land.face.strife.data.StrifeMob; import land.face.strife.util.LogUtil; -import org.bukkit.craftbukkit.libs.org.apache.commons.lang3.StringUtils; +import lombok.Setter; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.util.Vector; @@ -13,6 +14,8 @@ public class Push extends Effect { private double height; private boolean cancelFall; private boolean clamp; + @Setter + private boolean uncheckedHeight; private PushType pushType; private Vector tempVector; @@ -32,19 +35,22 @@ public void apply(StrifeMob caster, StrifeMob target) { direction = getEffectVelocity(caster.getEntity().getLocation().toVector(), target.getEntity()); break; case CASTER_DIRECTION: - Vector casterDir = caster.getEntity().getLocation().getDirection(); - if (casterDir.getX() == 0 && casterDir.getZ() == 0) { - direction = new Vector(power / 10, 0, 0); - } else { - direction = casterDir.setY(0).normalize().multiply(power / 10); + direction = caster.getEntity().getLocation().getDirection(); + if (!uncheckedHeight) { + direction.setY(0.001); } + direction.normalize().multiply(power / 10); break; case TEMP_DIRECTION: LogUtil.printDebug(tempVector.getX() + " " + tempVector.getY() + " " + tempVector.getZ()); direction = getEffectVelocity(tempVector, target.getEntity()); break; case WSE_DIRECTION: - direction = tempVector.clone().setY(0.001).normalize().multiply(power / 10); + direction = tempVector.clone(); + if (!uncheckedHeight) { + direction.setY(0.001); + } + direction.normalize().multiply(power / 10); break; default: return; @@ -57,13 +63,23 @@ public void apply(StrifeMob caster, StrifeMob target) { } target.getEntity().setFallDistance(0); } - if (clamp) { - newVelocity.setX(clampRay(oldVelocity.getX(), direction.getX())); - newVelocity.setY(clampRay(oldVelocity.getY(), height / 10)); - newVelocity.setZ(clampRay(oldVelocity.getZ(), direction.getZ())); + if (uncheckedHeight) { + if (clamp) { + newVelocity.setX(clampRay(oldVelocity.getX(), direction.getX())); + newVelocity.setY(clampRay(oldVelocity.getY(), direction.getY())); + newVelocity.setZ(clampRay(oldVelocity.getZ(), direction.getZ())); + } else { + newVelocity.add(direction); + } } else { - newVelocity.add(direction); - newVelocity.add(new Vector(0, height / 10, 0)); + if (clamp) { + newVelocity.setX(clampRay(oldVelocity.getX(), direction.getX())); + newVelocity.setY(clampRay(oldVelocity.getY(), height / 10)); + newVelocity.setZ(clampRay(oldVelocity.getZ(), direction.getZ())); + } else { + newVelocity.add(direction); + newVelocity.add(new Vector(0, height / 10, 0)); + } } target.getEntity().setVelocity(newVelocity); } @@ -91,8 +107,11 @@ private Vector getEffectVelocity(Vector originLocation, Entity to) { if (originLocation.equals(to.getLocation().toVector())) { return new Vector(0, power / 10, 0); } - return to.getLocation().toVector().subtract(originLocation).setY(0.001).normalize() - .multiply(power / 10); + Vector velocity = to.getLocation().toVector().subtract(originLocation); + if (!uncheckedHeight) { + velocity.setY(0.001); + } + return velocity.normalize().multiply(power / 10); } public void setPower(double power) { diff --git a/src/main/java/land/face/strife/data/effects/Riptide.java b/src/main/java/land/face/strife/data/effects/Riptide.java new file mode 100644 index 00000000..1d868cc1 --- /dev/null +++ b/src/main/java/land/face/strife/data/effects/Riptide.java @@ -0,0 +1,114 @@ +package land.face.strife.data.effects; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; +import land.face.strife.StrifePlugin; +import land.face.strife.data.StrifeMob; +import lombok.Setter; +import org.bukkit.Bukkit; +import org.bukkit.entity.LivingEntity; +import org.bukkit.scheduler.BukkitTask; + +public class Riptide extends Effect { + + public static Object RIPTIDE_POSE_ENUM = null; + public static Object STANDING_POSE_ENUM = null; + private static Map RIPTIDE_MAP = new WeakHashMap<>(); + private static BukkitTask TASK = null; + + @Setter + private int ticks; + + @Override + public void apply(StrifeMob caster, StrifeMob target) { + if (RIPTIDE_POSE_ENUM == null || STANDING_POSE_ENUM == null) { + return; + } + RIPTIDE_MAP.put(target.getEntity(), ticks); + try { + PacketContainer fakeSpin = ProtocolLibrary.getProtocolManager() + .createPacket(PacketType.Play.Server.ENTITY_METADATA); + + WrappedDataWatcher w = WrappedDataWatcher.getEntityWatcher(target.getEntity()); + w.setObject(6, RIPTIDE_POSE_ENUM); + w.setObject(7, (byte) 4); + + fakeSpin.getWatchableCollectionModifier().write(0, w.getWatchableObjects()); + + ProtocolLibrary.getProtocolManager().broadcastServerPacket(fakeSpin); + } catch (Exception e) { + sendCancelPacket(target.getEntity()); + e.printStackTrace(); + } + } + + private static void tickRiptide() { + Iterator iterator = RIPTIDE_MAP.keySet().iterator(); + while (iterator.hasNext()) { + LivingEntity le = iterator.next(); + if (!le.isValid()) { + Bukkit.getLogger().info("CANCELED INVALID"); + sendCancelPacket(le); + continue; + } + if (le.getVelocity().getY() < 0.1 && le.isOnGround()) { + Bukkit.getLogger().info("CANCELED GROUND"); + continue; + } + if (RIPTIDE_MAP.get(le) < 1) { + Bukkit.getLogger().info("CANCELED TIMEOUT"); + sendCancelPacket(le); + continue; + } + RIPTIDE_MAP.put(le, RIPTIDE_MAP.get(le) - 1); + } + } + + public static boolean isRiptideAnimationPlaying(LivingEntity target) { + return RIPTIDE_MAP.containsKey(target); + } + + public static void sendCancelPacket(LivingEntity target) { + RIPTIDE_MAP.remove(target); + try { + PacketContainer restoreStanding = ProtocolLibrary.getProtocolManager() + .createPacket(PacketType.Play.Server.ENTITY_METADATA); + + WrappedDataWatcher w = WrappedDataWatcher.getEntityWatcher(target); + w.setObject(6, STANDING_POSE_ENUM); + w.setObject(7, (byte) 0); + + restoreStanding.getWatchableCollectionModifier().write(0, w.getWatchableObjects()); + + ProtocolLibrary.getProtocolManager().broadcastServerPacket(restoreStanding); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void startTask(StrifePlugin plugin) { + if (TASK != null) { + TASK.cancel(); + } + if (TASK == null || TASK.isCancelled()) { + TASK = Bukkit.getScheduler().runTaskTimer(plugin, Riptide::tickRiptide, 200L, 2L); + } + } + + public static void buildNMSEnum(StrifePlugin plugin) { + try { + RIPTIDE_POSE_ENUM = StrifePlugin.getNMSClass("EntityPose", plugin) + .getField("SPIN_ATTACK").get(null); + STANDING_POSE_ENUM = StrifePlugin.getNMSClass("EntityPose", plugin) + .getField("STANDING").get(null); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/land/face/strife/listeners/CombatListener.java b/src/main/java/land/face/strife/listeners/CombatListener.java index 21024074..04bfe8f2 100644 --- a/src/main/java/land/face/strife/listeners/CombatListener.java +++ b/src/main/java/land/face/strife/listeners/CombatListener.java @@ -33,6 +33,7 @@ import land.face.strife.data.effects.Effect; import land.face.strife.events.StrifeDamageEvent; import land.face.strife.stats.StrifeStat; +import land.face.strife.stats.StrifeTrait; import land.face.strife.util.DamageUtil; import land.face.strife.util.DamageUtil.AbilityMod; import land.face.strife.util.DamageUtil.AttackType; @@ -297,6 +298,15 @@ public void strifeDamageHandler(EntityDamageByEntityEvent event) { } } + if (defender.hasTrait(StrifeTrait.BLEEDING_EDGE)) { + finalDamage *= 0.5; + float bleed = finalDamage; + if (defender.getStat(StrifeStat.BLEED_RESIST) > 0) { + bleed *= 1 - defender.getStat(StrifeStat.BLEED_RESIST) / 100; + } + DamageUtil.applyBleed(defender, bleed, true); + } + Bukkit.getScheduler().runTaskLater(plugin, () -> DamageUtil.postDamage(attacker, defender, damageModifiers), 0L); diff --git a/src/main/java/land/face/strife/listeners/DataListener.java b/src/main/java/land/face/strife/listeners/DataListener.java index 7ab7f2ce..f9e6b79a 100644 --- a/src/main/java/land/face/strife/listeners/DataListener.java +++ b/src/main/java/land/face/strife/listeners/DataListener.java @@ -21,6 +21,7 @@ import land.face.strife.data.StrifeMob; import land.face.strife.data.champion.Champion; import land.face.strife.data.champion.ChampionSaveData.HealthDisplayType; +import land.face.strife.data.effects.Riptide; import land.face.strife.managers.StatUpdateManager; import land.face.strife.managers.UniqueEntityManager; import land.face.strife.stats.AbilitySlot; @@ -254,6 +255,7 @@ public void onEntityChangeBlock(EntityChangeBlockEvent event) { @EventHandler(priority = EventPriority.LOWEST) public void onPlayerTeleport(PlayerTeleportEvent event) { + Riptide.sendCancelPacket(event.getPlayer()); if (event.getTo().getWorld() != event.getTo().getWorld()) { ensureAbilitiesDontInstantCast(event.getPlayer()); return; @@ -304,6 +306,7 @@ public void onInvyClose(InventoryCloseEvent event) { @EventHandler(priority = EventPriority.NORMAL) public void onRespawn(PlayerRespawnEvent event) { + Riptide.sendCancelPacket(event.getPlayer()); StrifeMob mob = plugin.getStrifeMobManager().getStatMob(event.getPlayer()); mob.restartTimers(); for (AttributeModifier mod : event.getPlayer().getAttribute(Attribute.GENERIC_ARMOR).getModifiers()) { diff --git a/src/main/java/land/face/strife/listeners/LaunchAndLandListener.java b/src/main/java/land/face/strife/listeners/LaunchAndLandListener.java index 0cfbee0a..23a0b2bc 100644 --- a/src/main/java/land/face/strife/listeners/LaunchAndLandListener.java +++ b/src/main/java/land/face/strife/listeners/LaunchAndLandListener.java @@ -10,6 +10,7 @@ import land.face.strife.data.StrifeMob; import land.face.strife.data.champion.Champion; import land.face.strife.data.champion.LifeSkillType; +import land.face.strife.data.effects.Riptide; import land.face.strife.stats.StrifeStat; import land.face.strife.util.PlayerDataUtil; import land.face.strife.util.StatUtil; @@ -75,6 +76,7 @@ public void onLaunch(LaunchEvent event) { @EventHandler public void onLand(LandEvent event) { + Riptide.sendCancelPacket(event.getPlayer()); for (AgilityLocationContainer cont : plugin.getAgilityManager() .getInWorld(event.getLocation().getWorld().getName())) { boolean success = AgilityLocationContainer.setProgress(cont, event.getPlayer(), event.getLocation()); diff --git a/src/main/java/land/face/strife/listeners/ShootListener.java b/src/main/java/land/face/strife/listeners/ShootListener.java index 71e9f7cf..d5f561c4 100644 --- a/src/main/java/land/face/strife/listeners/ShootListener.java +++ b/src/main/java/land/face/strife/listeners/ShootListener.java @@ -1,18 +1,20 @@ /** * The MIT License Copyright (c) 2015 Teal Cube Games *

- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: *

- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the - * Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package land.face.strife.listeners; @@ -85,7 +87,8 @@ public ShootListener(StrifePlugin plugin) { @EventHandler(priority = EventPriority.HIGH) public void onPlayerArrowShoot(ProjectileLaunchEvent event) { - if (!(event.getEntity().getShooter() instanceof Player) || !(event.getEntity() instanceof Arrow)) { + if (!(event.getEntity().getShooter() instanceof Player) + || !(event.getEntity() instanceof Arrow)) { return; } @@ -105,8 +108,9 @@ public void onPlayerArrowShoot(ProjectileLaunchEvent event) { ItemStack mainHand = player.getEquipment().getItemInMainHand(); ItemStack offHand = player.getEquipment().getItemInOffHand(); - EquipmentSlot slot = mainHand.getType() == Material.BOW || mainHand.getType() == Material.CROSSBOW ? - EquipmentSlot.HAND : EquipmentSlot.OFF_HAND; + EquipmentSlot slot = + mainHand.getType() == Material.BOW || mainHand.getType() == Material.CROSSBOW ? + EquipmentSlot.HAND : EquipmentSlot.OFF_HAND; if (ItemUtil.isPistol(slot == EquipmentSlot.HAND ? mainHand : offHand)) { if (!ItemUtil.isBullets(slot == EquipmentSlot.HAND ? offHand : mainHand)) { @@ -137,7 +141,8 @@ public void onEntityShoot(ProjectileLaunchEvent event) { StrifeMob mob = plugin.getStrifeMobManager() .getStatMob((LivingEntity) event.getEntity().getShooter()); - if (event.getEntity().getShooter() instanceof Mob && ((Mob) event.getEntity().getShooter()).getTarget() != null) { + if (event.getEntity().getShooter() instanceof Mob + && ((Mob) event.getEntity().getShooter()).getTarget() != null) { StrifeMob target = plugin.getStrifeMobManager() .getStatMob(((Mob) event.getEntity().getShooter()).getTarget()); @@ -162,13 +167,13 @@ public void onEntityShoot(ProjectileLaunchEvent event) { } if (ItemUtil.isPistol(weapon)) { - doPistolShot(mob, 1); + doPistolShot(mob, 1f); event.setCancelled(true); return; } if (event.getEntity() instanceof Arrow) { - ProjectileUtil.shootArrow(mob, 1.0f); + ProjectileUtil.shootArrow(mob, 1f); event.setCancelled(true); } } @@ -223,7 +228,8 @@ public void onDragonFireballHit(final EnderDragonFireballHitEvent event) { return; } - StrifeMob caster = plugin.getStrifeMobManager().getStatMob((LivingEntity) event.getEntity().getShooter()); + StrifeMob caster = plugin.getStrifeMobManager() + .getStatMob((LivingEntity) event.getEntity().getShooter()); Location loc = event.getEntity().getLocation().clone() .add(event.getEntity().getLocation().getDirection().multiply(-0.25)); @@ -258,7 +264,8 @@ public void onEffectProjectileHit(final ProjectileHitEvent event) { List hitEffects = ProjectileUtil.getHitEffects(event.getEntity()); if (hitEffects.isEmpty()) { - LogUtil.printWarning("A handled effectProjectile was missing effect meta... something's wrong"); + LogUtil.printWarning( + "A handled effectProjectile was missing effect meta... something's wrong"); return; } @@ -271,11 +278,13 @@ private void doPistolShot(StrifeMob mob, float attackMultiplier) { if (((Player) mob.getEntity()).getCooldown(Material.BOW) > 0) { return; } - ((Player) mob.getEntity()).setCooldown(Material.BOW, (int) (StatUtil.getAttackTime(mob) * 20)); + ((Player) mob.getEntity()).setCooldown(Material.BOW, + (int) (StatUtil.getAttackTime(mob) * 20)); } if (mob.getStat(StrifeStat.MULTISHOT) > 0.05) { double randomMultishot = 0.15 + Math.random() * 0.85; - int projectiles = ProjectileUtil.getTotalProjectiles(1, mob.getStat(StrifeStat.MULTISHOT) * randomMultishot); + int projectiles = ProjectileUtil.getTotalProjectiles(1, + mob.getStat(StrifeStat.MULTISHOT) * randomMultishot); flintlockHitscan.setMaxTargets(projectiles); flintlockHitscan.setRadius(0.4f * projectiles); } else { @@ -307,7 +316,8 @@ private StrifeParticle buildFlintlockSmoke() { particle.setRadius(0); particle.setLineIncrement(0.25f); particle.setQuantity(plugin.getSettings().getInt("config.flintlock.smoke-quantity", 1)); - particle.setLineOffset((float) plugin.getSettings().getDouble("config.flintlock.smoke-offset", 1)); + particle.setLineOffset( + (float) plugin.getSettings().getDouble("config.flintlock.smoke-offset", 1)); particle.setSpeed((float) plugin.getSettings().getDouble("config.flintlock.smoke-speed", 2f)); particle.setSpread((float) plugin.getSettings().getDouble("config.flintlock.smoke-spread", 2f)); return particle; @@ -335,7 +345,8 @@ private StrifeParticle buildFlintlockFlare() { particle.setRadius(0); particle.setLineIncrement(0.25f); particle.setQuantity(plugin.getSettings().getInt("config.flintlock.flare-quantity", 1)); - particle.setLineOffset((float) plugin.getSettings().getDouble("config.flintlock.flare-offset", 1)); + particle.setLineOffset( + (float) plugin.getSettings().getDouble("config.flintlock.flare-offset", 1)); particle.setSpeed((float) plugin.getSettings().getDouble("config.flintlock.flare-speed", 1f)); particle.setSpread((float) plugin.getSettings().getDouble("config.flintlock.flare-spread", 1f)); return particle; diff --git a/src/main/java/land/face/strife/listeners/SpawnListener.java b/src/main/java/land/face/strife/listeners/SpawnListener.java index f31ef868..9bf005fe 100644 --- a/src/main/java/land/face/strife/listeners/SpawnListener.java +++ b/src/main/java/land/face/strife/listeners/SpawnListener.java @@ -84,9 +84,9 @@ public void onJockeySpawn(CreatureSpawnEvent event) { if (event.getSpawnReason() != SpawnReason.JOCKEY) { return; } - String world = event.getEntity().getLocation().getWorld().getName(); - if (plugin.getSettings().getStringList("config.leveled-monsters.enabled-worlds") - .contains(world)) { + if (event.getEntity().getVehicle() instanceof LivingEntity && StringUtils.isNotBlank( + plugin.getStrifeMobManager().getStatMob((LivingEntity) event.getEntity().getVehicle()) + .getUniqueEntityId())) { event.setCancelled(true); } } diff --git a/src/main/java/land/face/strife/listeners/TargetingListener.java b/src/main/java/land/face/strife/listeners/TargetingListener.java index 2d6a9c74..b40737c7 100644 --- a/src/main/java/land/face/strife/listeners/TargetingListener.java +++ b/src/main/java/land/face/strife/listeners/TargetingListener.java @@ -18,7 +18,9 @@ */ package land.face.strife.listeners; +import static org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY; import static org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER; +import static org.bukkit.event.entity.EntityTargetEvent.TargetReason.RANDOM_TARGET; import static org.bukkit.potion.PotionEffectType.BLINDNESS; import static org.bukkit.potion.PotionEffectType.INVISIBILITY; @@ -40,7 +42,6 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityTargetEvent.TargetReason; import org.bukkit.event.entity.EntityTargetLivingEntityEvent; import org.bukkit.util.Vector; @@ -138,11 +139,8 @@ public void onNormalTarget(EntityTargetLivingEntityEvent event) { return; } if (SpecialStatusUtil.isWeakAggro(event.getEntity())) { - if (event.getReason() == TargetReason.TARGET_ATTACKED_NEARBY_ENTITY - || event.getReason() == TargetReason.FOLLOW_LEADER - || event.getReason() == TargetReason.PIG_ZOMBIE_TARGET - || event.getReason() == TargetReason.REINFORCEMENT_TARGET - || event.getReason() == TargetReason.DEFEND_VILLAGE) { + if (!(event.getReason() == CLOSEST_PLAYER || event.getReason() == RANDOM_TARGET || + event.getReason() == CLOSEST_ENTITY)) { event.setCancelled(true); return; } diff --git a/src/main/java/land/face/strife/managers/AbilityManager.java b/src/main/java/land/face/strife/managers/AbilityManager.java index 00478cee..2073b42a 100644 --- a/src/main/java/land/face/strife/managers/AbilityManager.java +++ b/src/main/java/land/face/strife/managers/AbilityManager.java @@ -588,7 +588,7 @@ public void loadAbility(String key, ConfigurationSection cs) { return; } String name = StringExtensionsKt - .chatColorize(Objects.requireNonNull(cs.getString("name", "ABILITY NOT NAMED"))); + .chatColorize(Objects.requireNonNull(cs.getString("name", key))); TargetType targetType; try { targetType = TargetType.valueOf(cs.getString("target-type")); diff --git a/src/main/java/land/face/strife/managers/BleedManager.java b/src/main/java/land/face/strife/managers/BleedManager.java index bfabf08f..652de7d7 100644 --- a/src/main/java/land/face/strife/managers/BleedManager.java +++ b/src/main/java/land/face/strife/managers/BleedManager.java @@ -52,22 +52,32 @@ public float getBleedOnEntity(LivingEntity entity) { return 0; } - public void addBleed(StrifeMob mob, float amount, boolean bypassBarrier) { + public boolean addBleed(StrifeMob mob, float amount, boolean bypassBarrier) { if (!mob.getEntity().isValid()) { - return; + return false; } if (!bypassBarrier && mob.getBarrier() > 0) { - return; + return false; } + mob.getEntity().getWorld().spawnParticle( + Particle.ITEM_CRACK, + mob.getEntity().getEyeLocation().clone() + .add(0, -mob.getEntity().getEyeHeight() / 2, 0), + 10, + 0.0, 0.0, 0.0, + 0.25, + BLOCK_DATA + ); if (bleedMap.containsKey(mob.getEntity().getUniqueId())) { bleedMap.get(mob.getEntity().getUniqueId()).bumpBleed(amount); - return; + return true; } bleedMap.put(mob.getEntity().getUniqueId(), new BleedTimer(plugin, mob.getEntity(), amount)); + return true; } public void spawnBleedParticles(LivingEntity entity, double damage) { - int particleAmount = Math.min(2 + (int) (damage * 12), 50); + int particleAmount = Math.min(2 + (int) (damage * 10), 40); entity.getWorld().spawnParticle( Particle.ITEM_CRACK, entity.getEyeLocation().clone().add(0, -entity.getEyeHeight() / 2, 0), diff --git a/src/main/java/land/face/strife/managers/ChampionManager.java b/src/main/java/land/face/strife/managers/ChampionManager.java index 8f484e95..3242aaad 100644 --- a/src/main/java/land/face/strife/managers/ChampionManager.java +++ b/src/main/java/land/face/strife/managers/ChampionManager.java @@ -145,6 +145,7 @@ public void savePendingStats(Champion champion) { } } champion.getSaveData().savePendingStats(); + champion.buildAttributeHeatmap(); rebuildAttributes(champion); } diff --git a/src/main/java/land/face/strife/managers/DamageManager.java b/src/main/java/land/face/strife/managers/DamageManager.java index 4de608b8..523ef0da 100644 --- a/src/main/java/land/face/strife/managers/DamageManager.java +++ b/src/main/java/land/face/strife/managers/DamageManager.java @@ -24,10 +24,11 @@ import land.face.strife.StrifePlugin; import land.face.strife.data.DamageModifiers; import land.face.strife.data.StrifeMob; +import land.face.strife.stats.StrifeStat; import land.face.strife.stats.StrifeTrait; +import land.face.strife.util.DamageUtil; import land.face.strife.util.StatUtil; import org.bukkit.entity.Entity; -import org.bukkit.util.Vector; public class DamageManager { @@ -48,7 +49,7 @@ public double getHandledDamage(Entity entity) { public double dealDamage(StrifeMob attacker, StrifeMob defender, float damage, DamageModifiers modifiers) { if (!modifiers.isBypassBarrier()) { - damage = Math.max(0.002f, defender.damageBarrier(damage)); + damage = defender.damageBarrier(damage); } damage = doEnergyAbsorb(defender, damage); if (attacker == defender) { @@ -59,14 +60,20 @@ public double dealDamage(StrifeMob attacker, StrifeMob defender, float damage, D defender.getEntity().setHealth(defender.getEntity().getHealth() - damage); return damage; } - Vector velocity = defender.getEntity().getVelocity(); + + if (defender.hasTrait(StrifeTrait.BLEEDING_EDGE)) { + damage *= 0.5; + float bleed = damage; + if (defender.getStat(StrifeStat.BLEED_RESIST) > 0) { + bleed *= 1 - defender.getStat(StrifeStat.BLEED_RESIST) / 100; + } + DamageUtil.applyBleed(defender, bleed, true); + } handledDamages.put(attacker.getEntity().getUniqueId(), (double) damage); defender.getEntity().damage(damage, attacker.getEntity()); handledDamages.remove(attacker.getEntity().getUniqueId()); - defender.getEntity().setVelocity(velocity); - return damage; } diff --git a/src/main/java/land/face/strife/managers/EffectManager.java b/src/main/java/land/face/strife/managers/EffectManager.java index cc2abe79..8a047f9e 100644 --- a/src/main/java/land/face/strife/managers/EffectManager.java +++ b/src/main/java/land/face/strife/managers/EffectManager.java @@ -40,6 +40,7 @@ import land.face.strife.data.conditions.EnergyCondition; import land.face.strife.data.conditions.EntityTypeCondition; import land.face.strife.data.conditions.FactionCondition; +import land.face.strife.data.conditions.FlyingCondition; import land.face.strife.data.conditions.GroundedCondition; import land.face.strife.data.conditions.HealthCondition; import land.face.strife.data.conditions.HeightCondition; @@ -103,6 +104,7 @@ import land.face.strife.data.effects.RemoveEntity; import land.face.strife.data.effects.RestoreBarrier; import land.face.strife.data.effects.Revive; +import land.face.strife.data.effects.Riptide; import land.face.strife.data.effects.SetFall; import land.face.strife.data.effects.ShootBlock; import land.face.strife.data.effects.ShootProjectile; @@ -443,6 +445,10 @@ public void loadEffect(String key, ConfigurationSection cs) { } }, 5L); break; + case RIPTIDE: + effect = new Riptide(); + ((Riptide) effect).setTicks(cs.getInt("ticks", 40) / 2); + break; case PROJECTILE: effect = new ShootProjectile(); ((ShootProjectile) effect).setQuantity(cs.getInt("quantity", 1)); @@ -549,7 +555,7 @@ public void loadEffect(String key, ConfigurationSection cs) { ((Bleed) effect).setAmount((float) cs.getDouble("amount", 10)); ((Bleed) effect).setDamageScale(DamageScale.valueOf(cs.getString("scale", "FLAT"))); ((Bleed) effect).setIgnoreArmor(cs.getBoolean("ignore-armor", true)); - ((Bleed) effect).setBypassBarrier(cs.getBoolean("bypass-barrier", true)); + ((Bleed) effect).setBypassBarrier(cs.getBoolean("bypass-barrier", false)); ((Bleed) effect).setApplyBleedMods(cs.getBoolean("apply-bleed-mods", true)); break; case CORRUPT: @@ -637,6 +643,7 @@ public void loadEffect(String key, ConfigurationSection cs) { ((Push) effect).setHeight(cs.getDouble("height", 10)); ((Push) effect).setCancelFall(cs.getBoolean("cancel-fall", false)); ((Push) effect).setClamp(cs.getBoolean("clamp", true)); + ((Push) effect).setUncheckedHeight(cs.getBoolean("unchecked-height", false)); ((Push) effect).setPushType( PushType.valueOf(cs.getString("push-type", "AWAY_FROM_CASTER"))); break; @@ -1018,6 +1025,9 @@ public void loadCondition(String key, ConfigurationSection cs) { String factionId = cs.getString("faction-id"); condition = new FactionCondition(factionId); break; + case FLYING: + condition = new FlyingCondition(); + break; case VELOCITY: VelocityType velocityType = VelocityType.valueOf(cs.getString("type", "TOTAL")); boolean absolute = cs.getBoolean("absolute", true); diff --git a/src/main/java/land/face/strife/managers/MobModManager.java b/src/main/java/land/face/strife/managers/MobModManager.java index e665711a..2e505c71 100644 --- a/src/main/java/land/face/strife/managers/MobModManager.java +++ b/src/main/java/land/face/strife/managers/MobModManager.java @@ -15,6 +15,7 @@ import land.face.strife.util.SpecialStatusUtil; import land.face.strife.util.StatUtil; import org.apache.commons.lang.StringUtils; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.block.Biome; @@ -64,7 +65,9 @@ public void applyMobMod(StrifeMob strifeMob, MobMod mobMod) { } } if (!mobMod.getEquipment().isEmpty()) { - ItemUtil.delayedEquip(mobMod.getEquipment(), strifeMob.getEntity(), false); + Bukkit.getScheduler().runTaskLater(StrifePlugin.getInstance(), () -> { + ItemUtil.equipMob(mobMod.getEquipment(), strifeMob.getEntity(), false); + }, 6L); } int level = StatUtil.getMobLevel(strifeMob.getEntity()); Map stats = StatUpdateManager.combineMaps(strifeMob.getBaseStats(), mobMod.getBaseStats()); diff --git a/src/main/java/land/face/strife/managers/RageManager.java b/src/main/java/land/face/strife/managers/RageManager.java index bf8d73d0..3b31b3cd 100644 --- a/src/main/java/land/face/strife/managers/RageManager.java +++ b/src/main/java/land/face/strife/managers/RageManager.java @@ -21,6 +21,7 @@ import java.util.UUID; import land.face.strife.data.StrifeMob; import land.face.strife.stats.StrifeStat; +import land.face.strife.stats.StrifeTrait; import land.face.strife.timers.RageTimer; import land.face.strife.util.LogUtil; import org.bukkit.entity.LivingEntity; @@ -37,6 +38,9 @@ public float getRage(LivingEntity entity) { } public void changeRage(StrifeMob mob, float amount) { + if (amount > 0 && mob.hasTrait(StrifeTrait.BLOOD_BOIL)) { + amount *= 1.3; + } if (rageMap.containsKey(mob.getEntity().getUniqueId())) { rageMap.get(mob.getEntity().getUniqueId()).bumpRage(amount); return; diff --git a/src/main/java/land/face/strife/managers/SkillExperienceManager.java b/src/main/java/land/face/strife/managers/SkillExperienceManager.java index c8d123f0..699ce4f6 100644 --- a/src/main/java/land/face/strife/managers/SkillExperienceManager.java +++ b/src/main/java/land/face/strife/managers/SkillExperienceManager.java @@ -27,6 +27,8 @@ import java.util.Map; import land.face.strife.StrifePlugin; import land.face.strife.data.StrifeMob; +import land.face.strife.data.ability.Ability; +import land.face.strife.data.champion.Champion; import land.face.strife.data.champion.ChampionSaveData; import land.face.strife.data.champion.LifeSkillType; import land.face.strife.events.SkillExpGainEvent; @@ -53,11 +55,14 @@ public SkillExperienceManager(StrifePlugin plugin) { setupLevelingRates(plugin); } - public void addExperience(Player player, LifeSkillType type, double amount, boolean exact, boolean forceDisplay) { - addExperience(plugin.getStrifeMobManager().getStatMob(player), type, amount, exact, forceDisplay); + public void addExperience(Player player, LifeSkillType type, double amount, boolean exact, + boolean forceDisplay) { + addExperience(plugin.getStrifeMobManager().getStatMob(player), type, amount, exact, + forceDisplay); } - public void addExperience(StrifeMob mob, LifeSkillType type, double amount, boolean exact, boolean forceDisplay) { + public void addExperience(StrifeMob mob, LifeSkillType type, double amount, boolean exact, + boolean forceDisplay) { Player player = (Player) mob.getEntity(); ChampionSaveData saveData = mob.getChampion().getSaveData(); if (amount < 0.001) { @@ -67,7 +72,8 @@ public void addExperience(StrifeMob mob, LifeSkillType type, double amount, bool return; } if (!exact) { - float skillXpMult = plugin.getStrifeMobManager().getStatMob(player).getStat(StrifeStat.SKILL_XP_GAIN) / 100; + float skillXpMult = plugin.getStrifeMobManager().getStatMob(player) + .getStat(StrifeStat.SKILL_XP_GAIN) / 100; amount *= 1 + skillXpMult; } if (saveData.isDisplayExp() || forceDisplay) { @@ -97,6 +103,7 @@ public void addExperience(StrifeMob mob, LifeSkillType type, double amount, bool break; } maxExp = (double) getMaxExp(type, saveData.getSkillLevel(type)); + checkSkillUnlock(player, type); } saveData.setSkillExp(type, (float) currentExp); plugin.getBossBarManager().pushSkillBar(player, type); @@ -106,6 +113,23 @@ public Integer getMaxExp(LifeSkillType type, int level) { return levelingRates.get(type).get(level); } + public void checkSkillUnlock(Player player, LifeSkillType skill) { + Champion champion = plugin.getChampionManager().getChampion(player); + for (Ability ability : plugin.getAbilityManager().getLoadedAbilities().values()) { + if (ability.getAbilityIconData() != null) { + int reqLv = ability.getAbilityIconData().getLifeSkillRequirements().getOrDefault(skill, -1); + if (reqLv == champion.getLifeSkillLevel(skill)) { + if (ability.getAbilityIconData().isRequirementMet(champion)) { + MessageUtils.sendMessage(player, + "&b❖ Neato! You've unlocked the " + skill.getColor() + skill.getName() + + "&b ability, " + skill.getColor() + ability.getName() + + "&b! Visit an ability trainer to try it out!"); + } + } + } + } + } + private void setupLevelingRates(StrifePlugin plugin) { LevelingRate combatRate = new LevelingRate(); Expression expression = new ExpressionBuilder(plugin.getSettings() @@ -115,9 +139,9 @@ private void setupLevelingRates(StrifePlugin plugin) { combatRate.put(i, i, (int) Math.round(expression.setVariable("LEVEL", i).evaluate())); } for (LifeSkillType type : LifeSkillType.values()) { - if (type.isComnbat()) { - levelingRates.put(type, combatRate); - continue; + if (type.isCombat()) { + levelingRates.put(type, combatRate); + continue; } LevelingRate skillRate = new LevelingRate(); Expression rateExpr = new ExpressionBuilder(plugin.getSettings() diff --git a/src/main/java/land/face/strife/managers/UniqueEntityManager.java b/src/main/java/land/face/strife/managers/UniqueEntityManager.java index c212e5c1..1344b726 100644 --- a/src/main/java/land/face/strife/managers/UniqueEntityManager.java +++ b/src/main/java/land/face/strife/managers/UniqueEntityManager.java @@ -222,7 +222,9 @@ private void lambdaSetup(Entity entity, UniqueEntity uniqueEntity, Location loca if (le.getEquipment() != null) { Map equipmentMap = plugin.getEquipmentManager() .getEquipmentMap(uniqueEntity.getEquipment()); - ItemUtil.delayedEquip(equipmentMap, le, true); + ItemUtil.equipMob(equipmentMap, le, true); + Bukkit.getScheduler().runTaskLater(StrifePlugin.getInstance(), () -> + ItemUtil.equipMob(equipmentMap, le, true), 5L); } if (uniqueEntity.isSaddled() && le.getType() == EntityType.HORSE) { @@ -368,9 +370,8 @@ public void loadUniques(VersionedSmartYamlConfiguration uniqueEnemiesYAML) { } uniqueEntity.setBaseLevel(cs.getInt("base-level", -1)); - Disguise disguise = PlayerDataUtil - .parseDisguise(cs.getConfigurationSection("disguise"), uniqueEntity.getName(), - uniqueEntity.getMaxMods() > 0); + Disguise disguise = PlayerDataUtil.parseDisguise(cs.getConfigurationSection("disguise"), + uniqueEntity.getName(), uniqueEntity.getMaxMods() > 0); if (disguise != null) { cacheDisguise(uniqueEntity, disguise); diff --git a/src/main/java/land/face/strife/menus/stats/StatsEffectMenuItem.java b/src/main/java/land/face/strife/menus/stats/StatsEffectMenuItem.java index 595b4d82..710128d7 100644 --- a/src/main/java/land/face/strife/menus/stats/StatsEffectMenuItem.java +++ b/src/main/java/land/face/strife/menus/stats/StatsEffectMenuItem.java @@ -60,7 +60,9 @@ public ItemStack getFinalIcon(Player commandSender) { List traitLores = new ArrayList<>(); for (StrifeTrait trait : pStats.getTraits()) { - traitLores.add(ChatColor.YELLOW + "❂ " + trait.getName()); + if (trait.getAdditionalText().isEmpty()) { + traitLores.add(ChatColor.YELLOW + "❂ " + trait.getName()); + } } if (!traitLores.isEmpty()) { @@ -69,6 +71,12 @@ public ItemStack getFinalIcon(Player commandSender) { } List abilityLores = new ArrayList<>(); + for (StrifeTrait trait : pStats.getTraits()) { + if (!trait.getAdditionalText().isEmpty()) { + abilityLores.add(trait.getName()); + abilityLores.addAll(trait.getAdditionalText()); + } + } for (TriggerType triggerType : pStats.getLoreAbilities().keySet()) { for (LoreAbility la : pStats.getLoreAbilities().get(triggerType)) { abilityLores.add(la.getTriggerText()); diff --git a/src/main/java/land/face/strife/stats/StrifeTrait.java b/src/main/java/land/face/strife/stats/StrifeTrait.java index d7d39a7c..fb665ac8 100644 --- a/src/main/java/land/face/strife/stats/StrifeTrait.java +++ b/src/main/java/land/face/strife/stats/StrifeTrait.java @@ -1,7 +1,14 @@ package land.face.strife.stats; +import io.pixeloutlaw.minecraft.spigot.garbage.ListExtensionsKt; +import io.pixeloutlaw.minecraft.spigot.garbage.StringExtensionsKt; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; +import lombok.Getter; +import net.md_5.bungee.api.ChatColor; public enum StrifeTrait { @@ -14,6 +21,8 @@ public enum StrifeTrait { NO_ENERGY_BASICS("Basic Attacks Cost No Energy"), ENERGY_ABSORB("20% Of Damage Taken From Energy"), NO_ENERGY_REGEN("Energy Does Not Regenerate"), + BLEEDING_EDGE("&6&nPassive Effect - Bleeding Edge", " &eHalf of attack damage taken from", " &elife is instead added as &4Bleeding"), + BLOOD_BOIL("&6&nPassive Effect - Blood Boil", " &eWhen &4Bleeding&e, &eall &cRage &egained", " &eis increased by &f30%"), SOUL_FLAME("Passive Effect - Blue Flame"); // TODO: We map String to StrifeStat, why not let the user @@ -26,27 +35,23 @@ private static Map buildStringToTraitMap() { if (trait.getName() == null) { continue; } - values.put(trait.getName(), trait); + values.put(ChatColor.stripColor(trait.getName()), trait); } return values; } - public static StrifeTrait fromName(String name) { - return copyOfValues.getOrDefault(name, null); + public static StrifeTrait fromName(String trigger) { + return copyOfValues.getOrDefault(trigger, null); } + @Getter private final String name; + @Getter + private final List additionalText = new ArrayList<>(); - StrifeTrait(String name) { - this.name = name; - } - - StrifeTrait() { - this.name = null; - } - - public String getName() { - return name; + StrifeTrait(String trigger, String... additionalText) { + this.name = StringExtensionsKt.chatColorize(trigger); + this.additionalText.addAll(ListExtensionsKt.chatColorize(Arrays.asList(additionalText))); } } diff --git a/src/main/java/land/face/strife/util/DamageUtil.java b/src/main/java/land/face/strife/util/DamageUtil.java index b1313e48..0b22d378 100644 --- a/src/main/java/land/face/strife/util/DamageUtil.java +++ b/src/main/java/land/face/strife/util/DamageUtil.java @@ -587,17 +587,23 @@ public static float getDamageReduction(DamageType type, StrifeMob attack, Strife } return getWardingMult(warding); case FIRE: - return 1 - getFireResist(defend, attack.hasTrait(StrifeTrait.SOUL_FLAME)) / 100; + float fireResist = getFireResist(defend, attack.hasTrait(StrifeTrait.SOUL_FLAME)) / 100; + return fireResist >= 0 ? (1 - fireResist) : 1 + Math.abs(fireResist); case ICE: - return 1 - getIceResist(defend) / 100; + float iceResist = getIceResist(defend) / 100; + return iceResist >= 0 ? (1 - iceResist) : 1 + Math.abs(iceResist); case LIGHTNING: - return 1 - getLightningResist(defend) / 100; + float lightningResist = getLightningResist(defend) / 100; + return lightningResist >= 0 ? (1 - lightningResist) : 1 + Math.abs(lightningResist); case DARK: - return 1 - getShadowResist(defend) / 100; + float darkResist = getShadowResist(defend) / 100; + return darkResist >= 0 ? (1 - darkResist) : 1 + Math.abs(darkResist); case EARTH: - return 1 - getEarthResist(defend) / 100; + float earthResist = getEarthResist(defend) / 100; + return earthResist >= 0 ? (1 - earthResist) : 1 + Math.abs(earthResist); case LIGHT: - return 1 - getLightResist(defend) / 100; + float lightResist = getLightResist(defend) / 100; + return lightResist >= 0 ? (1 - lightResist) : 1 + Math.abs(lightResist); case TRUE_DAMAGE: default: return 1; @@ -807,8 +813,10 @@ public static boolean attemptBleed(StrifeMob attacker, StrifeMob defender, float float chance = (attacker.getStat(StrifeStat.BLEED_CHANCE) + mods.getAbilityMods().getOrDefault(AbilityMod.BLEED_CHANCE, 0f)) / 100; if (chance >= rollDouble()) { - float multiplier = mods.isScaleChancesWithAttack() ? mods.getAttackMultiplier() : 1f; - float damage = rawPhysical * multiplier * BLEED_PERCENT; + float damage = rawPhysical * BLEED_PERCENT; + if (mods.isScaleChancesWithAttack()) { + damage *= Math.min(1f, mods.getAttackMultiplier()); + } float bleedDamage = attacker.getStat(StrifeStat.BLEED_DAMAGE) + mods.getAbilityMods() .getOrDefault(AbilityMod.BLEED_DAMAGE, 0f); damage *= 1 + (bleedDamage / 100); @@ -822,9 +830,11 @@ public static void applyBleed(StrifeMob defender, float amount, boolean bypassBa if (amount < 0.1) { return; } - StrifePlugin.getInstance().getBleedManager().addBleed(defender, amount, bypassBarrier); - defender.getEntity().getWorld() - .playSound(defender.getEntity().getLocation(), Sound.ENTITY_SHEEP_SHEAR, 1f, 1f); + boolean bleedSuccess = plugin.getBleedManager().addBleed(defender, amount, bypassBarrier); + if (bleedSuccess) { + defender.getEntity().getWorld() + .playSound(defender.getEntity().getLocation(), Sound.ENTITY_SHEEP_SHEAR, 1f, 0.7f); + } } public static void applyCorrupt(LivingEntity defender, float amount, boolean silent) { diff --git a/src/main/java/land/face/strife/util/ItemUtil.java b/src/main/java/land/face/strife/util/ItemUtil.java index fad55bd3..3a39b59a 100644 --- a/src/main/java/land/face/strife/util/ItemUtil.java +++ b/src/main/java/land/face/strife/util/ItemUtil.java @@ -12,7 +12,6 @@ import java.util.Map; import java.util.Set; import java.util.UUID; -import land.face.strife.StrifePlugin; import land.face.strife.stats.StrifeStat; import land.face.strife.stats.StrifeTrait; import org.bukkit.Bukkit; @@ -55,7 +54,8 @@ public static ItemStack withBase64(ItemStack item, String base64) { public static boolean isArmor(Material material) { String name = material.name(); - return name.endsWith("HELMET") || name.endsWith("CHESTPLATE") || name.endsWith("LEGGINGS") || name.endsWith("BOOTS") + return name.endsWith("HELMET") || name.endsWith("CHESTPLATE") || name.endsWith("LEGGINGS") + || name.endsWith("BOOTS") || name.endsWith("SKULL") || name.endsWith("HEAD"); } @@ -208,24 +208,23 @@ public static Set getTraits(ItemStack stack) { return traits; } - public static void delayedEquip(Map items, LivingEntity entity, boolean overwrite) { - Bukkit.getScheduler().runTaskLater(StrifePlugin.getInstance(), () -> { - if (overwrite) { - entity.getEquipment().clear(); - } - entity.getEquipment().setHelmetDropChance(0f); - entity.getEquipment().setChestplateDropChance(0f); - entity.getEquipment().setLeggingsDropChance(0f); - entity.getEquipment().setBootsDropChance(0f); - entity.getEquipment().setItemInMainHandDropChance(0f); - entity.getEquipment().setItemInOffHandDropChance(0f); - entity.getEquipment().setHelmet(items.getOrDefault(EquipmentSlot.HEAD, null)); - entity.getEquipment().setChestplate(items.getOrDefault(EquipmentSlot.CHEST, null)); - entity.getEquipment().setLeggings(items.getOrDefault(EquipmentSlot.LEGS, null)); - entity.getEquipment().setBoots(items.getOrDefault(EquipmentSlot.FEET, null)); - entity.getEquipment().setItemInMainHand(items.getOrDefault(EquipmentSlot.HAND, null)); - entity.getEquipment().setItemInOffHand(items.getOrDefault(EquipmentSlot.OFF_HAND, null)); - }, 2L); + public static void equipMob(Map items, LivingEntity entity, + boolean overwrite) { + if (overwrite) { + entity.getEquipment().clear(); + } + entity.getEquipment().setHelmetDropChance(0f); + entity.getEquipment().setChestplateDropChance(0f); + entity.getEquipment().setLeggingsDropChance(0f); + entity.getEquipment().setBootsDropChance(0f); + entity.getEquipment().setItemInMainHandDropChance(0f); + entity.getEquipment().setItemInOffHandDropChance(0f); + entity.getEquipment().setHelmet(items.getOrDefault(EquipmentSlot.HEAD, null)); + entity.getEquipment().setChestplate(items.getOrDefault(EquipmentSlot.CHEST, null)); + entity.getEquipment().setLeggings(items.getOrDefault(EquipmentSlot.LEGS, null)); + entity.getEquipment().setBoots(items.getOrDefault(EquipmentSlot.FEET, null)); + entity.getEquipment().setItemInMainHand(items.getOrDefault(EquipmentSlot.HAND, null)); + entity.getEquipment().setItemInOffHand(items.getOrDefault(EquipmentSlot.OFF_HAND, null)); } public static int getCustomData(ItemStack stack) { diff --git a/src/main/java/land/face/strife/util/PlayerDataUtil.java b/src/main/java/land/face/strife/util/PlayerDataUtil.java index 9e07fba4..8205cd21 100644 --- a/src/main/java/land/face/strife/util/PlayerDataUtil.java +++ b/src/main/java/land/face/strife/util/PlayerDataUtil.java @@ -35,6 +35,7 @@ import me.libraryaddict.disguise.disguisetypes.watchers.SheepWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.SlimeWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.SnowmanWatcher; +import me.libraryaddict.disguise.disguisetypes.watchers.WolfWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.ZombieWatcher; import org.bukkit.Bukkit; import org.bukkit.DyeColor; @@ -153,6 +154,7 @@ public static Disguise parseDisguise(ConfigurationSection section, String name, Bukkit.getLogger().warning("Invalid disguise type " + disguiseType + " for " + name); return null; } + Disguise disguise = null; if (type == DisguiseType.PLAYER) { String disguisePlayer = section.getString("disguise-player"); if (StringUtils.isBlank(disguisePlayer)) { @@ -167,7 +169,7 @@ public static Disguise parseDisguise(ConfigurationSection section, String name, playerDisguise.setName(name); playerDisguise.setDynamicName(false); } - return playerDisguise; + disguise = playerDisguise; } if (type.isMob()) { String typeData = section.getString("disguise-type-data", ""); @@ -194,6 +196,9 @@ public static Disguise parseDisguise(ConfigurationSection section, String name, Fox.Type foxType = Fox.Type.valueOf(typeData); ((FoxWatcher) watcher).setType(foxType); break; + case WOLF: + ((WolfWatcher) watcher).setAngry(Boolean.parseBoolean(typeData)); + break; case PARROT: Parrot.Variant parrotType = Parrot.Variant.valueOf(typeData); ((ParrotWatcher) watcher).setVariant(parrotType); @@ -218,7 +223,7 @@ public static Disguise parseDisguise(ConfigurationSection section, String name, } } mobDisguise.setReplaceSounds(true); - return mobDisguise; + disguise = mobDisguise; } if (type.isMisc()) { MiscDisguise miscDisguise = new MiscDisguise(type); @@ -238,9 +243,12 @@ public static Disguise parseDisguise(ConfigurationSection section, String name, } catch (Exception e) { LogUtil.printWarning("Cannot load data for " + name); } - return miscDisguise; + disguise = miscDisguise; + } + if (disguise != null) { + disguise.setSoundGroup(section.getString("sound-group", null)); } - return null; + return disguise; } public static boolean areConditionsMet(StrifeMob caster, StrifeMob target, Set conditions) { diff --git a/src/main/java/land/face/strife/util/ProjectileUtil.java b/src/main/java/land/face/strife/util/ProjectileUtil.java index e363a541..0c157c3b 100644 --- a/src/main/java/land/face/strife/util/ProjectileUtil.java +++ b/src/main/java/land/face/strife/util/ProjectileUtil.java @@ -110,8 +110,7 @@ public static void shootWand(StrifeMob mob, double attackMult) { randomWandOffset(projectiles), 0.24, true); } - mob.getEntity().getWorld() - .playSound(mob.getEntity().getLocation(), Sound.ENTITY_BLAZE_HURT, 0.7f, 2f); + mob.getEntity().getWorld().playSound(mob.getEntity().getLocation(), Sound.ENTITY_BLAZE_HURT, 0.7f, 2f); shotId++; }