|
|
@ -17,7 +17,6 @@ import engine.InterestManagement.WorldGrid; |
|
|
|
import engine.ai.utilities.CombatUtilities; |
|
|
|
import engine.ai.utilities.CombatUtilities; |
|
|
|
import engine.ai.utilities.MovementUtilities; |
|
|
|
import engine.ai.utilities.MovementUtilities; |
|
|
|
import engine.gameManager.*; |
|
|
|
import engine.gameManager.*; |
|
|
|
import engine.math.Vector3f; |
|
|
|
|
|
|
|
import engine.math.Vector3fImmutable; |
|
|
|
import engine.math.Vector3fImmutable; |
|
|
|
import engine.net.DispatchMessage; |
|
|
|
import engine.net.DispatchMessage; |
|
|
|
import engine.net.client.msg.PerformActionMsg; |
|
|
|
import engine.net.client.msg.PerformActionMsg; |
|
|
@ -25,8 +24,6 @@ import engine.net.client.msg.PowerProjectileMsg; |
|
|
|
import engine.net.client.msg.UpdateStateMsg; |
|
|
|
import engine.net.client.msg.UpdateStateMsg; |
|
|
|
import engine.objects.*; |
|
|
|
import engine.objects.*; |
|
|
|
import engine.powers.ActionsBase; |
|
|
|
import engine.powers.ActionsBase; |
|
|
|
import engine.powers.EffectsBase; |
|
|
|
|
|
|
|
import engine.powers.PowerPrereq; |
|
|
|
|
|
|
|
import engine.powers.PowersBase; |
|
|
|
import engine.powers.PowersBase; |
|
|
|
import engine.server.MBServerStatics; |
|
|
|
import engine.server.MBServerStatics; |
|
|
|
import org.pmw.tinylog.Logger; |
|
|
|
import org.pmw.tinylog.Logger; |
|
|
@ -53,7 +50,8 @@ public class MobileFSM { |
|
|
|
Home, |
|
|
|
Home, |
|
|
|
Dead, |
|
|
|
Dead, |
|
|
|
Recalling, |
|
|
|
Recalling, |
|
|
|
Retaliate |
|
|
|
Retaliate, |
|
|
|
|
|
|
|
Chase |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static void run(Mob mob) { |
|
|
|
public static void run(Mob mob) { |
|
|
@ -116,7 +114,6 @@ public class MobileFSM { |
|
|
|
rwss.setPlayer(mob); |
|
|
|
rwss.setPlayer(mob); |
|
|
|
DispatchMessage.sendToAllInRange(mob, rwss); |
|
|
|
DispatchMessage.sendToAllInRange(mob, rwss); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (mob.isPlayerGuard()) |
|
|
|
if (mob.isPlayerGuard()) |
|
|
|
guardAttack(mob); |
|
|
|
guardAttack(mob); |
|
|
|
else if (mob.isPet() || mob.isSiege()) |
|
|
|
else if (mob.isPet() || mob.isSiege()) |
|
|
@ -144,6 +141,9 @@ public class MobileFSM { |
|
|
|
case Retaliate: |
|
|
|
case Retaliate: |
|
|
|
retaliate(mob); |
|
|
|
retaliate(mob); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
case Chase: |
|
|
|
|
|
|
|
handleMobChase(mob); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -339,8 +339,8 @@ public class MobileFSM { |
|
|
|
if (!MovementUtilities.canMove(aiAgent)) |
|
|
|
if (!MovementUtilities.canMove(aiAgent)) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double WeaponRange = aiAgent.getEquip().get(0).getItemBase().getRange(); |
|
|
|
if (CombatUtilities.inRangeToAttack2D(aiAgent, mob)) |
|
|
|
if (CombatUtilities.inRange2D(aiAgent, mob, WeaponRange)) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -465,11 +465,12 @@ public class MobileFSM { |
|
|
|
aiAgent.setState(STATE.Patrol); |
|
|
|
aiAgent.setState(STATE.Patrol); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
aiAgent.setCombatTarget(aggroTarget); |
|
|
|
if (canCast(aiAgent) == true) { |
|
|
|
if (canCast(aiAgent) == true) { |
|
|
|
if (MobCast(aiAgent) == false) { |
|
|
|
if (MobCast(aiAgent) == false) { |
|
|
|
attack(aiAgent, targetID); |
|
|
|
attack(aiAgent, targetID); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (CombatUtilities.inRangeToAttack(aiAgent, aggroTarget)) { |
|
|
|
} else if (CombatUtilities.inRange2D(aiAgent, aggroTarget, aiAgent.getRange())) { |
|
|
|
aiAgent.setState(STATE.Attack); |
|
|
|
aiAgent.setState(STATE.Attack); |
|
|
|
attack(aiAgent, targetID); |
|
|
|
attack(aiAgent, targetID); |
|
|
|
return; |
|
|
|
return; |
|
|
@ -824,18 +825,19 @@ public class MobileFSM { |
|
|
|
aiAgent.setState(STATE.Awake); |
|
|
|
aiAgent.setState(STATE.Awake); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (CombatUtilities.inRangeToAttack(aiAgent, player)) { |
|
|
|
if (CombatUtilities.inRange2D(aiAgent, player, aiAgent.getRange())) { |
|
|
|
|
|
|
|
|
|
|
|
//no weapons, defualt mob attack speed 3 seconds.
|
|
|
|
//no weapons, defualt mob attack speed 3 seconds.
|
|
|
|
|
|
|
|
|
|
|
|
if (System.currentTimeMillis() < aiAgent.getLastAttackTime()) |
|
|
|
if (System.currentTimeMillis() < aiAgent.getLastAttackTime()) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
if (!CombatUtilities.RunAIRandom()) |
|
|
|
//if (!CombatUtilities.RunAIRandom())
|
|
|
|
return; |
|
|
|
// return;
|
|
|
|
|
|
|
|
|
|
|
|
// ranged mobs cant attack while running. skip until they finally stop.
|
|
|
|
// ranged mobs cant attack while running. skip until they finally stop.
|
|
|
|
if (aiAgent.getRange() >= 30 && aiAgent.isMoving()) |
|
|
|
//if (aiAgent.getRange() >= 30 && aiAgent.isMoving())
|
|
|
|
|
|
|
|
if(aiAgent.isMoving()) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// add timer for last attack.
|
|
|
|
// add timer for last attack.
|
|
|
@ -888,10 +890,8 @@ public class MobileFSM { |
|
|
|
//this stops mobs from attempting to move while they are underneath a player.
|
|
|
|
//this stops mobs from attempting to move while they are underneath a player.
|
|
|
|
if (CombatUtilities.inRangeToAttack2D(aiAgent, player)) |
|
|
|
if (CombatUtilities.inRangeToAttack2D(aiAgent, player)) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
//set mob to pursue target
|
|
|
|
aiAgent.destination = MovementUtilities.GetDestinationToCharacter(aiAgent, player); |
|
|
|
aiAgent.setState(MobileFSM.STATE.Chase); |
|
|
|
MovementUtilities.moveToLocation(aiAgent, aiAgent.destination, aiAgent.getRange()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
private static void handleMobAttackForPet(Mob aiAgent, Mob mob) { |
|
|
|
private static void handleMobAttackForPet(Mob aiAgent, Mob mob) { |
|
|
|
|
|
|
|
|
|
|
@ -1146,12 +1146,6 @@ public class MobileFSM { |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
aiAgent.setCombatTarget(null); |
|
|
|
aiAgent.setState(STATE.Awake); |
|
|
|
aiAgent.setState(STATE.Awake); |
|
|
|
} |
|
|
|
} |
|
|
|
private static void recall(Mob aiAgent) { |
|
|
|
|
|
|
|
//recall home.
|
|
|
|
|
|
|
|
PowersBase recall = PowersManager.getPowerByToken(-1994153779); |
|
|
|
|
|
|
|
PowersManager.useMobPower(aiAgent, aiAgent, recall, 40); |
|
|
|
|
|
|
|
aiAgent.setState(MobileFSM.STATE.Recalling); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private static void recalling(Mob aiAgent) { |
|
|
|
private static void recalling(Mob aiAgent) { |
|
|
|
//recall home.
|
|
|
|
//recall home.
|
|
|
|
if (aiAgent.getLoc() == aiAgent.getBindLoc()) |
|
|
|
if (aiAgent.getLoc() == aiAgent.getBindLoc()) |
|
|
@ -1648,72 +1642,59 @@ public class MobileFSM { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
public static boolean MobCast(Mob mob) { |
|
|
|
public static boolean MobCast(Mob mob) { |
|
|
|
|
|
|
|
if (mob.getMobBase().getFlags().contains(Enum.MobFlagType.CALLSFORHELP)) { |
|
|
|
// Method picks a random spell from a mobile's list of powers
|
|
|
|
|
|
|
|
// and casts it on the player. Validation (including empty lists)
|
|
|
|
|
|
|
|
// if done previously in canCast();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ArrayList<Integer> powerTokens; |
|
|
|
|
|
|
|
PlayerCharacter target = (PlayerCharacter) mob.getCombatTarget(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mob.getMobBase().getFlags().contains(Enum.MobFlagType.CALLSFORHELP)) |
|
|
|
|
|
|
|
MobCallForHelp(mob); |
|
|
|
MobCallForHelp(mob); |
|
|
|
|
|
|
|
} |
|
|
|
// Generate a list of tokens from the mob powers for this mobile.
|
|
|
|
PlayerCharacter target = (PlayerCharacter) mob.getCombatTarget(); |
|
|
|
|
|
|
|
HashMap<Integer,Integer> eligiblePowers = mob.mobPowers; |
|
|
|
powerTokens = new ArrayList<>(mob.mobPowers.keySet()); |
|
|
|
for(Map.Entry<Integer,Integer> power : mob.mobPowers.entrySet()) { |
|
|
|
|
|
|
|
PowersBase pwr= PowersManager.getPowerByToken(power.getKey()); |
|
|
|
// If player has this effect on them already then remove the token
|
|
|
|
|
|
|
|
// from the list of mob powers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int powerToken : powerTokens){ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PowersBase pwr= PowersManager.getPowerByToken(powerToken); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(ActionsBase act : pwr.getActions()){ |
|
|
|
for(ActionsBase act : pwr.getActions()){ |
|
|
|
|
|
|
|
|
|
|
|
String des = act.stackType; |
|
|
|
String des = act.stackType; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (target.getEffects() != null && target.getEffects().containsKey(des) == true) { |
|
|
|
|
|
|
|
eligiblePowers.remove(power.getKey()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}catch(Exception ex){ |
|
|
|
|
|
|
|
|
|
|
|
if (target.getEffects() != null && target.getEffects().containsKey(des)) |
|
|
|
|
|
|
|
powerTokens.remove(powerToken); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Pick random spell from our list of powers
|
|
|
|
} |
|
|
|
|
|
|
|
int random = ThreadLocalRandom.current().nextInt(eligiblePowers.size()); |
|
|
|
int powerToken = powerTokens.get(ThreadLocalRandom.current().nextInt(powerTokens.size())); |
|
|
|
int powerToken = 0; |
|
|
|
int powerRank = mob.mobPowers.get(powerToken); |
|
|
|
int powerRank = 0; |
|
|
|
|
|
|
|
Map<Integer, Integer> entries = eligiblePowers; |
|
|
|
|
|
|
|
int count = -1; |
|
|
|
|
|
|
|
for (Map.Entry<Integer, Integer> entry : entries.entrySet()) { |
|
|
|
|
|
|
|
count += 1; |
|
|
|
|
|
|
|
if (count == random) { |
|
|
|
|
|
|
|
powerToken = entry.getKey(); |
|
|
|
|
|
|
|
powerRank = entry.getValue(); |
|
|
|
PowersBase mobPower = PowersManager.getPowerByToken(powerToken); |
|
|
|
PowersBase mobPower = PowersManager.getPowerByToken(powerToken); |
|
|
|
|
|
|
|
if (CombatUtilities.inRange2D(mob, target, mobPower.getRange())) { |
|
|
|
// Cast the spell
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mobPower.getRange())) { |
|
|
|
|
|
|
|
PowersManager.useMobPower(mob,(AbstractCharacter)mob.getCombatTarget(),mobPower,powerRank); |
|
|
|
PowersManager.useMobPower(mob,(AbstractCharacter)mob.getCombatTarget(),mobPower,powerRank); |
|
|
|
PerformActionMsg msg; |
|
|
|
PerformActionMsg msg = new PerformActionMsg(); |
|
|
|
|
|
|
|
if(mobPower.isHarmful() == false || mobPower.targetSelf == true){ |
|
|
|
if(mobPower.isHarmful() == false || mobPower.targetSelf == true) |
|
|
|
|
|
|
|
msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, mob); |
|
|
|
msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, mob); |
|
|
|
else |
|
|
|
} else { |
|
|
|
msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, target); |
|
|
|
msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, target); |
|
|
|
|
|
|
|
} |
|
|
|
msg.setUnknown04(2); |
|
|
|
msg.setUnknown04(2); |
|
|
|
PowersManager.finishUseMobPower(msg, mob, 0, 0); |
|
|
|
PowersManager.finishUseMobPower(msg, mob, 0, 0); |
|
|
|
|
|
|
|
|
|
|
|
//default minimum seconds between cast = 10
|
|
|
|
//default minimum seconds between cast = 10
|
|
|
|
|
|
|
|
long cooldown = mobPower.getCooldown(); |
|
|
|
long coolDown = mobPower.getCooldown(); |
|
|
|
if(cooldown < 10000){ |
|
|
|
|
|
|
|
mob.nextCastTime = System.currentTimeMillis() + 10000 + cooldown; |
|
|
|
if(coolDown < 10000) |
|
|
|
} else { |
|
|
|
mob.nextCastTime = System.currentTimeMillis() + 10000 + coolDown; |
|
|
|
mob.nextCastTime = System.currentTimeMillis() + cooldown; |
|
|
|
else |
|
|
|
} |
|
|
|
mob.nextCastTime = System.currentTimeMillis() + coolDown; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static void MobCallForHelp(Mob mob) { |
|
|
|
public static void MobCallForHelp(Mob mob) { |
|
|
|
if(mob.nextCallForHelp == 0){ |
|
|
|
if(mob.nextCallForHelp == 0){ |
|
|
|
mob.nextCallForHelp = System.currentTimeMillis(); |
|
|
|
mob.nextCallForHelp = System.currentTimeMillis(); |
|
|
@ -1734,4 +1715,29 @@ public class MobileFSM { |
|
|
|
//wait 60 seconds to call for help again
|
|
|
|
//wait 60 seconds to call for help again
|
|
|
|
mob.nextCallForHelp = System.currentTimeMillis() + 60000; |
|
|
|
mob.nextCallForHelp = System.currentTimeMillis() + 60000; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static void handleMobChase(Mob mob){ |
|
|
|
|
|
|
|
if (!MovementUtilities.inRangeOfBindLocation(mob)) { |
|
|
|
|
|
|
|
mob.setCombatTarget(null); |
|
|
|
|
|
|
|
mob.setAggroTargetID(0); |
|
|
|
|
|
|
|
mob.setWalkingHome(false); |
|
|
|
|
|
|
|
mob.setState(STATE.Home); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mob.updateMovementState(); |
|
|
|
|
|
|
|
mob.updateLocation(); |
|
|
|
|
|
|
|
if(CombatUtilities.inRange2D(mob,mob.getCombatTarget(), mob.getRange()) == true) { |
|
|
|
|
|
|
|
MovementUtilities.moveToLocation(mob, mob.getLoc(), 0); |
|
|
|
|
|
|
|
mob.setState(STATE.Attack); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else {//if (mob.isMoving() == false){
|
|
|
|
|
|
|
|
if(mob.getRange() > 15) { |
|
|
|
|
|
|
|
mob.destination = mob.getCombatTarget().getLoc(); |
|
|
|
|
|
|
|
MovementUtilities.moveToLocation(mob, mob.destination, 0); |
|
|
|
|
|
|
|
} else{ |
|
|
|
|
|
|
|
mob.destination = MovementUtilities.GetDestinationToCharacter(mob, (AbstractCharacter) mob.getCombatTarget()); |
|
|
|
|
|
|
|
MovementUtilities.moveToLocation(mob, mob.destination, mob.getRange()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|