TownShop.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. public enum ShopType
  5. {
  6. Weapons,
  7. Armor,
  8. Potions,
  9. General,
  10. Magic,
  11. Tools
  12. }
  13. [System.Serializable]
  14. public class TownShop : TownBuilding
  15. {
  16. [Header("Shop Configuration")]
  17. public ShopType shopType = ShopType.General;
  18. public string shopkeeperName = "Merchant";
  19. public float profitMargin = 1.2f; // 20% markup on base item prices
  20. public float sellbackRate = 0.6f; // Player gets 60% of base price when selling
  21. [Header("Shop Inventory")]
  22. public List<Item> baseInventory = new List<Item>();
  23. public int maxInventorySize = 20;
  24. public bool restockDaily = true;
  25. [Header("Shop Filters")]
  26. public List<ItemType> acceptedItemTypes = new List<ItemType>();
  27. public List<ItemRarity> acceptedRarities = new List<ItemRarity>();
  28. public List<ShopInventoryItem> currentInventory = new List<ShopInventoryItem>();
  29. private System.DateTime lastRestockTime;
  30. protected override void Start()
  31. {
  32. base.Start();
  33. buildingType = BuildingType.Shop;
  34. InitializeShop();
  35. }
  36. private void InitializeShop()
  37. {
  38. // Set default accepted item types based on shop type
  39. if (acceptedItemTypes.Count == 0)
  40. {
  41. switch (shopType)
  42. {
  43. case ShopType.Weapons:
  44. acceptedItemTypes.Add(ItemType.Weapon);
  45. break;
  46. case ShopType.Armor:
  47. acceptedItemTypes.Add(ItemType.Armor);
  48. acceptedItemTypes.Add(ItemType.Accessory);
  49. break;
  50. case ShopType.Potions:
  51. acceptedItemTypes.Add(ItemType.Consumable);
  52. break;
  53. case ShopType.General:
  54. acceptedItemTypes.AddRange(System.Enum.GetValues(typeof(ItemType)).Cast<ItemType>());
  55. break;
  56. case ShopType.Tools:
  57. acceptedItemTypes.Add(ItemType.Tool);
  58. acceptedItemTypes.Add(ItemType.Miscellaneous);
  59. break;
  60. }
  61. }
  62. // Initialize inventory
  63. RestockInventory();
  64. // Set building colors based on shop type
  65. switch (shopType)
  66. {
  67. case ShopType.Weapons:
  68. buildingColor = new Color(0.8f, 0.2f, 0.2f); // Red
  69. break;
  70. case ShopType.Armor:
  71. buildingColor = new Color(0.2f, 0.2f, 0.8f); // Blue
  72. break;
  73. case ShopType.Potions:
  74. buildingColor = new Color(0.2f, 0.8f, 0.2f); // Green
  75. break;
  76. case ShopType.General:
  77. buildingColor = new Color(0.6f, 0.4f, 0.2f); // Brown
  78. break;
  79. default:
  80. buildingColor = Color.gray;
  81. break;
  82. }
  83. }
  84. public void RestockInventory()
  85. {
  86. currentInventory.Clear();
  87. // Add base inventory items with markup
  88. foreach (var item in baseInventory)
  89. {
  90. if (item != null)
  91. {
  92. var shopItem = new ShopInventoryItem(item, profitMargin);
  93. currentInventory.Add(shopItem);
  94. }
  95. }
  96. // Add some random items based on shop type
  97. AddRandomItems();
  98. lastRestockTime = System.DateTime.Now;
  99. Debug.Log($"{buildingName} restocked with {currentInventory.Count} items");
  100. }
  101. private void AddRandomItems()
  102. {
  103. // Get all items of appropriate types from Resources
  104. var allItems = Resources.LoadAll<Item>("Items");
  105. var filteredItems = allItems.Where(item =>
  106. acceptedItemTypes.Contains(item.itemType) &&
  107. (acceptedRarities.Count == 0 || acceptedRarities.Contains(item.rarity))
  108. ).ToList();
  109. // Add 3-5 random items
  110. int randomItemCount = Random.Range(3, 6);
  111. for (int i = 0; i < randomItemCount && currentInventory.Count < maxInventorySize; i++)
  112. {
  113. if (filteredItems.Count > 0)
  114. {
  115. var randomItem = filteredItems[Random.Range(0, filteredItems.Count)];
  116. var shopItem = new ShopInventoryItem(randomItem, profitMargin);
  117. currentInventory.Add(shopItem);
  118. }
  119. }
  120. }
  121. public List<ShopInventoryItem> GetInventory()
  122. {
  123. // Check if restock is needed
  124. if (restockDaily && (System.DateTime.Now - lastRestockTime).TotalDays >= 1)
  125. {
  126. RestockInventory();
  127. }
  128. return new List<ShopInventoryItem>(currentInventory);
  129. }
  130. public bool CanBuyItem(Item item)
  131. {
  132. return acceptedItemTypes.Contains(item.itemType) &&
  133. (acceptedRarities.Count == 0 || acceptedRarities.Contains(item.rarity));
  134. }
  135. public int GetSellPrice(Item item)
  136. {
  137. if (!CanBuyItem(item)) return 0;
  138. int basePrice = item.goldCost * 100 + item.silverCost * 10 + item.copperCost;
  139. return Mathf.RoundToInt(basePrice * sellbackRate);
  140. }
  141. public void SellItemToShop(Item item, TeamCharacter seller)
  142. {
  143. if (!CanBuyItem(item)) return;
  144. int sellPrice = GetSellPrice(item);
  145. // Convert copper to gold/silver/copper
  146. int gold = sellPrice / 100;
  147. sellPrice %= 100;
  148. int silver = sellPrice / 10;
  149. int copper = sellPrice % 10;
  150. // Add money to seller
  151. seller.gold += gold;
  152. seller.silver += silver;
  153. seller.copper += copper;
  154. // Normalize currency (convert excess copper/silver)
  155. if (seller.copper >= 10)
  156. {
  157. seller.silver += seller.copper / 10;
  158. seller.copper %= 10;
  159. }
  160. if (seller.silver >= 10)
  161. {
  162. seller.gold += seller.silver / 10;
  163. seller.silver %= 10;
  164. }
  165. Debug.Log($"Sold {item.itemName} to {buildingName} for {gold}g {silver}s {copper}c");
  166. }
  167. /// <summary>
  168. /// Update shop names after initialization (called by TownShopManager)
  169. /// </summary>
  170. public void UpdateNames(string newBuildingName, string newShopkeeperName)
  171. {
  172. this.buildingName = newBuildingName;
  173. this.shopkeeperName = newShopkeeperName;
  174. Debug.Log($"TownShop: Updated names to '{this.buildingName}' run by '{this.shopkeeperName}'");
  175. }
  176. }
  177. [System.Serializable]
  178. public class ShopInventoryItem
  179. {
  180. public Item item;
  181. public int markupGold;
  182. public int markupSilver;
  183. public int markupCopper;
  184. public int quantity;
  185. public bool isUnlimited;
  186. public ShopInventoryItem(Item baseItem, float profitMargin, int qty = 1, bool unlimited = false)
  187. {
  188. item = baseItem;
  189. quantity = qty;
  190. isUnlimited = unlimited;
  191. // Calculate markup prices
  192. int baseCopperPrice = baseItem.goldCost * 100 + baseItem.silverCost * 10 + baseItem.copperCost;
  193. int markupCopperPrice = Mathf.RoundToInt(baseCopperPrice * profitMargin);
  194. markupGold = markupCopperPrice / 100;
  195. markupCopperPrice %= 100;
  196. markupSilver = markupCopperPrice / 10;
  197. markupCopper = markupCopperPrice % 10;
  198. }
  199. public bool CanAfford(TeamCharacter customer)
  200. {
  201. if (customer == null || quantity <= 0) return false;
  202. int totalCopperCost = markupGold * 100 + markupSilver * 10 + markupCopper;
  203. int totalCopperAvailable = customer.gold * 100 + customer.silver * 10 + customer.copper;
  204. return totalCopperAvailable >= totalCopperCost;
  205. }
  206. public void Purchase(TeamCharacter customer)
  207. {
  208. if (!CanAfford(customer) || quantity <= 0) return;
  209. // Deduct money
  210. int totalCopperCost = markupGold * 100 + markupSilver * 10 + markupCopper;
  211. int totalCopperAvailable = customer.gold * 100 + customer.silver * 10 + customer.copper;
  212. int remainingCopper = totalCopperAvailable - totalCopperCost;
  213. customer.gold = remainingCopper / 100;
  214. remainingCopper %= 100;
  215. customer.silver = remainingCopper / 10;
  216. customer.copper = remainingCopper % 10;
  217. // Add item to customer inventory
  218. // This will be handled by the shop UI
  219. // Reduce quantity
  220. if (!isUnlimited)
  221. quantity--;
  222. Debug.Log($"Purchased {item.itemName} for {markupGold}g {markupSilver}s {markupCopper}c");
  223. }
  224. public string GetPriceString()
  225. {
  226. string price = "";
  227. if (markupGold > 0) price += $"{markupGold}g ";
  228. if (markupSilver > 0) price += $"{markupSilver}s ";
  229. if (markupCopper > 0) price += $"{markupCopper}c";
  230. return price.Trim();
  231. }
  232. }