diff --git a/src/engine/mobileAI/MobAI.java b/src/engine/mobileAI/MobAI.java index df1c7581..35ad9880 100644 --- a/src/engine/mobileAI/MobAI.java +++ b/src/engine/mobileAI/MobAI.java @@ -624,7 +624,7 @@ public class MobAI { SuperSimpleMobAI.run(mob); return; } - boolean override = false; + boolean override; switch (mob.BehaviourType) { case GuardCaptain: case GuardMinion: diff --git a/src/engine/mobileAI/MobHandlers/PlayerGuardHandler.java b/src/engine/mobileAI/MobHandlers/PlayerGuardHandler.java index e062d753..e6713f21 100644 --- a/src/engine/mobileAI/MobHandlers/PlayerGuardHandler.java +++ b/src/engine/mobileAI/MobHandlers/PlayerGuardHandler.java @@ -1,9 +1,281 @@ package engine.mobileAI.MobHandlers; -import engine.objects.Mob; +import engine.gameManager.PowersManager; +import engine.mobileAI.Threads.MobAIThread; +import engine.mobileAI.utilities.CombatUtilities; +import engine.mobileAI.utilities.MovementUtilities; +import engine.net.client.msg.PerformActionMsg; +import engine.objects.*; +import engine.powers.ActionsBase; +import engine.powers.PowersBase; + +import java.util.ArrayList; +import java.util.concurrent.ThreadLocalRandom; public class PlayerGuardHandler { - public static void run(Mob guard){ + public static void run(Mob guard) { + try { + if (guard.combatTarget != null) { + checkToDropGuardAggro(guard); + } + + if (guard.combatTarget == null) + CheckForPlayerGuardAggro(guard); + + CheckGuardMovement(guard); + + if (guard.combatTarget != null && CombatUtilities.inRangeToAttack(guard, guard.combatTarget)) + CheckToAttack(guard); + + } catch (Exception ignored) { + + } + } + + public static void checkToDropGuardAggro(Mob guard){ + if(guard.combatTarget.loc.distanceSquared(guard.loc) > (128f * 128f)) + guard.setCombatTarget(null); + } + + public static void CheckForPlayerGuardAggro(Mob guard){ + PlayerCharacter tar = null; + for(int id : guard.playerAgroMap.keySet()){ + PlayerCharacter target = PlayerCharacter.getFromCache(id); + + if(target.loc.distanceSquared(guard.loc) > guard.getAggroRange() * guard.getAggroRange()) + continue; + + if(tar == null || guard.loc.distanceSquared(tar.loc) < guard.loc.distanceSquared(target.loc)) + if(MobCanAggro(guard,target)) + tar = target; + } + if(tar != null) + guard.setCombatTarget(tar); + } + + public static Boolean MobCanAggro(Mob mob, PlayerCharacter loadedPlayer){ + if (loadedPlayer == null) + return false; + + //Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map. + if (!loadedPlayer.isAlive()) + return false; + + //Can't see target, skip aggro. + if (!mob.canSee(loadedPlayer)) + return false; + + if(mob.guardedCity != null && mob.guardedCity.cityOutlaws.contains(loadedPlayer.getObjectUUID())) + return true; + + if(loadedPlayer.guild.getNation().equals(mob.guardedCity.getGuild().getNation())) + return false; + + if(mob.guardedCity.isOpen()) + return false; + + return true; + } + + public static boolean GuardCast(Mob mob) { + + try { + // Method picks a random spell from a mobile's list of powers + // and casts it on the current target (or itself). Validation + // (including empty lists) is done previously within canCast(); + + ArrayList powerTokens; + ArrayList purgeTokens; + AbstractCharacter target = (AbstractCharacter) mob.getCombatTarget(); + + // Generate a list of tokens from the mob powers for this mobile. + + powerTokens = new ArrayList<>(mob.mobPowers.keySet()); + purgeTokens = new ArrayList<>(); + + // If player has this effect on them currently then remove + // this token from our list. + + for (int powerToken : powerTokens) { + + PowersBase powerBase = PowersManager.getPowerByToken(powerToken); + + for (ActionsBase actionBase : powerBase.getActions()) { + + String stackType = actionBase.stackType; + + if (target.getEffects() != null && target.getEffects().containsKey(stackType)) + purgeTokens.add(powerToken); + } + } + + powerTokens.removeAll(purgeTokens); + + // Sanity check + + if (powerTokens.isEmpty()) + return false; + + int powerToken = 0; + int nukeRoll = ThreadLocalRandom.current().nextInt(1,100); + + if (nukeRoll < 55) { + + //use direct damage spell + powerToken = powerTokens.get(powerTokens.size() - 1); + + } else { + //use random spell + powerToken = powerTokens.get(ThreadLocalRandom.current().nextInt(powerTokens.size())); + } + + int powerRank = 1; + + switch(mob.getRank()){ + case 1: + powerRank = 10; + break; + case 2: + powerRank = 15; + break; + case 3: + powerRank = 20; + break; + case 4: + powerRank = 25; + break; + case 5: + powerRank = 30; + break; + case 6: + powerRank = 35; + break; + case 7: + powerRank = 40; + break; + } + + PowersBase mobPower = PowersManager.getPowerByToken(powerToken); + + //check for hit-roll + + if (mobPower.requiresHitRoll) + if (CombatUtilities.triggerDefense(mob, mob.getCombatTarget())) + return false; + + // Cast the spell + + if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mobPower.getRange())) { + + PerformActionMsg msg; + + if (!mobPower.isHarmful() || mobPower.targetSelf) { + + if (mobPower.category.equals("DISPEL")) { + PowersManager.useMobPower(mob, target, mobPower, powerRank); + msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, target); + } else { + PowersManager.useMobPower(mob, mob, mobPower, powerRank); + msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, mob); + } + } else { + PowersManager.useMobPower(mob, target, mobPower, powerRank); + msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, target); + } + + msg.setUnknown04(2); + + PowersManager.finishUseMobPower(msg, mob, 0, 0); + return true; + } + } catch (Exception e) { + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage()); + } + return false; + } + + public static void CheckToAttack(Mob mob){ + try { + + if(mob.getLastAttackTime() > System.currentTimeMillis()) + return; + + PlayerCharacter target = (PlayerCharacter) mob.combatTarget; + + if (!mob.canSee(target)) { + mob.setCombatTarget(null); + return; + } + + if (mob.isMoving() && mob.getRange() > 20) + return; + + if(target.combatStats == null) + target.combatStats = new PlayerCombatStats(target); + + ItemBase mainHand = mob.getWeaponItemBase(true); + ItemBase offHand = mob.getWeaponItemBase(false); + + if (mainHand == null && offHand == null) { + CombatUtilities.combatCycle(mob, target, true, null); + int delay = 3000; + mob.setLastAttackTime(System.currentTimeMillis() + delay); + } else if (mob.getWeaponItemBase(true) != null) { + int delay = 3000; + CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); + mob.setLastAttackTime(System.currentTimeMillis() + delay); + } else if (mob.getWeaponItemBase(false) != null) { + int attackDelay = 3000; + CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); + mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + } + + if (target.getPet() != null) + if (target.getPet().getCombatTarget() == null && target.getPet().assist) + target.getPet().setCombatTarget(mob); + + } catch (Exception e) { + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer" + " " + e.getMessage()); + } + } + + public static void CheckGuardMovement(Mob mob){ + if (mob.getCombatTarget() == null) { + if (!mob.isMoving()) + Patrol(mob); + else { + mob.stopPatrolTime = System.currentTimeMillis(); + } + } else { + MovementUtilities.moveToLocation(mob, mob.combatTarget.loc, mob.getRange()); + } + } + + private static void Patrol(Mob mob) { + + try { + + if(mob.isMoving()) + return; + //make sure mob is out of combat stance + + int patrolDelay = ThreadLocalRandom.current().nextInt((int) (MobAIThread.AI_PATROL_DIVISOR * 0.5f), MobAIThread.AI_PATROL_DIVISOR) + MobAIThread.AI_PATROL_DIVISOR; + + //early exit while waiting to patrol again + + if (mob.stopPatrolTime + (patrolDelay * 1000) > System.currentTimeMillis()) + return; + + if (mob.lastPatrolPointIndex > mob.patrolPoints.size() - 1) + mob.lastPatrolPointIndex = 0; + + mob.destination = mob.patrolPoints.get(mob.lastPatrolPointIndex); + mob.lastPatrolPointIndex += 1; + + MovementUtilities.aiMove(mob, mob.destination, true); + } catch (Exception e) { + ////(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); + } } }