All pastes #790995 Raw Edit

tobz

public text v1 · immutable
·published 2007-11-20 18:16 UTC
rendered paste body
/*************************************************************************
 *                            StatCollection.cs
 *                            -----------------
 *   begin                : Jan 24, 2007
 *   copyright            : (C) The WCell Team
 *   email                : info@wcell.org
 *************************************************************************/

/*************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCell.Core;
using Cell.Core;
using WCell.RealmServer.Entities;

namespace WCell.RealmServer.Stats
{
	/// <summary>
	/// Manages the different categories of stat modification and allows calculators to be 
	/// implemented as scripts for calculating totals.
	/// </summary>
	public class StatCollection
	{
		private Unit m_owner;
		private HashSet<StatChange> m_changeTracker;
		private Queue<StatChange> m_changes;
		private Dictionary<StatCollectionType, Dictionary<StatTypes, double>> m_stats;
		private SpinWaitLock m_changeLock;
		private SpinWaitLock m_flagLock;

		/// <summary>
		/// Creates a <see cref="StatCollection" /> object with the given <see cref="Unit" /> as the owner.
		/// </summary>
		/// <param name="unit">the <see cref="Unit" /> that this collection belongs to</param>
		public StatCollection(Unit unit)
		{
			m_owner = unit;

			m_changes = new Queue<StatChange>();
			m_changeTracker = new HashSet<StatChange>();
			m_stats = new Dictionary<StatCollectionType, Dictionary<StatTypes, double>>();

			Dictionary<StatTypes, double> tempDict;

			for (int i = (int)StatCollectionType.Base; i < (int)StatCollectionType.End; i++)
			{
				tempDict = new Dictionary<StatTypes, double>();

				for (int j = (int)StatTypes.Base; j < (int)StatTypes.End; j++)
				{
					if ((StatCollectionType)i == StatCollectionType.Multiplicative)
					{
						tempDict.Add((StatTypes)j, 1.0);
					}
					else
					{
						tempDict.Add((StatTypes)j, 0.0);
					}
				}

				m_stats.Add((StatCollectionType)i, tempDict);
			}

			m_changeLock = new SpinWaitLock();
			m_flagLock = new SpinWaitLock();
		}

		/// <summary>
		/// Adds a given value to the existing value for a specific <see cref="StatTypes" /> in a
		/// specific <see cref="StatCollectionType">collection</see>. 
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to add</param>
		public void AddToStat(StatCollectionType collectionType, StatTypes statType, double value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = m_stats[collectionType][statType] + value;
				FlagChange(statType);
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Adds a given value to the existing value for a specific <see cref="StatTypes" /> in a
		/// specific <see cref="StatCollectionType">collection</see>.
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to add</param>
		public void AddToStat(StatCollectionType collectionType, StatTypes statType, short value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = m_stats[collectionType][statType] + (double)value;
				FlagChange(statType);
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Adds a given value to the existing value for a specific <see cref="StatTypes" /> in a
		/// specific <see cref="StatCollectionType">collection</see>. 
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to add</param>
		public void AddToStat(StatCollectionType collectionType, StatTypes statType, int value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = m_stats[collectionType][statType] + (double)value;
				FlagChange(statType);
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Removes a given amount from the existing value for a specific <see cref="StatTypes" /> in a
		/// specific <see cref="StatCollectionType">collection</see>. 
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to remove</param>
		public void RemoveFromStat(StatCollectionType collectionType, StatTypes statType, double value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = m_stats[collectionType][statType] - value;
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Removes a given amount from the existing value for a specific <see cref="StatTypes" /> in a
		/// specific <see cref="StatCollectionType">collection</see>. 
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to remove</param>
		public void RemoveFromStat(StatCollectionType collectionType, StatTypes statType, short value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = m_stats[collectionType][statType] - (double)value;
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Removes a given amount from the existing value for a specific <see cref="StatTypes" /> in a
		/// specific <see cref="StatCollectionType">collection</see>. 
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to remove</param>
		public void RemoveFromStat(StatCollectionType collectionType, StatTypes statType, int value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = m_stats[collectionType][statType] - (double)value;
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Sets a specific value for a specific <see cref="StatTypes" /> in a specific 
		/// <see cref="StatCollectionTypes">collection</see>.
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to set</param>
		public void SetValue(StatCollectionType collectionType, StatTypes statType, double value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = value;
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Sets a specific value for a specific <see cref="StatTypes" /> in a specific 
		/// <see cref="StatCollectionTypes">collection</see>.
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to set</param>
		public void SetValue(StatCollectionType collectionType, StatTypes statType, short value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = (double)value;
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Sets a specific value for a specific <see cref="StatTypes" /> in a specific 
		/// <see cref="StatCollectionTypes">collection</see>.
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <param name="value">the amount to set</param>
		public void SetValue(StatCollectionType collectionType, StatTypes statType, int value)
		{
			m_changeLock.Enter();

			try
			{
				m_stats[collectionType][statType] = (double)value;
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Gets the value for a specific <see cref="StatTypes" /> and a specific <see cref="StatCollectionType" />. 
		/// </summary>
		/// <param name="collectionType">the collection type</param>
		/// <param name="statType">the stat type</param>
		/// <returns>the value for the given collection type/stat type</returns>
		public double GetStat(StatCollectionType collectionType, StatTypes statType)
		{
			m_changeLock.Enter();

			try
			{
				return m_stats[collectionType][statType];
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Gets the modified (total/final) value of a specific <see cref="StatTypes" /> for the 
		/// <see cref="Unit">owner</see>.
		/// </summary>
		/// <param name="statType">the stat type</param>
		/// <returns>the modified value for the given <see cref="StatTypes" />; or <see cref="Double.MinValue" /> 
		/// if there was anexception when executing the calculator.</returns>
		public double GetModified(StatTypes statType)
		{
			m_changeLock.Enter();

			try
			{
				double staticVal = (m_stats[StatCollectionType.BaseModifier][statType] +
									 m_stats[StatCollectionType.PositiveModifier][statType] +
									 m_stats[StatCollectionType.NegativeModifier][statType]);

				double posPercentMod = staticVal * m_stats[StatCollectionType.PositiveMultiplier][statType];
				double negPercentMod = staticVal * m_stats[StatCollectionType.NegativeMultiplier][statType];

				return staticVal + posPercentMod + negPercentMod;
			}
			finally
			{
				m_changeLock.Exit();
			}
		}

		/// <summary>
		/// Manually flags a stat as changed.
		/// </summary>
		/// <param name="statType"></param>
		public void FlagChange(StatTypes statType)
		{
			m_flagLock.Enter();

			try
			{
				StatChange change = new StatChange(statType);

				if (!m_changeTracker.Contains(change))
				{
					m_changeTracker.Add(change);
					m_changes.Add(change);
				}
			}
			finally
			{
				m_flagLock.Exit();
			}
		}

		/// <summary>
		/// Synchonizes all the pending stat changes with the owner <see cref="Unit" />.
		/// </summary>
		public void SynchronizeChanges()
		{
			if (m_changes.Count == 0)
			{
				return;
			}

			LinkedList<StatChange> changes;

			m_changeLock.Enter();

			try
			{
				changes = new LinkedList<StatChange>(m_changes);
			}
			finally
			{
				m_flagLock.Exit();
			}

			foreach (StatChange change in changes)
			{
				change.CommitChange(m_owner);
			}
		}
	}
}