5 changed files with 384 additions and 0 deletions
@ -0,0 +1,259 @@ |
|||||||
|
package engine.mobileAI.behaviours; |
||||||
|
|
||||||
|
import engine.Enum; |
||||||
|
import engine.gameManager.MovementManager; |
||||||
|
import engine.gameManager.PowersManager; |
||||||
|
import engine.gameManager.ZoneManager; |
||||||
|
import engine.math.Vector3f; |
||||||
|
import engine.math.Vector3fImmutable; |
||||||
|
import engine.mobileAI.utilities.CombatUtilities; |
||||||
|
import engine.mobileAI.utilities.MovementUtilities; |
||||||
|
import engine.objects.*; |
||||||
|
import engine.powers.MobPowerEntry; |
||||||
|
import engine.powers.PowersBase; |
||||||
|
import org.pmw.tinylog.Logger; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
import java.util.concurrent.ThreadLocalRandom; |
||||||
|
|
||||||
|
public class GuardAI { |
||||||
|
|
||||||
|
public static HashMap<Mob,PowersBase> quedPowerCasts = new HashMap<>(); |
||||||
|
|
||||||
|
public static void run(Mob guard){ |
||||||
|
|
||||||
|
//1. check for players nearby to aggro to
|
||||||
|
if(guard.combatTarget == null) |
||||||
|
CheckForPlayerGuardAggro(guard); |
||||||
|
|
||||||
|
//2. patrol if no target acquired
|
||||||
|
if(guard.combatTarget == null) { |
||||||
|
patrol(guard); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
//3. attack based on whether spellcaster, archer or mele
|
||||||
|
if(guard.mobPowers.isEmpty()){ |
||||||
|
if(guard.getEquip().get(2) != null && guard.getEquip().get(2).getItemBase().getRange() > 20) { |
||||||
|
runArcher(guard); |
||||||
|
}else { |
||||||
|
runMele(guard); |
||||||
|
} |
||||||
|
}else{ |
||||||
|
runCaster(guard); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void runCaster(Mob guard){ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static void runMele(Mob guard){ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static void runArcher(Mob guard){ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static void CheckForPlayerGuardAggro(Mob mob) { |
||||||
|
|
||||||
|
try { |
||||||
|
|
||||||
|
//looks for and sets mobs combatTarget
|
||||||
|
|
||||||
|
if (!mob.isAlive()) |
||||||
|
return; |
||||||
|
|
||||||
|
ConcurrentHashMap<Integer, Boolean> loadedPlayers = mob.playerAgroMap; |
||||||
|
|
||||||
|
for (Map.Entry playerEntry : loadedPlayers.entrySet()) { |
||||||
|
|
||||||
|
int playerID = (int) playerEntry.getKey(); |
||||||
|
PlayerCharacter loadedPlayer = PlayerCharacter.getFromCache(playerID); |
||||||
|
|
||||||
|
//Player is null, let's remove them from the list.
|
||||||
|
|
||||||
|
if (loadedPlayer == null) { |
||||||
|
loadedPlayers.remove(playerID); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
//Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map.
|
||||||
|
|
||||||
|
if (!loadedPlayer.isAlive()) { |
||||||
|
loadedPlayers.remove(playerID); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
//Can't see target, skip aggro.
|
||||||
|
|
||||||
|
if (!mob.canSee(loadedPlayer)) |
||||||
|
continue; |
||||||
|
|
||||||
|
// No aggro for this player
|
||||||
|
|
||||||
|
if (GuardCanAggro(mob, loadedPlayer) == false) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (MovementUtilities.inRangeToAggro(mob, loadedPlayer) && mob.getCombatTarget() == null) { |
||||||
|
mob.setCombatTarget(loadedPlayer); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro" + e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Boolean GuardCanAggro(Mob mob, PlayerCharacter target) { |
||||||
|
|
||||||
|
try { |
||||||
|
|
||||||
|
if (mob.getGuild().getNation().equals(target.getGuild().getNation())) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardMinion.ordinal()) { |
||||||
|
if (((Mob) mob.npcOwner).building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} else if (mob.building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
//first check condemn list for aggro allowed (allies button is checked)
|
||||||
|
|
||||||
|
if (ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().reverseKOS) { |
||||||
|
for (Map.Entry<Integer, Condemned> entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) { |
||||||
|
|
||||||
|
//target is listed individually
|
||||||
|
|
||||||
|
if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive()) |
||||||
|
return false; |
||||||
|
|
||||||
|
//target's guild is listed
|
||||||
|
|
||||||
|
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild()) |
||||||
|
return false; |
||||||
|
|
||||||
|
//target's nation is listed
|
||||||
|
|
||||||
|
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation()) |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
|
||||||
|
//allies button is not checked
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, Condemned> entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) { |
||||||
|
|
||||||
|
//target is listed individually
|
||||||
|
|
||||||
|
if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive()) |
||||||
|
return true; |
||||||
|
|
||||||
|
//target's guild is listed
|
||||||
|
|
||||||
|
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild()) |
||||||
|
return true; |
||||||
|
|
||||||
|
//target's nation is listed
|
||||||
|
|
||||||
|
if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation()) |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro" + " " + e.getMessage()); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public static void randomGuardPatrolPoint(Mob mob) { |
||||||
|
|
||||||
|
try { |
||||||
|
|
||||||
|
//early exit for a mob who is already moving to a patrol point
|
||||||
|
//while mob moving, update lastPatrolTime so that when they stop moving the 10 second timer can begin
|
||||||
|
|
||||||
|
if (mob.isMoving() == true) { |
||||||
|
mob.stopPatrolTime = System.currentTimeMillis(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
//wait between 10 and 15 seconds after reaching patrol point before moving
|
||||||
|
|
||||||
|
int patrolDelay = ThreadLocalRandom.current().nextInt(10000) + 5000; |
||||||
|
|
||||||
|
//early exit while waiting to patrol again
|
||||||
|
|
||||||
|
if (mob.stopPatrolTime + patrolDelay > System.currentTimeMillis()) |
||||||
|
return; |
||||||
|
|
||||||
|
float xPoint = ThreadLocalRandom.current().nextInt(400) - 200; |
||||||
|
float zPoint = ThreadLocalRandom.current().nextInt(400) - 200; |
||||||
|
Vector3fImmutable TreePos = mob.getGuild().getOwnedCity().getLoc(); |
||||||
|
mob.destination = new Vector3fImmutable(TreePos.x + xPoint, TreePos.y, TreePos.z + zPoint); |
||||||
|
|
||||||
|
MovementUtilities.aiMove(mob, mob.destination, true); |
||||||
|
|
||||||
|
if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { |
||||||
|
for (Map.Entry<Mob, Integer> minion : mob.siegeMinionMap.entrySet()) { |
||||||
|
|
||||||
|
//make sure mob is out of combat stance
|
||||||
|
|
||||||
|
if (minion.getKey().despawned == false) { |
||||||
|
if (MovementUtilities.canMove(minion.getKey())) { |
||||||
|
Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3); |
||||||
|
minion.getKey().updateLocation(); |
||||||
|
Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(mob.destination.x + minionOffset.x, mob.destination.y, mob.destination.z + minionOffset.z); |
||||||
|
MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints" + " " + e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void patrol(Mob guard){ |
||||||
|
if (!guard.BehaviourType.equals(Enum.MobBehaviourType.GuardCaptain) && guard.npcOwner.isAlive()) |
||||||
|
return; |
||||||
|
|
||||||
|
//patrol
|
||||||
|
Building barracks = guard.building; |
||||||
|
|
||||||
|
if (barracks != null && barracks.patrolPoints != null && !barracks.getPatrolPoints().isEmpty()) { |
||||||
|
guard.patrolPoints = barracks.patrolPoints; |
||||||
|
} else { |
||||||
|
randomGuardPatrolPoint(guard); |
||||||
|
return; |
||||||
|
} |
||||||
|
if (guard.lastPatrolPointIndex > guard.patrolPoints.size() - 1) |
||||||
|
guard.lastPatrolPointIndex = 0; |
||||||
|
|
||||||
|
guard.destination = guard.patrolPoints.get(guard.lastPatrolPointIndex); |
||||||
|
guard.lastPatrolPointIndex += 1; |
||||||
|
|
||||||
|
MovementUtilities.aiMove(guard, guard.destination, true); |
||||||
|
|
||||||
|
if (guard.BehaviourType.equals(Enum.MobBehaviourType.GuardCaptain)) { |
||||||
|
for (Map.Entry<Mob, Integer> minion : guard.siegeMinionMap.entrySet()) |
||||||
|
|
||||||
|
//make sure mob is out of combat stance
|
||||||
|
|
||||||
|
if (!minion.getKey().despawned) { |
||||||
|
if (MovementUtilities.canMove(minion.getKey())) { |
||||||
|
Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3); |
||||||
|
minion.getKey().updateLocation(); |
||||||
|
Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(guard.destination.x + minionOffset.x, guard.destination.y, guard.destination.z + minionOffset.z); |
||||||
|
MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package engine.mobileAI.behaviours; |
||||||
|
|
||||||
|
import engine.objects.Mob; |
||||||
|
|
||||||
|
public class PetAI { |
||||||
|
|
||||||
|
public static void run(Mob pet){ |
||||||
|
|
||||||
|
//1. check for combat
|
||||||
|
|
||||||
|
//2. check for distance from player
|
||||||
|
|
||||||
|
//3. follow player
|
||||||
|
|
||||||
|
//4. chase combat target
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
package engine.mobileAI.behaviours; |
||||||
|
|
||||||
|
import engine.Enum; |
||||||
|
import engine.gameManager.BuildingManager; |
||||||
|
import engine.gameManager.CombatManager; |
||||||
|
import engine.gameManager.MovementManager; |
||||||
|
import engine.gameManager.ZoneManager; |
||||||
|
import engine.mobileAI.utilities.CombatUtilities; |
||||||
|
import engine.objects.Building; |
||||||
|
import engine.objects.City; |
||||||
|
import engine.objects.Mob; |
||||||
|
import engine.server.MBServerStatics; |
||||||
|
import org.pmw.tinylog.Logger; |
||||||
|
|
||||||
|
public class SiegeEngineAI { |
||||||
|
|
||||||
|
public static void run(Mob engine) { |
||||||
|
|
||||||
|
//1. check to respawn if engine is dead or initially spawning
|
||||||
|
if (!engine.isAlive() || engine.despawned) { |
||||||
|
if (System.currentTimeMillis() - engine.deathTime > MBServerStatics.FIFTEEN_MINUTES) { |
||||||
|
engine.respawn(); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//2. early exit if owner is null, siege engines cannot act with player intervention
|
||||||
|
if (engine.getOwner() == null) |
||||||
|
return; |
||||||
|
|
||||||
|
//3. early exit if target is null, siege engines have no purpose without a target
|
||||||
|
if (engine.combatTarget == null) |
||||||
|
return; |
||||||
|
|
||||||
|
//4. early exit if target is not a building, siege engines can only attack buildings
|
||||||
|
if (!engine.combatTarget.getObjectType().equals(Enum.GameObjectType.Building)) { |
||||||
|
engine.setCombatTarget(null); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
//5. early exit if target is out of range, engines don't move and neither do buildings, avoid infinite loop
|
||||||
|
if(CombatManager.NotInRange(engine,engine.combatTarget,engine.getRange())) { |
||||||
|
engine.setCombatTarget(null); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
//6. attack target, sanity checks passed, attack target
|
||||||
|
AttackBuilding(engine,(Building) engine.combatTarget); |
||||||
|
} |
||||||
|
|
||||||
|
public static void AttackBuilding(Mob engine, Building target) { |
||||||
|
|
||||||
|
try { |
||||||
|
|
||||||
|
if (engine == null || target == null) |
||||||
|
return; |
||||||
|
|
||||||
|
if (target.getRank() == -1 || !target.isVulnerable() || BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) { |
||||||
|
engine.setCombatTarget(null); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
City playercity = ZoneManager.getCityAtLocation(engine.getLoc()); |
||||||
|
|
||||||
|
if (playercity != null) |
||||||
|
for (Mob guard : playercity.getParent().zoneMobSet) |
||||||
|
if (guard.BehaviourType != null && guard.BehaviourType.equals(Enum.MobBehaviourType.GuardCaptain)) |
||||||
|
if (guard.getCombatTarget() == null && guard.getGuild() != null && engine.getGuild() != null && !guard.getGuild().equals(engine.getGuild())) |
||||||
|
guard.setCombatTarget(engine); |
||||||
|
|
||||||
|
|
||||||
|
MovementManager.sendRWSSMsg(engine); |
||||||
|
|
||||||
|
CombatUtilities.combatCycle(engine, target, true, null); |
||||||
|
int delay = 15000; |
||||||
|
engine.setLastAttackTime(System.currentTimeMillis() + delay); |
||||||
|
|
||||||
|
|
||||||
|
//if (mob.isSiege()) {
|
||||||
|
// PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target);
|
||||||
|
// ppm.setRange(50);
|
||||||
|
// DispatchMessage.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
||||||
|
//}
|
||||||
|
|
||||||
|
} catch (Exception e) { |
||||||
|
Logger.info(engine.getObjectUUID() + " " + engine.getName() + " Failed At: AttackBuilding" + " " + e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue