diff --git a/src/engine/ai/MobileFSM.java b/src/engine/ai/MobileFSM.java index fe6a2aa3..8a841f11 100644 --- a/src/engine/ai/MobileFSM.java +++ b/src/engine/ai/MobileFSM.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; +import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; @@ -41,7 +42,6 @@ import static engine.math.FastMath.sqr; public class MobileFSM { - public enum STATE { Disabled, Respawn, @@ -56,13 +56,10 @@ public class MobileFSM { Recalling, Retaliate } - public static void run(Mob mob) { if (mob == null) { return; } - - STATE state = mob.getState(); switch (state) { case Idle: @@ -73,11 +70,9 @@ public class MobileFSM { guardAwake(mob); break; } - idle(mob); break; case Awake: - if (mob.isAlive()) mob.updateLocation(); @@ -91,11 +86,8 @@ public class MobileFSM { else awake(mob); } - break; case Aggro: - - if (mob.isAlive()) mob.updateLocation(); @@ -609,8 +601,12 @@ public class MobileFSM { aiAgent.setState(STATE.Idle); return; } - - handlePlayerAttackForMob(aiAgent, player); + if(canCast(aiAgent) == true){ + MobCast(aiAgent); + } + else { + handlePlayerAttackForMob(aiAgent, player); + } break; case Building: Building building = (Building) target; @@ -824,20 +820,6 @@ public class MobileFSM { return; } - if (aiAgent.getLastMobPowerToken() != 0) { - - PowersBase mobPower = PowersManager.getPowerByToken(aiAgent.getLastMobPowerToken()); - - if (System.currentTimeMillis() > aiAgent.getTimeStamp("FInishCast")) { - PerformActionMsg msg = PowersManager.createPowerMsg(mobPower, 40, aiAgent, player); - msg.setUnknown04(2); - PowersManager.finishUseMobPower(msg, aiAgent, 0, 0); - aiAgent.setLastMobPowerToken(0); - aiAgent.setIsCasting(false); - } - return; - } - if (System.currentTimeMillis() > aiAgent.getTimeStamp("CallForHelp")) { CombatUtilities.CallForHelp(aiAgent); aiAgent.getTimestamps().put("CallForHelp", System.currentTimeMillis() + 60000); @@ -1682,8 +1664,12 @@ public class MobileFSM { aiAgent.setState(STATE.Idle); return; } - - handlePlayerAttackForMob(aiAgent, player); + if(canCast(aiAgent) == true){ + MobCast(aiAgent); + } + else { + handlePlayerAttackForMob(aiAgent, player); + } break; case Building: Logger.info("PLAYER GUARD ATTEMPTING TO ATTACK BUILDING IN " + aiAgent.getParentZone().getName()); @@ -1765,4 +1751,42 @@ public class MobileFSM { MovementManager.translocate(mob, regionObject.getLoc(), null); } + + public static boolean canCast(Mob mob){ + if(mob == null || mob.mobPowers.isEmpty() || mob.nextCastTime > System.currentTimeMillis()){ + return false; + } + else{ + return true; + } + } + public static void MobCast(Mob mob){ + if(mob.getMobBase().getFlags().contains(Enum.MobFlagType.CALLSFORHELP)){ + MobCallForHelp(mob); + } + PlayerCharacter target = (PlayerCharacter)mob.getCombatTarget(); + Random rand = new Random(); + int powerPos = rand.nextInt(mob.mobPowers.size()); + int spellId = mob.mobPowers.get(powerPos); + PowersBase mobPower = PowersManager.getPowerByToken(spellId); + if(CombatUtilities.inRangeToCast2D(mob, mob.getCombatTarget(),mobPower)) { + PerformActionMsg msg = PowersManager.createPowerMsg(mobPower, 40, mob, target); + msg.setUnknown04(2); + PowersManager.finishUseMobPower(msg, mob, 0, 0); + mob.setLastMobPowerToken(0); + mob.setIsCasting(false); + mob.nextCastTime = System.currentTimeMillis() + mobPower.getCooldown(); + }else{ + MovementUtilities.moveToLocation(mob,mob.getCombatTarget().getLoc(),mobPower.getRange()); + } + } + public static void MobCallForHelp(Mob mob){ + Zone mobCamp = mob.getParentZone(); + for (Mob mob1 : mobCamp.zoneMobSet) { + if(mob1.getMobBase().getFlags().contains(Enum.MobFlagType.RESPONDSTOCALLSFORHELP)){ + mob1.setCombatTarget(mob.getCombatTarget()); + mob1.setState(STATE.Aggro); + } + } + } } diff --git a/src/engine/ai/utilities/CombatUtilities.java b/src/engine/ai/utilities/CombatUtilities.java index 32fb1fe5..f913b84d 100644 --- a/src/engine/ai/utilities/CombatUtilities.java +++ b/src/engine/ai/utilities/CombatUtilities.java @@ -58,7 +58,6 @@ public class CombatUtilities { } } - public static boolean inRangeToAttack2D(Mob agent,AbstractWorldObject target){ if (Float.isNaN(agent.getLoc().x)) @@ -82,7 +81,21 @@ public class CombatUtilities { } } + public static boolean inRangeToCast2D(Mob agent,AbstractWorldObject target, PowersBase power) { + if (Float.isNaN(agent.getLoc().x)) + return false; + try { + Vector3fImmutable sl = agent.getLoc(); + Vector3fImmutable tl = target.getLoc(); + float range = power.getRange(); + range += CombatManager.calcHitBox(target) + CombatManager.calcHitBox(agent); + return !(sl.distanceSquared2D(tl) > sqr(range)); + } catch (Exception e) { + Logger.error(e.toString()); + return false; + } + } public static void swingIsBlock(Mob agent,AbstractWorldObject target, int animation) { if (!target.isAlive()) diff --git a/src/engine/objects/Mob.java b/src/engine/objects/Mob.java index 4f0979bd..7d5d7d31 100644 --- a/src/engine/objects/Mob.java +++ b/src/engine/objects/Mob.java @@ -91,6 +91,7 @@ public class Mob extends AbstractIntelligenceAgent { private int aggroTargetID = 0; private boolean walkingHome = true; private long lastAttackTime = 0; + public long nextCastTime = 0; private long deathTime = 0; private ConcurrentHashMap siegeMinionMap = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); public ReentrantReadWriteLock minionLock = new ReentrantReadWriteLock();