public void AddPartyMember(CreatureObject Creature)
{
if (Creature.Party != null)
{
throw new ApplicationException(String.Format(
"Adding creature {0} to party, but it is already joined to a party."));
}
PartyMembers.Add(Creature);
Creature.Party = this;
// No party leader defined. Guess it's this guy!
if (PartyLeader == null)
{
PartyLeader = Creature;
}
// Existing party leader. Is this guy better at it?
else
{
// If I'm the more charismatic leader, I take over.
if (Creature.Script.GetAbilityScore(Creature.ObjectId, CLRScriptBase.ABILITY_CHARISMA, CLRScriptBase.TRUE) > PartyLeader.Script.GetAbilityScore(PartyLeader.ObjectId, CLRScriptBase.ABILITY_CHARISMA, CLRScriptBase.TRUE))
PartyLeader = Creature;
// We're equally charismatic, but I'm more experienced. I take over.
else if (Creature.Script.GetAbilityScore(Creature.ObjectId, CLRScriptBase.ABILITY_CHARISMA, CLRScriptBase.TRUE) == PartyLeader.Script.GetAbilityScore(PartyLeader.ObjectId, CLRScriptBase.ABILITY_CHARISMA, CLRScriptBase.TRUE) &&
Creature.Script.GetHitDice(Creature.ObjectId) > PartyLeader.Script.GetHitDice(PartyLeader.ObjectId))
PartyLeader = Creature;
}
// Now that leadership is established, what sort of guy is this?
AIParty.AIType TacticsType = (AIParty.AIType)Creature.Script.GetLocalInt(Creature.ObjectId, "ACR_CREATURE_BEHAVIOR");
if (TacticsType == AIType.BEHAVIOR_TYPE_UNDEFINED)
{
string Tactics = Creature.Script.GetLocalString(Creature.ObjectId, "ACR_CREATURE_BEHAVIOR");
if (!Enum.TryParse<AIParty.AIType>(Tactics.ToUpper(), out TacticsType))
TacticsType = AIType.BEHAVIOR_TYPE_UNDEFINED;
}
if(TacticsType != AIType.BEHAVIOR_TYPE_UNDEFINED)
{
if(TacticsType == AIType.BEHAVIOR_TYPE_ANIMAL)
{
this.PartyAnimals.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_ARCHER)
{
this.PartyArchers.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_BUFFS)
{
this.PartyBuffs.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_CONTROL)
{
this.PartyControls.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_COWARD)
{
this.PartyCowards.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_FLANK)
{
this.PartyFlanks.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_MEDIC)
{
this.PartyMedics.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_MINDLESS)
{
this.PartyMindless.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_NUKE)
{
this.PartyNukes.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_SHOCK)
{
this.PartyShocks.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_SKIRMISH)
{
this.PartySkrimishers.Add(Creature);
Creature.TacticsType = TacticsType;
}
else if(TacticsType == AIType.BEHAVIOR_TYPE_TANK)
{
this.PartyTanks.Add(Creature);
Creature.TacticsType = TacticsType;
}
else
{
TacticsType = AIType.BEHAVIOR_TYPE_UNDEFINED;
Creature.Script.SendMessageToAllDMs(String.Format("** ERROR ** : {0} has an AI type {1} defined, but that type is not understood by ACR_CreatureBehavior. This creature DOES NOT KNOW HOW TO FIGHT, and needs to be despawned.", Creature, TacticsType));
throw new ApplicationException(String.Format("Creature {0} has an AI type {1} defined, but that type is not understood by ACR_CreatureBehavior.", Creature, TacticsType));
}
}
else if (TacticsType == AIType.BEHAVIOR_TYPE_UNDEFINED)
{
//==================================================================================================================================================
// Maybe this is an easy question. Is the creature stupid?
//==================================================================================================================================================
// The creature is mindless; that's a simple thing.
if (Creature.Script.GetAbilityScore(Creature.ObjectId, CLRScriptBase.ABILITY_INTELLIGENCE, CLRScriptBase.TRUE) == 0)
{
Creature.TacticsType = AIType.BEHAVIOR_TYPE_MINDLESS;
this.PartyMindless.Add(Creature);
}
// The creature is too dumb to take more than simple orders.
else if (Creature.Script.GetAbilityScore(Creature.ObjectId, CLRScriptBase.ABILITY_INTELLIGENCE, CLRScriptBase.TRUE) < 6)
{
Creature.TacticsType = AIType.BEHAVIOR_TYPE_ANIMAL;
this.PartyAnimals.Add(Creature);
}
//==================================================================================================================================================
// No such luck. We have to figure out how to make this creature act. Count and categorize classes.
//==================================================================================================================================================
else
{
int Heal = 0;
int Buff = 0;
int Blast = 0;
int Tank = 0;
int Crush = 0;
int Flank = 0;
int Skirm = 0;
int Arch = 0;
int Cont = 0;
for (int nClassPosition = 0; nClassPosition < 4; nClassPosition++)
{
int nClass = Creature.Script.GetClassByPosition(nClassPosition, Creature.ObjectId);
int nClassLevel = Creature.Script.GetLevelByClass(nClass, Creature.ObjectId);
// Members of these classes commonly have and prepare healing spells.
if (nClass == CLRScriptBase.CLASS_TYPE_CLERIC ||
nClass == CLRScriptBase.CLASS_TYPE_DRUID ||
nClass == CLRScriptBase.CLASS_TYPE_FAVORED_SOUL ||
nClass == CLRScriptBase.CLASS_TYPE_SPIRIT_SHAMAN)
{
Heal += nClassLevel;
}
// Members of these classes commonly have good support magic.
else if (nClass == CLRScriptBase.CLASS_TYPE_BARD)
{
Buff += nClassLevel;
}
// Members of these classes are usually well-set to focus on aggressive magic.
else if (nClass == CLRScriptBase.CLASS_TYPE_SORCERER ||
nClass == CLRScriptBase.CLASS_TYPE_WARLOCK)
{
Blast += nClassLevel;
}
// Members of these classes tend to have some combination of high AC, good saves, and/or damage reduction.
else if (nClass == CLRScriptBase.CLASS_TYPE_FIGHTER ||
nClass == CLRScriptBase.CLASS_TYPE_PALADIN ||
nClass == 35 ||
nClass == CLRScriptBase.CLASS_TYPE_UNDEAD ||
nClass == CLRScriptBase.CLASS_TYPE_CONSTRUCT) // CLASS_TYPE_PLANT is undefined.
{
Tank += nClassLevel;
}
// Members of these classes tend to do a lot of damage in direct melee combat.
else if (nClass == CLRScriptBase.CLASS_TYPE_BARBARIAN ||
nClass == CLRScriptBase.CLASS_TYPE_OOZE ||
nClass == CLRScriptBase.CLASS_TYPE_VERMIN ||
nClass == CLRScriptBase.CLASS_TYPE_OUTSIDER ||
nClass == CLRScriptBase.CLASS_TYPE_GIANT ||
nClass == CLRScriptBase.CLASS_TYPE_BEAST ||
nClass == CLRScriptBase.CLASS_TYPE_ELEMENTAL ||
nClass == CLRScriptBase.CLASS_TYPE_MONSTROUS ||
nClass == CLRScriptBase.CLASS_TYPE_HUMANOID)
{
Crush += nClassLevel;
}
// Members of these classes are typically the most-threatening if they can stab an opponent in the back.
else if (nClass == CLRScriptBase.CLASS_TYPE_ROGUE ||
nClass == CLRScriptBase.CLASS_TYPE_SWASHBUCKLER)
{
Flank += nClassLevel;
}
// Members of these classes are typically highly-mobile.
else if (nClass == CLRScriptBase.CLASS_TYPE_MONK ||
nClass == CLRScriptBase.CLASS_TYPE_RANGER ||
nClass == CLRScriptBase.CLASS_TYPE_SHAPECHANGER ||
nClass == CLRScriptBase.CLASS_TYPE_MAGICAL_BEAST ||
nClass == CLRScriptBase.CLASS_TYPE_ANIMAL)
{
Skirm += nClassLevel;
}
// Members of these classes are typically best at attacking from a distance.
else if (nClass == CLRScriptBase.CLASS_TYPE_RANGER)
{
Arch += nClassLevel;
}
// Members of these classes typically have or prepare spells which control the battlefield.
else if (nClass == CLRScriptBase.CLASS_TYPE_WIZARD ||
nClass == CLRScriptBase.CLASS_TYPE_FEY ||
nClass == CLRScriptBase.CLASS_TYPE_ABERRATION)
{
Cont += nClassLevel;
}
}
//==================================================================================================================================================
// Now that we know classes by their generic type, we compare the varieties.
//==================================================================================================================================================
// Spellcasting conters are higher than the others; this person is mostly a spellcaster.
if (Heal + Buff + Blast + Cont > Tank + Crush &&
Heal + Buff + Blast + Cont > Flank + Skirm + Arch)
{
// Spellcaster is better at controlling the field than others.
if (Cont > Buff &&
Cont > Blast &&
Cont > Heal)
{
this.PartyControls.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_CONTROL;
}
// Spellcaster is better at support magic than others.
else if (Buff > Blast &&
Buff > Heal)
{
this.PartyBuffs.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_BUFFS;
}
// Spellcaster is better at destroying things than not.
else if (Blast > Heal)
{
this.PartyNukes.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_NUKE;
}
// Spellcaster is either a healer or we don't know. We'll set them to taking care of pals.
else
{
this.PartyMedics.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_MEDIC;
}
}
// Looks like a melee fighter.
else if (Tank + Crush > Flank + Skirm + Arch)
{
if (Tank > Crush)
{
this.PartyTanks.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_TANK;
}
else
{
this.PartyShocks.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_SHOCK;
}
}
// Looks like a skilled character.
else if (Flank + Skirm + Arch > 0)
{
if (Flank > Skirm &&
Flank > Arch)
{
this.PartyFlanks.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_FLANK;
}
else if (Arch > Skirm)
{
this.PartyArchers.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_ARCHER;
}
else
{
this.PartySkrimishers.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_SKIRMISH;
}
}
// None of them have any value. This guy is probably useless, except that he can run for help.
else
{
this.PartyCowards.Add(Creature);
Creature.TacticsType = AIType.BEHAVIOR_TYPE_COWARD;
}
}
}
}