2
0
Эх сурвалжийг харах

Initial work on crossbows

nossr50 5 жил өмнө
parent
commit
7543d8be12

+ 1 - 0
Changelog.txt

@@ -17,6 +17,7 @@ Version 2.1.133
     Smelting now has a Bonus Drops section in config.yml
     Smelting now has a Bonus Drops section in config.yml
     Second Smelt now only doubles smelting results for items which have bonus drop entries in the config
     Second Smelt now only doubles smelting results for items which have bonus drop entries in the config
     Fixed an array out of index bug for inventory click events
     Fixed an array out of index bug for inventory click events
+    mcMMO will now register arrows shot from the offhand as being from either Archery or Crossbows (before mcMMO ignored offhand Archery)
 
 
     (These permissions are all included in the mcmmo.defaults node)
     (These permissions are all included in the mcmmo.defaults node)
     New permission node 'mcmmo.commands.tridents'
     New permission node 'mcmmo.commands.tridents'

+ 17 - 0
src/main/java/com/gmail/nossr50/datatypes/meta/ProjectileOriginMeta.java

@@ -0,0 +1,17 @@
+package com.gmail.nossr50.datatypes.meta;
+
+import org.bukkit.metadata.FixedMetadataValue;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+public class ProjectileOriginMeta extends FixedMetadataValue {
+    /**
+     * Initializes a FixedMetadataValue with an Object
+     *
+     * @param owningPlugin the {@link Plugin} that created this metadata value
+     * @param value        the value assigned to this metadata value
+     */
+    public ProjectileOriginMeta(@NotNull Plugin owningPlugin, int value) {
+        super(owningPlugin, value);
+    }
+}

+ 22 - 2
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -4,6 +4,7 @@ import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
+import com.gmail.nossr50.datatypes.meta.ProjectileOriginMeta;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.subskills.interfaces.InteractType;
 import com.gmail.nossr50.datatypes.skills.subskills.interfaces.InteractType;
@@ -19,6 +20,7 @@ import com.gmail.nossr50.skills.taming.Taming;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.util.BlockUtils;
 import com.gmail.nossr50.util.BlockUtils;
+import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
@@ -122,7 +124,7 @@ public class EntityListener implements Listener {
         projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, projectile.getLocation()));
         projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, projectile.getLocation()));
     }
     }
 
 
-    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+    @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
     public void onProjectileLaunch(ProjectileLaunchEvent event) {
     public void onProjectileLaunch(ProjectileLaunchEvent event) {
         /* WORLD BLACKLIST CHECK */
         /* WORLD BLACKLIST CHECK */
         if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
         if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld()))
@@ -144,9 +146,19 @@ public class EntityListener implements Listener {
             if(!(projectile instanceof Arrow))
             if(!(projectile instanceof Arrow))
                 return;
                 return;
 
 
-            projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(plugin, 1.0));
             projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, projectile.getLocation()));
             projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, projectile.getLocation()));
 
 
+            //Track origin of projectile
+            if(ItemUtils.hasItemInMainHand(player, "bow")) {
+                markProjectileOriginAsBow(projectile);
+            } else if(ItemUtils.hasItemInMainHand(player, "crossbow")) {
+                markProjectileOriginAsCrossbow(projectile);
+            } else if(ItemUtils.hasItemInOffHand(player, "bow")) {
+                markProjectileOriginAsBow(projectile);
+            } else if(ItemUtils.hasItemInOffHand(player, "crossbow")) {
+                markProjectileOriginAsCrossbow(projectile);
+            }
+
             for(Enchantment enchantment : player.getInventory().getItemInMainHand().getEnchantments().keySet()) {
             for(Enchantment enchantment : player.getInventory().getItemInMainHand().getEnchantments().keySet()) {
                 if(enchantment.getName().equalsIgnoreCase("piercing"))
                 if(enchantment.getName().equalsIgnoreCase("piercing"))
                     return;
                     return;
@@ -158,6 +170,14 @@ public class EntityListener implements Listener {
         }
         }
     }
     }
 
 
