using System.Collections; using System.Collections.Generic; using UnityEngine; using KairoEngine.Core; using KairoEngine.Core.GameActions; using KairoEngine.Stockpiles; using Sirenix.OdinInspector; using KairoEngine.GameTools.Selectables; using KairoEngine.SFX; using KairoEngine.UI.Encyclopedia; namespace KairoEngine.Grids { [CreateAssetMenu(fileName = "PlaceObjectType", menuName = "KairoEngine/BuildingSystem/PlaceObjectType")] [HideMonoScript] public class PlacedObjectType : ScriptableObject, IEncyclopediaArticle { public static Dir GetNextDir(Dir dir) { switch (dir) { default: case Dir.Down: return Dir.Left; case Dir.Left: return Dir.Up; case Dir.Up: return Dir.Right; case Dir.Right: return Dir.Down; } } public enum Dir { Down, Up, Left, Right } [BoxGroup("Properties", showLabel: false)] public string title; [BoxGroup("Properties")] public string category; [BoxGroup("Properties")] public Transform prefab; [BoxGroup("Properties")] public Transform visual; [BoxGroup("Properties")] public Sprite image; [BoxGroup("Properties")] public Sprite icon; [BoxGroup("Properties")] public SFXClip createdSound; [BoxGroup("Properties")] public SFXClip removedSound; [BoxGroup("Properties")] public bool isDestructable = true; [BoxGroup("Properties"), HorizontalGroup("Properties/size"), LabelText("Width/Height")] public int width; [BoxGroup("Properties"), HorizontalGroup("Properties/size", 0.3f), HideLabel] public int height; [BoxGroup("Properties"), TextArea(2, 8), HideLabel, PropertySpace(4, 4)] public string description; [PropertySpace(1, 1)] public List cost = new List(); [PropertySpace(1, 1)] public List connectors = new List(); [PropertySpace(1, 1)] public List effectAreas = new List(); [FoldoutGroup("Rules"), PropertySpace(2, 2)] [InfoBox("Rules for positioning the building in the game world", InfoMessageType.Info)] public ConditionType rulesetCondition; [ListDrawerSettings(HideAddButton = false, HideRemoveButton = false, DraggableItems = false, Expanded = true, ShowPaging = false, ShowItemCount = true)] [PropertySpace(2, 2)] [FoldoutGroup("Rules")] public List ruleset = new List(); [FoldoutGroup("Functionality")] [HideLabel, InlineProperty, OnInspectorInit("SetupContext"), PropertySpace(2, 4)] public GameActionContext context = new GameActionContext(); [FoldoutGroup("Functionality")] [TabGroup("Functionality/Triggers", "On Action"), PropertySpace(1, 2)] [InfoBox("Actions that can be triggered by the player or game events", InfoMessageType.Info)] [LabelText("Actions")] public List objectActions; [FoldoutGroup("Functionality")] [TabGroup("Functionality/Triggers", "On Create"), InlineProperty, HideLabel, PropertySpace(1, 2)] [InfoBox("Execute actions when the building is placed", InfoMessageType.Info)] public GameActionsController onCreateController; [FoldoutGroup("Functionality")] [TabGroup("Functionality/Triggers", "On Update"), InlineProperty, HideLabel, PropertySpace(1, 2)] [InfoBox("Executes every frame while the building is active", InfoMessageType.Info)] public GameActionsController onUpdateController; [FoldoutGroup("Functionality")] [TabGroup("Functionality/Triggers", "On Remove"), InlineProperty, HideLabel, PropertySpace(1, 2)] [InfoBox("Executes when the building is removed", InfoMessageType.Info)] public GameActionsController onRemoveController; public int GetRotationAngle(Dir dir) { switch (dir) { default: case Dir.Down: return 0; case Dir.Left: return 90; case Dir.Up: return 180; case Dir.Right: return 270; } } public Vector2Int GetRotationOffset(Dir dir) { switch (dir) { default: case Dir.Down: return new Vector2Int(0, 0); case Dir.Left: return new Vector2Int(0, width); case Dir.Up: return new Vector2Int(width, height); case Dir.Right: return new Vector2Int(height, 0); } } public Vector2Int GetRotationOffset(Dir dir, int width, int height) { switch (dir) { default: case Dir.Down: return new Vector2Int(0, 0); case Dir.Left: return new Vector2Int(0, width); case Dir.Up: return new Vector2Int(width, height); case Dir.Right: return new Vector2Int(height, 0); } } public List GetGridPositionList(Vector2Int offset, Dir dir) { List gridPositionList = new List(); switch (dir) { default: case Dir.Down: case Dir.Up: for(int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { gridPositionList.Add(offset + new Vector2Int(x, y)); } } break; case Dir.Left: case Dir.Right: for (int x = 0; x < height; x++) { for (int y = 0; y < width; y++) { gridPositionList.Add(offset + new Vector2Int(x, y)); } } break; } return gridPositionList; } public bool CanPlaceObject(Grid grid, Vector3 worldPos, PlacedObjectType.Dir dir) { grid.GetGridPosition(worldPos, out int x, out int y); return CanPlaceObject(grid, x, y, dir); } public bool CanPlaceObject(Grid grid, int x, int y, PlacedObjectType.Dir dir) { return EvaluateRuleset(grid, x, y, dir); } public bool EvaluateRuleset(Grid grid, int x, int y, PlacedObjectType.Dir dir) { List results = new List(); for (int i = 0; i < ruleset.Count; i++) { results.Add(ruleset[i].Evaluate(grid, this, x, y, dir)); } if(rulesetCondition == ConditionType.AND) { foreach (var value in results) { if(value == false) return false; } return true; } else { foreach (var value in results) { if(value == true) return true; } return false; } } public List GetRulesetError(Grid grid, int x, int y, PlacedObjectType.Dir dir) { List brokenRules = new List(); for (int i = 0; i < ruleset.Count; i++) { for (int a = 0; a < ruleset[i].rules.Count; a++) { bool result = ruleset[i].rules[a].Evaluate(grid, this, x, y, dir); if(result == false) brokenRules.Add(ruleset[i].rules[a]); } } return brokenRules; } public Vector2Int GetConnectorPositionOffset(int index, PlacedObjectType.Dir dir) { PlaceableObjectConnector connector = connectors[index]; switch (dir) { default: case Dir.Down: return connector.position; case Dir.Left: return new Vector2Int(connector.position.y, (connector.position.x * -1) + width - 1); case Dir.Up: return new Vector2Int((connector.position.x * -1) + width - 1, (connector.position.y * -1) + height - 1); case Dir.Right: return new Vector2Int((connector.position.y * -1) + height - 1, connector.position.x); } } public Vector2Int GetConnectorTargetPositionOffset(int index, PlacedObjectType.Dir objectDir) { var targetDir = connectors[index].dir; return GetPositionOffsetFromDirection(objectDir, targetDir); } public Vector2Int GetPositionOffsetFromDirection(PlacedObjectType.Dir objectDir, PlacedObjectType.Dir targetDir) { switch (objectDir) { default: case Dir.Down: switch (targetDir) { default: case Dir.Down: return new Vector2Int(0, -1); case Dir.Left: return new Vector2Int(-1, 0); case Dir.Up: return new Vector2Int(0, 1); case Dir.Right: return new Vector2Int(1, 0); } case Dir.Left: switch (targetDir) { default: case Dir.Down: return new Vector2Int(-1, 0); case Dir.Left: return new Vector2Int(0, 1); case Dir.Up: return new Vector2Int(1, 0); case Dir.Right: return new Vector2Int(0, -1); } case Dir.Up: switch (targetDir) { default: case Dir.Down: return new Vector2Int(0, 1); case Dir.Left: return new Vector2Int(1, 0); case Dir.Up: return new Vector2Int(0, -1); case Dir.Right: return new Vector2Int(-1, 0); } case Dir.Right: switch (targetDir) { default: case Dir.Down: return new Vector2Int(1, 0); case Dir.Left: return new Vector2Int(0, -1); case Dir.Up: return new Vector2Int(-1, 0); case Dir.Right: return new Vector2Int(0, 1); } } } private void SetupContext() { if(context == null) return; onCreateController.context = context; onUpdateController.context = context; onRemoveController.context = context; for (int i = 0; i < objectActions.Count; i++) { if(objectActions[i] != null) objectActions[i].actions.context = context; } if(!context.HasVariable("Building GameObject")) { var variable = new GameActionContextGameObject(); variable.name = "Building GameObject"; variable.value = null; variable.canEdit = false; context.variables.Add(variable); } } public Vector2Int OffsetValue(Vector2Int offset, Dir dir) { switch (dir) { default: case Dir.Down: return new Vector2Int(offset.x, offset.y); case Dir.Left: return new Vector2Int(offset.y, offset.x * -1); case Dir.Up: return new Vector2Int(offset.x * -1, offset.y * -1); case Dir.Right: return new Vector2Int(offset.y * -1, offset.x); } } public EncyclopediaArticle GetArticle() { EncyclopediaArticle article = new EncyclopediaArticle(); article.id = title; article.title = title; article.icon = icon; article.description = description; article.content.Add("title", title); article.content.Add("category", category); article.content.Add("description", description); article.integers.Add("width", width); article.integers.Add("height", height); article.images.Add("icon", icon); article.images.Add("image", image); article.integers.Add("cost-slots", cost.Count); for (int i = 0; i < cost.Count; i++) { article.content.Add($"cost-{i}-type", cost[i].stockpileType.title); article.images.Add($"cost-{i}-icon", cost[i].stockpileType.icon); article.integers.Add($"cost-{i}-value", cost[i].ammount); } return article; } } }