diff --git a/README.md b/README.md index 91bae0f..8aa0be7 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Sentinel integrations with a few external plugins, including: - /sentinel greetrange RANGE - Sets how far a player can be from an NPC before they are greeted. - /sentinel accuracy OFFSET - Sets the accuracy of an NPC. - /sentinel squad SQUAD - Sets the NPC's squad name (null for none). +- /sentinel realistic - Toggles whether the NPC should use "realistic" targetting logic (don't attack things you can't see.) ### Sentry user? diff --git a/src/main/java/org/mcmonkey/sentinel/SentinelPlugin.java b/src/main/java/org/mcmonkey/sentinel/SentinelPlugin.java index eb8152e..071cadb 100644 --- a/src/main/java/org/mcmonkey/sentinel/SentinelPlugin.java +++ b/src/main/java/org/mcmonkey/sentinel/SentinelPlugin.java @@ -710,6 +710,24 @@ else if (arg0.equals("autoswitch") && sender.hasPermission("sentinel.autoswitch" } return true; } + else if (arg0.equals("realistic") && sender.hasPermission("sentinel.realistic")) { + boolean mode = !sentinel.realistic; + if (args.length > 1 && "true".equalsIgnoreCase(args[1])) { + mode = true; + } + if (args.length > 1 && "false".equalsIgnoreCase(args[1])) { + mode = false; + } + sentinel.realistic = mode; + + if (sentinel.realistic) { + sender.sendMessage(prefixGood + "NPC now targets realistically!"); + } + else { + sender.sendMessage(prefixGood + "NPC no longer targets realistically!"); + } + return true; + } else if (arg0.equals("fightback") && sender.hasPermission("sentinel.fightback")) { boolean mode = !sentinel.fightback; if (args.length > 1 && "true".equalsIgnoreCase(args[1])) { @@ -916,6 +934,7 @@ else if (arg0.equals("info") && sender.hasPermission("sentinel.info")) { sender.sendMessage(prefixGood + "Safe-Shot Enabled: " + ChatColor.AQUA + sentinel.safeShot); sender.sendMessage(prefixGood + "Enemy-Drops Enabled: " + ChatColor.AQUA + sentinel.enemyDrops); sender.sendMessage(prefixGood + "Autoswitch Enabled: " + ChatColor.AQUA + sentinel.autoswitch); + sender.sendMessage(prefixGood + "Realistic Targetting Enabled: " + ChatColor.AQUA + sentinel.realistic); sender.sendMessage(prefixGood + "Squad: " + ChatColor.AQUA + (sentinel.squad == null ? "None" : sentinel.squad)); return true; } @@ -1030,6 +1049,9 @@ else if (arg0.equals("stats") && sender.hasPermission("sentinel.info")) { if (sender.hasPermission("sentinel.squad")) { sender.sendMessage(prefixGood + "/sentinel squad SQUAD - Sets the NPC's squad name (null for none)."); } + if (sender.hasPermission("sentinel.realistic")) { + sender.sendMessage(prefixGood + "/sentinel realistic - Toggles whether the NPC should use \"realistic\" targetting logic (don't attack things you can't see.)"); + } if (sender.hasPermission("sentinel.greet")) { sender.sendMessage(prefixGood + "/sentinel greeting GREETING - Sets a greeting message for the NPC to say."); } diff --git a/src/main/java/org/mcmonkey/sentinel/SentinelTrait.java b/src/main/java/org/mcmonkey/sentinel/SentinelTrait.java index 0688ed7..fe74bc5 100644 --- a/src/main/java/org/mcmonkey/sentinel/SentinelTrait.java +++ b/src/main/java/org/mcmonkey/sentinel/SentinelTrait.java @@ -222,6 +222,9 @@ public SentinelTrait() { @Persist("accuracy") public double accuracy = 0; + @Persist("realistic") + public boolean realistic = false; + public LivingEntity chasing = null; public UUID getGuarding() { @@ -1331,8 +1334,48 @@ else if (closeChase) { } } + public float getYaw(Vector vector) { + double dx = vector.getX(); + double dz = vector.getZ(); + double yaw = 0; + // Set yaw + if (dx != 0) { + // Set yaw start value based on dx + if (dx < 0) { + yaw = 1.5 * Math.PI; + } + else { + yaw = 0.5 * Math.PI; + } + yaw -= Math.atan(dz / dx); // or atan2? + } + else if (dz < 0) { + yaw = Math.PI; + } + return (float) (-yaw * 180 / Math.PI); + } + public boolean canSee(LivingEntity entity) { - return getLivingEntity().hasLineOfSight(entity); + if (!getLivingEntity().hasLineOfSight(entity)) { + return false; + } + if (realistic) { + float yaw = getLivingEntity().getEyeLocation().getYaw(); + while (yaw < 0) { + yaw += 360; + } + while (yaw >= 360) { + yaw -= 360; + } + Vector rel = entity.getLocation().toVector().subtract(getLivingEntity().getLocation().toVector()).normalize(); + float yawHelp = getYaw(rel); + if (!(Math.abs(yawHelp - yaw) < 90 || + Math.abs(yawHelp + 360 - yaw) < 90 || + Math.abs(yaw + 360 - yawHelp) < 90)) { + return false; + } + } + return true; } public LivingEntity getLivingEntity() { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ef0c638..f82ac3a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -36,6 +36,8 @@ sentinel defaults: autoswitch: false # Accuracy offset, 0 means perfectly accurate, 5 means pretty inaccurate. accuracy: 0 + # "Realistic" logic, don't attack targets we can't see, if enabled. + realistic: false random: # What sound to play when the "spectral" attack is used. diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c7ba281..5a190e0 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -78,6 +78,8 @@ permissions: sentinel.accuracy: true # /sentinel squad SQUAD sentinel.squad: true + # /sentinel realistic + sentinel.realistic: true # /sentinel debug sentinel.debug: true # /sentinel greeting GREETING, sentinel warning WARNING, sentinel greetrange RANGE