+    private void markProjectileOriginAsCrossbow(Projectile projectile) {
+        projectile.setMetadata(mcMMO.PROJECTILE_ORIGIN_METAKEY, new ProjectileOriginMeta(plugin, 2));
+    }
+
+    private void markProjectileOriginAsBow(Projectile projectile) {
+        projectile.setMetadata(mcMMO.PROJECTILE_ORIGIN_METAKEY, new ProjectileOriginMeta(plugin, 1));
+    }
+
     /**
     /**
      * Monitor EntityChangeBlock events.
      * Monitor EntityChangeBlock events.
      *
      *

+ 1 - 0
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -134,6 +134,7 @@ public class mcMMO extends JavaPlugin {
     public final static String greenThumbDataKey   = "mcMMO: Green Thumb";
     public final static String greenThumbDataKey   = "mcMMO: Green Thumb";
     public final static String databaseCommandKey  = "mcMMO: Processing Database Command";
     public final static String databaseCommandKey  = "mcMMO: Processing Database Command";
     public final static String bredMetadataKey     = "mcMMO: Bred Animal";
     public final static String bredMetadataKey     = "mcMMO: Bred Animal";
+    public final static String PROJECTILE_ORIGIN_METAKEY = "mcMMO: Projectile Origin";
 
 
     public static FixedMetadataValue metadataValue;
     public static FixedMetadataValue metadataValue;
 
 

+ 28 - 0
src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowManager.java

@@ -2,10 +2,38 @@ package com.gmail.nossr50.skills.crossbows;
 
 
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.SkillManager;
+import com.gmail.nossr50.skills.archery.Archery;
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
 
 
 public class CrossbowManager extends SkillManager {
 public class CrossbowManager extends SkillManager {
     public CrossbowManager(McMMOPlayer mcMMOPlayer) {
     public CrossbowManager(McMMOPlayer mcMMOPlayer) {
         super(mcMMOPlayer, PrimarySkillType.CROSSBOWS);
         super(mcMMOPlayer, PrimarySkillType.CROSSBOWS);
     }
     }
+
+    /**
+     * Calculate bonus XP awarded for Archery when hitting a far-away target.
+     *
+     * @param target The {@link LivingEntity} damaged by the arrow
+     * @param damager The {@link Entity} who shot the arrow
+     */
+    public double distanceXpBonusMultiplier(LivingEntity target, Entity damager) {
+        //Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires
+        if(!damager.hasMetadata(mcMMO.arrowDistanceKey))
+            return damager.getLocation().distance(target.getLocation());
+
+        Location firedLocation = (Location) damager.getMetadata(mcMMO.arrowDistanceKey).get(0).value();
+        Location targetLocation = target.getLocation();
+
+        if (firedLocation.getWorld() != targetLocation.getWorld()) {
+            return 1;
+        }
+
+        //TODO: Should use its own variable
+        return 1 + Math.min(firedLocation.distance(targetLocation), 50) * Archery.DISTANCE_XP_MULTIPLIER;
+    }
+
 }
 }

+ 15 - 1
src/main/java/com/gmail/nossr50/util/ItemUtils.java

