diff --git a/src/engine/mobileAI/BehaviourFiles/PlayerGuard.java b/src/engine/mobileAI/BehaviourFiles/PlayerGuard.java new file mode 100644 index 00000000..0d270976 --- /dev/null +++ b/src/engine/mobileAI/BehaviourFiles/PlayerGuard.java @@ -0,0 +1,10 @@ +package engine.mobileAI.BehaviourFiles; + +import engine.objects.Mob; + +public class PlayerGuard { + + public static void process(Mob guard){ + + } +} diff --git a/src/engine/mobileAI/BehaviourFiles/PlayerPet.java b/src/engine/mobileAI/BehaviourFiles/PlayerPet.java new file mode 100644 index 00000000..42574107 --- /dev/null +++ b/src/engine/mobileAI/BehaviourFiles/PlayerPet.java @@ -0,0 +1,88 @@ +package engine.mobileAI.BehaviourFiles; + +import engine.InterestManagement.WorldGrid; +import engine.gameManager.PowersManager; +import engine.mobileAI.enumMobState; +import engine.mobileAI.utilities.CombatUtilities; +import engine.mobileAI.utilities.MovementUtilities; +import engine.objects.AbstractWorldObject; +import engine.objects.ItemBase; +import engine.objects.Mob; +import engine.objects.PlayerCharacter; +import engine.powers.PowersBase; +import engine.server.MBServerStatics; + +import java.util.Map; + +public class PlayerPet { + + public static void process(Mob pet){ + if(pet.getOwner() == null){ + pet.despawn(); + return; + } + + if(!pet.playerAgroMap.contains(pet.getOwner().getObjectUUID())){ + pet.teleport(pet.getOwner().loc); + return; + } + + switch(enumMobState.getState(pet)){ + case dead: + pet.despawn(); + return; + case patrolling: + if(pet.loc.distanceSquared(pet.getOwner().loc) > 25){ + MovementUtilities.aiMove(pet,pet.getOwner().loc,false); + } else if (pet.isMoving()) { + pet.stopMovement(pet.getMovementLoc()); + } + return; + case attacking: + attack(pet); + return; + } + } + + public static void attack(Mob mob){ + + if (mob.combatTarget == null || !mob.combatTarget.isAlive()) { + mob.setCombatTarget(null); + aggro(mob); + return; + } + + if(!CombatUtilities.inRangeToAttack(mob,mob.combatTarget)){ + if (!MovementUtilities.canMove(mob)) + return; + MovementUtilities.aiMove(mob,mob.combatTarget.loc,false); + return; + } + + mob.stopMovement(mob.getMovementLoc()); + + ItemBase weapon = mob.getWeaponItemBase(true); + boolean mainHand = true; + if(weapon == null) { + weapon = mob.getWeaponItemBase(false); + mainHand = false; + } + + if (System.currentTimeMillis() > mob.getNextAttackTime()) { + CombatUtilities.combatCycle(mob, mob.combatTarget, mainHand, weapon); + mob.setNextAttackTime(System.currentTimeMillis() + 3000L); + } + } + public static void aggro(Mob mob){ + + for(AbstractWorldObject awo : WorldGrid.getObjectsInRangePartial(mob.loc,30, MBServerStatics.MASK_PET)) { + Mob potentialTarget = (Mob) awo; + if (!potentialTarget.isAlive()) + continue; + if (MovementUtilities.inRangeToAggro(mob, potentialTarget)) { + mob.setCombatTarget(potentialTarget); + return; + } + } + } +} diff --git a/src/engine/mobileAI/BehaviourFiles/SiegeMob.java b/src/engine/mobileAI/BehaviourFiles/SiegeMob.java new file mode 100644 index 00000000..f18b077e --- /dev/null +++ b/src/engine/mobileAI/BehaviourFiles/SiegeMob.java @@ -0,0 +1,47 @@ +package engine.mobileAI.BehaviourFiles; + +import engine.Enum; +import engine.mobileAI.utilities.CombatUtilities; +import engine.objects.Mob; + +public class SiegeMob { + public static void process(Mob treb){ + if(!treb.isAlive()){ + if(!treb.despawned){ + treb.despawn(); + treb.deathTime = System.currentTimeMillis(); + return; + } + + if(treb.deathTime == 0) { + treb.deathTime = System.currentTimeMillis(); + return; + } + if(treb.deathTime + 900000L > System.currentTimeMillis()) { + treb.respawn(); + treb.setCombatTarget(null); + return; + } + } + if(treb.combatTarget == null) + return; + + if(!treb.combatTarget.getObjectType().equals(Enum.GameObjectType.Building)) { + treb.setCombatTarget(null); + return; + } + + if(!treb.combatTarget.isAlive()) { + treb.setCombatTarget(null); + return; + } + + if(!CombatUtilities.inRangeToAttack(treb,treb.combatTarget)) + treb.setCombatTarget(null); + + if (System.currentTimeMillis() > treb.getNextAttackTime()) { + CombatUtilities.combatCycle(treb, treb.combatTarget, true, null); + treb.setNextAttackTime(System.currentTimeMillis() + 11000L); + } + } +} diff --git a/src/engine/mobileAI/BehaviourFiles/StandardMob.java b/src/engine/mobileAI/BehaviourFiles/StandardMob.java new file mode 100644 index 00000000..437f18fd --- /dev/null +++ b/src/engine/mobileAI/BehaviourFiles/StandardMob.java @@ -0,0 +1,161 @@ +package engine.mobileAI.BehaviourFiles; + +import engine.InterestManagement.WorldGrid; +import engine.gameManager.PowersManager; +import engine.mobileAI.enumMobState; +import engine.mobileAI.utilities.CombatUtilities; +import engine.mobileAI.utilities.MovementUtilities; +import engine.objects.*; +import engine.powers.PowersBase; +import engine.server.MBServerStatics; + +import java.util.Map; + +public class StandardMob { + public static void process(Mob mob){ + switch(enumMobState.getState(mob)){ + case idle: + return; + case dead: + respawn(mob); + return; + case patrolling: + if(mob.combatTarget == null) + aggro(mob); + if(mob.combatTarget == null) + patrol(mob); + return; + case attacking: + attack(mob); + return; + } + } + + public static void respawn(Mob mob){ + if (mob.deathTime == 0) { + mob.setDeathTime(System.currentTimeMillis()); + return; + } + + if (!mob.despawned) { + + if (mob.getCharItemManager() != null && mob.getCharItemManager().getInventoryCount() > 0) { + if (System.currentTimeMillis() > mob.deathTime + MBServerStatics.DESPAWN_TIMER_WITH_LOOT) { + mob.despawn(); + mob.deathTime = System.currentTimeMillis(); + return; + } + //No items in inventory. + } else if (mob.isHasLoot()) { + if (System.currentTimeMillis() > mob.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) { + mob.despawn(); + mob.deathTime = System.currentTimeMillis(); + return; + } + //Mob never had Loot. + } else { + if (System.currentTimeMillis() > mob.deathTime + MBServerStatics.DESPAWN_TIMER) { + mob.despawn(); + mob.deathTime = System.currentTimeMillis(); + return; + } + } + } + + if(Mob.discDroppers.contains(mob)) + return; + + if (System.currentTimeMillis() > (mob.deathTime + (mob.spawnTime * 1000L))) { + if (!Zone.respawnQue.contains(mob)) { + Zone.respawnQue.add(mob); + } + } + } + + public static void aggro(Mob mob){ + if(enumMobState.Agressive(mob)){ + for(int id : mob.playerAgroMap.keySet()){ + PlayerCharacter potentialTarget = PlayerCharacter.getFromCache(id); + if(!potentialTarget.isAlive() || mob.canSee(potentialTarget)) + continue; + if (MovementUtilities.inRangeToAggro(mob, potentialTarget)) { + mob.setCombatTarget(potentialTarget); + return; + } + } + for(AbstractWorldObject awo : WorldGrid.getObjectsInRangePartial(mob.loc,60, MBServerStatics.MASK_PET)){ + Mob potentialTarget = (Mob)awo; + if(!potentialTarget.isAlive()) + continue; + if (MovementUtilities.inRangeToAggro(mob, potentialTarget)) { + mob.setCombatTarget(potentialTarget); + return; + } + } + } + } + + public static void patrol(Mob mob){ + if (!MovementUtilities.canMove(mob)) + return; + + if (mob.stopPatrolTime + 5000L > System.currentTimeMillis()) + return; + + if(mob.isMoving()) + 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); + } + + public static void attack(Mob mob){ + if (!MovementUtilities.inRangeOfBindLocation(mob)) { + + PowersBase recall = PowersManager.getPowerByToken(-1994153779); + PowersManager.useMobPower(mob, mob, recall, 40); + mob.setCombatTarget(null); + + for (Map.Entry playerEntry : mob.playerAgroMap.entrySet()) + PlayerCharacter.getFromCache((int) playerEntry.getKey()).setHateValue(0); + mob.setCombatTarget(null); + return; + } + + if (mob.combatTarget == null || !mob.combatTarget.isAlive()) { + mob.setCombatTarget(null); + return; + } + + if(MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget())){ + mob.setCombatTarget(null); + MovementUtilities.aiMove(mob,mob.bindLoc,true); + return; + } + + if(!CombatUtilities.inRangeToAttack(mob,mob.combatTarget)){ + if (!MovementUtilities.canMove(mob)) + return; + MovementUtilities.aiMove(mob,mob.combatTarget.loc,false); + return; + } + + mob.stopMovement(mob.getMovementLoc()); + + ItemBase weapon = mob.getWeaponItemBase(true); + boolean mainHand = true; + if(weapon == null) { + weapon = mob.getWeaponItemBase(false); + mainHand = false; + } + + if (System.currentTimeMillis() > mob.getNextAttackTime()) { + CombatUtilities.combatCycle(mob, mob.combatTarget, mainHand, weapon); + mob.setNextAttackTime(System.currentTimeMillis() + 3000L); + } + } +} diff --git a/src/engine/mobileAI/EasyAI.java b/src/engine/mobileAI/EasyAI.java new file mode 100644 index 00000000..2f842e45 --- /dev/null +++ b/src/engine/mobileAI/EasyAI.java @@ -0,0 +1,32 @@ +package engine.mobileAI; + +import engine.mobileAI.BehaviourFiles.PlayerGuard; +import engine.mobileAI.BehaviourFiles.PlayerPet; +import engine.mobileAI.BehaviourFiles.SiegeMob; +import engine.mobileAI.BehaviourFiles.StandardMob; +import engine.objects.Mob; + +public class EasyAI { + + public static void aiRun(Mob mob) { + if (mob == null) + return; + + if (mob.isPlayerGuard) { + PlayerGuard.process(mob); + return; + } + + if(mob.isSiege()){ + SiegeMob.process(mob); + return; + } + + if (mob.isPet()) { + PlayerPet.process(mob); + return; + } + + StandardMob.process(mob); + } +} diff --git a/src/engine/mobileAI/MobAI.java b/src/engine/mobileAI/MobAI.java index cabe0d9d..5d1ee5f6 100644 --- a/src/engine/mobileAI/MobAI.java +++ b/src/engine/mobileAI/MobAI.java @@ -9,7 +9,6 @@ package engine.mobileAI; import engine.Enum; -import engine.Enum.DispatchChannel; import engine.InterestManagement.WorldGrid; import engine.gameManager.*; import engine.math.Vector3f; @@ -17,9 +16,7 @@ import engine.math.Vector3fImmutable; import engine.mobileAI.Threads.MobAIThread; import engine.mobileAI.utilities.CombatUtilities; import engine.mobileAI.utilities.MovementUtilities; -import engine.net.DispatchMessage; import engine.net.client.msg.PerformActionMsg; -import engine.net.client.msg.PowerProjectileMsg; import engine.objects.*; import engine.powers.ActionsBase; import engine.powers.PowersBase; @@ -118,7 +115,7 @@ public class MobAI { //no weapons, default mob attack speed 3 seconds. - if (System.currentTimeMillis() < mob.getLastAttackTime()) + if (System.currentTimeMillis() < mob.getNextAttackTime()) return; // ranged mobs cant attack while running. skip until they finally stop. @@ -136,19 +133,19 @@ public class MobAI { int delay = 3000; if (mob.isSiege()) delay = 11000; - mob.setLastAttackTime(System.currentTimeMillis() + delay); + mob.setNextAttackTime(System.currentTimeMillis() + delay); } else if (mob.getWeaponItemBase(true) != null) { int delay = 3000; if (mob.isSiege()) delay = 11000; CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); - mob.setLastAttackTime(System.currentTimeMillis() + delay); + mob.setNextAttackTime(System.currentTimeMillis() + delay); } else if (mob.getWeaponItemBase(false) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 11000; CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + mob.setNextAttackTime(System.currentTimeMillis() + attackDelay); } } @@ -193,19 +190,19 @@ public class MobAI { int delay = 3000; if (mob.isSiege()) delay = 15000; - mob.setLastAttackTime(System.currentTimeMillis() + delay); + mob.setNextAttackTime(System.currentTimeMillis() + delay); } else if (mob.getWeaponItemBase(true) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 15000; CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + mob.setNextAttackTime(System.currentTimeMillis() + attackDelay); } else if (mob.getWeaponItemBase(false) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 15000; CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + mob.setNextAttackTime(System.currentTimeMillis() + attackDelay); } //if (mob.isSiege()) { @@ -236,19 +233,19 @@ public class MobAI { int delay = 3000; if (mob.isSiege()) delay = 11000; - mob.setLastAttackTime(System.currentTimeMillis() + delay); + mob.setNextAttackTime(System.currentTimeMillis() + delay); } else if (mob.getWeaponItemBase(true) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 11000; CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + mob.setNextAttackTime(System.currentTimeMillis() + attackDelay); } else if (mob.getWeaponItemBase(false) != null) { int attackDelay = 3000; if (mob.isSiege()) attackDelay = 11000; CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + mob.setNextAttackTime(System.currentTimeMillis() + attackDelay); if (target.getCombatTarget() == null) { target.setCombatTarget(mob); } @@ -918,7 +915,7 @@ public class MobAI { mob.setCombatTarget(null); return; } - if (System.currentTimeMillis() > mob.getLastAttackTime()) + if (System.currentTimeMillis() > mob.getNextAttackTime()) AttackTarget(mob, mob.getCombatTarget()); } catch (Exception e) { diff --git a/src/engine/mobileAI/Threads/MobAIThread.java b/src/engine/mobileAI/Threads/MobAIThread.java index b3699879..8266329b 100644 --- a/src/engine/mobileAI/Threads/MobAIThread.java +++ b/src/engine/mobileAI/Threads/MobAIThread.java @@ -1,6 +1,7 @@ package engine.mobileAI.Threads; import engine.gameManager.ConfigManager; +import engine.mobileAI.EasyAI; import engine.mobileAI.MobAI; import engine.gameManager.ZoneManager; import engine.objects.Mob; @@ -33,7 +34,7 @@ public class MobAIThread implements Runnable{ try { if (mob != null) - MobAI.DetermineAction(mob); + EasyAI.aiRun(mob); } catch (Exception e) { Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e); e.printStackTrace(); diff --git a/src/engine/mobileAI/enumMobState.java b/src/engine/mobileAI/enumMobState.java new file mode 100644 index 00000000..cba383de --- /dev/null +++ b/src/engine/mobileAI/enumMobState.java @@ -0,0 +1,27 @@ +package engine.mobileAI; + +import engine.objects.Mob; + +public enum enumMobState { + idle, + attacking, + patrolling, + dead; + + public static enumMobState getState(Mob mob){ + if(mob.playerAgroMap.isEmpty()) + return enumMobState.idle; + + if(!mob.isAlive()) + return enumMobState.dead; + + if(mob.combatTarget != null) + return enumMobState.attacking; + + return enumMobState.patrolling; + } + + public static boolean Agressive(Mob mob){ + return mob.BehaviourType.name().contains("Aggro"); + } +} diff --git a/src/engine/mobileAI/utilities/MovementUtilities.java b/src/engine/mobileAI/utilities/MovementUtilities.java index 85affdca..7a49c22b 100644 --- a/src/engine/mobileAI/utilities/MovementUtilities.java +++ b/src/engine/mobileAI/utilities/MovementUtilities.java @@ -83,7 +83,7 @@ public class MovementUtilities { } - public static boolean inRangeToAggro(Mob agent, PlayerCharacter target) { + public static boolean inRangeToAggro(Mob agent, AbstractCharacter target) { Vector3fImmutable sl = agent.getLoc(); Vector3fImmutable tl = target.getLoc(); @@ -169,6 +169,9 @@ public class MovementUtilities { if (agent.getMobBase() != null && Enum.MobFlagType.SENTINEL.elementOf(agent.getMobBase().getFlags())) return false; + if(!agent.BehaviourType.canRoam) + return false; + return (agent.isAlive() && !agent.getBonuses().getBool(ModType.Stunned, SourceType.None) && !agent.getBonuses().getBool(ModType.CannotMove, SourceType.None)); } diff --git a/src/engine/objects/Mob.java b/src/engine/objects/Mob.java index 240c3f3f..4e67b080 100644 --- a/src/engine/objects/Mob.java +++ b/src/engine/objects/Mob.java @@ -96,7 +96,7 @@ public class Mob extends AbstractIntelligenceAgent { private AbstractWorldObject fearedObject = null; private int buildingID; private boolean isSiege = false; - private long lastAttackTime = 0; + private long nextAttackTime = 0; private int lastMobPowerToken = 0; private HashMap equip = null; private DeferredPowerJob weaponPower; @@ -2237,12 +2237,12 @@ public class Mob extends AbstractIntelligenceAgent { return this.upgradeDateTime != null; } - public long getLastAttackTime() { - return lastAttackTime; + public long getNextAttackTime() { + return nextAttackTime; } - public void setLastAttackTime(long lastAttackTime) { - this.lastAttackTime = lastAttackTime; + public void setNextAttackTime(long lastAttackTime) { + this.nextAttackTime = lastAttackTime; } public void setDeathTime(long deathTime) {