Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
759
Scripts/Services/Pet Training/AbilityProfile.cs
Normal file
759
Scripts/Services/Pet Training/AbilityProfile.cs
Normal file
@@ -0,0 +1,759 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[PropertyObject]
|
||||
public class AbilityProfile
|
||||
{
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public MagicalAbility MagicalAbility { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public AreaEffect[] AreaEffects { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public SpecialAbility[] SpecialAbilities { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public WeaponAbility[] WeaponAbilities { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool TokunoTame { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int RegenHits { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int RegenStam { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int RegenMana { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int DamageIndex { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public BaseCreature Creature { get; private set; }
|
||||
|
||||
public List<object> Advancements { get; private set; }
|
||||
|
||||
public AbilityProfile(BaseCreature bc)
|
||||
{
|
||||
Creature = bc;
|
||||
DamageIndex = -1;
|
||||
}
|
||||
|
||||
public void OnTame()
|
||||
{
|
||||
if (Creature.ControlMaster is PlayerMobile)
|
||||
{
|
||||
Server.Engines.Quests.TamingPetQuest.CheckTame((PlayerMobile)Creature.ControlMaster);
|
||||
}
|
||||
|
||||
if (Creature.Map == Map.Tokuno)
|
||||
{
|
||||
TokunoTame = true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool AddAbility(MagicalAbility ability, bool advancement = true)
|
||||
{
|
||||
if (Creature.Controlled)
|
||||
{
|
||||
var oldAbility = MagicalAbility;
|
||||
|
||||
if (IsSpecialMagicalAbility(oldAbility))
|
||||
{
|
||||
RemoveSpecialMagicalAbility(oldAbility);
|
||||
}
|
||||
|
||||
OnRemoveMagicalAbility(oldAbility, ability);
|
||||
|
||||
MagicalAbility = ability;
|
||||
}
|
||||
else
|
||||
{
|
||||
MagicalAbility |= ability;
|
||||
}
|
||||
|
||||
OnAddAbility(ability, advancement);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddAbility(SpecialAbility ability, bool advancement = true)
|
||||
{
|
||||
if (SpecialAbilities == null)
|
||||
{
|
||||
SpecialAbilities = new SpecialAbility[] { ability };
|
||||
}
|
||||
else if (!SpecialAbilities.Any(a => a == ability))
|
||||
{
|
||||
var temp = SpecialAbilities;
|
||||
|
||||
SpecialAbilities = new SpecialAbility[temp.Length + 1];
|
||||
|
||||
for (int i = 0; i < temp.Length; i++)
|
||||
SpecialAbilities[i] = temp[i];
|
||||
|
||||
SpecialAbilities[temp.Length] = ability;
|
||||
}
|
||||
|
||||
OnAddAbility(ability, advancement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddAbility(AreaEffect ability, bool advancement = true)
|
||||
{
|
||||
if (AreaEffects == null)
|
||||
{
|
||||
AreaEffects = new AreaEffect[] { ability };
|
||||
}
|
||||
else if (!AreaEffects.Any(a => a == ability))
|
||||
{
|
||||
var temp = AreaEffects;
|
||||
|
||||
AreaEffects = new AreaEffect[temp.Length + 1];
|
||||
|
||||
for (int i = 0; i < temp.Length; i++)
|
||||
AreaEffects[i] = temp[i];
|
||||
|
||||
AreaEffects[temp.Length] = ability;
|
||||
}
|
||||
|
||||
OnAddAbility(ability, advancement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddAbility(WeaponAbility ability, bool advancement = true)
|
||||
{
|
||||
if (WeaponAbilities == null)
|
||||
{
|
||||
WeaponAbilities = new WeaponAbility[] { ability };
|
||||
}
|
||||
else if(!WeaponAbilities.Any(a => a == ability))
|
||||
{
|
||||
var temp = WeaponAbilities;
|
||||
|
||||
WeaponAbilities = new WeaponAbility[temp.Length + 1];
|
||||
|
||||
for (int i = 0; i < temp.Length; i++)
|
||||
WeaponAbilities[i] = temp[i];
|
||||
|
||||
WeaponAbilities[temp.Length] = ability;
|
||||
}
|
||||
|
||||
OnAddAbility(ability, advancement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveAbility(MagicalAbility ability)
|
||||
{
|
||||
if ((MagicalAbility & ability) != 0)
|
||||
{
|
||||
MagicalAbility ^= ability;
|
||||
RemovePetAdvancement(ability);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAbility(SpecialAbility ability)
|
||||
{
|
||||
if (SpecialAbilities == null || !SpecialAbilities.Any(a => a == ability))
|
||||
return;
|
||||
|
||||
var list = SpecialAbilities.ToList();
|
||||
|
||||
list.Remove(ability);
|
||||
RemovePetAdvancement(ability);
|
||||
|
||||
SpecialAbilities = list.ToArray();
|
||||
|
||||
ColUtility.Free(list);
|
||||
}
|
||||
|
||||
public void RemoveAbility(WeaponAbility ability)
|
||||
{
|
||||
if (WeaponAbilities == null || !WeaponAbilities.Any(a => a == ability))
|
||||
return;
|
||||
|
||||
var list = WeaponAbilities.ToList();
|
||||
|
||||
list.Remove(ability);
|
||||
RemovePetAdvancement(ability);
|
||||
|
||||
WeaponAbilities = list.ToArray();
|
||||
|
||||
ColUtility.Free(list);
|
||||
}
|
||||
|
||||
public void RemoveAbility(AreaEffect ability)
|
||||
{
|
||||
if (AreaEffects == null || !AreaEffects.Any(a => a == ability))
|
||||
return;
|
||||
|
||||
var list = AreaEffects.ToList();
|
||||
|
||||
list.Remove(ability);
|
||||
RemovePetAdvancement(ability);
|
||||
|
||||
AreaEffects = list.ToArray();
|
||||
|
||||
ColUtility.Free(list);
|
||||
}
|
||||
|
||||
public bool AddAbility(SkillName skill, bool advancement = true)
|
||||
{
|
||||
OnAddAbility(skill, advancement);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanAddAbility(object o)
|
||||
{
|
||||
if (!Creature.Controlled)
|
||||
return true;
|
||||
|
||||
if (o is MagicalAbility)
|
||||
return true;
|
||||
|
||||
if (o is SpecialAbility && (SpecialAbilities == null || SpecialAbilities.Length == 0))
|
||||
return true;
|
||||
|
||||
if (o is AreaEffect && (AreaEffects == null || AreaEffects.Length == 0))
|
||||
return true;
|
||||
|
||||
if (o is WeaponAbility && (WeaponAbilities == null || WeaponAbilities.Length < 2))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnAddAbility(object newAbility, bool advancement)
|
||||
{
|
||||
if (advancement)
|
||||
{
|
||||
AddPetAdvancement(newAbility);
|
||||
}
|
||||
|
||||
if (newAbility is MagicalAbility)
|
||||
{
|
||||
AddMagicalAbility((MagicalAbility)newAbility);
|
||||
}
|
||||
|
||||
var trainPoint = PetTrainingHelper.GetTrainingPoint(newAbility);
|
||||
|
||||
if (trainPoint != null && trainPoint.Requirements != null)
|
||||
{
|
||||
foreach (var req in trainPoint.Requirements.Where(r => r != null))
|
||||
{
|
||||
if (req.Requirement is SkillName)
|
||||
{
|
||||
double skill = Creature.Skills[(SkillName)req.Requirement].Base;
|
||||
double toAdd = req.Cost == 100 ? 20 : 40;
|
||||
|
||||
if ((SkillName)req.Requirement == SkillName.Hiding)
|
||||
toAdd = 100;
|
||||
|
||||
if (skill < toAdd)
|
||||
Creature.Skills[(SkillName)req.Requirement].Base = toAdd;
|
||||
}
|
||||
else if (req.Requirement is WeaponAbility)
|
||||
{
|
||||
AddAbility((WeaponAbility)req.Requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddPetAdvancement(object o)
|
||||
{
|
||||
if (Creature.Controlled)
|
||||
{
|
||||
if (Advancements == null)
|
||||
Advancements = new List<object>();
|
||||
|
||||
if (!Advancements.Contains(o))
|
||||
{
|
||||
Advancements.Add(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovePetAdvancement(object o)
|
||||
{
|
||||
if (Creature.Controlled && Advancements != null && Advancements.Contains(o))
|
||||
{
|
||||
Advancements.Remove(o);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasAbility(object o)
|
||||
{
|
||||
if (o is MagicalAbility)
|
||||
{
|
||||
return (MagicalAbility & (MagicalAbility)o) != 0;
|
||||
}
|
||||
|
||||
if (o is SpecialAbility && SpecialAbilities != null)
|
||||
{
|
||||
return SpecialAbilities.Any(a => a == (SpecialAbility)o);
|
||||
}
|
||||
|
||||
if (o is AreaEffect && AreaEffects != null)
|
||||
{
|
||||
return AreaEffects.Any(a => a == (AreaEffect)o);
|
||||
}
|
||||
|
||||
if (o is WeaponAbility && WeaponAbilities != null)
|
||||
{
|
||||
return WeaponAbilities.Any(a => a == (WeaponAbility)o);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int AbilityCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (MagicalAbility != MagicalAbility.None)
|
||||
count++;
|
||||
|
||||
if (SpecialAbilities != null)
|
||||
count += SpecialAbilities.Where(a => !a.NaturalAbility).Count();
|
||||
|
||||
if (AreaEffects != null)
|
||||
count += AreaEffects.Length;
|
||||
|
||||
if (WeaponAbilities != null)
|
||||
count += WeaponAbilities.Length;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public bool CanChooseMagicalAbility(MagicalAbility ability)
|
||||
{
|
||||
if (!Creature.Controlled)
|
||||
return true;
|
||||
|
||||
if (HasSpecialMagicalAbility() &&
|
||||
IsSpecialMagicalAbility(ability) &&
|
||||
SpecialAbilities != null &&
|
||||
SpecialAbilities.Length > 0 &&
|
||||
SpecialAbilities.Any(a => !a.NaturalAbility))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanChooseSpecialAbility(SpecialAbility[] list)
|
||||
{
|
||||
if (!Creature.Controlled)
|
||||
return true;
|
||||
|
||||
if (HasSpecialMagicalAbility() &&
|
||||
list.Any(abil => IsRuleBreaker(abil)) &&
|
||||
(AreaEffects == null || AreaEffects.Length == 0) &&
|
||||
(SpecialAbilities == null || SpecialAbilities.Length == 0 || SpecialAbilities.All(a => a.NaturalAbility)))
|
||||
return true;
|
||||
|
||||
return !HasSpecialMagicalAbility() && (SpecialAbilities == null || SpecialAbilities.Where(a => !a.NaturalAbility).Count() == 0) && AbilityCount() < 3;
|
||||
}
|
||||
|
||||
public bool IsRuleBreaker(SpecialAbility ability)
|
||||
{
|
||||
return PetTrainingHelper.RuleBreakers.Any(abil => abil == ability);
|
||||
}
|
||||
|
||||
public bool CanChooseAreaEffect()
|
||||
{
|
||||
if (!Creature.Controlled)
|
||||
return true;
|
||||
|
||||
if (HasSpecialMagicalAbility() && (AreaEffects == null || AreaEffects.Length == 0) && (SpecialAbilities == null || SpecialAbilities.Length == 0))
|
||||
return true;
|
||||
|
||||
return !HasSpecialMagicalAbility() && (AreaEffects == null || AreaEffects.Length == 0) && AbilityCount() < 3;
|
||||
}
|
||||
|
||||
public bool CanChooseWeaponAbility()
|
||||
{
|
||||
if (!Creature.Controlled)
|
||||
return true;
|
||||
|
||||
return !HasSpecialMagicalAbility() && (WeaponAbilities == null || WeaponAbilities.Length < 2) && AbilityCount() < 3;
|
||||
}
|
||||
|
||||
public bool HasSpecialMagicalAbility()
|
||||
{
|
||||
return (MagicalAbility & MagicalAbility.Piercing) != 0 ||
|
||||
(MagicalAbility & MagicalAbility.Bashing) != 0 ||
|
||||
(MagicalAbility & MagicalAbility.Slashing) != 0 ||
|
||||
(MagicalAbility & MagicalAbility.BattleDefense) != 0 ||
|
||||
(MagicalAbility & MagicalAbility.WrestlingMastery) != 0;
|
||||
}
|
||||
|
||||
public bool IsSpecialMagicalAbility(MagicalAbility ability)
|
||||
{
|
||||
return ability != MagicalAbility.None && ability <= MagicalAbility.WrestlingMastery;
|
||||
}
|
||||
|
||||
public void AddMagicalAbility(MagicalAbility ability)
|
||||
{
|
||||
if (IsSpecialMagicalAbility(ability))
|
||||
{
|
||||
//SpecialAbilities = null;
|
||||
WeaponAbilities = null;
|
||||
Creature.AI = AIType.AI_Melee;
|
||||
}
|
||||
|
||||
switch (ability)
|
||||
{
|
||||
case MagicalAbility.Piercing:
|
||||
Creature.Mastery = SkillName.Fencing;
|
||||
break;
|
||||
case MagicalAbility.Bashing:
|
||||
Creature.Mastery = SkillName.Macing;
|
||||
break;
|
||||
case MagicalAbility.Slashing:
|
||||
Creature.Mastery = SkillName.Swords;
|
||||
break;
|
||||
case MagicalAbility.BattleDefense:
|
||||
Creature.Mastery = SkillName.Parry;
|
||||
break;
|
||||
case MagicalAbility.WrestlingMastery:
|
||||
Creature.Mastery = SkillName.Wrestling;
|
||||
break;
|
||||
case MagicalAbility.Poisoning:
|
||||
if(Creature.Controlled && Creature.AI != AIType.AI_Melee)
|
||||
Creature.AI = AIType.AI_Melee;
|
||||
break;
|
||||
case MagicalAbility.Bushido:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Samurai)
|
||||
Creature.AI = AIType.AI_Samurai;
|
||||
if (!HasAbility(WeaponAbility.WhirlwindAttack))
|
||||
{
|
||||
AddAbility(WeaponAbility.WhirlwindAttack, false);
|
||||
}
|
||||
break;
|
||||
case MagicalAbility.Ninjitsu:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Ninja)
|
||||
Creature.AI = AIType.AI_Ninja;
|
||||
if (!HasAbility(WeaponAbility.FrenziedWhirlwind))
|
||||
{
|
||||
AddAbility(WeaponAbility.FrenziedWhirlwind, false);
|
||||
}
|
||||
break;
|
||||
case MagicalAbility.Discordance:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Melee)
|
||||
Creature.AI = AIType.AI_Melee;
|
||||
break;
|
||||
case MagicalAbility.Magery:
|
||||
case MagicalAbility.MageryMastery:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Mage)
|
||||
Creature.AI = AIType.AI_Mage;
|
||||
break;
|
||||
case MagicalAbility.Mysticism:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Mystic)
|
||||
Creature.AI = AIType.AI_Mystic;
|
||||
break;
|
||||
case MagicalAbility.Spellweaving:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Spellweaving)
|
||||
Creature.AI = AIType.AI_Spellweaving;
|
||||
break;
|
||||
case MagicalAbility.Chivalry:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Paladin)
|
||||
Creature.AI = AIType.AI_Paladin;
|
||||
break;
|
||||
case MagicalAbility.Necromage:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_NecroMage)
|
||||
Creature.AI = AIType.AI_NecroMage;
|
||||
break;
|
||||
case MagicalAbility.Necromancy:
|
||||
if (Creature.Controlled && Creature.AI != AIType.AI_Necro)
|
||||
Creature.AI = AIType.AI_Necro;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRemoveMagicalAbility(MagicalAbility oldAbility, MagicalAbility newAbility)
|
||||
{
|
||||
if ((oldAbility & MagicalAbility.Bushido) != 0)
|
||||
{
|
||||
if (HasAbility(WeaponAbility.WhirlwindAttack))
|
||||
{
|
||||
RemoveAbility(WeaponAbility.WhirlwindAttack);
|
||||
}
|
||||
}
|
||||
|
||||
if ((oldAbility & MagicalAbility.Ninjitsu) != 0)
|
||||
{
|
||||
if (HasAbility(WeaponAbility.FrenziedWhirlwind))
|
||||
{
|
||||
RemoveAbility(WeaponAbility.FrenziedWhirlwind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSpecialMagicalAbility(MagicalAbility ability)
|
||||
{
|
||||
//SpecialAbilities = null;
|
||||
WeaponAbilities = null;
|
||||
|
||||
Creature.Mastery = SkillName.Alchemy; // default
|
||||
}
|
||||
|
||||
public bool HasCustomized()
|
||||
{
|
||||
return Advancements != null && Advancements.Count > 0;
|
||||
}
|
||||
|
||||
public bool IsNaturalAbility(object o)
|
||||
{
|
||||
if (Advancements == null)
|
||||
return true;
|
||||
|
||||
if (o is SpecialAbility)
|
||||
{
|
||||
return SpecialAbilities != null && !Advancements.Any(s => s is SpecialAbility && (SpecialAbility)s == (SpecialAbility)o);
|
||||
}
|
||||
|
||||
if (o is WeaponAbility)
|
||||
{
|
||||
return WeaponAbilities != null && !Advancements.Any(s => s is WeaponAbility && (WeaponAbility)s == (WeaponAbility)o);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<object> EnumerateAllAbilities()
|
||||
{
|
||||
if (MagicalAbility != MagicalAbility.None)
|
||||
{
|
||||
foreach (var abil in PetTrainingHelper.MagicalAbilities)
|
||||
{
|
||||
if ((MagicalAbility & abil) != 0)
|
||||
yield return abil;
|
||||
}
|
||||
}
|
||||
|
||||
if (SpecialAbilities != null)
|
||||
{
|
||||
foreach (var abil in SpecialAbilities)
|
||||
{
|
||||
yield return abil;
|
||||
}
|
||||
}
|
||||
|
||||
if (AreaEffects != null)
|
||||
{
|
||||
foreach (var effect in AreaEffects)
|
||||
{
|
||||
yield return effect;
|
||||
}
|
||||
}
|
||||
|
||||
if (WeaponAbilities != null)
|
||||
{
|
||||
foreach (var abil in WeaponAbilities)
|
||||
{
|
||||
yield return abil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<SpecialAbility> EnumerateSpecialAbilities()
|
||||
{
|
||||
if (SpecialAbilities == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var ability in SpecialAbilities)
|
||||
{
|
||||
yield return ability;
|
||||
}
|
||||
}
|
||||
|
||||
public SpecialAbility[] GetSpecialAbilities()
|
||||
{
|
||||
return EnumerateSpecialAbilities().ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<AreaEffect> EnumerateAreaEffects()
|
||||
{
|
||||
if (AreaEffects == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var ability in AreaEffects)
|
||||
{
|
||||
yield return ability;
|
||||
}
|
||||
}
|
||||
|
||||
public AreaEffect[] GetAreaEffects()
|
||||
{
|
||||
return EnumerateAreaEffects().ToArray();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "...";
|
||||
}
|
||||
|
||||
public AbilityProfile(BaseCreature bc, GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Creature = bc;
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
DamageIndex = -1;
|
||||
break;
|
||||
case 1:
|
||||
DamageIndex = reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
|
||||
MagicalAbility = (MagicalAbility)reader.ReadInt();
|
||||
TokunoTame = reader.ReadBool();
|
||||
|
||||
RegenHits = reader.ReadInt();
|
||||
RegenStam = reader.ReadInt();
|
||||
RegenMana = reader.ReadInt();
|
||||
|
||||
int count = reader.ReadInt();
|
||||
SpecialAbilities = new SpecialAbility[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
SpecialAbilities[i] = SpecialAbility.Abilities[reader.ReadInt()];
|
||||
}
|
||||
|
||||
count = reader.ReadInt();
|
||||
AreaEffects = new AreaEffect[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
AreaEffects[i] = AreaEffect.Effects[reader.ReadInt()];
|
||||
}
|
||||
|
||||
count = reader.ReadInt();
|
||||
WeaponAbilities = new WeaponAbility[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
WeaponAbilities[i] = WeaponAbility.Abilities[reader.ReadInt()];
|
||||
}
|
||||
|
||||
count = reader.ReadInt();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (Advancements == null)
|
||||
Advancements = new List<object>();
|
||||
|
||||
switch (reader.ReadInt())
|
||||
{
|
||||
case 1: Advancements.Add((MagicalAbility)reader.ReadInt()); break;
|
||||
case 2: Advancements.Add(SpecialAbility.Abilities[reader.ReadInt()]); break;
|
||||
case 3: Advancements.Add(AreaEffect.Effects[reader.ReadInt()]); break;
|
||||
case 4: Advancements.Add(WeaponAbility.Abilities[reader.ReadInt()]); break;
|
||||
case 5: Advancements.Add((SkillName)reader.ReadInt()); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(1);
|
||||
|
||||
writer.Write(DamageIndex);
|
||||
|
||||
writer.Write((int)MagicalAbility);
|
||||
writer.Write(TokunoTame);
|
||||
|
||||
writer.Write(RegenHits);
|
||||
writer.Write(RegenStam);
|
||||
writer.Write(RegenMana);
|
||||
|
||||
writer.Write(SpecialAbilities != null ? SpecialAbilities.Length : 0);
|
||||
|
||||
if (SpecialAbilities != null)
|
||||
{
|
||||
foreach (var abil in SpecialAbilities)
|
||||
{
|
||||
writer.Write(Array.IndexOf(SpecialAbility.Abilities, abil));
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write(AreaEffects != null ? AreaEffects.Length : 0);
|
||||
|
||||
if (AreaEffects != null)
|
||||
{
|
||||
foreach (var abil in AreaEffects)
|
||||
{
|
||||
writer.Write(Array.IndexOf(AreaEffect.Effects, abil));
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write(WeaponAbilities != null ? WeaponAbilities.Length : 0);
|
||||
|
||||
if (WeaponAbilities != null)
|
||||
{
|
||||
foreach (var abil in WeaponAbilities)
|
||||
{
|
||||
writer.Write(Array.IndexOf(WeaponAbility.Abilities, abil));
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write(Advancements != null ? Advancements.Count : 0);
|
||||
|
||||
if (Advancements != null)
|
||||
{
|
||||
foreach (var o in Advancements)
|
||||
{
|
||||
if (o is MagicalAbility)
|
||||
{
|
||||
writer.Write(1);
|
||||
writer.Write((int)(MagicalAbility)o);
|
||||
}
|
||||
else if (o is SpecialAbility)
|
||||
{
|
||||
writer.Write(2);
|
||||
writer.Write(Array.IndexOf(SpecialAbility.Abilities, (SpecialAbility)o));
|
||||
}
|
||||
else if (o is AreaEffect)
|
||||
{
|
||||
writer.Write(3);
|
||||
writer.Write(Array.IndexOf(AreaEffect.Effects, (AreaEffect)o));
|
||||
}
|
||||
else if (o is WeaponAbility)
|
||||
{
|
||||
writer.Write(4);
|
||||
writer.Write(Array.IndexOf(WeaponAbility.Abilities, (WeaponAbility)o));
|
||||
}
|
||||
else if (o is SkillName)
|
||||
{
|
||||
writer.Write(5);
|
||||
writer.Write((int)(SkillName)o);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
596
Scripts/Services/Pet Training/AreaEffects.cs
Normal file
596
Scripts/Services/Pet Training/AreaEffects.cs
Normal file
@@ -0,0 +1,596 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Collections.Generic;
|
||||
using Server.Spells;
|
||||
using System.Linq;
|
||||
using Server.Network;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public abstract class AreaEffect
|
||||
{
|
||||
public virtual int ManaCost { get { return 20; } }
|
||||
public virtual int MaxRange { get { return 3; } }
|
||||
public virtual double TriggerChance { get { return 1.0; } }
|
||||
public virtual TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(30); } }
|
||||
public virtual bool RequiresCombatant { get { return true; } }
|
||||
|
||||
public virtual int EffectRange { get { return 5; } }
|
||||
|
||||
public AreaEffect()
|
||||
{
|
||||
}
|
||||
|
||||
public static bool CheckThinkTrigger(BaseCreature bc)
|
||||
{
|
||||
var profile = PetTrainingHelper.GetAbilityProfile(bc);
|
||||
|
||||
if (profile != null)
|
||||
{
|
||||
AreaEffect effect = null;
|
||||
|
||||
var effects = profile.GetAreaEffects().Where(a => !a.IsInCooldown(bc)).ToArray();
|
||||
|
||||
if (effects != null && effects.Length > 0)
|
||||
{
|
||||
effect = effects[Utility.Random(effects.Length)];
|
||||
}
|
||||
|
||||
if (effect != null)
|
||||
{
|
||||
return effect.Trigger(bc, bc.Combatant as Mobile);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool Trigger(BaseCreature creature, Mobile combatant)
|
||||
{
|
||||
if (CheckMana(creature) && Validate(creature, combatant) && TriggerChance >= Utility.RandomDouble())
|
||||
{
|
||||
creature.Mana -= ManaCost;
|
||||
|
||||
DoEffects(creature, combatant);
|
||||
AddToCooldown(creature);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool Validate(BaseCreature attacker, Mobile defender)
|
||||
{
|
||||
if (!attacker.Alive || attacker.Deleted || attacker.IsDeadBondedPet || attacker.BardPacified)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !RequiresCombatant || (defender != null && defender.Alive && !defender.Deleted &&
|
||||
!defender.IsDeadBondedPet && defender.InRange(attacker.Location, MaxRange) &&
|
||||
defender.Map == attacker.Map && attacker.InLOS(defender));
|
||||
}
|
||||
|
||||
public bool CheckMana(BaseCreature bc)
|
||||
{
|
||||
return !bc.Controlled || bc.Mana >= ManaCost;
|
||||
}
|
||||
|
||||
public virtual void DoEffects(BaseCreature creature, Mobile combatant)
|
||||
{
|
||||
if (creature.Map == null || creature.Map == Map.Internal)
|
||||
return;
|
||||
|
||||
var count = 0;
|
||||
|
||||
foreach (var m in FindValidTargets(creature, EffectRange))
|
||||
{
|
||||
count++;
|
||||
DoEffect(creature, m);
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
OnAfterEffects(creature, combatant);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DoEffect(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnAfterEffects(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
}
|
||||
|
||||
public static IEnumerable<Mobile> FindValidTargets(BaseCreature creature, int range)
|
||||
{
|
||||
IPooledEnumerable eable = creature.GetMobilesInRange(range);
|
||||
|
||||
foreach (Mobile m in eable.OfType<Mobile>())
|
||||
{
|
||||
if (ValidTarget(creature, m))
|
||||
{
|
||||
yield return m;
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
public static bool ValidTarget(Mobile from, Mobile to)
|
||||
{
|
||||
return to != from && to.Alive && !to.IsDeadBondedPet &&
|
||||
from.CanBeHarmful(to, false) &&
|
||||
SpellHelper.ValidIndirectTarget(from, to) &&
|
||||
from.InLOS(to);
|
||||
}
|
||||
|
||||
public List<BaseCreature> _Cooldown;
|
||||
|
||||
public bool IsInCooldown(BaseCreature m)
|
||||
{
|
||||
return _Cooldown != null && _Cooldown.Contains(m);
|
||||
}
|
||||
|
||||
public void AddToCooldown(BaseCreature bc)
|
||||
{
|
||||
var cooldown = GetCooldown(bc);
|
||||
|
||||
if (cooldown != TimeSpan.MinValue)
|
||||
{
|
||||
if (_Cooldown == null)
|
||||
_Cooldown = new List<BaseCreature>();
|
||||
|
||||
_Cooldown.Add(bc);
|
||||
Timer.DelayCall<BaseCreature>(cooldown, RemoveFromCooldown, bc);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual TimeSpan GetCooldown(BaseCreature m)
|
||||
{
|
||||
return CooldownDuration;
|
||||
}
|
||||
|
||||
public void RemoveFromCooldown(BaseCreature m)
|
||||
{
|
||||
_Cooldown.Remove(m);
|
||||
}
|
||||
|
||||
public static AreaEffect[] Effects { get { return _Effects; } }
|
||||
private static AreaEffect[] _Effects;
|
||||
|
||||
static AreaEffect()
|
||||
{
|
||||
_Effects = new AreaEffect[7];
|
||||
|
||||
_Effects[0] = new AuraOfEnergy();
|
||||
_Effects[1] = new AuraOfNausea();
|
||||
_Effects[2] = new EssenceOfDisease();
|
||||
_Effects[3] = new EssenceOfEarth();
|
||||
_Effects[4] = new ExplosiveGoo();
|
||||
_Effects[5] = new AuraDamage();
|
||||
_Effects[6] = new PoisonBreath();
|
||||
}
|
||||
|
||||
public static AreaEffect AuraOfEnergy
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Effects[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static AreaEffect AuraOfNausea
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Effects[1];
|
||||
}
|
||||
}
|
||||
|
||||
public static AreaEffect EssenceOfDisease
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Effects[2];
|
||||
}
|
||||
}
|
||||
|
||||
public static AreaEffect EssenceOfEarth
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Effects[3];
|
||||
}
|
||||
}
|
||||
|
||||
public static AreaEffect ExplosiveGoo
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Effects[4];
|
||||
}
|
||||
}
|
||||
|
||||
public static AreaEffect AuraDamage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Effects[5];
|
||||
}
|
||||
}
|
||||
|
||||
public static AreaEffect PoisonBreath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Effects[6];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AuraOfEnergy : AreaEffect
|
||||
{
|
||||
public AuraOfEnergy()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DoEffect(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
AOS.Damage(defender, creature, Utility.RandomMinMax(20, 30), 0, 0, 0, 0, 100);
|
||||
|
||||
defender.SendLocalizedMessage(1072073, false, creature.Name); // : The creature's aura of energy is damaging you!
|
||||
|
||||
creature.DoHarmful(defender);
|
||||
defender.FixedParticles(0x374A, 10, 30, 5052, 1278, 0, EffectLayer.Waist);
|
||||
defender.PlaySound(0x51D);
|
||||
}
|
||||
}
|
||||
|
||||
public class AuraOfNausea : AreaEffect
|
||||
{
|
||||
public override TimeSpan CooldownDuration { get { return TimeSpan.FromSeconds(40 + Utility.RandomDouble() * 30); } }
|
||||
public override int MaxRange { get { return 4; } }
|
||||
public override int EffectRange { get { return 4; } }
|
||||
public override int ManaCost { get { return 100; } }
|
||||
|
||||
public static Dictionary<Mobile, Timer> _Table;
|
||||
|
||||
public AuraOfNausea()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DoEffect(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
if (_Table == null)
|
||||
{
|
||||
_Table = new Dictionary<Mobile, Timer>();
|
||||
}
|
||||
|
||||
if (_Table.ContainsKey(defender))
|
||||
{
|
||||
Timer timer = _Table[defender];
|
||||
|
||||
if (timer != null)
|
||||
timer.Stop();
|
||||
|
||||
_Table[defender] = Timer.DelayCall<Mobile>(TimeSpan.FromSeconds(30), EndNausea, defender);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Table.Add(defender, Timer.DelayCall<Mobile>(TimeSpan.FromSeconds(30), EndNausea, defender));
|
||||
}
|
||||
|
||||
defender.Animate(32, 5, 1, true, false, 0); // bow animation
|
||||
defender.SendLocalizedMessage(1072068); // Your enemy's putrid presence envelops you, overwhelming you with nausea.
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.AuraOfNausea, 1153792, 1153819, TimeSpan.FromSeconds(30), defender, "60\t60\t60\t5"));
|
||||
}
|
||||
|
||||
public static void EndNausea(Mobile m)
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(m))
|
||||
{
|
||||
_Table.Remove(m);
|
||||
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.AuraOfNausea);
|
||||
m.Delta(MobileDelta.WeaponDamage);
|
||||
|
||||
if (_Table.Count == 0)
|
||||
_Table = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool UnderNausea(Mobile m)
|
||||
{
|
||||
return _Table != null && _Table.ContainsKey(m);
|
||||
}
|
||||
}
|
||||
|
||||
public class EssenceOfDisease : AreaEffect
|
||||
{
|
||||
public EssenceOfDisease()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DoEffect(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
AOS.Damage(defender, creature, Utility.RandomMinMax(20, 30), 0, 0, 0, 100, 0);
|
||||
|
||||
defender.SendLocalizedMessage(1072074, false, creature.Name);
|
||||
|
||||
creature.DoHarmful(defender);
|
||||
defender.FixedParticles(0x374A, 10, 30, 5052, 1272, 0, EffectLayer.Waist);
|
||||
defender.PlaySound(0x476);
|
||||
}
|
||||
}
|
||||
|
||||
public class EssenceOfEarth : AreaEffect
|
||||
{
|
||||
public EssenceOfEarth()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DoEffect(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
AOS.Damage(defender, creature, Utility.RandomMinMax(20, 30), 100, 0, 0, 0, 0);
|
||||
|
||||
defender.SendLocalizedMessage(1072075, false, creature.Name);
|
||||
|
||||
creature.DoHarmful(defender);
|
||||
defender.FixedParticles(0x374A, 10, 30, 5052, 1836, 0, EffectLayer.Waist);
|
||||
defender.PlaySound(0x22C);
|
||||
}
|
||||
}
|
||||
|
||||
public class ExplosiveGoo : AreaEffect
|
||||
{
|
||||
public override int ManaCost { get { return 30; } }
|
||||
|
||||
private bool _DoingEffect;
|
||||
|
||||
public ExplosiveGoo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DoEffects(BaseCreature creature, Mobile combatant)
|
||||
{
|
||||
if (_DoingEffect)
|
||||
return;
|
||||
|
||||
Server.Effects.SendTargetParticles(creature, 0x3709, 10, 15, 2724, 0, 9907, EffectLayer.LeftFoot, 0);
|
||||
creature.PlaySound(0x348);
|
||||
|
||||
_DoingEffect = true;
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1.0), () =>
|
||||
{
|
||||
base.DoEffects(creature, combatant);
|
||||
_DoingEffect = false;
|
||||
});
|
||||
}
|
||||
|
||||
public override void DoEffect(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
Timer.DelayCall<Mobile>(TimeSpan.FromMilliseconds(Utility.RandomMinMax(10, 1000)), m =>
|
||||
{
|
||||
if (m.Alive && !m.Deleted && m.Map != null)
|
||||
{
|
||||
Point3D p = m.Location;
|
||||
for (int x = -1; x <= 1; x++)
|
||||
{
|
||||
for (int y = -1; y <= 1; y++)
|
||||
{
|
||||
Server.Effects.SendLocationEffect(new Point3D(p.X + x, p.Y + y, p.Z), m.Map, 0x3728, 13, 1921, 3);
|
||||
}
|
||||
}
|
||||
|
||||
creature.DoHarmful(defender);
|
||||
AOS.Damage(m, creature, Utility.RandomMinMax(30, 40), 0, 100, 0, 0, 0);
|
||||
m.SendLocalizedMessage(1112366); // The flammable goo covering you bursts into flame!
|
||||
}
|
||||
}, defender);
|
||||
}
|
||||
}
|
||||
|
||||
public class PoisonBreath : AreaEffect
|
||||
{
|
||||
public override double TriggerChance { get { return 0.4; } }
|
||||
public override int EffectRange { get { return 10; } }
|
||||
public override int ManaCost { get { return 50; } }
|
||||
|
||||
public PoisonBreath()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DoEffect(BaseCreature creature, Mobile m)
|
||||
{
|
||||
m.ApplyPoison(creature, GetPoison(creature));
|
||||
|
||||
Server.Effects.SendLocationParticles(
|
||||
EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x36B0, 1, 14, 63, 7, 9915, 0);
|
||||
|
||||
Server.Effects.PlaySound(m.Location, m.Map, 0x229);
|
||||
var damage = GetDamage(creature);
|
||||
|
||||
if (damage > 0)
|
||||
{
|
||||
creature.DoHarmful(m);
|
||||
AOS.Damage(m, creature, damage, 0, 0, 0, 100, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAfterEffects(BaseCreature creature, Mobile defender)
|
||||
{
|
||||
if (creature.Controlled)
|
||||
{
|
||||
var profile = PetTrainingHelper.GetAbilityProfile(creature);
|
||||
|
||||
if ((profile != null && profile.HasAbility(MagicalAbility.Poisoning)) || 0.2 > Utility.RandomDouble())
|
||||
creature.CheckSkill(SkillName.Poisoning, 0, creature.Skills[SkillName.Poisoning].Cap);
|
||||
}
|
||||
}
|
||||
|
||||
public Poison GetPoison(BaseCreature bc)
|
||||
{
|
||||
int level = 0;
|
||||
double total = bc.Skills[SkillName.Poisoning].Value;
|
||||
|
||||
if (total >= 100)
|
||||
level = 4;
|
||||
else if (total > 60)
|
||||
level = 3;
|
||||
else if (total > 40)
|
||||
level = 2;
|
||||
else if (total > 20)
|
||||
level = 1;
|
||||
|
||||
return Poison.GetPoison(level);
|
||||
}
|
||||
|
||||
public int GetDamage(BaseCreature bc)
|
||||
{
|
||||
if (_DamageCreatures.Any(t => t == bc.GetType()))
|
||||
return 50;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private Type[] _DamageCreatures =
|
||||
{
|
||||
typeof(ValoriteElemental), typeof(BronzeElemental), typeof(Dimetrosaur), typeof(ChiefParoxysmus)
|
||||
};
|
||||
}
|
||||
|
||||
public class AuraDamage : AreaEffect
|
||||
{
|
||||
public override double TriggerChance { get { return 0.4; } }
|
||||
public override int EffectRange { get { return 10; } }
|
||||
public override int ManaCost { get { return 0; } }
|
||||
public override bool RequiresCombatant { get { return false; } }
|
||||
|
||||
public AuraDamage()
|
||||
{
|
||||
}
|
||||
|
||||
public override TimeSpan GetCooldown(BaseCreature bc)
|
||||
{
|
||||
return AuraDefinition.GetDefinition(bc).Cooldown;
|
||||
}
|
||||
|
||||
public override void DoEffect(BaseCreature creature, Mobile m)
|
||||
{
|
||||
var def = AuraDefinition.GetDefinition(creature);
|
||||
|
||||
if (def.Damage > 0)
|
||||
{
|
||||
AOS.Damage(
|
||||
m,
|
||||
creature,
|
||||
def.Damage,
|
||||
def.Physical,
|
||||
def.Fire,
|
||||
def.Cold,
|
||||
def.Poison,
|
||||
def.Energy,
|
||||
def.Chaos,
|
||||
def.Direct,
|
||||
DamageType.SpellAOE);
|
||||
|
||||
m.RevealingAction();
|
||||
}
|
||||
|
||||
if (creature is IAuraCreature)
|
||||
{
|
||||
((IAuraCreature)creature).AuraEffect(m);
|
||||
}
|
||||
}
|
||||
|
||||
public class AuraDefinition
|
||||
{
|
||||
public TimeSpan Cooldown { get; set; }
|
||||
public int Range { get; set; }
|
||||
|
||||
public int Damage { get; set; }
|
||||
public int Physical { get; set; }
|
||||
public int Fire { get; set; }
|
||||
public int Cold { get; set; }
|
||||
public int Poison { get; set; }
|
||||
public int Energy { get; set; }
|
||||
public int Chaos { get; set; }
|
||||
public int Direct { get; set; }
|
||||
|
||||
public Type[] Uses { get; private set; }
|
||||
|
||||
public AuraDefinition()
|
||||
: this(TimeSpan.FromSeconds(5), 4, 5, 0, 0, 0, 0, 0, 0, 100, new Type[] { })
|
||||
{
|
||||
}
|
||||
|
||||
public AuraDefinition(params Type[] uses)
|
||||
: this(TimeSpan.FromSeconds(5), 2, 5, 0, 100, 0, 0, 0, 0, 0, uses)
|
||||
{
|
||||
}
|
||||
|
||||
public AuraDefinition(TimeSpan cooldown, int range, int baseDamage, int phys, int fire, int cold, int poison, int energy, int chaos, int direct, Type[] uses)
|
||||
{
|
||||
Cooldown = cooldown;
|
||||
Range = range;
|
||||
Damage = baseDamage;
|
||||
Physical = phys;
|
||||
Fire = fire;
|
||||
Cold = cold;
|
||||
Poison = poison;
|
||||
Energy = energy;
|
||||
Chaos = chaos;
|
||||
Direct = direct;
|
||||
|
||||
Uses = uses;
|
||||
}
|
||||
|
||||
public static List<AuraDefinition> Definitions { get; private set; } = new List<AuraDefinition>();
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
AuraDefinition defaul;
|
||||
AuraDefinition cora;
|
||||
AuraDefinition fireAura;
|
||||
AuraDefinition coldAura;
|
||||
|
||||
defaul = new AuraDefinition();
|
||||
Definitions.Add(defaul);
|
||||
|
||||
cora = new AuraDefinition(typeof(CoraTheSorceress));
|
||||
cora.Range = 3;
|
||||
cora.Damage = 10;
|
||||
cora.Fire = 0;
|
||||
Definitions.Add(cora);
|
||||
|
||||
fireAura = new AuraDefinition(typeof(FlameElemental), typeof(FireDaemon), typeof(LesserFlameElemental));
|
||||
fireAura.Range = 5;
|
||||
fireAura.Damage = 7;
|
||||
Definitions.Add(fireAura);
|
||||
|
||||
coldAura = new AuraDefinition(typeof(ColdDrake), typeof(FrostDrake), typeof(FrostDragon), typeof(SnowElemental), typeof(FrostMite), typeof(IceFiend), typeof(IceElemental), typeof(CorporealBrume));
|
||||
coldAura.Damage = 15;
|
||||
coldAura.Fire = 0;
|
||||
coldAura.Cold = 100;
|
||||
Definitions.Add(coldAura);
|
||||
}
|
||||
|
||||
public static AuraDefinition GetDefinition(BaseCreature bc)
|
||||
{
|
||||
var def = Definitions.FirstOrDefault(d => d.Uses.Any(t => t == bc.GetType()));
|
||||
|
||||
if (def == null)
|
||||
{
|
||||
return Definitions[0]; // Default
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Scripts/Services/Pet Training/EthologistTitleDeed.cs
Normal file
32
Scripts/Services/Pet Training/EthologistTitleDeed.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class EthologistTitleDeed : BaseRewardTitleDeed
|
||||
{
|
||||
public override TextDefinition Title { get { return 1157594; } } // Ethologist
|
||||
|
||||
[Constructable]
|
||||
public EthologistTitleDeed()
|
||||
{
|
||||
}
|
||||
|
||||
public EthologistTitleDeed(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int v = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
1918
Scripts/Services/Pet Training/Gumps.cs
Normal file
1918
Scripts/Services/Pet Training/Gumps.cs
Normal file
File diff suppressed because it is too large
Load Diff
186
Scripts/Services/Pet Training/PetTrainingGate.cs
Normal file
186
Scripts/Services/Pet Training/PetTrainingGate.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using Server;
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class PetTrainingGate : Item
|
||||
{
|
||||
public override bool ForceShowProperties { get { return true; } }
|
||||
|
||||
public override string DefaultName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Pet Training Gate - You Must Start Pet Training Before Bringing Your Pet Through The Gate!";
|
||||
}
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public PetTrainingGate()
|
||||
: base(3948)
|
||||
{
|
||||
Hue = 1918;
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public override bool OnMoveOver(Mobile m)
|
||||
{
|
||||
if (m is BaseCreature)
|
||||
{
|
||||
var bc = m as BaseCreature;
|
||||
var profile = PetTrainingHelper.GetTrainingProfile(bc);
|
||||
|
||||
if (bc.Controlled && bc.ControlMaster != null && bc.ControlMaster.InRange(bc.Location, 25)
|
||||
&& profile != null && profile.HasBegunTraining && profile.TrainingProgress < profile.TrainingProgressMax)
|
||||
{
|
||||
profile.TrainingProgress = profile.TrainingProgressMax;
|
||||
bc.FixedEffect(0x375A, 10, 30);
|
||||
|
||||
if (bc.ControlMaster is PlayerMobile)
|
||||
{
|
||||
var gump = bc.ControlMaster.FindGump<NewAnimalLoreGump>();
|
||||
|
||||
if (gump != null)
|
||||
gump.Refresh();
|
||||
else
|
||||
BaseGump.SendGump(new NewAnimalLoreGump((PlayerMobile)bc.ControlMaster, bc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public PetTrainingGate(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class PetBondRemoveGate : Item
|
||||
{
|
||||
public override bool ForceShowProperties { get { return true; } }
|
||||
|
||||
public override string DefaultName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Pet Bond Timer Remover";
|
||||
}
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public PetBondRemoveGate()
|
||||
: base(3948)
|
||||
{
|
||||
Hue = 1911;
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public override bool OnMoveOver(Mobile m)
|
||||
{
|
||||
if (m is BaseCreature)
|
||||
{
|
||||
var bc = m as BaseCreature;
|
||||
var profile = PetTrainingHelper.GetTrainingProfile(bc);
|
||||
|
||||
if (bc.Controlled && bc.ControlMaster != null && bc.ControlMaster.InRange(bc.Location, 25)
|
||||
&& !bc.IsBonded)
|
||||
{
|
||||
bc.IsBonded = true;
|
||||
bc.FixedEffect(0x375A, 10, 30);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public PetBondRemoveGate(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class PowerScrollGiver : Item
|
||||
{
|
||||
public override bool ForceShowProperties { get { return true; } }
|
||||
|
||||
public override string DefaultName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "+20 Power Scrolls";
|
||||
}
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public PowerScrollGiver()
|
||||
: base(0x1183)
|
||||
{
|
||||
Hue = 2214;
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile m)
|
||||
{
|
||||
if (m.InRange(Location, 3))
|
||||
{
|
||||
var bag = new Bag();
|
||||
foreach (var sk in PetTrainingHelper.MagicSkills)
|
||||
{
|
||||
bag.DropItem(new PowerScroll(sk, 120));
|
||||
}
|
||||
|
||||
foreach (var sk in PetTrainingHelper.CombatSkills)
|
||||
{
|
||||
bag.DropItem(new PowerScroll(sk, 120));
|
||||
}
|
||||
|
||||
m.AddToBackpack(bag);
|
||||
}
|
||||
}
|
||||
|
||||
public PowerScrollGiver(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
1778
Scripts/Services/Pet Training/PetTrainingHelper.cs
Normal file
1778
Scripts/Services/Pet Training/PetTrainingHelper.cs
Normal file
File diff suppressed because it is too large
Load Diff
161
Scripts/Services/Pet Training/PlanningProfile.cs
Normal file
161
Scripts/Services/Pet Training/PlanningProfile.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class PlanningProfile
|
||||
{
|
||||
public BaseCreature Creature { get; private set; }
|
||||
public List<PlanningEntry> Entries { get; private set; }
|
||||
|
||||
public PlanningProfile(BaseCreature bc)
|
||||
{
|
||||
Creature = bc;
|
||||
Entries = new List<PlanningEntry>();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Entries.Clear();
|
||||
}
|
||||
|
||||
public void AddToPlan(object tp, int value, int cost)
|
||||
{
|
||||
var entry = Entries.FirstOrDefault(e => e.TrainPoint == tp);
|
||||
|
||||
if (entry != null)
|
||||
Entries.Remove(entry);
|
||||
|
||||
Entries.Add(new PlanningEntry(tp, value, cost));
|
||||
|
||||
if (tp is MagicalAbility && (MagicalAbility)tp <= MagicalAbility.WrestlingMastery)
|
||||
{
|
||||
var trainingPoint = PetTrainingHelper.GetTrainingPoint(tp);
|
||||
|
||||
foreach (var en in Entries)
|
||||
{
|
||||
if (trainingPoint.Requirements != null && trainingPoint.Requirements.Length > 0)
|
||||
{
|
||||
foreach (var req in trainingPoint.Requirements.Where(r => r != null))
|
||||
{
|
||||
if ((req.Requirement is WeaponAbility && en.TrainPoint is WeaponAbility) ||
|
||||
(req.Requirement is SpecialAbility && en.TrainPoint is SpecialAbility) ||
|
||||
(req.Requirement is AreaEffect && en.TrainPoint is AreaEffect))
|
||||
{
|
||||
en.Value = 0;
|
||||
en.Cost = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PlanningEntry
|
||||
{
|
||||
public object TrainPoint { get; private set; }
|
||||
public int Value { get; set; }
|
||||
public int Cost { get; set; }
|
||||
|
||||
public PlanningEntry(object tp, int value, int cost)
|
||||
{
|
||||
TrainPoint = tp;
|
||||
Value = value;
|
||||
Cost = cost;
|
||||
}
|
||||
}
|
||||
|
||||
public PlanningProfile(BaseCreature bc, GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Entries = new List<PlanningEntry>();
|
||||
|
||||
int count = reader.ReadInt();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
switch (reader.ReadInt())
|
||||
{
|
||||
case 0: break;
|
||||
case 1: Entries.Add(new PlanningEntry((MagicalAbility)reader.ReadInt(), reader.ReadInt(), reader.ReadInt())); break;
|
||||
case 2: Entries.Add(new PlanningEntry(SpecialAbility.Abilities[reader.ReadInt()], reader.ReadInt(), reader.ReadInt())); break;
|
||||
case 3: Entries.Add(new PlanningEntry(AreaEffect.Effects[reader.ReadInt()], reader.ReadInt(), reader.ReadInt())); break;
|
||||
case 4: Entries.Add(new PlanningEntry(WeaponAbility.Abilities[reader.ReadInt()], reader.ReadInt(), reader.ReadInt())); break;
|
||||
case 5: Entries.Add(new PlanningEntry((PetStat)reader.ReadInt(), reader.ReadInt(), reader.ReadInt())); break;
|
||||
case 6: Entries.Add(new PlanningEntry((ResistanceType)reader.ReadInt(), reader.ReadInt(), reader.ReadInt())); break;
|
||||
case 7: Entries.Add(new PlanningEntry((SkillName)reader.ReadInt(), reader.ReadInt(), reader.ReadInt())); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(0);
|
||||
|
||||
writer.Write(Entries.Count);
|
||||
|
||||
for(int i = 0; i < Entries.Count; i++)
|
||||
{
|
||||
var entry = Entries[i];
|
||||
object o = entry.TrainPoint;
|
||||
|
||||
if (o is MagicalAbility)
|
||||
{
|
||||
writer.Write(1);
|
||||
writer.Write((int)(MagicalAbility)o);
|
||||
writer.Write(entry.Value);
|
||||
writer.Write(entry.Cost);
|
||||
}
|
||||
else if (o is SpecialAbility)
|
||||
{
|
||||
writer.Write(2);
|
||||
writer.Write(Array.IndexOf(SpecialAbility.Abilities, (SpecialAbility)o));
|
||||
writer.Write(entry.Value);
|
||||
writer.Write(entry.Cost);
|
||||
}
|
||||
else if (o is AreaEffect)
|
||||
{
|
||||
writer.Write(3);
|
||||
writer.Write(Array.IndexOf(AreaEffect.Effects, (AreaEffect)o));
|
||||
writer.Write(entry.Value);
|
||||
writer.Write(entry.Cost);
|
||||
}
|
||||
else if (o is WeaponAbility)
|
||||
{
|
||||
writer.Write(4);
|
||||
writer.Write(Array.IndexOf(WeaponAbility.Abilities, (WeaponAbility)o));
|
||||
writer.Write(entry.Value);
|
||||
writer.Write(entry.Cost);
|
||||
}
|
||||
else if (o is PetStat)
|
||||
{
|
||||
writer.Write(5);
|
||||
writer.Write((int)(PetStat)o);
|
||||
writer.Write(entry.Value);
|
||||
writer.Write(entry.Cost);
|
||||
}
|
||||
else if (o is ResistanceType)
|
||||
{
|
||||
writer.Write(6);
|
||||
writer.Write((int)(ResistanceType)o);
|
||||
writer.Write(entry.Value);
|
||||
writer.Write(entry.Cost);
|
||||
}
|
||||
else if (o is SkillName)
|
||||
{
|
||||
writer.Write(7);
|
||||
writer.Write((int)(SkillName)o);
|
||||
writer.Write(entry.Value);
|
||||
writer.Write(entry.Cost);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2688
Scripts/Services/Pet Training/SpecialAbility.cs
Normal file
2688
Scripts/Services/Pet Training/SpecialAbility.cs
Normal file
File diff suppressed because it is too large
Load Diff
51
Scripts/Services/Pet Training/TrainingDefinition.cs
Normal file
51
Scripts/Services/Pet Training/TrainingDefinition.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Items;
|
||||
using System.Linq;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class TrainingDefinition
|
||||
{
|
||||
public Type CreatureType { get; private set; }
|
||||
public Class Class { get; private set; }
|
||||
public MagicalAbility MagicalAbilities { get; private set; }
|
||||
public SpecialAbility[] SpecialAbilities { get; private set; }
|
||||
public WeaponAbility[] WeaponAbilities { get; private set; }
|
||||
public AreaEffect[] AreaEffects { get; private set; }
|
||||
|
||||
public int ControlSlotsMin { get; private set; }
|
||||
public int ControlSlotsMax { get; private set; }
|
||||
|
||||
public TrainingDefinition(
|
||||
Type type,
|
||||
Class classificaion,
|
||||
MagicalAbility magicalAbility,
|
||||
SpecialAbility[] specialAbility,
|
||||
WeaponAbility[] weaponAbility,
|
||||
AreaEffect[] areaEffect,
|
||||
int controlmin,
|
||||
int controlmax)
|
||||
{
|
||||
CreatureType = type;
|
||||
Class = classificaion;
|
||||
MagicalAbilities = magicalAbility;
|
||||
SpecialAbilities = specialAbility;
|
||||
WeaponAbilities = weaponAbility;
|
||||
AreaEffects = areaEffect;
|
||||
|
||||
ControlSlotsMin = controlmin;
|
||||
ControlSlotsMax = controlmax;
|
||||
}
|
||||
|
||||
public bool HasSpecialAbility(SpecialAbility ability)
|
||||
{
|
||||
return SpecialAbilities != null && SpecialAbilities.Any(a => a == ability);
|
||||
}
|
||||
|
||||
public bool HasAreaEffect(AreaEffect ability)
|
||||
{
|
||||
return AreaEffects != null && AreaEffects.Any(a => a == ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Scripts/Services/Pet Training/TrainingPoint.cs
Normal file
55
Scripts/Services/Pet Training/TrainingPoint.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class TrainingPoint
|
||||
{
|
||||
public object TrainPoint { get; set; }
|
||||
public double Weight { get; set; }
|
||||
public int Start { get; set; }
|
||||
public int Max { get; set; }
|
||||
public TextDefinition Name { get; set; }
|
||||
public TextDefinition Description { get; set; }
|
||||
|
||||
public TrainingPointRequirement[] Requirements { get; set; }
|
||||
|
||||
public TrainingPoint(object trainpoint, double weight, int start, int max, TextDefinition name, TextDefinition description, params TrainingPointRequirement[] requirements)
|
||||
{
|
||||
TrainPoint = trainpoint;
|
||||
Weight = weight;
|
||||
Start = start;
|
||||
Max = max;
|
||||
|
||||
Name = name;
|
||||
Description = description;
|
||||
|
||||
Requirements = requirements;
|
||||
}
|
||||
|
||||
public int GetMax(BaseCreature bc)
|
||||
{
|
||||
if (TrainPoint is PetStat && (PetStat)TrainPoint == PetStat.BaseDamage)
|
||||
{
|
||||
return PetTrainingHelper.GetMaxDamagePerSecond(bc);
|
||||
}
|
||||
|
||||
return Max;
|
||||
}
|
||||
}
|
||||
|
||||
public class TrainingPointRequirement
|
||||
{
|
||||
public object Requirement { get; set; }
|
||||
public int Cost { get; set; }
|
||||
public TextDefinition Name { get; set; }
|
||||
|
||||
public TrainingPointRequirement(object requirement, int cost, TextDefinition name)
|
||||
{
|
||||
Requirement = requirement;
|
||||
Cost = cost;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
442
Scripts/Services/Pet Training/TrainingProfile.cs
Normal file
442
Scripts/Services/Pet Training/TrainingProfile.cs
Normal file
@@ -0,0 +1,442 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
|
||||
public enum TrainingMode
|
||||
{
|
||||
Regular,
|
||||
Planning
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class TrainingProfile
|
||||
{
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TrainingMode TrainingMode { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool HasBegunTraining { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool HasIncreasedControlSlot { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int TrainedThisLevel { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool HasRecievedControlSlotWarning { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public double TrainingProgress { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public double TrainingProgressMax { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public BaseCreature Creature { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public double TrainingProgressPercentile { get { return TrainingProgress / TrainingProgressMax; } }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ControlSlots { get { return Creature.ControlSlots; } }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ControlSlotsMin { get { return Creature.ControlSlotsMin; } }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ControlSlotsMax { get { return Creature.ControlSlotsMax; } }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool CanApplyOptions { get { return HasBegunTraining && TrainingProgressPercentile >= 1.0; } }
|
||||
|
||||
private int _TrainingPoints;
|
||||
private int _StartingTrainingPoints;
|
||||
private PlanningProfile _Plan;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int TrainingPoints
|
||||
{
|
||||
get { return _TrainingPoints; }
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
EndTraining();
|
||||
}
|
||||
else
|
||||
{
|
||||
_TrainingPoints = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int StartingTrainingPoints
|
||||
{
|
||||
get { return _StartingTrainingPoints; }
|
||||
set { _StartingTrainingPoints = value; }
|
||||
}
|
||||
|
||||
public PlanningProfile PlanningProfile
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Plan == null)
|
||||
_Plan = new PlanningProfile(Creature);
|
||||
|
||||
return _Plan;
|
||||
}
|
||||
}
|
||||
|
||||
public static TimeSpan PowerHourDuration = TimeSpan.FromHours(1);
|
||||
public static TimeSpan PowerHourDelay = TimeSpan.FromHours(24);
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime PowerHourBegin { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool InPowerHour { get; set; }
|
||||
|
||||
public int PowerHourMultiplier
|
||||
{
|
||||
get
|
||||
{
|
||||
if (InPowerHour)
|
||||
{
|
||||
return 2; // 2x gains from creatures during power hour
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly int MaxTrainingProgress = 100;
|
||||
|
||||
private Dictionary<BaseCreature, int> _ProgressTable;
|
||||
|
||||
public TrainingProfile(BaseCreature bc)
|
||||
{
|
||||
Creature = bc;
|
||||
|
||||
_ProgressTable = new Dictionary<BaseCreature, int>();
|
||||
}
|
||||
|
||||
private int AssignStartingTrainingPoints()
|
||||
{
|
||||
if (ControlSlots != ControlSlotsMin)
|
||||
{
|
||||
return 1501;
|
||||
}
|
||||
|
||||
if (ControlSlotsMin == 1 && ControlSlotsMax == 2)
|
||||
{
|
||||
return 2556;
|
||||
}
|
||||
|
||||
if (ControlSlotsMin == 1 && ControlSlotsMax == 3)
|
||||
{
|
||||
return 2381;
|
||||
}
|
||||
|
||||
return 1501;
|
||||
}
|
||||
|
||||
public void BeginTraining()
|
||||
{
|
||||
if (ControlSlots < ControlSlotsMax)
|
||||
{
|
||||
TrainingPoints = AssignStartingTrainingPoints();
|
||||
HasBegunTraining = true;
|
||||
|
||||
TrainingProgress = 0;
|
||||
TrainingProgressMax = MaxTrainingProgress;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTrain(PlayerMobile pm, int points)
|
||||
{
|
||||
int reqInc;
|
||||
|
||||
if (!HasIncreasedControlSlot)
|
||||
{
|
||||
reqInc = GetRequirementIncrease(true);
|
||||
|
||||
Creature.RemoveFollowers();
|
||||
Creature.ControlSlots++;
|
||||
Creature.AddFollowers();
|
||||
TrainedThisLevel = 0;
|
||||
|
||||
pm.SendLocalizedMessage(1157537); // Your pet's control slot have been updated.
|
||||
HasIncreasedControlSlot = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TrainedThisLevel++;
|
||||
reqInc = GetRequirementIncrease(false);
|
||||
}
|
||||
|
||||
Creature.CurrentTameSkill = Math.Min(BaseCreature.MaxTameRequirement, Creature.CurrentTameSkill + reqInc);
|
||||
TrainingPoints -= points;
|
||||
}
|
||||
|
||||
public int GetRequirementIncrease(bool slotIncreased)
|
||||
{
|
||||
if (slotIncreased)
|
||||
{
|
||||
// First level
|
||||
if (ControlSlotsMin + 1 == ControlSlots)
|
||||
{
|
||||
return 21;
|
||||
}
|
||||
// subsequent trains of that level
|
||||
else
|
||||
{
|
||||
return 22;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// First train of that level (after level increase, so actually 2nd train)
|
||||
if (TrainedThisLevel == 1)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
// subsequent trains of that level
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EndTraining()
|
||||
{
|
||||
HasBegunTraining = false;
|
||||
_TrainingPoints = 0;
|
||||
|
||||
HasRecievedControlSlotWarning = false;
|
||||
HasIncreasedControlSlot = false;
|
||||
}
|
||||
|
||||
private bool CheckCanProgress(BaseCreature bc, double toGain)
|
||||
{
|
||||
if (_ProgressTable.ContainsKey(bc))
|
||||
{
|
||||
int gains = GetGainsPerCreature(toGain);
|
||||
|
||||
if (_ProgressTable[bc] >= gains)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ProgressTable[bc]++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_ProgressTable[bc] = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
private int GetGainsPerCreature(double toGain)
|
||||
{
|
||||
int gains = 0;
|
||||
|
||||
switch (ControlSlots)
|
||||
{
|
||||
case 1: gains = int.MaxValue; break;
|
||||
case 2: gains = int.MaxValue; break;
|
||||
case 3: gains = (int)(((double)MaxTrainingProgress / toGain) / 2.0); break;
|
||||
default: gains = (int)(((double)MaxTrainingProgress / toGain) / 4.0); break;
|
||||
}
|
||||
|
||||
if (gains < int.MaxValue)
|
||||
{
|
||||
gains *= PowerHourMultiplier;
|
||||
}
|
||||
|
||||
return gains;
|
||||
}
|
||||
|
||||
public void CheckProgress(BaseCreature bc)
|
||||
{
|
||||
if (ControlSlots >= ControlSlotsMax || !HasBegunTraining || TrainingProgress >= TrainingProgressMax || Creature.ControlMaster == null)
|
||||
return;
|
||||
|
||||
var ourDif = Creature.BardingDifficulty;
|
||||
var theirDif = bc.BardingDifficulty;
|
||||
var master = Creature.ControlMaster;
|
||||
|
||||
if (Utility.Random(100) < 8 - (1 + (ControlSlots - ControlSlotsMin)))
|
||||
{
|
||||
double toGain = GetAdvance(theirDif); // Math.Round(.25 + (Math.Max(0, (bc.BardingDifficulty / Creature.BardingDifficulty)) * 1.0), 2);
|
||||
|
||||
if (ourDif - theirDif <= 50 && CheckCanProgress(bc, toGain))
|
||||
{
|
||||
if (PowerHourBegin + PowerHourDelay < DateTime.UtcNow)
|
||||
{
|
||||
_ProgressTable.Clear();
|
||||
|
||||
PowerHourBegin = DateTime.UtcNow;
|
||||
InPowerHour = true;
|
||||
master.SendLocalizedMessage(1157569); // [Pet Training Power Hour]: Your pet is under the effects of enhanced training progress for the next hour!
|
||||
}
|
||||
else if (InPowerHour && PowerHourBegin + PowerHourDuration < DateTime.UtcNow)
|
||||
{
|
||||
InPowerHour = false;
|
||||
master.SendLocalizedMessage(1157570); // [Pet Training Power Hour]: Your pet is no longer under the effects of enhanced training progress.
|
||||
}
|
||||
|
||||
TrainingProgress = Math.Min(TrainingProgressMax, TrainingProgress + toGain);
|
||||
|
||||
if (!bc.Controlled && !bc.Summoned && master is PlayerMobile)
|
||||
{
|
||||
int cliloc = 1157574; // *The pet's battle experience has greatly increased!*
|
||||
|
||||
if (toGain < 1.3)
|
||||
cliloc = 1157565; // *The pet's battle experience has slightly increased!*
|
||||
else if (toGain < 2.5)
|
||||
cliloc = 1157573; // *The pet's battle experience has fairly increased!*
|
||||
|
||||
if (master.HasGump(typeof(PetTrainingProgressGump)))
|
||||
{
|
||||
ResendProgressGump(master);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (master.InRange(Creature.Location, 12))
|
||||
{
|
||||
BaseGump.SendGump(new PetTrainingProgressGump((PlayerMobile)master, Creature));
|
||||
}
|
||||
}
|
||||
|
||||
Creature.PrivateOverheadMessage(MessageType.Regular, 0x59, cliloc, master.NetState);
|
||||
|
||||
if (TrainingProgress >= TrainingProgressMax)
|
||||
{
|
||||
Creature.PrivateOverheadMessage(MessageType.Regular, 0x59, 1157543, master.NetState); // *The creature surges with battle experience and is ready to train!*
|
||||
|
||||
Server.Engines.Quests.LeadingIntoBattleQuest.CheckComplete((PlayerMobile)master);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Creature.PrivateOverheadMessage(MessageType.Regular, 0x21, 1157564, master.NetState); // *The pet does not appear to train from that*
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Creature.PrivateOverheadMessage(MessageType.Regular, 0x21, 1157564, master.NetState); // *The pet does not appear to train from that*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double GetAdvance(double difficulty)
|
||||
{
|
||||
var advance = difficulty / 64;
|
||||
|
||||
if (advance >= 2.5)
|
||||
advance = 2.5;
|
||||
|
||||
return advance;
|
||||
}
|
||||
|
||||
public void ResendProgressGump(Mobile m)
|
||||
{
|
||||
if (m == null || m.NetState == null || !(m is PlayerMobile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PetTrainingProgressGump g = m.FindGump(typeof(PetTrainingProgressGump)) as PetTrainingProgressGump;
|
||||
|
||||
if (g == null)
|
||||
{
|
||||
Server.Gumps.BaseGump.SendGump(new PetTrainingProgressGump((PlayerMobile)m, Creature));
|
||||
}
|
||||
else
|
||||
{
|
||||
g.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "...";
|
||||
}
|
||||
|
||||
public TrainingProfile(BaseCreature bc, GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 2:
|
||||
TrainedThisLevel = reader.ReadInt();
|
||||
goto case 1;
|
||||
case 1:
|
||||
PowerHourBegin = reader.ReadDateTime();
|
||||
InPowerHour = reader.ReadBool();
|
||||
break;
|
||||
}
|
||||
|
||||
Creature = bc;
|
||||
|
||||
if (reader.ReadInt() == 1)
|
||||
{
|
||||
_Plan = new PlanningProfile(bc, reader);
|
||||
}
|
||||
|
||||
TrainingMode = (TrainingMode)reader.ReadInt();
|
||||
HasBegunTraining = reader.ReadBool();
|
||||
HasIncreasedControlSlot = reader.ReadBool();
|
||||
HasRecievedControlSlotWarning = reader.ReadBool();
|
||||
TrainingProgress = reader.ReadDouble();
|
||||
TrainingProgressMax = reader.ReadDouble();
|
||||
|
||||
_StartingTrainingPoints = reader.ReadInt();
|
||||
_TrainingPoints = reader.ReadInt();
|
||||
|
||||
_ProgressTable = new Dictionary<BaseCreature, int>();
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(2);
|
||||
|
||||
writer.Write(TrainedThisLevel);
|
||||
|
||||
writer.Write(PowerHourBegin);
|
||||
writer.Write(InPowerHour);
|
||||
|
||||
if (_Plan != null)
|
||||
{
|
||||
writer.Write(1);
|
||||
_Plan.Serialize(writer);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
writer.Write((int)TrainingMode);
|
||||
writer.Write(HasBegunTraining);
|
||||
writer.Write(HasIncreasedControlSlot);
|
||||
writer.Write(HasRecievedControlSlotWarning);
|
||||
writer.Write(TrainingProgress);
|
||||
writer.Write(TrainingProgressMax);
|
||||
|
||||
writer.Write(_StartingTrainingPoints);
|
||||
writer.Write(_TrainingPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user