package engine.mobileAI.Behaviours; import engine.Enum; import engine.InterestManagement.WorldGrid; import engine.math.Vector3fImmutable; import engine.mobileAI.utilities.CombatUtilities; import engine.mobileAI.utilities.MovementUtilities; import engine.objects.*; import engine.server.MBServerStatics; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; public class StandardMob { public static void run(Mob mob){ if(!mob.isAlive()){ CheckForRespawn(mob); return; } HashSet inRange = WorldGrid.getObjectsInRangePartial(mob.loc, MBServerStatics.CHARACTER_LOAD_RANGE, MBServerStatics.MASK_PLAYER); if(inRange.isEmpty()) return; if (mob.isMoving()) { mob.setLoc(mob.getMovementLoc()); mob.updateLocation(); } if(mob.combatTarget == null) { if (!inRange.isEmpty()) { CheckForAggro(mob); } }else{ CheckToDropCombatTarget(mob); if(mob.combatTarget == null){ CheckForAggro(mob); } } if(MovementUtilities.canMove(mob)) CheckForMovement(mob); if(mob.combatTarget != null && !mob.isMoving()) CheckForAttack(mob); } public static void CheckToDropCombatTarget(Mob mob){ if(!mob.combatTarget.isAlive()){ mob.setCombatTarget(null); return; } if(mob.combatTarget.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)){ PlayerCharacter pcTarget = (PlayerCharacter) mob.combatTarget; if (!mob.canSee(pcTarget)) { mob.setCombatTarget(null); return; } } if(mob.bindLoc.distanceSquared(mob.combatTarget.loc) > 90 * 90){ mob.setCombatTarget(null); } } public static void CheckForRespawn(Mob mob){ if (mob.deathTime == 0) { mob.setDeathTime(System.currentTimeMillis()); return; } if (!mob.despawned) { if (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_ONCE_LOOTED) { mob.despawn(); mob.deathTime = System.currentTimeMillis(); return; } } return; } if(Mob.discDroppers.contains(mob)) return; if (System.currentTimeMillis() > (mob.deathTime + (mob.spawnTime * 1000L))) { Zone.respawnQue.add(mob); } } public static void CheckForAggro(Mob mob){ if(mob == null || !mob.isAlive() || mob.playerAgroMap.isEmpty()){ return; } if(mob.BehaviourType.equals(Enum.MobBehaviourType.HamletGuard)){ return; } if(mob.hate_values == null) mob.hate_values = new HashMap<>(); if(mob.combatTarget != null) return; HashSet inRange = WorldGrid.getObjectsInRangePartial(mob.loc, 60f, MBServerStatics.MASK_PLAYER); if(inRange.isEmpty()){ mob.setCombatTarget(null); return; } //clear out any players who are not in hated range anymore ArrayList toRemove = new ArrayList<>(); for(PlayerCharacter pc : mob.hate_values.keySet()){ if(!inRange.contains(pc)) toRemove.add(pc); } for(PlayerCharacter pc : toRemove){ mob.hate_values.remove(pc); } //find most hated target PlayerCharacter mostHated = null; for(AbstractWorldObject awo : inRange){ PlayerCharacter loadedPlayer = (PlayerCharacter)awo; if (loadedPlayer == null) continue; //Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map. if (!loadedPlayer.isAlive()) continue; //Can't see target, skip aggro. if (!mob.canSee(loadedPlayer)) continue; // No aggro for this race type if (mob.notEnemy != null && mob.notEnemy.size() > 0 && mob.notEnemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType())) continue; //mob has enemies and this player race is not it if (mob.enemy != null && mob.enemy.size() > 0 && !mob.enemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType())) continue; if(mostHated == null) mostHated = loadedPlayer; if(mob.hate_values.containsKey(loadedPlayer)) if(mob.hate_values.get(loadedPlayer) > mob.hate_values.get(mostHated)) mostHated = loadedPlayer; } if(mostHated != null) mob.setCombatTarget(mostHated); } public static void CheckForMovement(Mob mob){ if(mob.combatTarget != null){ //chase player if(!CombatUtilities.inRange2D(mob,mob.combatTarget,mob.getRange())) { MovementUtilities.aiMove(mob, mob.combatTarget.loc, false); }else{ mob.stopMovement(mob.getMovementLoc()); } }else{ //patrol if (mob.isMoving()) return; Vector3fImmutable patrolPoint = Vector3fImmutable.getRandomPointOnCircle(mob.bindLoc, 40f); MovementUtilities.aiMove(mob, patrolPoint, true); } } public static void CheckForAttack(Mob mob){ if(mob.isMoving()) return; if(mob.getLastAttackTime() > System.currentTimeMillis()) return; if (mob.BehaviourType.callsForHelp) MobCallForHelp(mob); ItemBase mainHand = mob.getWeaponItemBase(true); ItemBase offHand = mob.getWeaponItemBase(false); if(!CombatUtilities.inRange2D(mob,mob.combatTarget,mob.getRange())) return; if (mainHand == null && offHand == null) { CombatUtilities.combatCycle(mob, mob.combatTarget, true, null); int delay = 3000; mob.setLastAttackTime(System.currentTimeMillis() + delay); } else if (mob.getWeaponItemBase(true) != null) { int delay = 3000; CombatUtilities.combatCycle(mob, mob.combatTarget, true, mob.getWeaponItemBase(true)); mob.setLastAttackTime(System.currentTimeMillis() + delay); } else if (mob.getWeaponItemBase(false) != null) { int attackDelay = 3000; CombatUtilities.combatCycle(mob, mob.combatTarget, false, mob.getWeaponItemBase(false)); mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); } } public static void MobCallForHelp(Mob mob){ HashSet mobs = WorldGrid.getObjectsInRangePartial(mob.loc,60f, MBServerStatics.MASK_MOB); for(AbstractWorldObject awo : mobs){ Mob responder = (Mob)awo; if(responder.combatTarget == null) if(MovementUtilities.canMove(responder)) MovementUtilities.aiMove(responder,mob.loc,false); } } }