@ -23,6 +23,7 @@ import engine.net.client.msg.PowerProjectileMsg;
import engine.objects.* ;
import engine.objects.* ;
import engine.powers.ActionsBase ;
import engine.powers.ActionsBase ;
import engine.powers.PowersBase ;
import engine.powers.PowersBase ;
import engine.powers.RunePowerEntry ;
import engine.server.MBServerStatics ;
import engine.server.MBServerStatics ;
import org.pmw.tinylog.Logger ;
import org.pmw.tinylog.Logger ;
@ -49,17 +50,19 @@ public class MobAI {
return ;
return ;
}
}
if ( target . getObjectType ( ) = = Enum . GameObjectType . PlayerCharacter & & canCast ( mob ) ) {
if ( target . getObjectType ( ) . equals ( Enum . GameObjectType . PlayerCharacter ) & &
! mob . canSee ( ( AbstractCharacter ) target ) ) {
if ( mob . isPlayerGuard ( ) = = false & & MobCast ( mob ) ) {
mob . setCombatTarget ( null ) ;
mob . updateLocation ( ) ;
return ;
return ;
}
}
if ( mob . isPlayerGuard ( ) = = true & & GuardCast ( mob ) ) {
if ( target . getObjectType ( ) = = Enum . GameObjectType . PlayerCharacter & & canCast ( mob ) ) {
if ( MobCast ( mob ) ) {
mob . updateLocation ( ) ;
mob . updateLocation ( ) ;
return ;
return ;
}
}
}
}
if ( ! CombatUtilities . inRangeToAttack ( mob , target ) )
if ( ! CombatUtilities . inRangeToAttack ( mob , target ) )
@ -96,7 +99,7 @@ public class MobAI {
return ;
return ;
}
}
if ( mob . B ehaviourType. callsForHelp )
if ( mob . b ehaviourType. callsForHelp )
MobCallForHelp ( mob ) ;
MobCallForHelp ( mob ) ;
if ( ! MovementUtilities . inRangeDropAggro ( mob , target ) ) {
if ( ! MovementUtilities . inRangeDropAggro ( mob , target ) ) {
@ -165,7 +168,7 @@ public class MobAI {
if ( playercity ! = null )
if ( playercity ! = null )
for ( Mob guard : playercity . getParent ( ) . zoneMobSet )
for ( Mob guard : playercity . getParent ( ) . zoneMobSet )
if ( guard . BehaviourType ! = null & & guard . BehaviourType . ordinal ( ) = = Enum . MobBehaviourType . GuardCaptain . ordinal ( ) )
if ( guard . agentType . equals ( Enum . AIAgentType . GUARDCAPTAIN ) )
if ( guard . getCombatTarget ( ) = = null & & ! guard . getGuild ( ) . equals ( mob . getGuild ( ) ) )
if ( guard . getCombatTarget ( ) = = null & & ! guard . getGuild ( ) . equals ( mob . getGuild ( ) ) )
guard . setCombatTarget ( mob ) ;
guard . setCombatTarget ( mob ) ;
@ -249,18 +252,22 @@ public class MobAI {
try {
try {
//make sure mob is out of combat stance
int patrolDelay = ThreadLocalRandom . current ( ) . nextInt ( ( int ) ( MobAIThread . AI_PATROL_DIVISOR * 0 . 5f ) , MobAIThread . AI_PATROL_DIVISOR ) + MobAIThread . AI_PATROL_DIVISOR ;
int patrolDelay = ThreadLocalRandom . current ( ) . nextInt ( ( int ) ( MobAIThread . AI_PATROL_DIVISOR * 0 . 5f ) , MobAIThread . AI_PATROL_DIVISOR ) + MobAIThread . AI_PATROL_DIVISOR ;
//early exit while waiting to patrol again
// early exit while waiting to patrol again.
// Minions are force marched if captain is alive
boolean forced = mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) & &
mob . guardCaptain . isAlive ( ) ;
if ( mob . stopPatrolTime + ( patrolDelay * 1000 ) > System . currentTimeMillis ( ) )
if ( mob . stopPatrolTime + ( patrolDelay * 1000 ) > System . currentTimeMillis ( ) )
if ( ! forced )
return ;
return ;
//guard captain s inherit barracks patrol points dynamically
//guards inherit barracks patrol points dynamically
if ( mob . BehaviourType . ordinal ( ) = = Enum . MobBehaviourType . GuardCaptain . ordinal ( ) ) {
if ( mob . patrolPoints = = null | | mob . patrolPoints . isEmpty ( ) )
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDCAPTAIN ) | | mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) ) {
Building barracks = mob . building ;
Building barracks = mob . building ;
@ -275,24 +282,28 @@ public class MobAI {
if ( mob . lastPatrolPointIndex > mob . patrolPoints . size ( ) - 1 )
if ( mob . lastPatrolPointIndex > mob . patrolPoints . size ( ) - 1 )
mob . lastPatrolPointIndex = 0 ;
mob . lastPatrolPointIndex = 0 ;
// Minions are given marching orders by the captain if he is alive
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) ) {
Mob captain = ( Mob ) mob . guardCaptain ;
mob . destination = captain . destination . add ( Formation . getOffset ( 2 , mob . guardCaptain . minions . indexOf ( mob . getObjectUUID ( ) ) + 3 ) ) ;
mob . lastPatrolPointIndex = captain . lastPatrolPointIndex ;
} else {
mob . destination = mob . patrolPoints . get ( mob . lastPatrolPointIndex ) ;
mob . destination = mob . patrolPoints . get ( mob . lastPatrolPointIndex ) ;
mob . lastPatrolPointIndex + = 1 ;
mob . lastPatrolPointIndex + = 1 ;
}
MovementUtilities . aiMove ( mob , mob . destination , true ) ;
// Captain orders minions to patrol
if ( mob . BehaviourType . equals ( Enum . MobBehaviourType . GuardCaptain ) )
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDCAPTAIN ) )
for ( Entry < Mob , Integer > minion : mob . siegeMinionMap . entrySet ( ) )
for ( Integer minionUUID : mob . minions ) {
Mob minion = Mob . getMob ( minionUUID ) ;
if ( minion . isAlive ( ) & & minion . combatTarget = = null )
MobAI . Patrol ( minion ) ;
}
//make sure mob is out of combat stance
MovementUtilities . aiMove ( mob , mob . destination , true ) ;
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 ) {
} catch ( Exception e ) {
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: AttackTarget" + " " + e . getMessage ( ) ) ;
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: AttackTarget" + " " + e . getMessage ( ) ) ;
}
}
@ -300,6 +311,8 @@ public class MobAI {
public static boolean canCast ( Mob mob ) {
public static boolean canCast ( Mob mob ) {
int contractID = 0 ;
try {
try {
// Performs validation to determine if a
// Performs validation to determine if a
@ -308,26 +321,27 @@ public class MobAI {
if ( mob = = null )
if ( mob = = null )
return false ;
return false ;
if ( mob . isPlayerGuard = = true ) {
if ( mob . isPlayerGuard ( ) = = true ) {
int contractID ;
if ( mob . BehaviourType . equals ( Enum . MobBehaviourType . GuardMinion ) )
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDWALLARCHER ) )
contractID = mob . npcOwner . contract . getContractID ( ) ;
return false ; //wall archers don't cast
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) )
contractID = mob . guardCaptain . contract . getContractID ( ) ;
else
else
contractID = mob . contract . getContractID ( ) ;
contractID = mob . contract . getContractID ( ) ;
if ( Enum . MinionType . ContractToMinionMap . get ( contractID ) . isMage ( ) = = false )
// exception allowing werewolf and werebear guard captains to cast
if ( Enum . MinionType . ContractToMinionMap . get ( contractID ) . isMage ( ) = = false & & contractID ! = 980103 & & contractID ! = 980104 )
return false ;
return false ;
}
}
if ( mob . mobPowers . isEmpty ( ) )
// Mobile has no powers defined in mobbase or contract..
return false ;
if ( ! mob . canSee ( ( PlayerCharacter ) mob . getCombatTarget ( ) ) ) {
if ( PowersManager . getPowersForRune ( mob . getMobBaseID ( ) ) . isEmpty ( ) & &
mob . setCombatTarget ( null ) ;
PowersManager . getPowersForRune ( contractID ) . isEmpty ( ) )
return false ;
return false ;
}
if ( mob . nextCastTime = = 0 )
if ( mob . nextCastTime = = 0 )
mob . nextCastTime = System . currentTimeMillis ( ) ;
mob . nextCastTime = System . currentTimeMillis ( ) ;
@ -346,47 +360,67 @@ public class MobAI {
// and casts it on the current target (or itself). Validation
// and casts it on the current target (or itself). Validation
// (including empty lists) is done previously within canCast();
// (including empty lists) is done previously within canCast();
ArrayList < Integer > powerToken s;
ArrayList < RunePowerEntry > powerEntrie s;
ArrayList < Integer > purgeToken s;
ArrayList < RunePowerEntry > purgeEntrie s;
AbstractCharacter target = ( AbstractCharacter ) mob . getCombatTarget ( ) ;
AbstractCharacter target = ( AbstractCharacter ) mob . getCombatTarget ( ) ;
if ( mob . B ehaviourType. callsForHelp )
if ( mob . b ehaviourType. callsForHelp )
MobCallForHelp ( mob ) ;
MobCallForHelp ( mob ) ;
// Generate a list of tokens from the mob powers for this mobile.
// Generate a list of tokens from the mob powers for this mobile.
powerTokens = new ArrayList < > ( mob . mobPowers . keySet ( ) ) ;
powerEntries = new ArrayList < > ( PowersManager . getPowersForRune ( mob . getMobBaseID ( ) ) ) ;
purgeTokens = new ArrayList < > ( ) ;
purgeEntries = new ArrayList < > ( ) ;
// Additional powers may come from the contract ID. This is to support
// powers for player guards irrespective of the mobbase used.
if ( mob . isPlayerGuard ( ) ) {
ArrayList < RunePowerEntry > contractEntries = new ArrayList < > ( ) ;
if ( mob . contract ! = null )
contractEntries = PowersManager . getPowersForRune ( mob . contractUUID ) ;
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) )
contractEntries = PowersManager . getPowersForRune ( mob . guardCaptain . contractUUID ) ;
powerEntries . addAll ( contractEntries ) ;
}
// If player has this effect on them currently then remove
// If player has this effect on them currently then remove
// this token from our list.
// this token from our list.
for ( int powerToken : powerTokens ) {
for ( RunePowerEntry runePowerEntry : powerEntrie s) {
PowersBase powerBase = PowersManager . getPowerByToken ( powerToken ) ;
PowersBase powerBase = PowersManager . getPowerByToken ( runePowerEntry . t oken) ;
for ( ActionsBase actionBase : powerBase . getActions ( ) ) {
for ( ActionsBase actionBase : powerBase . getActions ( ) ) {
String stackType = actionBase . stackType ;
String stackType = actionBase . stackType ;
if ( target . getEffects ( ) ! = null & & target . getEffects ( ) . containsKey ( stackType ) )
if ( target . getEffects ( ) ! = null & & target . getEffects ( ) . containsKey ( stackType ) )
purgeTokens . add ( powerToken ) ;
purgeEntries . add ( runePowerEntry ) ;
}
}
}
}
powerToken s . removeAll ( purgeToken s ) ;
powerEntrie s . removeAll ( purgeEntrie s ) ;
// Sanity check
// Sanity check
if ( powerToken s . isEmpty ( ) )
if ( powerEntrie s . isEmpty ( ) )
return false ;
return false ;
// Pick random spell from our list of powers
// Pick random spell from our list of powers
int powerToken = powerTokens . get ( ThreadLocalRandom . current ( ) . nextInt ( powerTokens . size ( ) ) ) ;
RunePowerEntry runePowerEntry = powerEntries . get ( ThreadLocalRandom . current ( ) . nextInt ( powerEntries . size ( ) ) ) ;
int powerRank = mob . mobPowers . get ( powerToken ) ;
PowersBase mobPower = PowersManager . getPowerByToken ( runePowerEntry . token ) ;
int powerRank = runePowerEntry . rank ;
PowersBase mobPower = PowersManager . getPowerByToken ( powerToken ) ;
if ( mob . isPlayerGuard ( ) )
powerRank = getGuardPowerRank ( mob ) ;
//check for hit-roll
//check for hit-roll
@ -411,7 +445,7 @@ public class MobAI {
msg . setUnknown04 ( 2 ) ;
msg . setUnknown04 ( 2 ) ;
PowersManager . finishUseMobPower ( msg , mob , 0 , 0 ) ;
PowersManager . finishUseMobPower ( msg , mob , 0 , 0 ) ;
long randomCooldown = ( long ) ( ( ThreadLocalRandom . current ( ) . nextInt ( 10 , 15 ) * 1000 ) * MobAIThread . AI_CAST_FREQUENCY ) ;
long randomCooldown = ( long ) ( ( ThreadLocalRandom . current ( ) . nextInt ( 10 , 15 ) * 1000 ) * MobAIThread . AI_CAST_FREQUENCY ) ;
mob . nextCastTime = System . currentTimeMillis ( ) + randomCooldown ;
mob . nextCastTime = System . currentTimeMillis ( ) + randomCooldown ;
return true ;
return true ;
@ -422,64 +456,10 @@ public class MobAI {
return false ;
return false ;
}
}
public static boolean GuardCast ( Mob mob ) {
public static int getGuardPowerRank ( Mob mob ) {
try {
// Method picks a random spell from a mobile's list of powers
// and casts it on the current target (or itself). Validation
// (including empty lists) is done previously within canCast();
ArrayList < Integer > powerTokens ;
ArrayList < Integer > purgeTokens ;
AbstractCharacter target = ( AbstractCharacter ) mob . getCombatTarget ( ) ;
if ( mob . BehaviourType . callsForHelp )
MobCallForHelp ( mob ) ;
// Generate a list of tokens from the mob powers for this mobile.
powerTokens = new ArrayList < > ( mob . mobPowers . keySet ( ) ) ;
purgeTokens = new ArrayList < > ( ) ;
// If player has this effect on them currently then remove
// this token from our list.
for ( int powerToken : powerTokens ) {
PowersBase powerBase = PowersManager . getPowerByToken ( powerToken ) ;
for ( ActionsBase actionBase : powerBase . getActions ( ) ) {
String stackType = actionBase . stackType ;
if ( target . getEffects ( ) ! = null & & target . getEffects ( ) . containsKey ( stackType ) )
purgeTokens . add ( powerToken ) ;
}
}
powerTokens . removeAll ( purgeTokens ) ;
// Sanity check
if ( powerTokens . isEmpty ( ) )
return false ;
int powerToken = 0 ;
int nukeRoll = ThreadLocalRandom . current ( ) . nextInt ( 1 , 100 ) ;
if ( nukeRoll < 55 ) {
//use direct damage spell
powerToken = powerTokens . get ( powerTokens . size ( ) - 1 ) ;
} else {
//use random spell
powerToken = powerTokens . get ( ThreadLocalRandom . current ( ) . nextInt ( powerTokens . size ( ) ) ) ;
}
int powerRank = 1 ;
int powerRank = 1 ;
switch ( mob . getRank ( ) ) {
switch ( mob . getRank ( ) ) {
case 1 :
case 1 :
powerRank = 10 ;
powerRank = 10 ;
break ;
break ;
@ -502,47 +482,7 @@ public class MobAI {
powerRank = 40 ;
powerRank = 40 ;
break ;
break ;
}
}
return powerRank ;
PowersBase mobPower = PowersManager . getPowerByToken ( powerToken ) ;
//check for hit-roll
if ( mobPower . requiresHitRoll )
if ( CombatUtilities . triggerDefense ( mob , mob . getCombatTarget ( ) ) )
return false ;
// Cast the spell
if ( CombatUtilities . inRange2D ( mob , mob . getCombatTarget ( ) , mobPower . getRange ( ) ) ) {
PerformActionMsg msg ;
if ( ! mobPower . isHarmful ( ) | | mobPower . targetSelf ) {
if ( mobPower . category . equals ( "DISPEL" ) ) {
PowersManager . useMobPower ( mob , target , mobPower , powerRank ) ;
msg = PowersManager . createPowerMsg ( mobPower , powerRank , mob , target ) ;
} else {
PowersManager . useMobPower ( mob , mob , mobPower , powerRank ) ;
msg = PowersManager . createPowerMsg ( mobPower , powerRank , mob , mob ) ;
}
} else {
PowersManager . useMobPower ( mob , target , mobPower , powerRank ) ;
msg = PowersManager . createPowerMsg ( mobPower , powerRank , mob , target ) ;
}
msg . setUnknown04 ( 2 ) ;
PowersManager . finishUseMobPower ( msg , mob , 0 , 0 ) ;
long randomCooldown = ( long ) ( ( ThreadLocalRandom . current ( ) . nextInt ( 10 , 15 ) * 1000 ) * MobAIThread . AI_CAST_FREQUENCY ) ;
mob . nextCastTime = System . currentTimeMillis ( ) + randomCooldown ;
return true ;
}
} catch ( Exception e ) {
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: MobCast" + " " + e . getMessage ( ) ) ;
}
return false ;
}
}
public static void MobCallForHelp ( Mob mob ) {
public static void MobCallForHelp ( Mob mob ) {
@ -564,7 +504,7 @@ public class MobAI {
Zone mobCamp = mob . getParentZone ( ) ;
Zone mobCamp = mob . getParentZone ( ) ;
for ( Mob helper : mobCamp . zoneMobSet ) {
for ( Mob helper : mobCamp . zoneMobSet ) {
if ( helper . B ehaviourType. respondsToCallForHelp & & helper . B ehaviourType. BehaviourHelperType . equals ( mob . B ehaviourType) ) {
if ( helper . b ehaviourType. respondsToCallForHelp & & helper . b ehaviourType. BehaviourHelperType . equals ( mob . b ehaviourType) ) {
helper . setCombatTarget ( mob . getCombatTarget ( ) ) ;
helper . setCombatTarget ( mob . getCombatTarget ( ) ) ;
callGotResponse = true ;
callGotResponse = true ;
}
}
@ -606,10 +546,10 @@ public class MobAI {
//override for guards
//override for guards
if ( mob . despawned & & mob . isPlayerGuard ) {
if ( mob . despawned & & mob . isPlayerGuard ( ) ) {
if ( mob . BehaviourType . ordinal ( ) = = Enum . MobBehaviourType . GuardMinion . ordinal ( ) ) {
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) ) {
if ( mob . npcOwner . isAlive ( ) = = false | | ( ( Mob ) mob . npcOwner ) . despawned = = true ) {
if ( mob . guardCaptain . isAlive ( ) = = false | | ( ( Mob ) mob . guardCaptain ) . despawned = = true ) {
//minions don't respawn while guard captain is dead
//minions don't respawn while guard captain is dead
@ -625,7 +565,7 @@ public class MobAI {
//check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting
//check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting
if ( mob . BehaviourType . ordinal ( ) ! = Enum . MobBehaviourType . Pet1 . ordinal ( ) )
if ( ! mob . agentType . equals ( Enum . AIAgentType . PET ) )
CheckToSendMobHome ( mob ) ;
CheckToSendMobHome ( mob ) ;
return ;
return ;
@ -638,15 +578,23 @@ public class MobAI {
return ;
return ;
}
}
//no players loaded, no need to proceed
//no players loaded, no need to proceed unless it's a player guard
boolean bypassLoadedPlayerCheck = false ;
if ( mob . isPlayerGuard ( ) | | mob . isSiege ( ) ) {
bypassLoadedPlayerCheck = true ;
if ( mob . combatTarget ! = null & & mob . combatTarget . getObjectType ( ) . equals ( Enum . GameObjectType . PlayerCharacter ) )
if ( mob . combatTarget . loc . distanceSquared ( mob . loc ) > 10000 )
mob . setCombatTarget ( null ) ;
}
if ( mob . playerAgroMap . isEmpty ( ) ) {
if ( mob . playerAgroMap . isEmpty ( ) & & ! bypassLoadedPlayerCheck ) {
if ( mob . getCombatTarget ( ) ! = null )
if ( mob . getCombatTarget ( ) ! = null )
mob . setCombatTarget ( null ) ;
mob . setCombatTarget ( null ) ;
return ;
return ;
}
}
if ( mob . BehaviourType . ordinal ( ) ! = Enum . MobBehaviourType . Pet1 . ordinal ( ) )
if ( mob . agentType . equals ( Enum . AIAgentType . PET ) = = false )
CheckToSendMobHome ( mob ) ;
CheckToSendMobHome ( mob ) ;
if ( mob . getCombatTarget ( ) ! = null ) {
if ( mob . getCombatTarget ( ) ! = null ) {
@ -673,17 +621,14 @@ public class MobAI {
}
}
}
}
switch ( mob . B ehaviourType) {
switch ( mob . b ehaviourType) {
case GuardCaptain :
case GuardCaptain :
GuardCaptainLogic ( mob ) ;
break ;
case GuardMinion :
case GuardMinion :
GuardMinionLogic ( mob ) ;
break ;
case GuardWallArcher :
case GuardWallArcher :
GuardWallArcher Logic ( mob ) ;
GuardLogic ( mob ) ;
break ;
break ;
case Pet1 :
case Pet1 :
case SiegeEngine :
PetLogic ( mob ) ;
PetLogic ( mob ) ;
break ;
break ;
case HamletGuard :
case HamletGuard :
@ -707,7 +652,7 @@ public class MobAI {
if ( ! aiAgent . isAlive ( ) )
if ( ! aiAgent . isAlive ( ) )
return ;
return ;
ConcurrentHashMap < Integer , Boolean > loadedPlayers = aiAgent . playerAgroMap ;
ConcurrentHashMap < Integer , Float > loadedPlayers = aiAgent . playerAgroMap ;
for ( Entry playerEntry : loadedPlayers . entrySet ( ) ) {
for ( Entry playerEntry : loadedPlayers . entrySet ( ) ) {
@ -747,7 +692,6 @@ public class MobAI {
aiAgent . setCombatTarget ( loadedPlayer ) ;
aiAgent . setCombatTarget ( loadedPlayer ) ;
return ;
return ;
}
}
}
}
if ( aiAgent . getCombatTarget ( ) = = null ) {
if ( aiAgent . getCombatTarget ( ) = = null ) {
@ -782,47 +726,45 @@ public class MobAI {
mob . updateLocation ( ) ;
mob . updateLocation ( ) ;
switch ( mob . B ehaviourType) {
switch ( mob . b ehaviourType) {
case Pet1 :
case Pet1 :
if ( mob . getOwner ( ) = = null )
return ;
if ( ! mob . playerAgroMap . containsKey ( mob . getOwner ( ) . getObjectUUID ( ) ) ) {
if ( mob . guardCaptain = = null )
return ;
//mob no longer has its owner loaded, transloc ate pet to owner
//mob no longer has its owner loaded, translate pet to owner
MovementManager . translocate ( mob , mob . getOwner ( ) . getLoc ( ) , null ) ;
if ( ! mob . playerAgroMap . containsKey ( mob . guardCaptain . getObjectUUID ( ) ) ) {
MovementManager . translocate ( mob , mob . guardCaptain . getLoc ( ) ) ;
return ;
return ;
}
}
if ( mob . getCombatTarget ( ) = = null ) {
if ( mob . getCombatTarget ( ) = = null ) {
//move back to owner
//move back to owner
if ( CombatUtilities . inRange2D ( mob , mob . getOwner ( ) , 6 ) )
if ( CombatUtilities . inRange2D ( mob , mob . guardCaptain , 6 ) )
return ;
return ;
mob . destination = mob . getOwner ( ) . getLoc ( ) ;
mob . destination = mob . guardCaptain . getLoc ( ) ;
MovementUtilities . moveToLocation ( mob , mob . destination , 5 ) ;
MovementUtilities . moveToLocation ( mob , mob . destination , 5 , false ) ;
} else
} else
chaseTarget ( mob ) ;
chaseTarget ( mob ) ;
break ;
break ;
case GuardMinion :
if ( ! mob . npcOwner . isAlive ( ) | | ( ( Mob ) mob . npcOwner ) . despawned )
randomGuardPatrolPoint ( mob ) ;
else {
if ( mob . getCombatTarget ( ) ! = null ) {
chaseTarget ( mob ) ;
}
}
break ;
default :
default :
if ( mob . getCombatTarget ( ) = = null ) {
if ( mob . getCombatTarget ( ) = = null ) {
if ( ! mob . isMoving ( ) )
if ( ! mob . isMoving ( ) ) {
// Minions only patrol on their own if captain is dead.
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) = = false )
Patrol ( mob ) ;
Patrol ( mob ) ;
else {
else if ( mob . guardCaptain . isAlive ( ) = = false )
Patrol ( mob ) ;
} else
mob . stopPatrolTime = System . currentTimeMillis ( ) ;
mob . stopPatrolTime = System . currentTimeMillis ( ) ;
}
} else {
} else {
chaseTarget ( mob ) ;
chaseTarget ( mob ) ;
}
}
@ -893,7 +835,8 @@ public class MobAI {
if ( mob . getCombatTarget ( ) = = null )
if ( mob . getCombatTarget ( ) = = null )
return ;
return ;
if ( mob . getCombatTarget ( ) . getObjectType ( ) . equals ( Enum . GameObjectType . PlayerCharacter ) & & MovementUtilities . inRangeDropAggro ( mob , ( PlayerCharacter ) mob . getCombatTarget ( ) ) = = false & & mob . BehaviourType . ordinal ( ) ! = Enum . MobBehaviourType . Pet1 . ordinal ( ) ) {
if ( mob . getCombatTarget ( ) . getObjectType ( ) . equals ( Enum . GameObjectType . PlayerCharacter ) & & MovementUtilities . inRangeDropAggro ( mob , ( PlayerCharacter ) mob . getCombatTarget ( ) ) = = false & &
mob . agentType . equals ( Enum . AIAgentType . PET ) = = false ) {
mob . setCombatTarget ( null ) ;
mob . setCombatTarget ( null ) ;
return ;
return ;
@ -909,15 +852,6 @@ public class MobAI {
private static void CheckToSendMobHome ( Mob mob ) {
private static void CheckToSendMobHome ( Mob mob ) {
try {
try {
if ( mob . BehaviourType . isAgressive ) {
if ( mob . isPlayerGuard ( ) ) {
if ( mob . BehaviourType . ordinal ( ) = = Enum . MobBehaviourType . GuardCaptain . ordinal ( ) )
CheckForPlayerGuardAggro ( mob ) ;
} else {
CheckForAggro ( mob ) ;
}
}
if ( mob . getCombatTarget ( ) ! = null & & CombatUtilities . inRange2D ( mob , mob . getCombatTarget ( ) , MobAIThread . AI_BASE_AGGRO_RANGE * 0 . 5f ) )
if ( mob . getCombatTarget ( ) ! = null & & CombatUtilities . inRange2D ( mob , mob . getCombatTarget ( ) , MobAIThread . AI_BASE_AGGRO_RANGE * 0 . 5f ) )
return ;
return ;
@ -932,13 +866,15 @@ public class MobAI {
PowersManager . useMobPower ( mob , mob , recall , 40 ) ;
PowersManager . useMobPower ( mob , mob , recall , 40 ) ;
mob . setCombatTarget ( null ) ;
mob . setCombatTarget ( null ) ;
if ( mob . BehaviourType . ordinal ( ) = = Enum . MobBehaviourType . GuardCaptain . ordinal ( ) & & mob . isAlive ( ) ) {
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDCAPTAIN ) & & mob . isAlive ( ) ) {
//guard captain pulls his minions home with him
//guard captain pulls his minions home with him
for ( Entry < Mob , Integer > minion : mob . siegeMinionMap . entrySet ( ) ) {
for ( Integer minionUUID : mob . minions ) {
PowersManager . useMobPower ( minion . getKey ( ) , minion . getKey ( ) , recall , 40 ) ;
Mob minion = Mob . getMob ( minionUUID ) ;
minion . getKey ( ) . setCombatTarget ( null ) ;
PowersManager . useMobPower ( minion , minion , recall , 40 ) ;
minion . setCombatTarget ( null ) ;
}
}
}
}
}
}
@ -948,8 +884,8 @@ public class MobAI {
PowersManager . useMobPower ( mob , mob , recall , 40 ) ;
PowersManager . useMobPower ( mob , mob , recall , 40 ) ;
mob . setCombatTarget ( null ) ;
mob . setCombatTarget ( null ) ;
for ( Entry playerEntry : mob . playerAgroMap . entr ySet ( ) )
for ( Integer playerEntry : mob . playerAgroMap . k eySet( ) )
PlayerCharacter . getFromCache ( ( int ) playerEntry . getKey ( ) ) . setHateValue ( 0 ) ;
mob . playerAgroMap . put ( playerEntry , 0f ) ;
}
}
} catch ( Exception e ) {
} catch ( Exception e ) {
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: CheckToSendMobHome" + " " + e . getMessage ( ) ) ;
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: CheckToSendMobHome" + " " + e . getMessage ( ) ) ;
@ -960,16 +896,10 @@ public class MobAI {
try {
try {
float rangeSquared = mob . getRange ( ) * mob . getRange ( ) ;
if ( CombatUtilities . inRange2D ( mob , mob . getCombatTarget ( ) , mob . getRange ( ) ) = = false ) {
float distanceSquared = mob . getLoc ( ) . distanceSquared2D ( mob . getCombatTarget ( ) . getLoc ( ) ) ;
if ( mob . isMoving ( ) = = true & & distanceSquared < rangeSquared - 50 ) {
mob . destination = mob . getLoc ( ) ;
MovementUtilities . moveToLocation ( mob , mob . destination , 0 ) ;
} else 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 ( ) ;
MovementUtilities . moveToLocation ( mob , mob . destination , 0 ) ;
MovementUtilities . moveToLocation ( mob , mob . destination , 0 , false ) ;
} else {
} else {
//check if building
//check if building
@ -978,11 +908,11 @@ public class MobAI {
case PlayerCharacter :
case PlayerCharacter :
case Mob :
case Mob :
mob . destination = MovementUtilities . GetDestinationToCharacter ( mob , ( AbstractCharacter ) mob . getCombatTarget ( ) ) ;
mob . destination = MovementUtilities . GetDestinationToCharacter ( mob , ( AbstractCharacter ) mob . getCombatTarget ( ) ) ;
MovementUtilities . moveToLocation ( mob , mob . destination , mob . getRange ( ) + 1 ) ;
MovementUtilities . moveToLocation ( mob , mob . destination , mob . getRange ( ) + 1 , false ) ;
break ;
break ;
case Building :
case Building :
mob . destination = mob . getCombatTarget ( ) . getLoc ( ) ;
mob . destination = mob . getCombatTarget ( ) . getLoc ( ) ;
MovementUtilities . moveToLocation ( mob , mob . getCombatTarget ( ) . getLoc ( ) , 0 ) ;
MovementUtilities . moveToLocation ( mob , mob . getCombatTarget ( ) . getLoc ( ) , 0 , false ) ;
break ;
break ;
}
}
}
}
@ -1003,17 +933,17 @@ public class MobAI {
//dont scan self.
//dont scan self.
if ( mob . equals ( awoMob ) | | ( mob . agentType . equals ( Enum . AIAgentType . GUARD ) ) = = true )
if ( mob . equals ( awoMob ) | | ( mob . agentType . equals ( Enum . AIAgentType . GUARDCAPTAIN ) ) = = true )
continue ;
continue ;
Mob aggroMob = ( Mob ) awoMob ;
Mob aggroMob = ( Mob ) awoMob ;
//don't attack other guards
//don't attack other guards
if ( ( aggroMob . agentType . equals ( Enum . AIAgentType . GUARD ) ) )
if ( ( aggroMob . agentType . equals ( Enum . AIAgentType . GUARDCAPTAIN ) ) )
continue ;
continue ;
if ( aggroMob . Behaviour Type. equals ( Enum . MobBehaviourType . Pet1 ) )
if ( aggroMob . agent Type. equals ( Enum . AIAgentType . PET ) )
continue ;
continue ;
if ( mob . getLoc ( ) . distanceSquared2D ( aggroMob . getLoc ( ) ) > sqr ( 50 ) )
if ( mob . getLoc ( ) . distanceSquared2D ( aggroMob . getLoc ( ) ) > sqr ( 50 ) )
@ -1026,40 +956,13 @@ public class MobAI {
}
}
}
}
public static void GuardCaptainLogic ( Mob mob ) {
public static void GuardLogic ( Mob mob ) {
try {
if ( mob . getCombatTarget ( ) = = null )
CheckForPlayerGuardAggro ( mob ) ;
AbstractWorldObject newTarget = ChangeTargetFromHateValue ( mob ) ;
if ( newTarget ! = null ) {
if ( newTarget . getObjectType ( ) . equals ( Enum . GameObjectType . PlayerCharacter ) ) {
if ( GuardCanAggro ( mob , ( PlayerCharacter ) newTarget ) )
mob . setCombatTarget ( newTarget ) ;
} else
mob . setCombatTarget ( newTarget ) ;
}
CheckMobMovement ( mob ) ;
CheckForAttack ( mob ) ;
} catch ( Exception e ) {
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: GuardCaptainLogic" + " " + e . getMessage ( ) ) ;
}
}
public static void GuardMinionLogic ( Mob mob ) {
try {
try {
if ( ! mob . npcOwner . isAlive ( ) ) {
if ( mob . getCombatTarget ( ) = = null ) {
if ( mob . getCombatTarget ( ) = = null ) {
CheckForPlayerGuardAggro ( mob ) ;
CheckForPlayerGuardAggro ( mob ) ;
} else {
} else {
//do not need to look to change target if target is already null
AbstractWorldObject newTarget = ChangeTargetFromHateValue ( mob ) ;
AbstractWorldObject newTarget = ChangeTargetFromHateValue ( mob ) ;
if ( newTarget ! = null ) {
if ( newTarget ! = null ) {
@ -1069,32 +972,17 @@ public class MobAI {
mob . setCombatTarget ( newTarget ) ;
mob . setCombatTarget ( newTarget ) ;
} else
} else
mob . setCombatTarget ( newTarget ) ;
mob . setCombatTarget ( newTarget ) ;
}
}
} else {
if ( mob . npcOwner . getCombatTarget ( ) ! = null )
mob . setCombatTarget ( mob . npcOwner . getCombatTarget ( ) ) ;
else
if ( mob . getCombatTarget ( ) ! = null )
mob . setCombatTarget ( null ) ;
}
CheckMobMovement ( mob ) ;
CheckForAttack ( mob ) ;
} catch ( Exception e ) {
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: GuardMinionLogic" + " " + e . getMessage ( ) ) ;
}
}
}
}
public static void GuardWallArcherLogic ( Mob mob ) {
if ( mob . behaviourType . canRoam )
CheckMobMovement ( mob ) ; //all guards that can move check to move
if ( mob . combatTarget ! = null )
CheckForAttack ( mob ) ; //only check to attack if combat target is not null
try {
if ( mob . getCombatTarget ( ) = = null )
CheckForPlayerGuardAggro ( mob ) ;
else
CheckForAttack ( mob ) ;
} catch ( Exception e ) {
} catch ( Exception e ) {
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: GuardWallArcher Logic" + " " + e . getMessage ( ) ) ;
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: GuardLogic" + " " + e . getMessage ( ) ) ;
}
}
}
}
@ -1102,11 +990,11 @@ public class MobAI {
try {
try {
if ( mob . getOwner ( ) = = null & & mob . isNecroPet ( ) = = false & & mob . isSiege ( ) = = false )
if ( mob . guardCaptain = = null & & mob . isNecroPet ( ) = = false & & mob . isSiege ( ) = = false )
if ( ZoneManager . getSeaFloor ( ) . zoneMobSet . contains ( mob ) )
if ( ZoneManager . getSeaFloor ( ) . zoneMobSet . contains ( mob ) )
mob . killCharacter ( "no owner" ) ;
mob . killCharacter ( "no owner" ) ;
if ( MovementUtilities . canMove ( mob ) & & mob . B ehaviourType. canRoam )
if ( MovementUtilities . canMove ( mob ) & & mob . b ehaviourType. canRoam )
CheckMobMovement ( mob ) ;
CheckMobMovement ( mob ) ;
CheckForAttack ( mob ) ;
CheckForAttack ( mob ) ;
@ -1156,7 +1044,7 @@ public class MobAI {
if ( mob . getCombatTarget ( ) ! = null & & mob . playerAgroMap . containsKey ( mob . getCombatTarget ( ) . getObjectUUID ( ) ) = = false )
if ( mob . getCombatTarget ( ) ! = null & & mob . playerAgroMap . containsKey ( mob . getCombatTarget ( ) . getObjectUUID ( ) ) = = false )
mob . setCombatTarget ( null ) ;
mob . setCombatTarget ( null ) ;
if ( mob . B ehaviourType. isAgressive ) {
if ( mob . b ehaviourType. isAgressive ) {
AbstractWorldObject newTarget = ChangeTargetFromHateValue ( mob ) ;
AbstractWorldObject newTarget = ChangeTargetFromHateValue ( mob ) ;
@ -1164,7 +1052,7 @@ public class MobAI {
mob . setCombatTarget ( newTarget ) ;
mob . setCombatTarget ( newTarget ) ;
else {
else {
if ( mob . getCombatTarget ( ) = = null ) {
if ( mob . getCombatTarget ( ) = = null ) {
if ( mob . B ehaviourType = = Enum . MobBehaviourType . HamletGuard )
if ( mob . b ehaviourType = = Enum . MobBehaviourType . HamletGuard )
SafeGuardAggro ( mob ) ; //safehold guard
SafeGuardAggro ( mob ) ; //safehold guard
else
else
CheckForAggro ( mob ) ; //normal aggro
CheckForAggro ( mob ) ; //normal aggro
@ -1174,12 +1062,12 @@ public class MobAI {
//check if mob can move for patrol or moving to target
//check if mob can move for patrol or moving to target
if ( mob . B ehaviourType. canRoam )
if ( mob . b ehaviourType. canRoam )
CheckMobMovement ( mob ) ;
CheckMobMovement ( mob ) ;
//check if mob can attack if it isn't wimpy
//check if mob can attack if it isn't wimpy
if ( ! mob . B ehaviourType. isWimpy & & mob . getCombatTarget ( ) ! = null )
if ( ! mob . b ehaviourType. isWimpy & & mob . getCombatTarget ( ) ! = null )
CheckForAttack ( mob ) ;
CheckForAttack ( mob ) ;
} catch ( Exception e ) {
} catch ( Exception e ) {
@ -1196,7 +1084,16 @@ public class MobAI {
if ( ! mob . isAlive ( ) )
if ( ! mob . isAlive ( ) )
return ;
return ;
ConcurrentHashMap < Integer , Boolean > loadedPlayers = mob . playerAgroMap ;
// Defer to captain if possible for current target
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDMINION ) & &
mob . guardCaptain . isAlive ( )
& & mob . guardCaptain . combatTarget ! = null ) {
mob . setCombatTarget ( mob . guardCaptain . combatTarget ) ;
return ;
}
ConcurrentHashMap < Integer , Float > loadedPlayers = mob . playerAgroMap ;
for ( Entry playerEntry : loadedPlayers . entrySet ( ) ) {
for ( Entry playerEntry : loadedPlayers . entrySet ( ) ) {
@ -1231,27 +1128,39 @@ public class MobAI {
mob . setCombatTarget ( loadedPlayer ) ;
mob . setCombatTarget ( loadedPlayer ) ;
return ;
return ;
}
}
}
if ( mob . getCombatTarget ( ) = = null ) {
//look for siege equipment to aggro if no players found to aggro
HashSet < AbstractWorldObject > awoList = WorldGrid . getObjectsInRangePartial ( mob , MobAIThread . AI_BASE_AGGRO_RANGE , MBServerStatics . MASK_SIEGE ) ;
for ( AbstractWorldObject awoMob : awoList ) {
Mob aggroMob = ( Mob ) awoMob ;
if ( GuardCanAggro ( mob , aggroMob ) ) {
mob . setCombatTarget ( aggroMob ) ;
return ;
}
}
}
}
} catch ( Exception e ) {
} catch ( Exception e ) {
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: CheckForPlayerGuardAggro" + e . getMessage ( ) ) ;
Logger . info ( mob . getObjectUUID ( ) + " " + mob . getName ( ) + " Failed At: CheckForPlayerGuardAggro" + e . getMessage ( ) ) ;
}
}
}
}
public static Boolean GuardCanAggro ( Mob mob , PlayerCharacter target ) {
public static Boolean GuardCanAggro ( Mob mob , Abstract Character target ) {
try {
try {
if ( mob . guardedCity . cityOutlaws . contains ( target . getObjectUUID ( ) ) = = true )
return true ;
if ( mob . getGuild ( ) . getNation ( ) . equals ( target . getGuild ( ) . getNation ( ) ) )
if ( mob . getGuild ( ) . getNation ( ) . equals ( target . getGuild ( ) . getNation ( ) ) )
return false ;
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)
//first check condemn list for aggro allowed (allies button is checked)
if ( ZoneManager . getCityAtLocation ( mob . getLoc ( ) ) . getTOL ( ) . reverseKOS ) {
if ( ZoneManager . getCityAtLocation ( mob . getLoc ( ) ) . getTOL ( ) . reverseKOS ) {
@ -1329,17 +1238,19 @@ public class MobAI {
MovementUtilities . aiMove ( mob , mob . destination , true ) ;
MovementUtilities . aiMove ( mob , mob . destination , true ) ;
if ( mob . BehaviourType . ordinal ( ) = = Enum . MobBehaviourType . GuardCaptain . ordinal ( ) ) {
if ( mob . agentType . equals ( Enum . AIAgentType . GUARDCAPTAIN ) ) {
for ( Entry < Mob , Integer > minion : mob . siegeMinionMap . entrySet ( ) ) {
for ( Integer minionUUID : mob . minions ) {
Mob minion = Mob . getMob ( minionUUID ) ;
//make sure mob is out of combat stance
//make sure mob is out of combat stance
if ( minion . getKey ( ) . despawned = = false ) {
if ( minion . despawned = = false ) {
if ( MovementUtilities . canMove ( minion . getKey ( ) ) ) {
if ( MovementUtilities . canMove ( minion ) ) {
Vector3f minionOffset = Formation . getOffset ( 2 , minion . getValue ( ) + 3 ) ;
Vector3f minionOffset = Formation . getOffset ( 2 , mob . minions . indexOf ( minionUUID ) + 3 ) ;
minion . getKey ( ) . updateLocation ( ) ;
minion . updateLocation ( ) ;
Vector3fImmutable formationPatrolPoint = new Vector3fImmutable ( mob . destination . x + minionOffset . x , mob . destination . y , mob . destination . z + minionOffset . z ) ;
Vector3fImmutable formationPatrolPoint = new Vector3fImmutable ( mob . destination . x + minionOffset . x , mob . destination . y , mob . destination . z + minionOffset . z ) ;
MovementUtilities . aiMove ( minion . getKey ( ) , formationPatrolPoint , true ) ;
MovementUtilities . aiMove ( minion , formationPatrolPoint , true ) ;
}
}
}
}
}
}
@ -1356,7 +1267,7 @@ public class MobAI {
float CurrentHateValue = 0 ;
float CurrentHateValue = 0 ;
if ( mob . getCombatTarget ( ) ! = null & & mob . getCombatTarget ( ) . getObjectType ( ) . equals ( Enum . GameObjectType . PlayerCharacter ) )
if ( mob . getCombatTarget ( ) ! = null & & mob . getCombatTarget ( ) . getObjectType ( ) . equals ( Enum . GameObjectType . PlayerCharacter ) )
CurrentHateValue = ( ( PlayerCharacter ) mob . getCombatTarget ( ) ) . getHate Value( ) ;
CurrentHateValue = mob . playerAgroMap . get ( mob . combatTarget . getObjectUUID ( ) ) . float Value( ) ;
AbstractWorldObject mostHatedTarget = null ;
AbstractWorldObject mostHatedTarget = null ;
@ -1367,8 +1278,8 @@ public class MobAI {
if ( potentialTarget . equals ( mob . getCombatTarget ( ) ) )
if ( potentialTarget . equals ( mob . getCombatTarget ( ) ) )
continue ;
continue ;
if ( potentialTarget ! = null & & potentialTarget . getHate Value ( ) > CurrentHateValue & & MovementUtilities . inRangeToAggro ( mob , potentialTarget ) ) {
if ( potentialTarget ! = null & & mob . playerAgroMap . get ( potentialTarget . getObjectUUID ( ) ) . float Value ( ) > CurrentHateValue & & MovementUtilities . inRangeToAggro ( mob , potentialTarget ) ) {
CurrentHateValue = potentialTarget . getHate Value ( ) ;
CurrentHateValue = mob . playerAgroMap . get ( potentialTarget . getObjectUUID ( ) ) . float Value ( ) ;
mostHatedTarget = potentialTarget ;
mostHatedTarget = potentialTarget ;
}
}