PlacedObjectType.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using KairoEngine.Core;
  5. using KairoEngine.Core.GameActions;
  6. using KairoEngine.Stockpiles;
  7. using Sirenix.OdinInspector;
  8. using KairoEngine.GameTools.Selectables;
  9. using KairoEngine.SFX;
  10. using KairoEngine.UI.Encyclopedia;
  11. namespace KairoEngine.Grids
  12. {
  13. [CreateAssetMenu(fileName = "PlaceObjectType", menuName = "KairoEngine/BuildingSystem/PlaceObjectType")]
  14. [HideMonoScript]
  15. public class PlacedObjectType : ScriptableObject, IEncyclopediaArticle
  16. {
  17. public static Dir GetNextDir(Dir dir)
  18. {
  19. switch (dir)
  20. {
  21. default:
  22. case Dir.Down: return Dir.Left;
  23. case Dir.Left: return Dir.Up;
  24. case Dir.Up: return Dir.Right;
  25. case Dir.Right: return Dir.Down;
  26. }
  27. }
  28. public enum Dir
  29. {
  30. Down,
  31. Up,
  32. Left,
  33. Right
  34. }
  35. [BoxGroup("Properties", showLabel: false)] public string title;
  36. [BoxGroup("Properties")] public string category;
  37. [BoxGroup("Properties")] public Transform prefab;
  38. [BoxGroup("Properties")] public Transform visual;
  39. [BoxGroup("Properties")] public Sprite image;
  40. [BoxGroup("Properties")] public Sprite icon;
  41. [BoxGroup("Properties")] public SFXClip createdSound;
  42. [BoxGroup("Properties")] public SFXClip removedSound;
  43. [BoxGroup("Properties")] public bool isDestructable = true;
  44. [BoxGroup("Properties"), HorizontalGroup("Properties/size"), LabelText("Width/Height")] public int width;
  45. [BoxGroup("Properties"), HorizontalGroup("Properties/size", 0.3f), HideLabel] public int height;
  46. [BoxGroup("Properties"), TextArea(2, 8), HideLabel, PropertySpace(4, 4)] public string description;
  47. [PropertySpace(1, 1)] public List<KairoEngine.Stockpiles.Stockpile> cost = new List<KairoEngine.Stockpiles.Stockpile>();
  48. [PropertySpace(1, 1)] public List<PlaceableObjectConnector> connectors = new List<PlaceableObjectConnector>();
  49. [PropertySpace(1, 1)] public List<BuildingEffectArea> effectAreas = new List<BuildingEffectArea>();
  50. [FoldoutGroup("Rules"), PropertySpace(2, 2)]
  51. [InfoBox("Rules for positioning the building in the game world", InfoMessageType.Info)]
  52. public ConditionType rulesetCondition;
  53. [ListDrawerSettings(HideAddButton = false, HideRemoveButton = false, DraggableItems = false, Expanded = true, ShowPaging = false, ShowItemCount = true)]
  54. [PropertySpace(2, 2)]
  55. [FoldoutGroup("Rules")]
  56. public List<PlaceableObjectRuleGroup> ruleset = new List<PlaceableObjectRuleGroup>();
  57. [FoldoutGroup("Functionality")]
  58. [HideLabel, InlineProperty, OnInspectorInit("SetupContext"), PropertySpace(2, 4)]
  59. public GameActionContext context = new GameActionContext();
  60. [FoldoutGroup("Functionality")]
  61. [TabGroup("Functionality/Triggers", "On Action"), PropertySpace(1, 2)]
  62. [InfoBox("Actions that can be triggered by the player or game events", InfoMessageType.Info)]
  63. [LabelText("Actions")]
  64. public List<SelectableObjectAction> objectActions;
  65. [FoldoutGroup("Functionality")]
  66. [TabGroup("Functionality/Triggers", "On Create"), InlineProperty, HideLabel, PropertySpace(1, 2)]
  67. [InfoBox("Execute actions when the building is placed", InfoMessageType.Info)]
  68. public GameActionsController onCreateController;
  69. [FoldoutGroup("Functionality")]
  70. [TabGroup("Functionality/Triggers", "On Update"), InlineProperty, HideLabel, PropertySpace(1, 2)]
  71. [InfoBox("Executes every frame while the building is active", InfoMessageType.Info)]
  72. public GameActionsController onUpdateController;
  73. [FoldoutGroup("Functionality")]
  74. [TabGroup("Functionality/Triggers", "On Remove"), InlineProperty, HideLabel, PropertySpace(1, 2)]
  75. [InfoBox("Executes when the building is removed", InfoMessageType.Info)]
  76. public GameActionsController onRemoveController;
  77. public int GetRotationAngle(Dir dir)
  78. {
  79. switch (dir)
  80. {
  81. default:
  82. case Dir.Down: return 0;
  83. case Dir.Left: return 90;
  84. case Dir.Up: return 180;
  85. case Dir.Right: return 270;
  86. }
  87. }
  88. public Vector2Int GetRotationOffset(Dir dir)
  89. {
  90. switch (dir)
  91. {
  92. default:
  93. case Dir.Down: return new Vector2Int(0, 0);
  94. case Dir.Left: return new Vector2Int(0, width);
  95. case Dir.Up: return new Vector2Int(width, height);
  96. case Dir.Right: return new Vector2Int(height, 0);
  97. }
  98. }
  99. public Vector2Int GetRotationOffset(Dir dir, int width, int height)
  100. {
  101. switch (dir)
  102. {
  103. default:
  104. case Dir.Down: return new Vector2Int(0, 0);
  105. case Dir.Left: return new Vector2Int(0, width);
  106. case Dir.Up: return new Vector2Int(width, height);
  107. case Dir.Right: return new Vector2Int(height, 0);
  108. }
  109. }
  110. public List<Vector2Int> GetGridPositionList(Vector2Int offset, Dir dir)
  111. {
  112. List<Vector2Int> gridPositionList = new List<Vector2Int>();
  113. switch (dir)
  114. {
  115. default:
  116. case Dir.Down:
  117. case Dir.Up:
  118. for(int x = 0; x < width; x++)
  119. {
  120. for (int y = 0; y < height; y++)
  121. {
  122. gridPositionList.Add(offset + new Vector2Int(x, y));
  123. }
  124. }
  125. break;
  126. case Dir.Left:
  127. case Dir.Right:
  128. for (int x = 0; x < height; x++)
  129. {
  130. for (int y = 0; y < width; y++)
  131. {
  132. gridPositionList.Add(offset + new Vector2Int(x, y));
  133. }
  134. }
  135. break;
  136. }
  137. return gridPositionList;
  138. }
  139. public bool CanPlaceObject(Grid<GridObject> grid, Vector3 worldPos, PlacedObjectType.Dir dir)
  140. {
  141. grid.GetGridPosition(worldPos, out int x, out int y);
  142. return CanPlaceObject(grid, x, y, dir);
  143. }
  144. public bool CanPlaceObject(Grid<GridObject> grid, int x, int y, PlacedObjectType.Dir dir)
  145. {
  146. return EvaluateRuleset(grid, x, y, dir);
  147. }
  148. public bool EvaluateRuleset(Grid<GridObject> grid, int x, int y, PlacedObjectType.Dir dir)
  149. {
  150. List<bool> results = new List<bool>();
  151. for (int i = 0; i < ruleset.Count; i++)
  152. {
  153. results.Add(ruleset[i].Evaluate(grid, this, x, y, dir));
  154. }
  155. if(rulesetCondition == ConditionType.AND)
  156. {
  157. foreach (var value in results)
  158. {
  159. if(value == false) return false;
  160. }
  161. return true;
  162. }
  163. else
  164. {
  165. foreach (var value in results)
  166. {
  167. if(value == true) return true;
  168. }
  169. return false;
  170. }
  171. }
  172. public List<PlaceableObjectRule> GetRulesetError(Grid<GridObject> grid, int x, int y, PlacedObjectType.Dir dir)
  173. {
  174. List<PlaceableObjectRule> brokenRules = new List<PlaceableObjectRule>();
  175. for (int i = 0; i < ruleset.Count; i++)
  176. {
  177. for (int a = 0; a < ruleset[i].rules.Count; a++)
  178. {
  179. bool result = ruleset[i].rules[a].Evaluate(grid, this, x, y, dir);
  180. if(result == false) brokenRules.Add(ruleset[i].rules[a]);
  181. }
  182. }
  183. return brokenRules;
  184. }
  185. public Vector2Int GetConnectorPositionOffset(int index, PlacedObjectType.Dir dir)
  186. {
  187. PlaceableObjectConnector connector = connectors[index];
  188. switch (dir)
  189. {
  190. default:
  191. case Dir.Down: return connector.position;
  192. case Dir.Left: return new Vector2Int(connector.position.y, (connector.position.x * -1) + width - 1);
  193. case Dir.Up: return new Vector2Int((connector.position.x * -1) + width - 1, (connector.position.y * -1) + height - 1);
  194. case Dir.Right: return new Vector2Int((connector.position.y * -1) + height - 1, connector.position.x);
  195. }
  196. }
  197. public Vector2Int GetConnectorTargetPositionOffset(int index, PlacedObjectType.Dir objectDir)
  198. {
  199. var targetDir = connectors[index].dir;
  200. return GetPositionOffsetFromDirection(objectDir, targetDir);
  201. }
  202. public Vector2Int GetPositionOffsetFromDirection(PlacedObjectType.Dir objectDir, PlacedObjectType.Dir targetDir)
  203. {
  204. switch (objectDir)
  205. {
  206. default:
  207. case Dir.Down:
  208. switch (targetDir)
  209. {
  210. default:
  211. case Dir.Down: return new Vector2Int(0, -1);
  212. case Dir.Left: return new Vector2Int(-1, 0);
  213. case Dir.Up: return new Vector2Int(0, 1);
  214. case Dir.Right: return new Vector2Int(1, 0);
  215. }
  216. case Dir.Left:
  217. switch (targetDir)
  218. {
  219. default:
  220. case Dir.Down: return new Vector2Int(-1, 0);
  221. case Dir.Left: return new Vector2Int(0, 1);
  222. case Dir.Up: return new Vector2Int(1, 0);
  223. case Dir.Right: return new Vector2Int(0, -1);
  224. }
  225. case Dir.Up:
  226. switch (targetDir)
  227. {
  228. default:
  229. case Dir.Down: return new Vector2Int(0, 1);
  230. case Dir.Left: return new Vector2Int(1, 0);
  231. case Dir.Up: return new Vector2Int(0, -1);
  232. case Dir.Right: return new Vector2Int(-1, 0);
  233. }
  234. case Dir.Right:
  235. switch (targetDir)
  236. {
  237. default:
  238. case Dir.Down: return new Vector2Int(1, 0);
  239. case Dir.Left: return new Vector2Int(0, -1);
  240. case Dir.Up: return new Vector2Int(-1, 0);
  241. case Dir.Right: return new Vector2Int(0, 1);
  242. }
  243. }
  244. }
  245. private void SetupContext()
  246. {
  247. if(context == null) return;
  248. onCreateController.context = context;
  249. onUpdateController.context = context;
  250. onRemoveController.context = context;
  251. for (int i = 0; i < objectActions.Count; i++)
  252. {
  253. if(objectActions[i] != null) objectActions[i].actions.context = context;
  254. }
  255. if(!context.HasVariable("Building GameObject"))
  256. {
  257. var variable = new GameActionContextGameObject();
  258. variable.name = "Building GameObject";
  259. variable.value = null;
  260. variable.canEdit = false;
  261. context.variables.Add(variable);
  262. }
  263. }
  264. public Vector2Int OffsetValue(Vector2Int offset, Dir dir)
  265. {
  266. switch (dir)
  267. {
  268. default:
  269. case Dir.Down: return new Vector2Int(offset.x, offset.y);
  270. case Dir.Left: return new Vector2Int(offset.y, offset.x * -1);
  271. case Dir.Up: return new Vector2Int(offset.x * -1, offset.y * -1);
  272. case Dir.Right: return new Vector2Int(offset.y * -1, offset.x);
  273. }
  274. }
  275. public EncyclopediaArticle GetArticle()
  276. {
  277. EncyclopediaArticle article = new EncyclopediaArticle();
  278. article.id = title;
  279. article.title = title;
  280. article.icon = icon;
  281. article.description = description;
  282. article.content.Add("title", title);
  283. article.content.Add("category", category);
  284. article.content.Add("description", description);
  285. article.integers.Add("width", width);
  286. article.integers.Add("height", height);
  287. article.images.Add("icon", icon);
  288. article.images.Add("image", image);
  289. article.integers.Add("cost-slots", cost.Count);
  290. for (int i = 0; i < cost.Count; i++)
  291. {
  292. article.content.Add($"cost-{i}-type", cost[i].stockpileType.title);
  293. article.images.Add($"cost-{i}-icon", cost[i].stockpileType.icon);
  294. article.integers.Add($"cost-{i}-value", cost[i].ammount);
  295. }
  296. return article;
  297. }
  298. }
  299. }