PageRenderTime 97ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/DemoGame.Server/World/Map/Entities/Items/Inventory/CharacterInventory.cs

http://netgore.googlecode.com/
C# | 299 lines | 168 code | 44 blank | 87 comment | 31 complexity | 3a01258c03419b6e29cee189336dc375 MD5 | raw file
Possible License(s): MIT
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using System.Reflection;
  5. using DemoGame.Server.Queries;
  6. using log4net;
  7. using NetGore;
  8. using NetGore.Db;
  9. namespace DemoGame.Server
  10. {
  11. /// <summary>
  12. /// Base class for an inventory for a <see cref="Character"/>.
  13. /// </summary>
  14. public abstract class CharacterInventory : InventoryBase<ItemEntity>
  15. {
  16. static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  17. readonly Character _character;
  18. bool _isLoading;
  19. /// <summary>
  20. /// Initializes a new instance of the <see cref="CharacterInventory"/> class.
  21. /// </summary>
  22. /// <param name="character">The <see cref="Character"/> the inventory belongs to.</param>
  23. /// <exception cref="ArgumentNullException"><paramref name="character" /> is <c>null</c>.</exception>
  24. protected CharacterInventory(Character character) : base(GameData.MaxInventorySize)
  25. {
  26. if (character == null)
  27. throw new ArgumentNullException("character");
  28. _character = character;
  29. }
  30. /// <summary>
  31. /// Gets the Character that this Inventory belongs to.
  32. /// </summary>
  33. public Character Character
  34. {
  35. get { return _character; }
  36. }
  37. /// <summary>
  38. /// Gets the <see cref="IDbController"/> used by this CharacterInventory.
  39. /// </summary>
  40. public IDbController DbController
  41. {
  42. get { return Character.DbController; }
  43. }
  44. /// <summary>
  45. /// Gets if the state of this <see cref="CharacterInventory"/> is persistent.
  46. /// </summary>
  47. public bool IsPersistent
  48. {
  49. get { return Character.IsPersistent; }
  50. }
  51. /// <summary>
  52. /// Decrements the amount of the item at the given <paramref name="slot"/>.
  53. /// </summary>
  54. /// <param name="slot">The slot of the inventory item who's amount is to be decremented.</param>
  55. public void DecreaseItemAmount(InventorySlot slot)
  56. {
  57. // Get the ItemEntity
  58. var item = this[slot];
  59. if (item == null)
  60. {
  61. const string errmsg = "Tried to decrease amount of inventory slot `{0}`, but it contains no item.";
  62. Debug.Fail(string.Format(errmsg, slot));
  63. if (log.IsWarnEnabled)
  64. log.WarnFormat(errmsg, slot);
  65. return;
  66. }
  67. // Check for a valid amount
  68. if (item.Amount == 0)
  69. {
  70. // If amount is already 0, we will show a warning but still remove the item
  71. const string errmsg = "Item in slot `{0}` already contains an amount of 0.";
  72. Debug.Fail(string.Format(errmsg, slot));
  73. if (log.IsWarnEnabled)
  74. log.WarnFormat(errmsg, slot);
  75. // Remove the item
  76. ClearSlot(slot, true);
  77. }
  78. else
  79. {
  80. // Decrease the amount
  81. item.Amount--;
  82. // Remove the item if it ran out
  83. if (item.Amount <= 0)
  84. ClearSlot(slot, true);
  85. }
  86. }
  87. /// <summary>
  88. /// When overridden in the derived class, handles when this object is disposed.
  89. /// </summary>
  90. /// <param name="disposeManaged">True if dispose was called directly; false if this object was garbage collected.</param>
  91. protected override void Dispose(bool disposeManaged)
  92. {
  93. base.Dispose(disposeManaged);
  94. // If not persistent, destroy every item in the collection
  95. if (!IsPersistent)
  96. RemoveAll(true);
  97. }
  98. /// <summary>
  99. /// Makes the Character drop an item from their Inventory.
  100. /// </summary>
  101. /// <param name="slot">Slot of the item to drop.</param>
  102. /// <returns>True if the item was successfully dropped, else false.</returns>
  103. public bool Drop(InventorySlot slot)
  104. {
  105. // Get the item to drop
  106. var dropItem = this[slot];
  107. // Check for an invalid item
  108. if (dropItem == null)
  109. {
  110. const string errmsg = "Could not drop item since no item exists at slot `{0}`.";
  111. if (log.IsWarnEnabled)
  112. log.WarnFormat(errmsg, slot);
  113. return false;
  114. }
  115. // Remove the item from the inventory
  116. RemoveAt(slot, false);
  117. // Drop the item
  118. Character.DropItem(dropItem);
  119. return true;
  120. }
  121. /// <summary>
  122. /// Makes the Character drop an item from their Inventory.
  123. /// </summary>
  124. /// <param name="slot">Slot of the item to drop.</param>
  125. /// <param name="amount">The maximum amount of the item to drop.</param>
  126. /// <returns>True if the item was successfully dropped, else false.</returns>
  127. public bool Drop(InventorySlot slot, byte amount)
  128. {
  129. // Get the item to drop
  130. var dropItem = this[slot];
  131. // Check for an invalid item
  132. if (dropItem == null)
  133. {
  134. const string errmsg = "Could not drop item since no item exists at slot `{0}`.";
  135. if (log.IsWarnEnabled)
  136. log.WarnFormat(errmsg, slot);
  137. return false;
  138. }
  139. // If the amount to drop is greater than or equal to the amount available, drop it all
  140. if (dropItem.Amount <= amount)
  141. {
  142. // Remove the item from the inventory
  143. RemoveAt(slot, false);
  144. // Drop the item
  145. Character.DropItem(dropItem);
  146. }
  147. else
  148. {
  149. // Only drop some of the item
  150. var dropPart = dropItem.Split(amount);
  151. // Drop the portion of the item
  152. Character.DropItem(dropPart);
  153. }
  154. return true;
  155. }
  156. /// <summary>
  157. /// When overridden in the derived class, performs additional processing to handle an inventory slot
  158. /// changing. This is only called when the object references changes, not when any part of the object
  159. /// (such as the Item's amount) changes. It is guarenteed that if <paramref name="newItem"/> is null,
  160. /// <paramref name="oldItem"/> will not be, and vise versa. Both will never be null or non-null.
  161. /// </summary>
  162. /// <param name="slot">Slot that the change took place in.</param>
  163. /// <param name="newItem">The ItemEntity that was added to the <paramref name="slot"/>.</param>
  164. /// <param name="oldItem">The ItemEntity that used to be in the <paramref name="slot"/>,
  165. /// or null if the slot used to be empty.</param>
  166. protected override void HandleSlotChanged(InventorySlot slot, ItemEntity newItem, ItemEntity oldItem)
  167. {
  168. Debug.Assert(oldItem != newItem);
  169. if (newItem != null)
  170. newItem.IsPersistent = IsPersistent;
  171. // Slot change logic is only needed for when persistent
  172. if (!IsPersistent)
  173. return;
  174. // Stop listening for changes on the item that was removed
  175. if (oldItem != null)
  176. {
  177. oldItem.GraphicOrAmountChanged -= ItemGraphicOrAmountChangeHandler;
  178. }
  179. // Listen to the item for changes on the item that was added
  180. if (newItem != null)
  181. {
  182. newItem.GraphicOrAmountChanged -= ItemGraphicOrAmountChangeHandler;
  183. newItem.GraphicOrAmountChanged += ItemGraphicOrAmountChangeHandler;
  184. }
  185. // Do not update the database when we are loading the collection
  186. if (!_isLoading)
  187. {
  188. // Update the inventory slot in the database
  189. if (newItem == null)
  190. DbController.GetQuery<DeleteCharacterInventoryItemQuery>().Execute(Character.ID, slot);
  191. else
  192. DbController.GetQuery<InsertCharacterInventoryItemQuery>().Execute(Character.ID, newItem.ID, slot);
  193. }
  194. // Prepare the slot for updating
  195. SendSlotUpdate(slot);
  196. }
  197. /// <summary>
  198. /// Handles when an item in the UserInventory has changed the amount or graphic, and notifies the
  199. /// InventoryUpdater to handle the change.
  200. /// </summary>
  201. /// <param name="sender">Item that has changed.</param>
  202. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  203. void ItemGraphicOrAmountChangeHandler(ItemEntity sender, EventArgs e)
  204. {
  205. Debug.Assert(IsPersistent, "This should NEVER be called when IsPersistent == false!");
  206. InventorySlot slot;
  207. // Try to get the slot
  208. try
  209. {
  210. slot = GetSlot(sender);
  211. }
  212. catch (ArgumentException ex)
  213. {
  214. log.Warn(string.Format("Failed to get the inventory slot of item `{0}`", sender), ex);
  215. return;
  216. }
  217. // Set the slot as changed
  218. SendSlotUpdate(slot);
  219. }
  220. /// <summary>
  221. /// Loads the Character's inventory items from the database.
  222. /// </summary>
  223. public void Load()
  224. {
  225. _isLoading = true;
  226. var queryResults = DbController.GetQuery<SelectCharacterInventoryItemsQuery>().Execute(Character.ID);
  227. foreach (var values in queryResults)
  228. {
  229. // Make sure no item is already in the slot... just in case
  230. if (this[values.Key] != null)
  231. {
  232. const string errmsg =
  233. "Character `{0}` already had an item in slot `{1}` ({2})." +
  234. " It is going to have to be disposed to make room for the newest loaded item `{3}`." +
  235. " If this ever happens, its likely a problem.";
  236. var item = this[values.Key];
  237. if (log.IsErrorEnabled)
  238. log.ErrorFormat(errmsg, Character, values.Key, item, values.Value);
  239. Debug.Fail(string.Format(errmsg, Character, values.Key, item, values.Value));
  240. item.Dispose();
  241. }
  242. // Set the item into the slot
  243. this[values.Key] = new ItemEntity(values.Value);
  244. }
  245. _isLoading = false;
  246. }
  247. /// <summary>
  248. /// When overridden in the derived class, notifies the Client that a slot in the Inventory has changed.
  249. /// </summary>
  250. /// <param name="slot">The slot that changed.</param>
  251. protected virtual void SendSlotUpdate(InventorySlot slot)
  252. {
  253. }
  254. }
  255. }