|
|
@ -29,300 +29,150 @@ import java.util.concurrent.ConcurrentHashMap; |
|
|
|
import java.util.concurrent.ThreadLocalRandom; |
|
|
|
import java.util.concurrent.ThreadLocalRandom; |
|
|
|
import static engine.math.FastMath.sqr; |
|
|
|
import static engine.math.FastMath.sqr; |
|
|
|
public class MobileFSM { |
|
|
|
public class MobileFSM { |
|
|
|
private static void mobAttack(Mob aiAgent) { |
|
|
|
private static void AttackTarget(Mob mob, AbstractWorldObject target) { |
|
|
|
|
|
|
|
if(target == null || mob == null){ |
|
|
|
AbstractGameObject target = aiAgent.getCombatTarget(); |
|
|
|
|
|
|
|
if (target == null) { |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
switch (target.getObjectType()) { |
|
|
|
switch (target.getObjectType()) { |
|
|
|
case PlayerCharacter: |
|
|
|
case PlayerCharacter: |
|
|
|
PlayerCharacter player = (PlayerCharacter) target; |
|
|
|
PlayerCharacter targetPlayer = (PlayerCharacter) target; |
|
|
|
if (!player.isActive()) { |
|
|
|
if (canCast(mob) == true) { |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
if (MobCast(mob) == false) { |
|
|
|
CheckMobMovement(aiAgent); |
|
|
|
AttackPlayer(mob, targetPlayer); |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (aiAgent.isNecroPet() && player.inSafeZone()) { |
|
|
|
|
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (canCast(aiAgent) == true) { |
|
|
|
|
|
|
|
if (MobCast(aiAgent) == false) { |
|
|
|
|
|
|
|
handlePlayerAttackForMob(aiAgent, player); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
handlePlayerAttackForMob(aiAgent, player); |
|
|
|
AttackPlayer(mob, targetPlayer); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
case Building: |
|
|
|
case Building: |
|
|
|
Building building = (Building) target; |
|
|
|
Building targetBuilding = (Building) target; |
|
|
|
petHandleBuildingAttack(aiAgent, building); |
|
|
|
AttackBuilding(mob, targetBuilding); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case Mob: |
|
|
|
case Mob: |
|
|
|
Mob mob = (Mob) target; |
|
|
|
Mob targetMob = (Mob) target; |
|
|
|
handleMobAttackForMob(aiAgent, mob); |
|
|
|
AttackMob(mob,targetMob); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private static void petHandleBuildingAttack(Mob aiAgent, Building building) { |
|
|
|
public static void AttackPlayer(Mob mob, PlayerCharacter target){ |
|
|
|
|
|
|
|
if (mob.getMobBase().getSeeInvis() < target.getHidden() || !target.isAlive()) { |
|
|
|
int buildingHitBox = (int) CombatManager.calcHitBox(building); |
|
|
|
mob.setCombatTarget(null); |
|
|
|
|
|
|
|
|
|
|
|
if (building.getRank() == -1) { |
|
|
|
|
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (mob.BehaviourType.callsForHelp) { |
|
|
|
if (!building.isVulnerable()) { |
|
|
|
MobCallForHelp(mob); |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!MovementUtilities.inRangeDropAggro(mob, target)) { |
|
|
|
if (BuildingManager.getBuildingFromCache(building.getObjectUUID()) == null) { |
|
|
|
mob.setAggroTargetID(0); |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
mob.setCombatTarget(null); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (CombatUtilities.inRange2D(mob, target, mob.getRange())) { |
|
|
|
if (building.getParentZone() != null && building.getParentZone().isPlayerCity()) { |
|
|
|
//no weapons, default mob attack speed 3 seconds.
|
|
|
|
|
|
|
|
if (System.currentTimeMillis() < mob.getLastAttackTime()) |
|
|
|
for (Mob mob : building.getParentZone().zoneMobSet) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!mob.isPlayerGuard()) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mob.getCombatTarget() != null) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mob.getGuild() != null && building.getGuild() != null) |
|
|
|
|
|
|
|
if (!Guild.sameGuild(mob.getGuild().getNation(), building.getGuild().getNation())) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mob.setCombatTarget(aiAgent); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (CombatUtilities.inRangeToAttack(aiAgent, building)) { |
|
|
|
|
|
|
|
//not time to attack yet.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!CombatUtilities.RunAIRandom()) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (System.currentTimeMillis() < aiAgent.getLastAttackTime()) |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
// ranged mobs cant attack while running. skip until they finally stop.
|
|
|
|
if (aiAgent.getRange() >= 30 && aiAgent.isMoving()) |
|
|
|
if (mob.isMoving()) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
// add timer for last attack.
|
|
|
|
//reset attack animation
|
|
|
|
ItemBase mainHand = mob.getWeaponItemBase(true); |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
ItemBase offHand = mob.getWeaponItemBase(false); |
|
|
|
MovementManager.sendRWSSMsg(aiAgent); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fire siege balls
|
|
|
|
|
|
|
|
// TODO: Fix animations not following stone
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//no weapons, defualt mob attack speed 3 seconds.
|
|
|
|
|
|
|
|
ItemBase mainHand = aiAgent.getWeaponItemBase(true); |
|
|
|
|
|
|
|
ItemBase offHand = aiAgent.getWeaponItemBase(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mainHand == null && offHand == null) { |
|
|
|
if (mainHand == null && offHand == null) { |
|
|
|
|
|
|
|
CombatUtilities.combatCycle(mob, target, true, null); |
|
|
|
CombatUtilities.combatCycle(aiAgent, building, true, null); |
|
|
|
|
|
|
|
int delay = 3000; |
|
|
|
int delay = 3000; |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
delay = 11000; |
|
|
|
delay = 15000; |
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
|
|
|
|
} else if (mob.getWeaponItemBase(true) != null) { |
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
int delay = 3000; |
|
|
|
} else |
|
|
|
if (mob.isSiege()) |
|
|
|
//TODO set offhand attack time.
|
|
|
|
delay = 11000; |
|
|
|
if (aiAgent.getWeaponItemBase(true) != null) { |
|
|
|
CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); |
|
|
|
|
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
int attackDelay = 3000; |
|
|
|
} else if (mob.getWeaponItemBase(false) != null) { |
|
|
|
|
|
|
|
|
|
|
|
if (aiAgent.isSiege()) |
|
|
|
|
|
|
|
attackDelay = 15000; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CombatUtilities.combatCycle(aiAgent, building, true, aiAgent.getWeaponItemBase(true)); |
|
|
|
|
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (aiAgent.getWeaponItemBase(false) != null) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int attackDelay = 3000; |
|
|
|
int attackDelay = 3000; |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
attackDelay = 11000; |
|
|
|
attackDelay = 15000; |
|
|
|
CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); |
|
|
|
|
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
CombatUtilities.combatCycle(aiAgent, building, false, aiAgent.getWeaponItemBase(false)); |
|
|
|
|
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (aiAgent.isSiege()) { |
|
|
|
|
|
|
|
PowerProjectileMsg ppm = new PowerProjectileMsg(aiAgent, building); |
|
|
|
|
|
|
|
ppm.setRange(50); |
|
|
|
|
|
|
|
DispatchMessage.dispatchMsgToInterestArea(aiAgent, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Outside of attack Range, Move to players predicted loc.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!aiAgent.isMoving()) |
|
|
|
|
|
|
|
if (MovementUtilities.canMove(aiAgent)) |
|
|
|
|
|
|
|
MovementUtilities.moveToLocation(aiAgent, building.getLoc(), aiAgent.getRange() + buildingHitBox); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
private static void handlePlayerAttackForMob(Mob aiAgent, PlayerCharacter player) { |
|
|
|
public static void AttackBuilding(Mob mob, Building target){ |
|
|
|
|
|
|
|
if (target.getRank() == -1 || !target.isVulnerable() || BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) { |
|
|
|
if (aiAgent.getMobBase().getSeeInvis() < player.getHidden()) { |
|
|
|
mob.setCombatTarget(null); |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
City playercity = ZoneManager.getCityAtLocation(mob.getLoc()); |
|
|
|
if (!player.isAlive()) { |
|
|
|
if(playercity != null) { |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
for (Building barracks : playercity.cityBarracks) { |
|
|
|
return; |
|
|
|
for(AbstractCharacter guardCaptain : barracks.getHirelings().keySet()){ |
|
|
|
|
|
|
|
if(guardCaptain.getCombatTarget() == null){ |
|
|
|
|
|
|
|
guardCaptain.setCombatTarget(mob); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (aiAgent.BehaviourType.callsForHelp) { |
|
|
|
|
|
|
|
MobCallForHelp(aiAgent); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if (!MovementUtilities.inRangeDropAggro(aiAgent, player)) { |
|
|
|
|
|
|
|
aiAgent.setAggroTargetID(0); |
|
|
|
|
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
|
|
|
|
MovementUtilities.moveToLocation(aiAgent, aiAgent.getTrueBindLoc(), 0); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if (CombatUtilities.inRange2D(aiAgent, player, aiAgent.getRange())) { |
|
|
|
} |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
//no weapons, defualt mob attack speed 3 seconds.
|
|
|
|
MovementManager.sendRWSSMsg(mob); |
|
|
|
|
|
|
|
ItemBase mainHand = mob.getWeaponItemBase(true); |
|
|
|
if (System.currentTimeMillis() < aiAgent.getLastAttackTime()) |
|
|
|
ItemBase offHand = mob.getWeaponItemBase(false); |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if (!CombatUtilities.RunAIRandom())
|
|
|
|
|
|
|
|
// return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ranged mobs cant attack while running. skip until they finally stop.
|
|
|
|
|
|
|
|
//if (aiAgent.getRange() >= 30 && aiAgent.isMoving())
|
|
|
|
|
|
|
|
if (aiAgent.isMoving()) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// add timer for last attack.
|
|
|
|
|
|
|
|
// player.setTimeStamp("LastCombatPlayer", System.currentTimeMillis());
|
|
|
|
|
|
|
|
ItemBase mainHand = aiAgent.getWeaponItemBase(true); |
|
|
|
|
|
|
|
ItemBase offHand = aiAgent.getWeaponItemBase(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mainHand == null && offHand == null) { |
|
|
|
if (mainHand == null && offHand == null) { |
|
|
|
|
|
|
|
CombatUtilities.combatCycle(mob, target, true, null); |
|
|
|
CombatUtilities.combatCycle(aiAgent, player, true, null); |
|
|
|
|
|
|
|
int delay = 3000; |
|
|
|
int delay = 3000; |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
delay = 15000; |
|
|
|
delay = 11000; |
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
|
|
|
|
|
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else |
|
|
|
} else |
|
|
|
//TODO set offhand attack time.
|
|
|
|
if (mob.getWeaponItemBase(true) != null) { |
|
|
|
if (aiAgent.getWeaponItemBase(true) != null) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int delay = 3000; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (aiAgent.isSiege()) |
|
|
|
|
|
|
|
delay = 11000; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CombatUtilities.combatCycle(aiAgent, player, true, aiAgent.getWeaponItemBase(true)); |
|
|
|
|
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
|
|
|
|
} else if (aiAgent.getWeaponItemBase(false) != null) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int attackDelay = 3000; |
|
|
|
int attackDelay = 3000; |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
attackDelay = 15000; |
|
|
|
attackDelay = 11000; |
|
|
|
CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); |
|
|
|
if (aiAgent.BehaviourType.callsForHelp) { |
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
MobCallForHelp(aiAgent); |
|
|
|
} else if (mob.getWeaponItemBase(false) != null) { |
|
|
|
} |
|
|
|
int attackDelay = 3000; |
|
|
|
CombatUtilities.combatCycle(aiAgent, player, false, aiAgent.getWeaponItemBase(false)); |
|
|
|
if (mob.isSiege()) |
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
attackDelay = 15000; |
|
|
|
} |
|
|
|
CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); |
|
|
|
return; |
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!MovementUtilities.updateMovementToCharacter(aiAgent, player)) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!MovementUtilities.canMove(aiAgent)) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//this stops mobs from attempting to move while they are underneath a player.
|
|
|
|
|
|
|
|
if (CombatUtilities.inRangeToAttack2D(aiAgent, player)) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
private static void handleMobAttackForMob(Mob aiAgent, Mob mob) { |
|
|
|
if (mob.isSiege()) { |
|
|
|
|
|
|
|
PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target); |
|
|
|
|
|
|
|
ppm.setRange(50); |
|
|
|
if (!mob.isAlive()) { |
|
|
|
DispatchMessage.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (CombatUtilities.inRangeToAttack(aiAgent, mob)) { |
|
|
|
|
|
|
|
//not time to attack yet.
|
|
|
|
|
|
|
|
if (System.currentTimeMillis() < aiAgent.getLastAttackTime()) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static void AttackMob(Mob mob, Mob target){ |
|
|
|
if (!CombatUtilities.RunAIRandom()) |
|
|
|
if (mob.getRange() >= 30 && mob.isMoving()) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
//no weapons, default mob attack speed 3 seconds.
|
|
|
|
if (aiAgent.getRange() >= 30 && aiAgent.isMoving()) |
|
|
|
ItemBase mainHand = mob.getWeaponItemBase(true); |
|
|
|
return; |
|
|
|
ItemBase offHand = mob.getWeaponItemBase(false); |
|
|
|
//no weapons, defualt mob attack speed 3 seconds.
|
|
|
|
|
|
|
|
ItemBase mainHand = aiAgent.getWeaponItemBase(true); |
|
|
|
|
|
|
|
ItemBase offHand = aiAgent.getWeaponItemBase(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mainHand == null && offHand == null) { |
|
|
|
if (mainHand == null && offHand == null) { |
|
|
|
|
|
|
|
CombatUtilities.combatCycle(mob, target, true, null); |
|
|
|
CombatUtilities.combatCycle(aiAgent, mob, true, null); |
|
|
|
|
|
|
|
int delay = 3000; |
|
|
|
int delay = 3000; |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
|
|
|
|
delay = 11000; |
|
|
|
delay = 11000; |
|
|
|
|
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + delay); |
|
|
|
|
|
|
|
} else |
|
|
|
} else |
|
|
|
//TODO set offhand attack time.
|
|
|
|
if (mob.getWeaponItemBase(true) != null) { |
|
|
|
if (aiAgent.getWeaponItemBase(true) != null) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int attackDelay = 3000; |
|
|
|
int attackDelay = 3000; |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
|
|
|
|
attackDelay = 11000; |
|
|
|
attackDelay = 11000; |
|
|
|
|
|
|
|
CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); |
|
|
|
CombatUtilities.combatCycle(aiAgent, mob, true, aiAgent.getWeaponItemBase(true)); |
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
} else if (mob.getWeaponItemBase(false) != null) { |
|
|
|
|
|
|
|
|
|
|
|
} else if (aiAgent.getWeaponItemBase(false) != null) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int attackDelay = 3000; |
|
|
|
int attackDelay = 3000; |
|
|
|
|
|
|
|
if (mob.isSiege()) |
|
|
|
if (aiAgent.isSiege()) |
|
|
|
|
|
|
|
attackDelay = 11000; |
|
|
|
attackDelay = 11000; |
|
|
|
|
|
|
|
CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); |
|
|
|
CombatUtilities.combatCycle(aiAgent, mob, false, aiAgent.getWeaponItemBase(false)); |
|
|
|
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
aiAgent.setLastAttackTime(System.currentTimeMillis() + attackDelay); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static void Patrol(Mob mob) { |
|
|
|
//use this so mobs dont continue to try to move if they are underneath a flying target. only use 2D range check.
|
|
|
|
|
|
|
|
if (CombatUtilities.inRangeToAttack2D(aiAgent, mob)) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!MovementUtilities.updateMovementToCharacter(aiAgent, mob)) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private static void patrol(Mob mob) { |
|
|
|
|
|
|
|
//make sure mob is out of combat stance
|
|
|
|
//make sure mob is out of combat stance
|
|
|
|
if (mob.isCombat() && mob.getCombatTarget() == null) { |
|
|
|
if (mob.isCombat() && mob.getCombatTarget() == null) { |
|
|
|
mob.setCombat(false); |
|
|
|
mob.setCombat(false); |
|
|
@ -495,53 +345,32 @@ public class MobileFSM { |
|
|
|
if (mob == null) { |
|
|
|
if (mob == null) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if(mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()){ |
|
|
|
|
|
|
|
//this is a player slotted guard captain
|
|
|
|
|
|
|
|
GuardCaptainLogic(mob); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardMinion.ordinal()){ |
|
|
|
|
|
|
|
//this is a player slotted guard minion
|
|
|
|
|
|
|
|
GuardMinionLogic(mob); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardWallArcher.ordinal()){ |
|
|
|
|
|
|
|
//this is a player slotted guard minion
|
|
|
|
|
|
|
|
GuardWallArcherLogic(mob); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (mob.isPet() == false && mob.isSummonedPet() == false && mob.isNecroPet() == false) { |
|
|
|
|
|
|
|
if (mob.isAlive() == false) { |
|
|
|
if (mob.isAlive() == false) { |
|
|
|
//no need to continue if mob is dead, check for respawn and move on
|
|
|
|
//no need to continue if mob is dead, check for respawn and move on
|
|
|
|
CheckForRespawn(mob); |
|
|
|
CheckForRespawn(mob); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
//check to see if mob has wandered too far from his bind loc
|
|
|
|
|
|
|
|
CheckToSendMobHome(mob); |
|
|
|
|
|
|
|
//check to see if players have mob loaded
|
|
|
|
|
|
|
|
if (mob.playerAgroMap.isEmpty()) { |
|
|
|
if (mob.playerAgroMap.isEmpty()) { |
|
|
|
//no players loaded, no need to proceed
|
|
|
|
//no players loaded, no need to proceed
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
//check for players that can be aggroed if mob is agressive and has no target
|
|
|
|
CheckToSendMobHome(mob); |
|
|
|
if (mob.BehaviourType.isAgressive && mob.getCombatTarget() == null && mob.BehaviourType != Enum.MobBehaviourType.SimpleStandingGuard) { |
|
|
|
switch(mob.BehaviourType){ |
|
|
|
//normal aggro
|
|
|
|
case GuardCaptain: |
|
|
|
CheckForAggro(mob); |
|
|
|
GuardCaptainLogic(mob); |
|
|
|
} else if (mob.BehaviourType == Enum.MobBehaviourType.SimpleStandingGuard) { |
|
|
|
break; |
|
|
|
//safehold guard
|
|
|
|
case GuardMinion: |
|
|
|
SafeGuardAggro(mob); |
|
|
|
GuardMinionLogic(mob); |
|
|
|
} |
|
|
|
break; |
|
|
|
//check if mob can move for patrol or moving to target
|
|
|
|
case GuardWallArcher: |
|
|
|
if (mob.BehaviourType.canRoam) { |
|
|
|
GuardWallArcherLogic(mob); |
|
|
|
CheckMobMovement(mob); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Pet1: |
|
|
|
//check if mob can attack if it isn't wimpy
|
|
|
|
PetLogic(mob); |
|
|
|
if (!mob.BehaviourType.isWimpy && !mob.isMoving() && mob.combatTarget != null) { |
|
|
|
break; |
|
|
|
CheckForAttack(mob); |
|
|
|
default: |
|
|
|
} |
|
|
|
DefaultLogic(mob); |
|
|
|
} else { |
|
|
|
break; |
|
|
|
CheckMobMovement(mob); |
|
|
|
|
|
|
|
CheckForAttack(mob); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private static void CheckForAggro(Mob aiAgent) { |
|
|
|
private static void CheckForAggro(Mob aiAgent) { |
|
|
@ -584,7 +413,7 @@ public class MobileFSM { |
|
|
|
mob.updateLocation(); |
|
|
|
mob.updateLocation(); |
|
|
|
if (mob.isPet() == false && mob.isSummonedPet() == false && mob.isNecroPet() == false) { |
|
|
|
if (mob.isPet() == false && mob.isSummonedPet() == false && mob.isNecroPet() == false) { |
|
|
|
if (mob.getCombatTarget() == null) { |
|
|
|
if (mob.getCombatTarget() == null) { |
|
|
|
patrol(mob); |
|
|
|
Patrol(mob); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
chaseTarget(mob); |
|
|
|
chaseTarget(mob); |
|
|
|
} |
|
|
|
} |
|
|
@ -606,54 +435,49 @@ public class MobileFSM { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private static void CheckForRespawn(Mob aiAgent) { |
|
|
|
private static void CheckForRespawn(Mob aiAgent) { |
|
|
|
|
|
|
|
if (aiAgent.deathTime == 0) { |
|
|
|
|
|
|
|
aiAgent.setDeathTime(System.currentTimeMillis()); |
|
|
|
|
|
|
|
} |
|
|
|
//handles checking for respawn of dead mobs even when no players have mob loaded
|
|
|
|
//handles checking for respawn of dead mobs even when no players have mob loaded
|
|
|
|
//Despawn Timer with Loot currently in inventory.
|
|
|
|
//Despawn Timer with Loot currently in inventory.
|
|
|
|
if (aiAgent.getCharItemManager().getInventoryCount() > 0) { |
|
|
|
if (aiAgent.getCharItemManager().getInventoryCount() > 0) { |
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_WITH_LOOT) { |
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_WITH_LOOT) { |
|
|
|
aiAgent.despawn(); |
|
|
|
aiAgent.despawn(); |
|
|
|
//update time of death after mob despawns so respawn time happens after mob despawns.
|
|
|
|
|
|
|
|
if (aiAgent.deathTime != 0) { |
|
|
|
|
|
|
|
aiAgent.setDeathTime(System.currentTimeMillis()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
respawn(aiAgent); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//No items in inventory.
|
|
|
|
//No items in inventory.
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
//Mob's Loot has been looted.
|
|
|
|
//Mob's Loot has been looted.
|
|
|
|
if (aiAgent.isHasLoot()) { |
|
|
|
if (aiAgent.isHasLoot()) { |
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) { |
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) { |
|
|
|
aiAgent.despawn(); |
|
|
|
aiAgent.despawn(); |
|
|
|
//update time of death after mob despawns so respawn time happens after mob despawns.
|
|
|
|
|
|
|
|
if (aiAgent.deathTime != 0) { |
|
|
|
|
|
|
|
aiAgent.setDeathTime(System.currentTimeMillis()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
respawn(aiAgent); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
//Mob never had Loot.
|
|
|
|
//Mob never had Loot.
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER) { |
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER) { |
|
|
|
aiAgent.despawn(); |
|
|
|
aiAgent.despawn(); |
|
|
|
//update time of death after mob despawns so respawn time happens after mob despawns.
|
|
|
|
//update time of death after mob despawns so respawn time happens after mob despawns.
|
|
|
|
if (aiAgent.deathTime != 0) { |
|
|
|
|
|
|
|
aiAgent.setDeathTime(System.currentTimeMillis()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
respawn(aiAgent); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + (aiAgent.spawnTime * 1000)) { |
|
|
|
|
|
|
|
aiAgent.respawn(); |
|
|
|
|
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
public static void CheckForAttack(Mob mob) { |
|
|
|
public static void CheckForAttack(Mob mob) { |
|
|
|
//checks if mob can attack based on attack timer and range
|
|
|
|
//checks if mob can attack based on attack timer and range
|
|
|
|
if (mob.isAlive()) |
|
|
|
if (mob.isAlive() == false){ |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
if (!mob.isCombat()) { |
|
|
|
if (!mob.isCombat()) { |
|
|
|
mob.setCombat(true); |
|
|
|
mob.setCombat(true); |
|
|
|
UpdateStateMsg rwss = new UpdateStateMsg(); |
|
|
|
UpdateStateMsg rwss = new UpdateStateMsg(); |
|
|
|
rwss.setPlayer(mob); |
|
|
|
rwss.setPlayer(mob); |
|
|
|
DispatchMessage.sendToAllInRange(mob, rwss); |
|
|
|
DispatchMessage.sendToAllInRange(mob, rwss); |
|
|
|
} |
|
|
|
} |
|
|
|
mobAttack(mob); |
|
|
|
if(System.currentTimeMillis() > mob.getLastAttackTime()) { |
|
|
|
|
|
|
|
AttackTarget(mob, mob.getCombatTarget()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private static void CheckToSendMobHome(Mob mob) { |
|
|
|
private static void CheckToSendMobHome(Mob mob) { |
|
|
|
|
|
|
|
|
|
|
@ -705,23 +529,10 @@ public class MobileFSM { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private static void respawn(Mob aiAgent) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!aiAgent.canRespawn()) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long spawnTime = aiAgent.getSpawnTime(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (aiAgent.isPlayerGuard() && aiAgent.npcOwner != null && !aiAgent.npcOwner.isAlive()) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (System.currentTimeMillis() > aiAgent.deathTime + spawnTime) { |
|
|
|
|
|
|
|
aiAgent.respawn(); |
|
|
|
|
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private static void chaseTarget(Mob mob) { |
|
|
|
private static void chaseTarget(Mob mob) { |
|
|
|
mob.updateMovementState(); |
|
|
|
mob.updateMovementState(); |
|
|
|
|
|
|
|
if (CombatUtilities.inRangeToAttack2D(mob, mob.getCombatTarget())) |
|
|
|
|
|
|
|
return; |
|
|
|
if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mob.getRange()) == false) { |
|
|
|
if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mob.getRange()) == false) { |
|
|
|
if (mob.getRange() > 15) { |
|
|
|
if (mob.getRange() > 15) { |
|
|
|
mob.destination = mob.getCombatTarget().getLoc(); |
|
|
|
mob.destination = mob.getCombatTarget().getLoc(); |
|
|
@ -749,17 +560,9 @@ public class MobileFSM { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
public static void GuardCaptainLogic(Mob mob){ |
|
|
|
public static void GuardCaptainLogic(Mob mob){ |
|
|
|
if (mob.playerAgroMap.isEmpty()) { |
|
|
|
if(mob.getCombatTarget() == null) { |
|
|
|
//no players loaded, no need to proceed
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (mob.isAlive() == false) { |
|
|
|
|
|
|
|
//no need to continue if mob is dead, check for respawn and move on
|
|
|
|
|
|
|
|
CheckForRespawn(mob); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CheckToSendMobHome(mob); |
|
|
|
|
|
|
|
CheckForPlayerGuardAggro(mob); |
|
|
|
CheckForPlayerGuardAggro(mob); |
|
|
|
|
|
|
|
} |
|
|
|
CheckMobMovement(mob); |
|
|
|
CheckMobMovement(mob); |
|
|
|
if(mob.getCombatTarget() != null) { |
|
|
|
if(mob.getCombatTarget() != null) { |
|
|
|
CheckForAttack(mob); |
|
|
|
CheckForAttack(mob); |
|
|
@ -777,12 +580,7 @@ public class MobileFSM { |
|
|
|
} |
|
|
|
} |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if(mob.isAlive() == false){ |
|
|
|
if(mob.npcOwner.isAlive() == false && mob.getCombatTarget() == null){ |
|
|
|
CheckForRespawn(mob); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CheckToSendMobHome(mob); |
|
|
|
|
|
|
|
if(mob.npcOwner.isAlive() == false){ |
|
|
|
|
|
|
|
CheckForPlayerGuardAggro(mob); |
|
|
|
CheckForPlayerGuardAggro(mob); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
@ -792,11 +590,7 @@ public class MobileFSM { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
public static void GuardWallArcherLogic(Mob mob){ |
|
|
|
public static void GuardWallArcherLogic(Mob mob){ |
|
|
|
if(mob.isAlive() == false){ |
|
|
|
if(mob.getCombatTarget() == null){ |
|
|
|
CheckForRespawn(mob); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(mob.npcOwner.isAlive() == false){ |
|
|
|
|
|
|
|
CheckForPlayerGuardAggro(mob); |
|
|
|
CheckForPlayerGuardAggro(mob); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
@ -804,6 +598,34 @@ public class MobileFSM { |
|
|
|
CheckForAttack(mob); |
|
|
|
CheckForAttack(mob); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static void PetLogic(Mob mob){ |
|
|
|
|
|
|
|
if(MovementUtilities.canMove(mob)){ |
|
|
|
|
|
|
|
CheckMobMovement(mob); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(mob.getCombatTarget() != null) { |
|
|
|
|
|
|
|
CheckForAttack(mob); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private static void DefaultLogic(Mob mob){ |
|
|
|
|
|
|
|
//check for players that can be aggroed if mob is agressive and has no target
|
|
|
|
|
|
|
|
if (mob.BehaviourType.isAgressive && mob.getCombatTarget() == null) { |
|
|
|
|
|
|
|
if (mob.BehaviourType == Enum.MobBehaviourType.SimpleStandingGuard) { |
|
|
|
|
|
|
|
//safehold guard
|
|
|
|
|
|
|
|
SafeGuardAggro(mob); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
//normal aggro
|
|
|
|
|
|
|
|
CheckForAggro(mob); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//check if mob can move for patrol or moving to target
|
|
|
|
|
|
|
|
if (mob.BehaviourType.canRoam) { |
|
|
|
|
|
|
|
CheckMobMovement(mob); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//check if mob can attack if it isn't wimpy
|
|
|
|
|
|
|
|
if (!mob.BehaviourType.isWimpy && !mob.isMoving() && mob.combatTarget != null) { |
|
|
|
|
|
|
|
CheckForAttack(mob); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
public static void CheckForPlayerGuardAggro(Mob mob) { |
|
|
|
public static void CheckForPlayerGuardAggro(Mob mob) { |
|
|
|
//looks for and sets mobs combatTarget
|
|
|
|
//looks for and sets mobs combatTarget
|
|
|
|
if (!mob.isAlive()) { |
|
|
|
if (!mob.isAlive()) { |
|
|
|