@@ -31,9 +31,23 @@ public final class ItemUtils {
 
 
 
 
     public static boolean hasItemInEitherHand(Player player, Material material) {
     public static boolean hasItemInEitherHand(Player player, Material material) {
-        return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material;
+        return hasItemInEitherHand(player, material.getKey().getKey());
     }
     }
 
 
+    public static boolean hasItemInEitherHand(Player player, String id) {
+        return player.getInventory().getItemInMainHand().getType().getKey().getKey().equalsIgnoreCase(id)
+                || player.getInventory().getItemInOffHand().getType().getKey().getKey().equalsIgnoreCase(id);
+    }
+
+    public static boolean hasItemInMainHand(Player player, String id) {
+        return player.getInventory().getItemInMainHand().getType().getKey().getKey().equalsIgnoreCase(id);
+    }
+
+    public static boolean hasItemInOffHand(Player player, String id) {
+        return player.getInventory().getItemInOffHand().getType().getKey().getKey().equalsIgnoreCase(id);
+    }
+
+
     /**
     /**
      * Checks if the item is a sword.
      * Checks if the item is a sword.
      *
      *

+ 68 - 9
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -16,6 +16,7 @@ import com.gmail.nossr50.runnables.skills.AwardCombatXpTask;
 import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
 import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
 import com.gmail.nossr50.skills.archery.ArcheryManager;
 import com.gmail.nossr50.skills.archery.ArcheryManager;
 import com.gmail.nossr50.skills.axes.AxesManager;
 import com.gmail.nossr50.skills.axes.AxesManager;
+import com.gmail.nossr50.skills.crossbows.CrossbowManager;
 import com.gmail.nossr50.skills.swords.SwordsManager;
 import com.gmail.nossr50.skills.swords.SwordsManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.tridents.TridentManager;
 import com.gmail.nossr50.skills.tridents.TridentManager;
@@ -308,13 +309,49 @@ public final class CombatUtils {
         }
         }
 
 
         double distanceMultiplier = archeryManager.distanceXpBonusMultiplier(target, arrow);
         double distanceMultiplier = archeryManager.distanceXpBonusMultiplier(target, arrow);
-        double forceMultiplier = 1.0; //Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires
+//        double forceMultiplier = 1.0; //Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires
 
 
-        if(arrow.hasMetadata(mcMMO.bowForceKey))
-            forceMultiplier = arrow.getMetadata(mcMMO.bowForceKey).get(0).asDouble();
+//        if(arrow.hasMetadata(mcMMO.bowForceKey))
+//            forceMultiplier = arrow.getMetadata(mcMMO.bowForceKey).get(0).asDouble();
 
 
         applyScaledModifiers(initialDamage, finalDamage, event);
         applyScaledModifiers(initialDamage, finalDamage, event);
-        processCombatXP(mcMMOPlayer, target, PrimarySkillType.ARCHERY, forceMultiplier * distanceMultiplier);
+        processCombatXP(mcMMOPlayer, target, PrimarySkillType.ARCHERY, distanceMultiplier);
+    }
+
+    private static void processCrossbowCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Projectile arrow) {
+        double initialDamage = event.getDamage();
+
+        McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
+
+        //Make sure the profiles been loaded
+        if(mcMMOPlayer == null) {
+            return;
+        }
+
+        CrossbowManager crossbowManager = mcMMOPlayer.getCrossbowManager();
+
+        double finalDamage = event.getDamage();
+
+        if (target instanceof Player && PrimarySkillType.UNARMED.getPVPEnabled()) {
+            UnarmedManager unarmedManager = UserManager.getPlayer((Player) target).getUnarmedManager();
+
+            if (unarmedManager.canDeflect()) {
+                event.setCancelled(unarmedManager.deflectCheck());
+
+                if (event.isCancelled()) {
+                    return;
+                }
+            }
+        }
+
+        if(canUseLimitBreak(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK))
+        {
+            finalDamage+=getLimitBreakDamage(player, target, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK);
+        }
+
+        double distanceMultiplier = crossbowManager.distanceXpBonusMultiplier(target, arrow);
+        applyScaledModifiers(initialDamage, finalDamage, event);
+        processCombatXP(mcMMOPlayer, target, PrimarySkillType.CROSSBOWS, distanceMultiplier);
     }
     }
 
 
     /**
     /**
@@ -433,18 +470,32 @@ public final class CombatUtils {
         }
         }
         else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) {
         else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) {
             Projectile arrow = (Projectile) painSource;
             Projectile arrow = (Projectile) painSource;
-            ProjectileSource projectileSource = arrow.getShooter();
+            ProjectileSource projectileShooter = arrow.getShooter();
 
 
             //Determine if the arrow belongs to a bow or xbow
             //Determine if the arrow belongs to a bow or xbow
 
 
 
 
-            if (projectileSource instanceof Player && PrimarySkillType.ARCHERY.shouldProcess(target)) {
-                Player player = (Player) projectileSource;
+            if (projectileShooter instanceof Player) {
+                Player player = (Player) projectileShooter;
 
 
-                if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.ARCHERY.getPermissions(player)) {
-                    processArcheryCombat(target, player, event, arrow);
+                //Has metadata
+                if(arrow.getMetadata(mcMMO.PROJECTILE_ORIGIN_METAKEY).size() > 0) {
+                    if(isProjectileFromBow(arrow)) {
+                        if(PrimarySkillType.ARCHERY.shouldProcess(target)) {
+                            if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.ARCHERY.getPermissions(player)) {
+                                processArcheryCombat(target, player, event, arrow);
+                            }
+                        }
+                    } else if(isProjectileFromCrossbow(arrow)) {
+                        if(PrimarySkillType.CROSSBOWS.shouldProcess(target)) {
+                            if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.CROSSBOWS.getPermissions(player)) {
+                                processCrossbowCombat(target, player, event, arrow);
+                            }
+                        }
+                    }
                 }
                 }
 
 
+
                 if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) {
                 if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) {
                     McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
                     McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
                     TamingManager tamingManager = mcMMOPlayer.getTamingManager();
                     TamingManager tamingManager = mcMMOPlayer.getTamingManager();
@@ -454,6 +505,14 @@ public final class CombatUtils {
         }
         }
     }
     }
 
 
+    private static boolean isProjectileFromCrossbow(Projectile arrow) {
+        return arrow.getMetadata(mcMMO.PROJECTILE_ORIGIN_METAKEY).get(0).asInt() == 2;
+    }
+
+    private static boolean isProjectileFromBow(Projectile arrow) {
+        return arrow.getMetadata(mcMMO.PROJECTILE_ORIGIN_METAKEY).get(0).asInt() == 1;
+    }
+
     /**
     /**
      * This cleans up names from displaying in chat as hearts
      * This cleans up names from displaying in chat as hearts
      * @param entity target entity
      * @param entity target entity