123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740 |
- #region File Description
- //-----------------------------------------------------------------------------
- // FightingCharacter.cs
- //
- // Microsoft XNA Community Game Platform
- // Copyright (C) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- #endregion
- #region Using Statements
- using System;
- using System.Collections.Generic;
- using Microsoft.Xna.Framework.Content;
- #endregion
- namespace RolePlayingGameData
- {
- /// <summary>
- /// A character that engages in combat.
- /// </summary>
- public abstract class FightingCharacter : Character
- {
- #region Class Data
- /// <summary>
- /// The name of the character class.
- /// </summary>
- private string characterClassContentName;
- /// <summary>
- /// The name of the character class.
- /// </summary>
- public string CharacterClassContentName
- {
- get { return characterClassContentName; }
- set { characterClassContentName = value; }
- }
- /// <summary>
- /// The character class itself.
- /// </summary>
- private CharacterClass characterClass;
- /// <summary>
- /// The character class itself.
- /// </summary>
- [ContentSerializerIgnore]
- public CharacterClass CharacterClass
- {
- get { return characterClass; }
- set
- {
- characterClass = value;
- ResetBaseStatistics();
- }
- }
- /// <summary>
- /// The level of the character.
- /// </summary>
- private int characterLevel = 1;
- /// <summary>
- /// The level of the character.
- /// </summary>
- public int CharacterLevel
- {
- get { return characterLevel; }
- set
- {
- characterLevel = value;
- ResetBaseStatistics();
- spells = null;
- }
- }
- /// <summary>
- /// Returns true if the character is at the maximum level allowed by their class.
- /// </summary>
- public bool IsMaximumCharacterLevel
- {
- get
- {
- return characterLevel >= characterClass.LevelEntries.Count;
- }
- }
-
- /// <summary>
- /// The cached list of spells for this level.
- /// </summary>
- private List<Spell> spells = null;
- /// <summary>
- /// The cached list of spells for this level.
- /// </summary>
- [ContentSerializerIgnore]
- public List<Spell> Spells
- {
- get
- {
- if ((spells == null) && (characterClass != null))
- {
- spells = characterClass.GetAllSpellsForLevel(characterLevel);
- }
- return spells;
- }
- }
- #endregion
- #region Experience
- /// <summary>
- /// The amount of experience points that this character has.
- /// </summary>
- private int experience;
- /// <summary>
- /// The amount of experience points that this character has.
- /// </summary>
- [ContentSerializerIgnore]
- public int Experience
- {
- get { return experience; }
- set
- {
- experience = value;
- while (experience >= ExperienceForNextLevel)
- {
- if (IsMaximumCharacterLevel)
- {
- break;
- }
- experience -= ExperienceForNextLevel;
- CharacterLevel++;
- }
- }
- }
- /// <summary>
- /// Returns the amount of experience necessary to reach the next character level.
- /// </summary>
- public int ExperienceForNextLevel
- {
- get
- {
- int checkIndex = Math.Min(characterLevel,
- characterClass.LevelEntries.Count) - 1;
- return characterClass.LevelEntries[checkIndex].ExperiencePoints;
- }
- }
- #endregion
- #region Statistics
-
- /// <summary>
- /// The base statistics of this character, from the character class and level.
- /// </summary>
- private StatisticsValue baseStatistics = new StatisticsValue();
- /// <summary>
- /// The base statistics of this character, from the character class and level.
- /// </summary>
- [ContentSerializerIgnore]
- public StatisticsValue BaseStatistics
- {
- get { return baseStatistics; }
- set { baseStatistics = value; }
- }
- /// <summary>
- /// Reset the character's base statistics.
- /// </summary>
- public void ResetBaseStatistics()
- {
- if (characterClass == null)
- {
- baseStatistics = new StatisticsValue();
- }
- else
- {
- baseStatistics = characterClass.GetStatisticsForLevel(characterLevel);
- }
- }
- /// <summary>
- /// The total statistics for this character.
- /// </summary>
- [ContentSerializerIgnore]
- public StatisticsValue CharacterStatistics
- {
- get { return baseStatistics + equipmentBuffStatistics; }
- }
- #endregion
- #region Equipment
- /// <summary>
- /// The equipment currently equipped on this character.
- /// </summary>
- private List<Equipment> equippedEquipment = new List<Equipment>();
- /// <summary>
- /// The equipment currently equipped on this character.
- /// </summary>
- [ContentSerializerIgnore]
- public List<Equipment> EquippedEquipment
- {
- get { return equippedEquipment; }
- }
- /// <summary>
- /// The content names of the equipment initially equipped on the character.
- /// </summary>
- private List<string> initialEquipmentContentNames = new List<string>();
- /// <summary>
- /// The content names of the equipment initially equipped on the character.
- /// </summary>
- public List<string> InitialEquipmentContentNames
- {
- get { return initialEquipmentContentNames; }
- set { initialEquipmentContentNames = value; }
- }
- /// <summary>
- /// Retrieve the currently equipped weapon.
- /// </summary>
- /// <remarks>There can only be one weapon equipped at the same time.</remarks>
- public Weapon GetEquippedWeapon()
- {
- return equippedEquipment.Find(delegate(Equipment equipment)
- { return equipment is Weapon; }) as Weapon;
- }
- /// <summary>
- /// Equip a new weapon.
- /// </summary>
- /// <returns>True if the weapon was equipped.</returns>
- public bool EquipWeapon(Weapon weapon, out Equipment oldEquipment)
- {
- // check the parameter
- if (weapon == null)
- {
- throw new ArgumentNullException("weapon");
- }
- // check equipment restrictions
- if (!weapon.CheckRestrictions(this))
- {
- oldEquipment = null;
- return false;
- }
- // unequip any existing weapon
- Weapon existingWeapon = GetEquippedWeapon();
- if (existingWeapon != null)
- {
- oldEquipment = existingWeapon;
- equippedEquipment.Remove(existingWeapon);
- }
- else
- {
- oldEquipment = null;
- }
- // add the weapon
- equippedEquipment.Add(weapon);
- // recalculate the statistic changes from equipment
- RecalculateEquipmentStatistics();
- RecalculateTotalTargetDamageRange();
- return true;
- }
- /// <summary>
- /// Remove any equipped weapons.
- /// </summary>
- public void UnequipWeapon()
- {
- equippedEquipment.RemoveAll(delegate(Equipment equipment)
- { return equipment is Weapon; });
- RecalculateEquipmentStatistics();
- }
- /// <summary>
- /// Retrieve the armor equipped in the given slot.
- /// </summary>
- public Armor GetEquippedArmor(Armor.ArmorSlot slot)
- {
- return equippedEquipment.Find(delegate(Equipment equipment)
- {
- Armor armor = equipment as Armor;
- return ((armor != null) && (armor.Slot == slot));
- }) as Armor;
- }
- /// <summary>
- /// Equip a new piece of armor.
- /// </summary>
- /// <returns>True if the armor could be equipped.</returns>
- public bool EquipArmor(Armor armor, out Equipment oldEquipment)
- {
- // check the parameter
- if (armor == null)
- {
- throw new ArgumentNullException("armor");
- }
- // check equipment requirements
- if (!armor.CheckRestrictions(this))
- {
- oldEquipment = null;
- return false;
- }
- // remove any armor equipped in this slot
- Armor equippedArmor = GetEquippedArmor(armor.Slot);
- if (equippedArmor != null)
- {
- oldEquipment = equippedArmor;
- equippedEquipment.Remove(equippedArmor);
- }
- else
- {
- oldEquipment = null;
- }
- // add the armor
- equippedEquipment.Add(armor);
- // recalcuate the total armor defense values
- RecalculateTotalDefenseRanges();
- // recalculate the statistics buffs from equipment
- RecalculateEquipmentStatistics();
- return true;
- }
- /// <summary>
- /// Unequip any armor in the given slot.
- /// </summary>
- public void UnequipArmor(Armor.ArmorSlot slot)
- {
- equippedEquipment.RemoveAll(delegate(Equipment equipment)
- {
- Armor armor = equipment as Armor;
- return ((armor != null) && (armor.Slot == slot));
- });
- RecalculateEquipmentStatistics();
- RecalculateTotalDefenseRanges();
- }
- /// <summary>
- /// Equip a new piece of equipment.
- /// </summary>
- /// <returns>True if the equipment could be equipped.</returns>
- public virtual bool Equip(Equipment equipment)
- {
- Equipment oldEquipment;
- return Equip(equipment, out oldEquipment);
- }
-
- /// <summary>
- /// Equip a new piece of equipment, specifying any equipment auto-unequipped.
- /// </summary>
- /// <returns>True if the equipment could be equipped.</returns>
- public virtual bool Equip(Equipment equipment, out Equipment oldEquipment)
- {
- if (equipment == null)
- {
- throw new ArgumentNullException("equipment");
- }
- if (equipment is Weapon)
- {
- return EquipWeapon(equipment as Weapon, out oldEquipment);
- }
- else if (equipment is Armor)
- {
- return EquipArmor(equipment as Armor, out oldEquipment);
- }
- else
- {
- oldEquipment = null;
- }
- return false;
- }
- /// <summary>
- /// Unequip a piece of equipment.
- /// </summary>
- /// <returns>True if the equipment could be unequipped.</returns>
- public virtual bool Unequip(Equipment equipment)
- {
- if (equipment == null)
- {
- throw new ArgumentNullException("equipment");
- }
- if (equippedEquipment.Remove(equipment))
- {
- RecalculateEquipmentStatistics();
- RecalculateTotalTargetDamageRange();
- RecalculateTotalDefenseRanges();
- return true;
- }
- return false;
- }
- #endregion
- #region Combined Equipment Values
- /// <summary>
- /// The total statistics changes (buffs) from all equipped equipment.
- /// </summary>
- private StatisticsValue equipmentBuffStatistics = new StatisticsValue();
- /// <summary>
- /// The total statistics changes (buffs) from all equipped equipment.
- /// </summary>
- [ContentSerializerIgnore]
- public StatisticsValue EquipmentBuffStatistics
- {
- get { return equipmentBuffStatistics; }
- set { equipmentBuffStatistics = value; }
- }
- /// <summary>
- /// Recalculate the character's equipment-buff statistics.
- /// </summary>
- public void RecalculateEquipmentStatistics()
- {
- // start from scratch
- equipmentBuffStatistics = new StatisticsValue();
- // add the statistics for each piece of equipped equipment
- foreach (Equipment equipment in equippedEquipment)
- {
- equipmentBuffStatistics += equipment.OwnerBuffStatistics;
- }
- }
- /// <summary>
- /// The target damage range for this character, aggregated from all weapons.
- /// </summary>
- private Int32Range targetDamageRange;
- /// <summary>
- /// The health damage range for this character, aggregated from all weapons.
- /// </summary>
- public Int32Range TargetDamageRange
- {
- get { return targetDamageRange; }
- }
- /// <summary>
- /// Recalculate the character's defense ranges from all of their armor.
- /// </summary>
- public void RecalculateTotalTargetDamageRange()
- {
- // set the initial damage range to the physical offense statistic
- targetDamageRange = new Int32Range();
- // add each weapon's target damage range
- foreach (Equipment equipment in equippedEquipment)
- {
- Weapon weapon = equipment as Weapon;
- if (weapon != null)
- {
- targetDamageRange += weapon.TargetDamageRange;
- }
- }
- }
- /// <summary>
- /// The health defense range for this character, aggregated from all armor.
- /// </summary>
- private Int32Range healthDefenseRange;
- /// <summary>
- /// The health defense range for this character, aggregated from all armor.
- /// </summary>
- public Int32Range HealthDefenseRange
- {
- get { return healthDefenseRange; }
- }
- /// <summary>
- /// The magic defense range for this character, aggregated from all armor.
- /// </summary>
- private Int32Range magicDefenseRange;
- /// <summary>
- /// The magic defense range for this character, aggregated from all armor.
- /// </summary>
- public Int32Range MagicDefenseRange
- {
- get { return magicDefenseRange; }
- }
- /// <summary>
- /// Recalculate the character's defense ranges from all of their armor.
- /// </summary>
- public void RecalculateTotalDefenseRanges()
- {
- // set the initial damage ranges based on character statistics
- healthDefenseRange = new Int32Range();
- magicDefenseRange = new Int32Range();
- // add the defense ranges for each piece of equipped armor
- foreach (Equipment equipment in equippedEquipment)
- {
- Armor armor = equipment as Armor;
- if (armor != null)
- {
- healthDefenseRange += armor.OwnerHealthDefenseRange;
- magicDefenseRange += armor.OwnerMagicDefenseRange;
- }
- }
- }
- #endregion
- #region Inventory
- /// <summary>
- /// The gear in this character's inventory (and not equipped).
- /// </summary>
- private List<ContentEntry<Gear>> inventory = new List<ContentEntry<Gear>>();
- /// <summary>
- /// The gear in this character's inventory (and not equipped).
- /// </summary>
- public List<ContentEntry<Gear>> Inventory
- {
- get { return inventory; }
- }
- #endregion
- #region Graphics Data
- /// <summary>
- /// The animating sprite for the combat view of this character.
- /// </summary>
- private AnimatingSprite combatSprite;
- /// <summary>
- /// The animating sprite for the combat view of this character.
- /// </summary>
- public AnimatingSprite CombatSprite
- {
- get { return combatSprite; }
- set { combatSprite = value; }
- }
- /// <summary>
- /// Reset the animations for this character.
- /// </summary>
- public override void ResetAnimation(bool isWalking)
- {
- base.ResetAnimation(isWalking);
- if (combatSprite != null)
- {
- combatSprite.PlayAnimation("Idle");
- }
- }
- #endregion
- #region Static Animation Data
- /// <summary>
- /// The default animation interval for the combat map sprite.
- /// </summary>
- private int combatAnimationInterval = 100;
- /// <summary>
- /// The default animation interval for the combat map sprite.
- /// </summary>
- [ContentSerializer(Optional=true)]
- public int CombatAnimationInterval
- {
- get { return combatAnimationInterval; }
- set { combatAnimationInterval = value; }
- }
- /// <summary>
- /// Add the standard character walk animations to this character.
- /// </summary>
- private void AddStandardCharacterCombatAnimations()
- {
- if (combatSprite != null)
- {
- combatSprite.AddAnimation(new Animation("Idle", 37, 42,
- CombatAnimationInterval, true));
- combatSprite.AddAnimation(new Animation("Walk", 25, 30,
- CombatAnimationInterval, true));
- combatSprite.AddAnimation(new Animation("Attack", 1, 6,
- CombatAnimationInterval, false));
- combatSprite.AddAnimation(new Animation("SpellCast", 31, 36,
- CombatAnimationInterval, false));
- combatSprite.AddAnimation(new Animation("Defend", 13, 18,
- CombatAnimationInterval, false));
- combatSprite.AddAnimation(new Animation("Dodge", 13, 18,
- CombatAnimationInterval, false));
- combatSprite.AddAnimation(new Animation("Hit", 19, 24,
- CombatAnimationInterval, false));
- combatSprite.AddAnimation(new Animation("Die", 7, 12,
- CombatAnimationInterval, false));
- }
- }
- #endregion
- #region Content Type Reader
- /// <summary>
- /// Reads a FightingCharacter object from the content pipeline.
- /// </summary>
- public class FightingCharacterReader : ContentTypeReader<FightingCharacter>
- {
- /// <summary>
- /// Reads a FightingCharacter object from the content pipeline.
- /// </summary>
- protected override FightingCharacter Read(ContentReader input,
- FightingCharacter existingInstance)
- {
- FightingCharacter fightingCharacter = existingInstance;
- if (fightingCharacter == null)
- {
- throw new ArgumentNullException("existingInstance");
- }
- input.ReadRawObject<Character>(fightingCharacter as Character);
- fightingCharacter.CharacterClassContentName = input.ReadString();
- fightingCharacter.CharacterLevel = input.ReadInt32();
- fightingCharacter.InitialEquipmentContentNames.AddRange(
- input.ReadObject<List<string>>());
- fightingCharacter.Inventory.AddRange(
- input.ReadObject<List<ContentEntry<Gear>>>());
- fightingCharacter.CombatAnimationInterval = input.ReadInt32();
- fightingCharacter.CombatSprite = input.ReadObject<AnimatingSprite>();
- fightingCharacter.AddStandardCharacterCombatAnimations();
- fightingCharacter.ResetAnimation(false);
- // load the character class
- fightingCharacter.CharacterClass =
- input.ContentManager.Load<CharacterClass>(
- System.IO.Path.Combine("CharacterClasses",
- fightingCharacter.CharacterClassContentName));
- // populate the equipment list
- foreach (string gearName in
- fightingCharacter.InitialEquipmentContentNames)
- {
- fightingCharacter.Equip(input.ContentManager.Load<Equipment>(
- System.IO.Path.Combine("Gear", gearName)));
- }
- fightingCharacter.RecalculateEquipmentStatistics();
- fightingCharacter.RecalculateTotalTargetDamageRange();
- fightingCharacter.RecalculateTotalDefenseRanges();
- // populate the inventory based on the content names
- foreach (ContentEntry<Gear> inventoryEntry in
- fightingCharacter.Inventory)
- {
- inventoryEntry.Content = input.ContentManager.Load<Gear>(
- System.IO.Path.Combine("Gear", inventoryEntry.ContentName));
- }
- return fightingCharacter;
- }
- }
- #endregion
- }
- }
|