From d85878311736e2c7abe3bd7029725163423aa695 Mon Sep 17 00:00:00 2001 From: FN-FAL113 Date: Mon, 1 Jan 2024 15:19:12 +0800 Subject: [PATCH 1/2] Gem buffs and chores --- pom.xml | 2 +- .../gems/AchillesHeelGem.java | 7 +- .../fnamplifications/gems/AdamantineGem.java | 1 + .../fnamplifications/gems/ArmorImpairGem.java | 22 +++-- .../fnamplifications/gems/ArrowAvertGem.java | 5 +- .../fnamplifications/gems/AtrohpyGem.java | 2 +- .../fnamplifications/gems/AvengeGem.java | 4 +- .../fnamplifications/gems/AwakenGem.java | 5 ++ .../fnamplifications/gems/BaneGem.java | 2 +- .../fnamplifications/gems/BerserkGem.java | 4 +- .../fnamplifications/gems/BlindBindGem.java | 3 +- .../fnamplifications/gems/CelerityGem.java | 3 +- .../fnamplifications/gems/DeberserkGem.java | 4 +- .../fnamplifications/gems/DeceptionGem.java | 3 +- .../fnamplifications/gems/DecrepitGem.java | 2 +- .../fnamplifications/gems/DisarmGem.java | 2 + .../fnamplifications/gems/DisruptedGem.java | 8 +- .../fnamplifications/gems/HastyGem.java | 4 +- .../fnamplifications/gems/InfernoGem.java | 14 ++-- .../fnamplifications/gems/LifestealGem.java | 7 +- .../fnamplifications/gems/LootGem.java | 3 +- .../fnamplifications/gems/ParryGem.java | 19 +++-- .../gems/PsychokinesisGem.java | 2 + .../fnamplifications/gems/SedateGem.java | 16 ++-- .../fnamplifications/gems/ShockwaveGem.java | 2 +- .../gems/SmokeCriminalGem.java | 12 +-- .../fnamplifications/gems/StoutGem.java | 7 +- .../fnamplifications/gems/TelepathyGem.java | 14 ++-- .../fnamplifications/gems/ThornAwayGem.java | 14 ++-- .../fnamplifications/gems/ThunderBoltGem.java | 12 ++- .../fnamplifications/gems/TriSwordGem.java | 7 +- .../gems/implementation/ReturnWeaponTask.java | 31 ++++--- .../gems/implementation/ThrowWeaponTask.java | 80 ++++++++++++------- .../fnamplifications/items/FNAmpItems.java | 40 +++++----- 34 files changed, 220 insertions(+), 143 deletions(-) diff --git a/pom.xml b/pom.xml index 0bf4b937..e77cf5b2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ne.fnfal113 FNAmplifications - Unoffical-4.1.4 + Unoffical-4.1.5 jar FNAmplifications diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/AchillesHeelGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/AchillesHeelGem.java index 9801b578..21635d18 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/AchillesHeelGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/AchillesHeelGem.java @@ -42,9 +42,10 @@ public void onProjectileDamage(EntityDamageByEntityEvent event, Player shooter, return; } - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId()) && - (projectile.getLocation().getY() - entity.getLocation().getY()) < 0.5) { - event.setDamage(event.getDamage() * 2.0); + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId()) + && (projectile.getLocation().getY() - entity.getLocation().getY()) < 0.5) { + event.setDamage(event.getDamage() * 3.5); + sendGemMessage(shooter, this.getItemName()); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/AdamantineGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/AdamantineGem.java index d3db42c1..5e964101 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/AdamantineGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/AdamantineGem.java @@ -40,6 +40,7 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte public void onDurabilityChange(PlayerItemDamageEvent event) { if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(event.getItem(), this.getId())) { event.setCancelled(true); + sendGemMessage(event.getPlayer(), this.getItemName()); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/ArmorImpairGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/ArmorImpairGem.java index 044f926f..5107cc75 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/ArmorImpairGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/ArmorImpairGem.java @@ -26,8 +26,8 @@ public ArmorImpairGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType re } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ - if ((WeaponArmorEnum.SWORDS.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.AXES.isTagged(itemStackToSocket.getType()))) { + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { + if((WeaponArmorEnum.SWORDS.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.AXES.isTagged(itemStackToSocket.getType()))) { if(isUpgradeGem(gemItem, this.getId())) { upgradeGem(slimefunGemItem, itemStackToSocket, gemItem, player); } else { @@ -39,7 +39,7 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte } @Override - public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ + public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { if(!(event.getEntity() instanceof LivingEntity)) { return; } @@ -48,16 +48,24 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ return; } + if(event.getEntity().isInvulnerable()) { + return; + } + LivingEntity livingEntity = (LivingEntity) event.getEntity(); ItemStack[] armorContents = livingEntity.getEquipment().getArmorContents(); - for(ItemStack entityEquipment : armorContents){ - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId()) && entityEquipment != null){ + for(ItemStack entityEquipment : armorContents) { + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId()) && entityEquipment != null) { ItemMeta meta = entityEquipment.getItemMeta(); - if(meta instanceof Damageable){ + + if(meta instanceof Damageable) { Damageable damageable = (Damageable) meta; - damageable.setDamage(damageable.getDamage() + 4); + + damageable.setDamage(damageable.getDamage() + 8); + entityEquipment.setItemMeta(meta); + if(event.getDamager() instanceof Player) { sendGemMessage((Player) event.getDamager(), this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/ArrowAvertGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/ArrowAvertGem.java index 7bc08b54..274d233c 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/ArrowAvertGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/ArrowAvertGem.java @@ -42,11 +42,12 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { return; } - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId()) && - event.getCause() == EntityDamageEvent.DamageCause.PROJECTILE) { + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId()) + && event.getCause() == EntityDamageEvent.DamageCause.PROJECTILE) { if(event.getEntity() instanceof Player) { sendGemMessage((Player) event.getEntity(), this.getItemName()); } + event.setCancelled(true); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/AtrohpyGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/AtrohpyGem.java index addb2ede..bf48ed28 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/AtrohpyGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/AtrohpyGem.java @@ -60,7 +60,7 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier) { int level = Math.abs(tier - 4); - livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.WITHER, 80, level)); + livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.WITHER, 120, level)); sendGemMessage(player, this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/AvengeGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/AvengeGem.java index 1f00ba6e..d854215b 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/AvengeGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/AvengeGem.java @@ -42,8 +42,10 @@ public void onPlayerDeath(PlayerDeathEvent event, ItemStack itemStack) { Player player = event.getEntity(); Location loc = player.getLocation(); Creeper creeper = player.getWorld().spawn(loc.clone(), Creeper.class); + creeper.setPowered(true); // big boomer creeper - creeper.setExplosionRadius(3); + creeper.setExplosionRadius(4); + sendGemMessage(event.getEntity(), this.getItemName()); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/AwakenGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/AwakenGem.java index 20feb7f8..5e493d1b 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/AwakenGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/AwakenGem.java @@ -51,15 +51,20 @@ public void onPlayerDeath(PlayerDeathEvent event, ItemStack itemStack) { player.spigot().respawn(); player.teleport(loc.clone()); player.playSound(loc, Sound.ENTITY_VINDICATOR_CELEBRATE, 1.0F, 1.0F); + sendGemMessage(player, this.getItemName()); + for (int d = 0; d <= 90; d++) { int r = ThreadLocalRandom.current().nextInt(255); int g = ThreadLocalRandom.current().nextInt(255); int b = ThreadLocalRandom.current().nextInt(255); + Location particleLoc = new Location(loc.getWorld(), loc.getX(), loc.getY(), loc.getZ()); + // calculate the angle of x, z and multiply it by the size particleLoc.setX(loc.getX() + Math.cos(d) * 2); particleLoc.setZ(loc.getZ() + Math.sin(d) * 2); + player.getWorld().spawnParticle(Particle.REDSTONE, particleLoc, 2, new Particle.DustOptions(Color.fromRGB(r, g, b), 2)); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/BaneGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/BaneGem.java index 678b89ec..bdf477de 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/BaneGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/BaneGem.java @@ -60,7 +60,7 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier) { int level = Math.abs(tier - 4); - livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.POISON, 80, level)); + livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.POISON, 120, level)); sendGemMessage(player, this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/BerserkGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/BerserkGem.java index 72751c6b..32840859 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/BerserkGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/BerserkGem.java @@ -28,7 +28,7 @@ public class BerserkGem extends AbstractGem implements OnDamageHandler, GemUpgra tierDamageMap.put(4, 0.06); tierDamageMap.put(3, 0.12); tierDamageMap.put(2, 0.18); - tierDamageMap.put(1, 0.30); + tierDamageMap.put(1, 0.36); } public BerserkGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { @@ -65,7 +65,7 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { return; } - if (playerCurrentHealth <= playerDefaultHealth * 0.30 && !damager.isDead()) { + if (playerCurrentHealth <= playerDefaultHealth * 0.40 && !damager.isDead()) { double damage = event.getDamage(); double finalDamage = (tierDamageMap.get(tier) * damage) + damage; diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/BlindBindGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/BlindBindGem.java index d4fc11e7..01fb915c 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/BlindBindGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/BlindBindGem.java @@ -45,7 +45,8 @@ public void onProjectileDamage(EntityDamageByEntityEvent event, Player shooter, } if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())) { - entity.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 80, 2, true, false, false)); + entity.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 120, 2, true, false, false)); + sendGemMessage(shooter, this.getItemName()); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/CelerityGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/CelerityGem.java index 8648233a..e1a19ea0 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/CelerityGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/CelerityGem.java @@ -54,7 +54,8 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier) { int level = Math.abs(tier - 4); - victim.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 80, level)); + victim.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 120, level)); + sendGemMessage(victim, this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/DeberserkGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/DeberserkGem.java index 2b6729d6..55f4b204 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/DeberserkGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/DeberserkGem.java @@ -53,8 +53,8 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { } if(WeaponArmorEnum.AXES.isTagged(damager.getEquipment().getItemInMainHand().getType())) { - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())){ - event.setDamage(event.getDamage() * 0.75); + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())) { + event.setDamage(event.getDamage() * 0.6); if(event.getEntity() instanceof Player) { sendGemMessage((Player) event.getEntity(), this.getItemName()); diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/DeceptionGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/DeceptionGem.java index 83e64e39..28475f79 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/DeceptionGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/DeceptionGem.java @@ -61,7 +61,8 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier) { int level = Math.abs(tier - 4); - livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 80, level)); + livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 120, level)); + sendGemMessage(player, this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/DecrepitGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/DecrepitGem.java index ae847321..4d77265c 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/DecrepitGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/DecrepitGem.java @@ -61,7 +61,7 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier) { int level = Math.abs(tier - 4); - livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 80, level)); + livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 120, level)); sendGemMessage(player, this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/DisarmGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/DisarmGem.java index 929ff18f..16c2fb18 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/DisarmGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/DisarmGem.java @@ -58,11 +58,13 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { int slot = victim.getInventory().firstEmpty(); // get first empty slot from left to right victim.getInventory().setItemInMainHand(null); + if (slot != -1) { victim.getInventory().setItem(slot, itemInMainHand.clone()); } else { victim.getWorld().dropItem(victim.getLocation(), itemInMainHand.clone()); } + sendGemMessage(damager, this.getItemName()); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/DisruptedGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/DisruptedGem.java index b5f2cc4e..89343685 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/DisruptedGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/DisruptedGem.java @@ -23,7 +23,7 @@ public DisruptedGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType reci } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { if ((WeaponArmorEnum.SWORDS.isTagged(itemStackToSocket.getType()))) { if(isUpgradeGem(gemItem, this.getId())) { upgradeGem(slimefunGemItem, itemStackToSocket, gemItem, player); @@ -36,15 +36,17 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte } @Override - public void onGuardianSpawn(GuardianSpawnEvent event, ItemStack itemStack){ + public void onGuardianSpawn(GuardianSpawnEvent event, ItemStack itemStack) { if(event.isCancelled()) { return; } - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())){ + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())) { event.setCancelled(true); + event.getDamager().sendMessage(Utils .colorTranslator("&eYou have redeemed the guardian of your enemy and destroyed it upon spawn")); + event.getGuardianOwner().sendMessage(Utils .colorTranslator("&6Your guardian has been redeemed by your attacker and was destroyed upon spawn!")); event.getGuardianOwner().playSound(event.getGuardianOwner().getLocation(), Sound.ENTITY_ZOMBIE_DEATH, 1.0F, 1.0F); diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/HastyGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/HastyGem.java index 9ad8d7cb..e16bac9c 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/HastyGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/HastyGem.java @@ -51,8 +51,10 @@ public void onBlockBreak(BlockBreakEvent event, Player player, ItemStack itemSta if(SlimefunTag.ORES.isTagged(block.getType()) || SlimefunTag.STONE_VARIANTS.isTagged(block.getType())) { if (ThreadLocalRandom.current().nextInt(100) < (getChance() / getTier(itemStack, this.getId()))) { - PotionEffect potionEffect = new PotionEffect(PotionEffectType.FAST_DIGGING, 80, 2, true, false, false); + PotionEffect potionEffect = new PotionEffect(PotionEffectType.FAST_DIGGING, 120, 2, true, false, false); + player.addPotionEffect(potionEffect); + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(Utils.colorTranslator("&eYou're too hasty now!"))); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/InfernoGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/InfernoGem.java index 8d0c61a4..ec71e41c 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/InfernoGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/InfernoGem.java @@ -24,7 +24,7 @@ public InfernoGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipe } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { if (WeaponArmorEnum.SWORDS.isTagged(itemStackToSocket.getType())) { if(isUpgradeGem(gemItem, this.getId())) { upgradeGem(slimefunGemItem, itemStackToSocket, gemItem, player); @@ -37,7 +37,7 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte } @Override - public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ + public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { if(event.isCancelled()) { return; } @@ -50,17 +50,17 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ int random = ThreadLocalRandom.current().nextInt(100); - if(random < getChance() / getTier(itemStack, this.getId())){ + if(random < getChance() / getTier(itemStack, this.getId())){ livingEntity.setFireTicks(60); if(event.getDamager() instanceof Player) { sendGemMessage((Player) event.getDamager(), this.getItemName()); } } // set the attacked entity on fire - for(Entity entity : livingEntity.getNearbyEntities(7, 4,7)){ - if(random < getChance()){ - if(entity.getUniqueId() != event.getDamager().getUniqueId()){ - entity.setFireTicks(60); + for(Entity entity : livingEntity.getNearbyEntities(8, 4,8)) { + if(random < getChance()) { + if(entity.getUniqueId() != event.getDamager().getUniqueId()) { + entity.setFireTicks(80); } // make sure entity is not the attacker } } // loop nearby entities in a 7 block bounding box and set them on fire diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/LifestealGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/LifestealGem.java index 97d13351..e4c01698 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/LifestealGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/LifestealGem.java @@ -60,10 +60,11 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())) { Bukkit.getScheduler().runTaskLater(FNAmplifications.getInstance(), () -> { // delay getting the actual hp of the damager int playerDefaultHealth = (int) Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getValue(); - if (player.getHealth() <= playerDefaultHealth - 2 && !livingEntity.isDead()) { + + if (player.getHealth() <= playerDefaultHealth - 2 && livingEntity.getHealth() > 2 && !livingEntity.isDead()) { player.setHealth(player.getHealth() + 2); - livingEntity.setHealth(livingEntity.getHealth() < 2 ? livingEntity.getHealth() + (livingEntity.getHealth() * (-1)) : - livingEntity.getHealth() - 2); + livingEntity.setHealth(livingEntity.getHealth() - 2); + sendGemMessage(player, this.getItemName()); } }, 3L); diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/LootGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/LootGem.java index cbddcf34..ccc8ff08 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/LootGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/LootGem.java @@ -55,9 +55,10 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ int random = ThreadLocalRandom.current().nextInt(100); - if(random < getChance() / getTier(itemStack, this.getId())){ + if(random < getChance() / getTier(itemStack, this.getId())) { FNAmplifications.getVaultIntegration().getEconomy().withdrawPlayer(Bukkit.getOfflinePlayer(victim.getUniqueId()), 4.0D); FNAmplifications.getVaultIntegration().getEconomy().depositPlayer(Bukkit.getOfflinePlayer(damager.getUniqueId()), 4.0D); + sendGemMessage(damager, this.getItemName()); sendGemMessage(victim, Utils.colorTranslator("&cEnemy ") + this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/ParryGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/ParryGem.java index bda9f018..9a012e27 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/ParryGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/ParryGem.java @@ -23,7 +23,7 @@ public ParryGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeTy } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { if (WeaponArmorEnum.HELMET.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.CHESTPLATE.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.LEGGINGS.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.BOOTS.isTagged(itemStackToSocket.getType())) { if(isUpgradeGem(gemItem, this.getId())) { @@ -38,26 +38,29 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte @Override public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { - if(event.isCancelled()){ + if(event.isCancelled()) { return; } - if(!(event.getDamager() instanceof LivingEntity)){ + + if(!(event.getDamager() instanceof LivingEntity)) { return; } - if(!(event.getEntity() instanceof Player)){ + + if(!(event.getEntity() instanceof Player)) { return; } LivingEntity damager = (LivingEntity) event.getDamager(); Player player = (Player) event.getEntity(); - if(damager.getEquipment() == null){ + if(damager.getEquipment() == null) { return; } - if(WeaponArmorEnum.SWORDS.isTagged(damager.getEquipment().getItemInMainHand().getType())){ - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())){ - event.setDamage(event.getDamage() * 0.75); + if(WeaponArmorEnum.SWORDS.isTagged(damager.getEquipment().getItemInMainHand().getType())) { + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())) { + event.setDamage(event.getDamage() * 0.6); + if(event.getEntity() instanceof Player) { sendGemMessage(player, this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/PsychokinesisGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/PsychokinesisGem.java index 448603a0..89a68b23 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/PsychokinesisGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/PsychokinesisGem.java @@ -45,7 +45,9 @@ public void onProjectileDamage(EntityDamageByEntityEvent event, Player shooter, if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())){ shooter.getWorld().spawnParticle(Particle.FLASH, entity.getLocation(), 2); + entity.teleport(shooter); + sendGemMessage(shooter, this.getItemName()); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/SedateGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/SedateGem.java index 23658b83..76ebc649 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/SedateGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/SedateGem.java @@ -25,7 +25,7 @@ public SedateGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeT } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { if (WeaponArmorEnum.SWORDS.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.AXES.isTagged(itemStackToSocket.getType())) { if(isUpgradeGem(gemItem, this.getId())) { upgradeGem(slimefunGemItem, itemStackToSocket, gemItem, player); @@ -38,14 +38,16 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte } @Override - public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ - if(!(event.getEntity() instanceof LivingEntity)){ + public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { + if(!(event.getEntity() instanceof LivingEntity)) { return; } - if(!(event.getDamager() instanceof Player)){ + + if(!(event.getDamager() instanceof Player)) { return; } - if(event.isCancelled()){ + + if(event.isCancelled()) { return; } @@ -55,10 +57,10 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ int tier = getTier(itemStack, this.getId()); - if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier){ + if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier) { int level = Math.abs(tier - 4); - livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 80, level)); + livingEntity.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 120, level)); sendGemMessage(player, this.getItemName()); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/ShockwaveGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/ShockwaveGem.java index db916144..14aaffb2 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/ShockwaveGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/ShockwaveGem.java @@ -87,7 +87,7 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { LivingEntity livingEntity = (LivingEntity) event.getDamager(); int tier = getTier(itemStack, this.getId()); - double amount = 3.0D * (tier == 4 ? 1 : Math.abs(tier - 5)); // damage multiplier per tier + double amount = 3.5D * (5 - tier); // damage multiplier per tier if(ThreadLocalRandom.current().nextInt(100) < getChance() / tier){ // cooldown check diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/SmokeCriminalGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/SmokeCriminalGem.java index d6166d32..19dc3d3d 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/SmokeCriminalGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/SmokeCriminalGem.java @@ -42,10 +42,11 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte @Override public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { - if(event.isCancelled()){ + if(event.isCancelled()) { return; } - if(!(event.getEntity() instanceof Player)){ + + if(!(event.getEntity() instanceof Player)) { return; } @@ -61,15 +62,16 @@ public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { AtomicInteger i = new AtomicInteger(0); - Bukkit.getScheduler().runTaskTimer(FNAmplifications.getInstance(), task ->{ - for(double a = 0; a < 50; a += 0.15){ + Bukkit.getScheduler().runTaskTimer(FNAmplifications.getInstance(), task -> { + for(double a = 0; a < 50; a += 0.15) { double x = Math.cos(a) * 0.65; double z = Math.sin(a) * 0.65; double y = a / 25; + victim.getWorld().spawnParticle(Particle.SMOKE_NORMAL, victim.getLocation().clone().add(x, y, z), 0); } - if(i.get() == 10 || victim.isDead() || !victim.isValid()){ + if(i.get() == 10 || victim.isDead() || !victim.isValid()) { task.cancel(); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/StoutGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/StoutGem.java index cb4e4a26..5a0eeba4 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/StoutGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/StoutGem.java @@ -22,7 +22,7 @@ public StoutGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeTy } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { if (WeaponArmorEnum.HELMET.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.CHESTPLATE.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.LEGGINGS.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.BOOTS.isTagged(itemStackToSocket.getType())) { if(isUpgradeGem(gemItem, this.getId())) { @@ -37,12 +37,13 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte @Override public void onDurabilityChange(PlayerItemDamageEvent event) { - if(event.isCancelled()){ + if(event.isCancelled()) { return; } - if(ThreadLocalRandom.current().nextInt(100) < getChance()/ getTier(event.getItem(), this.getId())){ + if(ThreadLocalRandom.current().nextInt(100) < getChance()/ getTier(event.getItem(), this.getId())) { event.setCancelled(true); + sendGemMessage(event.getPlayer(), this.getItemName()); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/TelepathyGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/TelepathyGem.java index 92022c85..dd45e728 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/TelepathyGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/TelepathyGem.java @@ -25,7 +25,7 @@ public TelepathyGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType reci } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { if (WeaponArmorEnum.PICKAXE.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.HOES.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.SHOVELS.isTagged(itemStackToSocket.getType()) || WeaponArmorEnum.AXES.isTagged(itemStackToSocket.getType()) ) { @@ -36,30 +36,30 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte } @Override - public void onBlockBreak(BlockBreakEvent event, Player player, ItemStack itemStack){ - if (event.isCancelled()){ + public void onBlockBreak(BlockBreakEvent event, Player player, ItemStack itemStack) { + if (event.isCancelled()) { return; } Block block = event.getBlock(); - if(block.getType() == Material.LADDER){ // dupe fix against auto ladder + if(block.getType() == Material.LADDER) { // dupe fix against auto ladder return; } Optional sfItem = Optional.ofNullable(BlockStorage.check(block)); - if(sfItem.isPresent()){ // drop sf blocks instead + if(sfItem.isPresent()) { // drop sf blocks instead return; } Collection drops = block.getDrops(player.getInventory().getItemInMainHand()); - if(drops.isEmpty()){ + if(drops.isEmpty()) { return; } // if collection is empty don't do anything further - if(player.getInventory().firstEmpty() == -1){ + if(player.getInventory().firstEmpty() == -1) { return; } // if player inventory is full drop item instead diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/ThornAwayGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/ThornAwayGem.java index 3b0bbbe3..2066e652 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/ThornAwayGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/ThornAwayGem.java @@ -23,7 +23,7 @@ public ThornAwayGem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType reci } @Override - public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket){ + public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemItem, ItemStack itemStackToSocket) { if (WeaponArmorEnum.CHESTPLATE.isTagged(itemStackToSocket.getType())) { if(isUpgradeGem(gemItem, this.getId())) { upgradeGem(slimefunGemItem, itemStackToSocket, gemItem, player); @@ -36,22 +36,24 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte } @Override - public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ - if(event.isCancelled()){ + public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack) { + if(event.isCancelled()) { return; } - if(!(event.getEntity() instanceof Player)){ + + if(!(event.getEntity() instanceof Player)) { return; } Player player = (Player) event.getEntity(); - if(event.getCause() != EntityDamageEvent.DamageCause.THORNS){ + if(event.getCause() != EntityDamageEvent.DamageCause.THORNS) { return; } // if damage cause is not thorns, don't continue - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())){ + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())) { event.setCancelled(true); + sendGemMessage(player, this.getItemName()); } // cancel any thorn damage } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/ThunderBoltGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/ThunderBoltGem.java index 5ea817d3..6ca048c0 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/ThunderBoltGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/ThunderBoltGem.java @@ -37,22 +37,26 @@ public void onDrag(Player player, SlimefunItem slimefunGemItem, ItemStack gemIte @Override public void onDamage(EntityDamageByEntityEvent event, ItemStack itemStack){ - if(event.isCancelled()){ + if(event.isCancelled()) { return; } - if(!(event.getEntity() instanceof LivingEntity)){ + + if(!(event.getEntity() instanceof LivingEntity)) { return; } - if(!(event.getDamager() instanceof Player)){ + + if(!(event.getDamager() instanceof Player)) { return; } Player player = (Player) event.getDamager(); LivingEntity livingEntity = (LivingEntity) event.getEntity(); - if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())){ + if(ThreadLocalRandom.current().nextInt(100) < getChance() / getTier(itemStack, this.getId())) { livingEntity.getWorld().strikeLightning(livingEntity.getLocation()); + player.setNoDamageTicks(20); + sendGemMessage(player, this.getItemName()); } // if below the chance, strike lightning at the victim and set no damage for the attacker for 1 second } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/TriSwordGem.java b/src/main/java/ne/fnfal113/fnamplifications/gems/TriSwordGem.java index 4995e64a..38a3d1bc 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/TriSwordGem.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/TriSwordGem.java @@ -57,9 +57,10 @@ public void onRightClick(Player player){ ThrowWeaponTask throwWeaponTask = new ThrowWeaponTask(player, itemStack.clone(), false, true, pdcValue.equalsIgnoreCase("true"), vector); ArmorStand armorStand = throwWeaponTask.getArmorStand(); - armorStand.setRightArmPose(Utils.setRightArmAngle(armorStand, 0, 348, 0)); - armorStand.setLeftArmPose(Utils.setLeftArmAngle(armorStand, 0, 12, 0)); - armorStand.setHeadPose(Utils.setHeadAngle(armorStand, 98, 32, 97)); + int pitch = (int) player.getLocation().getPitch(); + + armorStand.setRightArmPose(Utils.setRightArmAngle(armorStand, 0 + pitch, 348, 0)); + armorStand.setLeftArmPose(Utils.setLeftArmAngle(armorStand, 0 + pitch, 12, 0)); throwWeaponTask.runTaskTimer(FNAmplifications.getInstance(), 0L, 1L); } catch (IllegalArgumentException e){ diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ReturnWeaponTask.java b/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ReturnWeaponTask.java index 882026f1..d21ddc16 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ReturnWeaponTask.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ReturnWeaponTask.java @@ -16,17 +16,23 @@ */ public class ReturnWeaponTask extends BukkitRunnable { + @Getter + private final Player player; + @Getter private final ItemStack itemStack; + @Getter private final ArmorStand armorStand; + @Getter - private final Player player; + private final boolean isTriWeapon; - public ReturnWeaponTask(ItemStack itemStack, ArmorStand armorStand, Player player){ + public ReturnWeaponTask(Player player, ItemStack itemStack, ArmorStand armorStand, boolean isTriWeapon) { + this.player = player; this.itemStack = itemStack; this.armorStand = armorStand; - this.player = player; + this.isTriWeapon = isTriWeapon; } @Override @@ -64,14 +70,19 @@ value is converted to unit vector(normalized) then we are slowly decrementing th Location asLocationNormalized = asLocation.subtract(asVector.subtract(pVector).normalize()).setDirection(pLocation.getDirection()); getArmorStand().teleport(asLocationNormalized); + if(isTriWeapon()) { + getArmorStand().setHeadPose(Utils.setHeadAngle(getArmorStand(), 18, 30, 18)); + } + // if player is not online, drop the throwable immediately - if(!getPlayer().isOnline()){ + if(!getPlayer().isOnline()) { dropItem(asLocation); + stopTask(); } // drop the item if the distance between player and throwable is 150 blocks away - if(distanceBetween(asLocation, pLocation) > 150){ + if(distanceBetween(asLocation, pLocation) > 150) { Location dropLoc = dropItem(asLocation); getPlayer().sendMessage(Utils.colorTranslator("&cWeapon has not been returned because you're too far!")); getPlayer().sendMessage(Utils.colorTranslator("&cit was dropped at: &e" + @@ -82,7 +93,7 @@ value is converted to unit vector(normalized) then we are slowly decrementing th stopTask(); } - if(distanceBetween(asLocation, pLocation) < 0.5){ + if(distanceBetween(asLocation, pLocation) < 0.5) { if(getPlayer().getInventory().firstEmpty() == -1){ getPlayer().sendMessage(Utils.colorTranslator("&eInventory full! dropped the item instead")); dropItem(pLocation); @@ -95,7 +106,7 @@ value is converted to unit vector(normalized) then we are slowly decrementing th } } - public Location dropItem(Location location){ // drop the throwable weapon if player inventory is full + public Location dropItem(Location location) { // drop the throwable weapon if player inventory is full Item droppedItem = getPlayer().getWorld().dropItem(location, getItemStack().clone()); droppedItem.setOwner(getPlayer().getUniqueId()); droppedItem.setGlowing(true); @@ -104,13 +115,13 @@ public Location dropItem(Location location){ // drop the throwable weapon if pla } // get the distance between two locations and return the square root of the distance - public double distanceBetween(Location asLoc, Location pLoc){ + public double distanceBetween(Location asLoc, Location pLoc) { return asLoc.distance(pLoc); } public void stopTask(){ // stop the task once task has been completed - getArmorStand().remove(); - this.cancel(); + + getArmorStand().remove(); } } diff --git a/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ThrowWeaponTask.java b/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ThrowWeaponTask.java index 7b909136..1355e562 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ThrowWeaponTask.java +++ b/src/main/java/ne/fnfal113/fnamplifications/gems/implementation/ThrowWeaponTask.java @@ -7,6 +7,7 @@ import ne.fnfal113.fnamplifications.utils.WeaponArmorEnum; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Particle; import org.bukkit.Sound; import org.bukkit.Tag; import org.bukkit.entity.ArmorStand; @@ -31,16 +32,22 @@ public class ThrowWeaponTask extends BukkitRunnable { @Getter private final ArmorStand armorStand; + @Getter private final Player player; + @Getter private final ItemStack itemStack; + @Getter private final boolean rotateWeapon; + @Getter private final boolean isTriWeapon; + @Getter private final boolean isRetaliated; + @Getter private final ReturnWeaponTask returnWeaponTask; @@ -48,11 +55,11 @@ public class ThrowWeaponTask extends BukkitRunnable { @Setter private Vector vector; - public ThrowWeaponTask(Player player, ItemStack itemStack, boolean rotateWeapon, boolean isTriWeapon, boolean returnWeapon){ + public ThrowWeaponTask(Player player, ItemStack itemStack, boolean rotateWeapon, boolean isTriWeapon, boolean returnWeapon) { this(player, itemStack, rotateWeapon, isTriWeapon, returnWeapon, new Vector(0, 0, 0)); } - public ThrowWeaponTask(Player player, ItemStack itemStack, boolean rotateWeapon, boolean isTriWeapon, boolean isRetaliated, Vector vector){ + public ThrowWeaponTask(Player player, ItemStack itemStack, boolean rotateWeapon, boolean isTriWeapon, boolean isRetaliated, Vector vector) { this.player = player; this.itemStack = itemStack; this.rotateWeapon = rotateWeapon; @@ -60,11 +67,11 @@ public ThrowWeaponTask(Player player, ItemStack itemStack, boolean rotateWeapon, this.isRetaliated = isRetaliated; this.vector = vector; this.armorStand = spawnArmorstand(player, itemStack); - this.returnWeaponTask = new ReturnWeaponTask(getItemStack(), getArmorStand(), getPlayer()); + this.returnWeaponTask = new ReturnWeaponTask(getPlayer(), getItemStack(), getArmorStand(), isTriWeapon); } - public ArmorStand spawnArmorstand(Player player, ItemStack itemStack){ - return player.getWorld().spawn(player.getLocation().add(0, 0.9, 0), ArmorStand.class, armorStand ->{ + public ArmorStand spawnArmorstand(Player player, ItemStack itemStack) { + return player.getWorld().spawn(player.getLocation().add(0, 0.9, 0), ArmorStand.class, armorStand -> { armorStand.setArms(true); armorStand.setGravity(false); armorStand.setVisible(false); @@ -75,17 +82,17 @@ public ArmorStand spawnArmorstand(Player player, ItemStack itemStack){ getPlayer().playSound(getPlayer().getLocation(), Sound.ENTITY_WITCH_THROW, 1.0F, 1.0F); + ItemStack weapon = itemStack.clone(); + // sets armor stand arm item and body angle if(isTriWeapon()) { // tri-weapon variant - armorStand.setRightArmPose(Utils.setRightArmAngle(armorStand, 0, 0, 0)); - - Objects.requireNonNull(armorStand.getEquipment()).setItemInMainHand(itemStack.clone()); - Objects.requireNonNull(armorStand.getEquipment()).setItemInOffHand(itemStack.clone()); - Objects.requireNonNull(armorStand.getEquipment()).setHelmet(itemStack.clone()); + Objects.requireNonNull(armorStand.getEquipment()).setItemInMainHand(weapon); + Objects.requireNonNull(armorStand.getEquipment()).setItemInOffHand(weapon); + Objects.requireNonNull(armorStand.getEquipment()).setHelmet(weapon); } else { // not a tri-weapon variant armorStand.setRightArmPose(Utils.setRightArmAngle(armorStand, 270, 0, 0)); - Objects.requireNonNull(armorStand.getEquipment()).setItemInMainHand(itemStack.clone()); + Objects.requireNonNull(armorStand.getEquipment()).setItemInMainHand(weapon); } }); } @@ -93,43 +100,52 @@ public ArmorStand spawnArmorstand(Player player, ItemStack itemStack){ @Override public void run() { getArmorStand().teleport(getArmorStand().getLocation().add(getVector())); + getArmorStand().getWorld().spawnParticle(Particle.ASH, getArmorStand().getLocation(), 8, 0.5, 0.5, 0); // rotate floating item by 45 degrees per tick if(isRotateWeapon()) { getArmorStand().setRightArmPose(Utils.setRightArmAngle(getArmorStand(), 45, 0, 0)); } + if(isTriWeapon()) { + getArmorStand().setHeadPose(Utils.setHeadAngle(getArmorStand(), 18, 30, 18)); + } + RayTraceResult result = getArmorStand().rayTraceBlocks(0.109); List entityList = getArmorStand().getNearbyEntities(0.3, 0.3, 0.3); // check if the raytrace result has a block within the max distance // if it hits a block, the weapon is either returned or dropped - if(result != null && - Objects.requireNonNull(result.getHitBlock()).getType() != Material.GRASS && - !Tag.FLOWERS.isTagged(result.getHitBlock().getType())){ + if(result != null && Objects.requireNonNull(result.getHitBlock()).getType() != Material.GRASS + && !Tag.FLOWERS.isTagged(result.getHitBlock().getType())) { if(shouldReturnWeapon(false)) { + returnWeapon(); + return; } dropWeapon(); + return; } // check if there are nearby entities around the given bounding box // if weapon has retaliate gem, return the weapon after damaging an entity else drop it instead // tri-weapon can cut through entities, will not be dropped or returned unless it hits a block or reach max distance - if(!entityList.isEmpty() && !entityList.contains(getPlayer())){ - for(int i = 0; i < entityList.size(); i++){ // using primitive for-loop here, can also use enhanced for-loop + if(!entityList.isEmpty() && !entityList.contains(getPlayer())) { + for(int i = 0; i < entityList.size(); i++) { if(entityList.get(i) instanceof Damageable && entityList.get(i).getUniqueId() != getPlayer().getUniqueId()){ - if(WeaponArmorEnum.SWORDS.isTagged(getItemStack().clone().getType())) { - ((Damageable) entityList.get(i)).damage(ThreadLocalRandom.current().nextInt(100) < 35 ? 8 : 5, getPlayer()); - } else { - ((Damageable) entityList.get(i)).damage(ThreadLocalRandom.current().nextInt(100) < 35 ? 10 : 6, getPlayer()); + if(WeaponArmorEnum.SWORDS.isTagged(getItemStack().clone().getType())) { // for throwable swords + ((Damageable) entityList.get(i)).damage(13, getPlayer()); + } else { + ((Damageable) entityList.get(i)).damage(16, getPlayer()); } } } if(shouldReturnWeapon(true)) { + returnWeapon(); + return; } @@ -141,26 +157,30 @@ public void run() { } // drop the weapon if the distance is greater square-root of 3600 or 60 blocks - if(getArmorStand().getLocation().distanceSquared(getPlayer().getLocation()) > 3600){ + if(getArmorStand().getLocation().distanceSquared(getPlayer().getLocation()) > 3600) { getPlayer().sendMessage(Utils.colorTranslator("&eYour weapon has reached the max distance of 60 blocks!")); if(shouldReturnWeapon(false)) { + returnWeapon(); + return; } + dropWeapon(); } } - public boolean shouldReturnWeapon(boolean entityHit){ - if(!isRetaliated() || (isTriWeapon() && entityHit)) { - return false; - } - returnWeapon(); + public boolean shouldReturnWeapon(boolean entityHit) { + // weapon does not have retaliate gem + if(!isRetaliated()) return false; + + // tri-weapon can pass-through entities + if(isTriWeapon() && entityHit) return false; return true; } - public void dropWeapon(){ + public void dropWeapon() { this.cancel(); Item droppedItem = getArmorStand().getWorld().dropItem(getArmorStand().getLocation(), getItemStack().clone()); @@ -177,17 +197,17 @@ public void dropWeapon(){ "z: " + (int) locInfo.getZ())); } - public void returnWeapon(){ + public void returnWeapon() { this.cancel(); getReturnWeaponTask().runTaskTimer(FNAmplifications.getInstance(), 4L, 1L); } - public void centeredThrow(){ + public void centeredThrow() { getArmorStand().teleport(getPlayer().getLocation().add(0,0.9, 0)); } - public void resetArmorstandArmPos(){ + public void resetArmorstandArmPos() { getArmorStand().setRightArmPose(new EulerAngle(0, 0, 0)); } } \ No newline at end of file diff --git a/src/main/java/ne/fnfal113/fnamplifications/items/FNAmpItems.java b/src/main/java/ne/fnfal113/fnamplifications/items/FNAmpItems.java index a2a4662a..ab0adaa7 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/items/FNAmpItems.java +++ b/src/main/java/ne/fnfal113/fnamplifications/items/FNAmpItems.java @@ -1688,7 +1688,7 @@ public class FNAmpItems { "&cInferno Gem", "", "&eA chance to set enemies in a", - "&e7 block radius on fire", + "&e8 block radius on fire for 4 seconds", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -1706,8 +1706,8 @@ public class FNAmpItems { Material.EMERALD, "&cArmor Impair Gem", "", - "&eA chance to deal extra durability", - "&edamage to all enemy armor at proc", + "&eA chance to deal extra 8 durability", + "&edamage to all enemy armor", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -1756,7 +1756,7 @@ public class FNAmpItems { Material.EMERALD, "&cHasty Gem", "", - "&eA chance to receive 4 seconds", + "&eA chance to receive 5 seconds", "&eof haste when mining ores", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", @@ -1972,7 +1972,7 @@ public class FNAmpItems { "&cDeberserk Gem", "", "&eA chance to decrease damage", - "&etaken from axes by 30%", + "&etaken from axes by 40%", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -1991,7 +1991,7 @@ public class FNAmpItems { "&cParry Gem", "", "&eA chance to decrease damage", - "&etaken from swords by 25%", + "&etaken from swords by 40%", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -2141,7 +2141,7 @@ public class FNAmpItems { Material.EMERALD, "&cAchilles Heel Gem", "", - "&eA chance to deal 2x damage when", + "&eA chance to deal 3.5x damage when", "ðe arrow hits the achilles heel", "&eof an entity or player", "", @@ -2220,8 +2220,8 @@ public class FNAmpItems { "&cLifesteal Gem", "", "&eA chance to steal 1 heart from", - "&eyour enemy as long as your", - "&ehealth is below your max health", + "&eyour enemy as long as you're", + "&enot in full health", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -2241,7 +2241,7 @@ public class FNAmpItems { "", "&eA chance to deal wither effect", "&eat your enemies that lasts for", - "&e4 seconds", + "&e6 seconds", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -2265,7 +2265,7 @@ public class FNAmpItems { "", "&eA chance to deal poison effect", "&eat your enemies that lasts for", - "&e4 seconds", + "&e6 seconds", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -2313,7 +2313,7 @@ public class FNAmpItems { "", "&eA chance to deal weakness effect", "&eat your enemies that lasts for", - "&e4 seconds", + "&e6 seconds", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -2337,7 +2337,7 @@ public class FNAmpItems { "", "&eA chance to deal blindness effect", "&eat your enemies that lasts for", - "&e4 seconds", + "&e6 seconds", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -2361,7 +2361,7 @@ public class FNAmpItems { "", "&eA chance to deal swiftness effect", "&eat your enemies that lasts for", - "&e4 seconds", + "&e6 seconds", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", @@ -2409,13 +2409,13 @@ public class FNAmpItems { "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", "&6⨳ Tier I: " + "&e%", - "&6 - Damage: &f3", + "&6 - Damage: &f4", "&6⨳ Tier II: " + "&e%", - "&6 - Damage: &f6", + "&6 - Damage: &f8", "&6⨳ Tier III: " + "&e%", - "&6 - Damage: &f9", - "&6⨳ Tier IV: " + "&e%", "&6 - Damage: &f12", + "&6⨳ Tier IV: " + "&e%", + "&6 - Damage: &f16", "&c◢◤◢◤◢◤◢◤◢◤◢&6◣◥◣◥◣◥◣◥◣◥◣", "", "&dDrag and drop on any armor type", @@ -2428,7 +2428,7 @@ public class FNAmpItems { "&cBerserk Gem", "", "&eA chance to deal more damage against", - "&eenemies when your health is below 30%.", + "&eenemies when your health is below 40%.", "&eHigher tier gem, much deadly!", "", "&c◢◤◢◤◢◤ Tiers &6◥◣◥◣◥◣", @@ -2439,7 +2439,7 @@ public class FNAmpItems { "&6⨳ Tier III: " + "&e%", "&6 - Damage: &f+18% base damage", "&6⨳ Tier IV: " + "&e%", - "&6 - Damage: &f+30% base damage", + "&6 - Damage: &f+36% base damage", "&c◢◤◢◤◢◤◢◤◢◤◢&6◣◥◣◥◣◥◣◥◣◥◣", "", "&dDrag and drop on sword or axe", From 6bcdb5f3870a321d4054ab7269e3639874747e92 Mon Sep 17 00:00:00 2001 From: FN-FAL113 Date: Wed, 3 Jan 2024 20:03:00 +0800 Subject: [PATCH 2/2] bug fix --- pom.xml | 2 +- .../abstracts/AbstractStick.java | 3 +- .../implementation/StickTask.java | 53 +++++++++++++------ .../tools/abstracts/AbstractHoe.java | 9 ++-- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index e77cf5b2..256cb736 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ne.fnfal113 FNAmplifications - Unoffical-4.1.5 + Unoffical-4.1.6 jar FNAmplifications diff --git a/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/abstracts/AbstractStick.java b/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/abstracts/AbstractStick.java index 7912a01c..6c8d177f 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/abstracts/AbstractStick.java +++ b/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/abstracts/AbstractStick.java @@ -4,6 +4,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; import lombok.Getter; import ne.fnfal113.fnamplifications.mysteriousitems.implementation.StickTask; import org.bukkit.Material; @@ -14,7 +15,7 @@ import java.util.Map; -public abstract class AbstractStick extends SlimefunItem { +public abstract class AbstractStick extends SlimefunItem implements NotPlaceable { @Getter private final StickTask stickTask; diff --git a/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/implementation/StickTask.java b/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/implementation/StickTask.java index b63730fa..d2f8c674 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/implementation/StickTask.java +++ b/src/main/java/ne/fnfal113/fnamplifications/mysteriousitems/implementation/StickTask.java @@ -44,12 +44,12 @@ public class StickTask { public final int requiredLevel; @ParametersAreNonnullByDefault - public StickTask(NamespacedKey key1, NamespacedKey key2, Map enchantmentMap, String weaponLore, String stickLore){ + public StickTask(NamespacedKey key1, NamespacedKey key2, Map enchantmentMap, String weaponLore, String stickLore) { this(key1, key2, enchantmentMap, weaponLore, stickLore, 0, 0); } @ParametersAreNonnullByDefault - public StickTask(NamespacedKey key1, NamespacedKey key2, Map enchantmentMap, String weaponLore, String stickLore, int effectCount, int levelReq){ + public StickTask(NamespacedKey key1, NamespacedKey key2, Map enchantmentMap, String weaponLore, String stickLore, int effectCount, int levelReq) { this.xpKey = key1; this.damageInflictedKey = key2; this.enchantmentMap = enchantmentMap; @@ -59,7 +59,7 @@ public StickTask(NamespacedKey key1, NamespacedKey key2, Map= getRequiredLevel())) { - darkenVision(e.getPlayer(), getRequiredLevel()); + public void onInteract(PlayerInteractEvent event, Material material) { + if(event.getPlayer().getLevel() < getRequiredLevel()) { + darkenVision(event.getPlayer(), getRequiredLevel()); + return; } - Player player = e.getPlayer(); + Player player = event.getPlayer(); + ItemStack itemStack = player.getInventory().getItemInMainHand(); + ItemMeta meta = itemStack.getItemMeta(); convertToWeapon(itemStack, meta, material, player); } - public void convertToWeapon(ItemStack itemStack, ItemMeta meta ,Material material, Player player){ + public void convertToWeapon(ItemStack itemStack, ItemMeta meta ,Material material, Player player) { if(itemStack.getType() == material) { - return; - } // convert the stick to a weapon - + return; + } + + // convert the stick to a weapon meta.setUnbreakable(true); + getEnchantmentMap().forEach((Key, Value) -> meta.addEnchant(Key, Value, true)); + itemMetaUpdate(itemStack, meta ,getWeaponLore(), 0, getPdc(meta.getPersistentDataContainer(), - getXpKey()), false); + getXpKey()), false); + itemStack.setType(material); + player.playSound(player.getLocation(), Sound.ENTITY_ILLUSIONER_MIRROR_MOVE, 1, 1); + player.getWorld().playEffect(player.getLocation().add(0.3, 0.4, 0.45), Effect.ENDER_SIGNAL, 1); player.getWorld().spawnParticle(Particle.FLASH, player.getLocation().add(0.3, 0.4, 0.45), 2, 0.1, 0.1, 0.1, 0.1); } @@ -104,6 +113,7 @@ public void convertToStick(ItemStack item) { lore.add(getStickLore()); meta.setLore(lore); + meta.getEnchants().forEach((enchant, value) -> meta.removeEnchant(enchant)); item.setType(Material.STICK); @@ -119,14 +129,16 @@ public void convertToStick(ItemStack item) { * @param levelDeduction the amount of level to be deducted * @return true if xp level deduction is applied */ - public boolean onSwing(ItemStack item, Player player, double damageAmount, int chance, int levelDeduction){ + public boolean onSwing(ItemStack item, Player player, double damageAmount, int chance, int levelDeduction) { if (player.getLevel() >= getRequiredLevel()) { if(ThreadLocalRandom.current().nextInt(100) > chance){ itemMetaUpdate(item, item.getItemMeta(), getWeaponLore(), (int) damageAmount, levelDeduction, false); + return false; } player.setLevel(player.getLevel() - levelDeduction); + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent. fromLegacyText(Utils.colorTranslator("&d" + levelDeduction + " xp levels has been consumed from you"))); @@ -136,7 +148,9 @@ public boolean onSwing(ItemStack item, Player player, double damageAmount, int c } convertToStick(item); + darkenVision(player, getRequiredLevel()); + return false; } @@ -147,7 +161,7 @@ public boolean onSwing(ItemStack item, Player player, double damageAmount, int c * @param damageInflicted the damage amount inflicted to the enemy * @param xpLevelDeduction the amount of xp levels deducted from the owner */ - public void itemMetaUpdate(ItemStack item, ItemMeta meta, String loreType, int damageInflicted, int xpLevelDeduction, boolean isLevelDeducted){ + public void itemMetaUpdate(ItemStack item, ItemMeta meta, String loreType, int damageInflicted, int xpLevelDeduction, boolean isLevelDeducted) { List lore2 = meta.getLore(); PersistentDataContainer pdc = meta.getPersistentDataContainer(); @@ -162,6 +176,7 @@ public void itemMetaUpdate(ItemStack item, ItemMeta meta, String loreType, int d pdc.set(getDamageInflictedKey(), PersistentDataType.INTEGER, damageAmount); lore2.set(0, loreType); + try { lore2.set(1, ChatColor.YELLOW + "Total Exp Levels Consumed: " + ChatColor.WHITE + xpAmount); lore2.set(2, ChatColor.YELLOW + "Total Damage inflicted: " + ChatColor.WHITE + damageAmount); @@ -170,7 +185,8 @@ public void itemMetaUpdate(ItemStack item, ItemMeta meta, String loreType, int d lore2.add(2, ChatColor.YELLOW + "Total Damage inflicted: " + ChatColor.WHITE + damageAmount); } - if(!(lore2.size() >= 4)){ // add the mystery effect lore + // add the mystery effect lore + if(!(lore2.size() >= 4)) { lore2.add(""); lore2.add(Utils.colorTranslator("&c◢◤◢◤◢◤◢◤| &4&lEffects &f|◥◣◥◣◥◣◥◣")); lore2.add(ChatColor.BLUE + "◆ " + getEffectCount() + " Mystery effect/s"); @@ -178,13 +194,16 @@ public void itemMetaUpdate(ItemStack item, ItemMeta meta, String loreType, int d } meta.setLore(lore2); + item.setItemMeta(meta); } @ParametersAreNonnullByDefault - public void darkenVision(Player player, int level){ + public void darkenVision(Player player, int level) { player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 300, 2, false, false)); - player.sendTitle(ChatColor.DARK_RED + "Your vision darkens!", ChatColor.RED + "The stick is unpredictable", 45, 120, 135); + + player.sendTitle(ChatColor.DARK_RED + "Your vision darkens!", ChatColor.RED + "The stick is unpredictable", 40, 120, 40); + player.sendMessage(ChatColor.RED + "" + ChatColor.BOLD + "[FNAmpli" + ChatColor.AQUA + "" + ChatColor.BOLD + "fications] > " + ChatColor.YELLOW + "You're too weak, make sure your exp level is higher than " + level); } diff --git a/src/main/java/ne/fnfal113/fnamplifications/tools/abstracts/AbstractHoe.java b/src/main/java/ne/fnfal113/fnamplifications/tools/abstracts/AbstractHoe.java index e2320fc1..009b3ff9 100644 --- a/src/main/java/ne/fnfal113/fnamplifications/tools/abstracts/AbstractHoe.java +++ b/src/main/java/ne/fnfal113/fnamplifications/tools/abstracts/AbstractHoe.java @@ -4,11 +4,13 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; + import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -public abstract class AbstractHoe extends SlimefunItem { +public abstract class AbstractHoe extends SlimefunItem implements NotPlaceable { public AbstractHoe(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(itemGroup, item, recipeType, recipe); @@ -29,9 +31,4 @@ public AbstractHoe(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recip */ public abstract void onLeftClick(Player player, Block clickedBlock, ItemStack itemStack); - @Override - public boolean useVanillaBlockBreaking(){ - return true; - } - } \ No newline at end of file