public void SelectCombatRoundAction(bool fromAllyCall)
{
HasCombatRoundProcess = true;
if (Script.GetIsObjectValid(ObjectId) == CLRScriptBase.FALSE) return;
#region Clean Up Before Attempting Action
List<CreatureObject> deadEnemies = new List<CreatureObject>();
foreach(CreatureObject enemy in Party.Enemies)
{
if(Script.GetCurrentHitPoints(enemy.ObjectId) < 1)
{
if (Script.GetIsPC(enemy.ObjectId) != CLRScriptBase.FALSE)
{
if (!Party.CleanUpEnemies.Contains(enemy))
Party.CleanUpEnemies.Add(enemy);
}
deadEnemies.Add(enemy);
}
}
foreach(CreatureObject enemy in deadEnemies)
{
Party.RemovePartyEnemy(enemy);
}
List<CreatureObject> revivedEnemies = new List<CreatureObject>();
foreach(CreatureObject enemy in Party.CleanUpEnemies)
{
if(Script.GetCurrentHitPoints(enemy.ObjectId) > 0)
{
Party.AddPartyEnemy(enemy);
revivedEnemies.Add(enemy);
}
}
foreach(CreatureObject enemy in revivedEnemies)
{
Party.CleanUpEnemies.Remove(enemy);
}
#endregion
#region Rally Any Party Mates
if (!fromAllyCall)
{
foreach (CreatureObject ally in Party.PartyMembers)
{
if (Script.GetCurrentAction(ally.ObjectId) == CLRScriptBase.ACTION_INVALID)
{
if (!ally.HasCombatRoundProcess)
{
ally.HasCombatRoundProcess = true;
ally.SelectCombatRoundAction(true);
}
}
}
}
#endregion
#region Gather Data on Status
RefreshNegativeStatuses();
#endregion
#region Early return for not being able to act.
// Can't do anything. Might as well give up early and pray there's help on the way.
if (!CanAct())
{
return;
}
#endregion
#region Specify panic behavior due to injury
int nWellBeing = HealthPercentage;
int nMissingHitPoints = MaxHitPoints - CurrentHitPoints;
// Do we even have anyone to fight?
if (Party.Enemies.Count == 0 &&
Party.EnemiesLost.Count == 0)
{
HasCombatRoundProcess = false;
UsingEndCombatRound = false;
CreatureObject Healer = Party.GetNearest(this, Party.PartyMedics);
// Everyone gather around the healer; he or she might be using mass heals.
if (Healer != null && Healer != this)
{
Script.ActionMoveToObject(Healer.ObjectId, CLRScriptBase.TRUE, 1.0f);
return;
}
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_MEDIC &&
CurrentAction == CLRScriptBase.ACTION_INVALID)
{
if (TryToHealAll())
CleanUpNeeded = true;
else
CleanUpNeeded = false;
return;
}
else
TryToHeal(this, nMissingHitPoints);
_AmbientBehavior();
return;
}
// Are we in critical condition?
if (nWellBeing < 10)
{
CreatureObject Healer = Party.GetNearest(this, Party.PartyMedics);
if (Healer == null)
Healer = Party.GetNearest(this, Party.PartyBuffs);
if (Healer != null && Healer != this)
{
if (Script.GetDistanceBetween(Healer.ObjectId, this.ObjectId) > 5.0f)
{
Script.ActionMoveToObject(Healer.ObjectId, CLRScriptBase.TRUE, 1.0f);
TryToHeal(this, nMissingHitPoints);
return;
}
}
else if (Party.PartyLeader != null && Party.PartyLeader != this)
{
Healer = Party.PartyLeader;
if (Script.GetDistanceBetween(Healer.ObjectId, this.ObjectId) > 5.0f)
{
Script.ActionMoveToObject(Healer.ObjectId, CLRScriptBase.TRUE, 1.0f);
TryToHeal(this, nMissingHitPoints);
return;
}
}
if (TryToHeal(this, nMissingHitPoints))
return;
}
#region Early Returns: Mindless
// We're mindless, and thus too stupid to do anything special. Hit the nearest bad guy.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_MINDLESS)
{
CreatureObject AttackTarget = Party.GetNearest(this, Party.Enemies);
if (AttackTarget == null)
{
uint newEnemy = Script.GetNearestCreature(CLRScriptBase.CREATURE_TYPE_REPUTATION, CLRScriptBase.REPUTATION_TYPE_ENEMY, this.ObjectId, 1, -1, -1, -1, -1);
if(Script.GetIsObjectValid(newEnemy) != CLRScriptBase.FALSE &&
Script.GetObjectSeen(newEnemy, this.ObjectId) != CLRScriptBase.FALSE &&
Script.GetObjectHeard(newEnemy, this.ObjectId) != CLRScriptBase.FALSE)
{
AttackTarget = Server.ObjectManager.GetCreatureObject(newEnemy, true);
Party.AddPartyEnemy(AttackTarget);
}
}
if (AttackTarget == null) return;
_AttackWrapper(AttackTarget);
return;
}
#endregion
// Bad enough to self heal?
else if (nWellBeing < 50)
{
if (TryToHeal(this, nMissingHitPoints))
return;
}
#endregion
#region AIType-Specific Behaviors
#region Animals
// Time to break off into the particular types
// Animals are simple creatures; they want to protect themselves and their masters.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_ANIMAL)
{
// Animals are too dumb to do anything other than use their direct attacks on foes.
CreatureObject AttackTarget = Party.GetNearest(this, Party.Enemies);
if (AttackTarget == null)
{
uint newEnemy = Script.GetNearestCreature(CLRScriptBase.CREATURE_TYPE_REPUTATION, CLRScriptBase.REPUTATION_TYPE_ENEMY, this.ObjectId, 1, -1, -1, -1, -1);
if (Script.GetIsObjectValid(newEnemy) != CLRScriptBase.FALSE &&
Script.GetObjectSeen(newEnemy, this.ObjectId) != CLRScriptBase.FALSE &&
Script.GetObjectHeard(newEnemy, this.ObjectId) != CLRScriptBase.FALSE)
{
AttackTarget = Server.ObjectManager.GetCreatureObject(newEnemy, true);
Party.AddPartyEnemy(AttackTarget);
}
}
if (AttackTarget == null) return;
_AttackWrapper(AttackTarget);
return;
}
#endregion
#region Archers
// Archers have the advantage of reach and accuracy with acceptable damage. They strike weak and soft targets.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_ARCHER)
{
if (TryToAttackRanged())
return;
if (TryToDebuffAll())
return;
if (TryToCallForHelp())
return;
if (TryToDebuffCareful())
return;
if (TryToBuffAll())
return;
if (TryToAttackMelee(true, false))
return;
if (TryToHealAll())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyArchers.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyArchers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Buffs
// Buffs try to boost the capabilities of their allies
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_BUFFS)
{
if (TryToBuffAll())
return;
if (TryToHealAll())
return;
if (TryToCallForHelp())
return;
if (TryToDebuffAll())
return;
if (TryToDebuffCareful())
return;
if (TryToAttackRanged())
return;
if (TryToAttackMelee())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyControls.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyControls).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyNukes.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyNukes).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Controls
// Controls try to debuff enemies and impede movement on the field.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_CONTROL)
{
if (TryToDebuffAll())
return;
if (TryToCallForHelp())
return;
if (TryToDebuffCareful())
return;
if (TryToBuffAll())
return;
if (TryToHealAll())
return;
if (TryToAttackRanged())
return;
if (TryToAttackMelee())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyNukes.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyNukes).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Cowards
// Cowards avoid fights and look for help.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_COWARD)
{
CreatureObject medic = Party.GetNearest(this, Party.PartyMedics);
if(medic == null)
{
medic = Party.GetNearest(this, Party.PartyMembers);
}
if(medic != null)
{
Script.AssignCommand(ObjectId, delegate { Script.ActionMoveToObject(medic.ObjectId, CLRScriptBase.TRUE, 1.0f); });
}
else if(Party.Enemies.Count > 0)
{
Script.AssignCommand(ObjectId, delegate { Script.ActionMoveAwayFromObject(Party.Enemies[0].ObjectId, CLRScriptBase.TRUE, 50.0f); });
}
return;
}
#endregion
#region Flanks
// Flanks try to backstab people, and counter attack people who come after squishies.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_FLANK)
{
if (TryToAttackMelee(true, false))
return;
if (TryToAttackRanged())
return;
if (TryToDebuffAll())
return;
if (TryToDebuffCareful())
return;
if (TryToBuffAll())
return;
if (TryToCallForHelp())
return;
if (TryToHealAll())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyArchers.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyArchers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Medics
// Medics try to heal their friends.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_MEDIC)
{
if (TryToHealAll())
return;
if (TryToBuffAll())
return;
if (TryToDebuffAll())
return;
if (TryToDebuffCareful())
return;
if (TryToCallForHelp())
return;
if (TryToAttackRanged())
return;
if (TryToAttackMelee())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if(Party.PartyArchers.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyArchers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if(Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if(Party.PartyControls.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyControls).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyNukes.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyNukes).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMedics.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if(Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Nukes
// Nukes try to explode hardened targets.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_NUKE)
{
if (TryToDebuffAll())
return;
if (TryToDebuffCareful())
return;
if (TryToBuffAll())
return;
if (TryToCallForHelp())
return;
if (TryToHealAll())
return;
if (TryToAttackRanged())
return;
if (TryToAttackMelee())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyArchers.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyArchers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyControls.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyControls).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Shocks
// Shocks try to break through the lines and take down squishies.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_SHOCK)
{
if (TryToAttackMelee(true, false))
return;
if (TryToAttackRanged())
return;
if (TryToDebuffAll())
return;
if (TryToDebuffCareful())
return;
if (TryToBuffAll())
return;
if (TryToCallForHelp())
return;
if (TryToHealAll())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyArchers.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyArchers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Skirmishers
// Skirmishers try to resist shocks, flanks, and other skirmishers.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_SKIRMISH)
{
if (TryToAttackRanged())
return;
if (TryToAttackMelee(true, false))
return;
if (TryToDebuffAll())
return;
if (TryToDebuffCareful())
return;
if (TryToBuffAll())
return;
if (TryToCallForHelp())
return;
if (TryToHealAll())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyArchers.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyArchers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#region Tanks
// Tanks try to hold ground and contain dangerous foes.
if (TacticsType == AIParty.AIType.BEHAVIOR_TYPE_TANK)
{
if (TryToAttackMelee(false, true))
return;
if (TryToAttackRanged())
return;
if (TryToDebuffAll())
return;
if (TryToDebuffCareful())
return;
if (TryToBuffAll())
return;
if (TryToCallForHelp())
return;
if (TryToHealAll())
return;
if (TryToCleanUp())
return;
// We don't have anything productive to do. Figure out who we'd like to snuggle up against.
if (Party.PartyMedics.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMedics).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyBuffs.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyBuffs).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyArchers.Count > 0)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyArchers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
if (Party.PartyMembers.Count > 1)
{
Script.ActionMoveToObject(Party.GetNearest(this, Party.PartyMembers).ObjectId, CLRScriptBase.TRUE, 3.0f);
return;
}
return;
}
#endregion
#endregion
// Making it this far is some kind of error case. Try to salvage something.
return;
}