123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using KairoEngine.Utility;
- using KairoEngine.Core;
- using KairoEngine.UI;
- using KairoEngine.Stockpiles;
- using Utils = KairoEngine.Utility.Utilities;
- using Sirenix.OdinInspector;
- namespace KairoEngine.Grids
- {
- [HideMonoScript]
- public class GridBuildingSystem : MonoBehaviour
- {
- public static GridBuildingSystem Instance;
- public Vector2Int gridSize = new Vector2Int(8,8);
- public float cellSize = 10f;
- public Vector3 gridPosition = new Vector3();
- public bool debug = false;
- public string stockpileOwner = "Player";
- public bool enableBuildingPlacement = true;
- public bool enableBuildingDestruction = false;
- [SerializeField] private Grid<GridObject> grid;
- //[OnInspectorInit("CreateGrid")]
- public List<PlacedObjectType> placeObjectTypeList;
- private PlacedObjectType placedObjectType;
- private PlacedObjectType.Dir dir = PlacedObjectType.Dir.Down;
- public List<PlacedObject> placedObjects = new List<PlacedObject>();
- public LayerMask layerMask;
- public static bool buildingToolAvailable
- {
- get;
- private set;
- }
- public static bool buildingDestructionToolAvailable
- {
- get;
- private set;
- }
-
- void Awake()
- {
- CreateGrid();
- placedObjectType = placeObjectTypeList[0];
- if(Instance == null) Instance = this;
- else Destroy(gameObject);
- }
- void Update()
- {
- Vector3 worldPos = Utils.GetMouseWorldPosition(layerMask.value);
- if(!MouseInputUIBlocker.BlockedByUI && grid.IsPositionInsideGrid(worldPos))
- {
- if(enableBuildingPlacement)
- {
- buildingToolAvailable = true;
- if(Input.GetKeyDown(KeyCode.R)) RotatePlacebableObject();
- if(Input.GetMouseButtonDown(0)) PlaceObjectInGrid(worldPos);
- }
- else buildingToolAvailable = false;
- if(enableBuildingDestruction)
- {
- buildingDestructionToolAvailable = true;
- if(Input.GetMouseButtonDown(0)) RemoveObjectFromGrid(worldPos);
- }
- else buildingDestructionToolAvailable = false;
- }
- }
- public bool IsGridCreated() => grid != null;
- public void CreateGrid()
- {
- if(grid == null)
- {
- grid = new Grid<GridObject>(gridSize.x, gridSize.y, cellSize, gridPosition,
- (Grid<GridObject> g, int x, int y) => new GridObject(g, x, 0, y), GridPlane.XZ, debug);
- }
- }
- public void ClearGrid() => grid = null;
- private void DeselectObjectType()
- {
- placedObjectType = null;
- RefreshSelectedObjectType();
- }
- private void RefreshSelectedObjectType() => GenericEvents.Trigger("OnSelectedChanged");
- public Vector2Int GetGridPosition(Vector3 worldPosition) {
- if(grid == null) return new Vector2Int();
- grid.GetGridPosition(worldPosition, out int x, out int z);
- return new Vector2Int(x, z);
- }
- public Vector3 GetPositionFromGrid(int x, int y) => grid != null ? grid.GetWorldPosition(x, y) : new Vector3();
- public Vector3 GetGridPositionOffset() => gridPosition - transform.position;
- public PlacedObjectType.Dir GetDir() => dir;
- public Vector3 GetCellSize()
- {
- if(grid == null) return new Vector3(cellSize, cellSize, cellSize);
- switch(grid.GetGridPlane())
- {
- default:
- case GridPlane.XY:
- return new Vector3(cellSize, cellSize, 0);
- case GridPlane.XZ:
- return new Vector3(cellSize, 0, cellSize);
- case GridPlane.YZ:
- return new Vector3(0, cellSize, cellSize);
- }
- }
- public Vector3 GetMouseWorldSnappedPosition() {
- Vector3 mousePosition = Utils.GetMouseWorldPosition(layerMask.value);
- if(grid == null) return new Vector3();
- grid.GetGridPosition(mousePosition, out int x, out int z);
- if (placedObjectType != null) {
- Vector2Int rotationOffset = placedObjectType.GetRotationOffset(dir);
- Vector3 placedObjectWorldPosition = grid.GetWorldPosition(x, z) + new Vector3(rotationOffset.x, 0, rotationOffset.y) * grid.GetCellSize();
- return placedObjectWorldPosition;
- } else {
- return mousePosition;
- }
- }
- public Quaternion GetPlacedObjectRotation() {
- if (placedObjectType != null) {
- return Quaternion.Euler(0, placedObjectType.GetRotationAngle(dir), 0);
- } else {
- return Quaternion.identity;
- }
- }
- public PlacedObjectType GetPlacedObjectTypeSO() => placedObjectType;
- public bool CanPlaceObject(int x, int z) => placedObjectType.CanPlaceObject(grid, x, z, dir);
- public void PlaceObjectInGrid(Vector3 worldPos)
- {
- grid.GetGridPosition(Utils.GetMouseWorldPosition(layerMask.value), out int x, out int z);
- PlaceObjectInGrid(x, z);
- }
- public void PlaceObjectInGrid(int x, int z)
- {
- PlaceObjectInGrid(x, z, placedObjectType, dir);
- }
- public void PlaceObjectInGrid(int x, int z, PlacedObjectType placedObjectType, PlacedObjectType.Dir dir, bool checkResources = true,
- bool checkPlace = true, bool playSound = true, bool destructable = true)
- {
- Vector3 worldPos = grid.GetWorldPosition(x, z);
- if(CanPlaceObject(x, z) || checkPlace == false)
- {
- if(HasResources() || checkResources == false)
- {
- Vector2Int rotationOffset = placedObjectType.GetRotationOffset(dir);
- Vector3 pos = grid.GetWorldPosition(x + rotationOffset.x, z + rotationOffset.y);
- PlacedObject placedObject = PlacedObject.Create(pos, new Vector2Int(x, z), dir, placedObjectType, playSound);
- placedObject.destructable = destructable;
- placedObjects.Add(placedObject);
- List<Vector2Int> gridPositionList = placedObjectType.GetGridPositionList(new Vector2Int(x, z), dir);
- foreach (var gridPosition in gridPositionList)
- {
- grid.GetObject(gridPosition.x, gridPosition.y).SetPlacedObject(placedObject);
- }
- if(checkResources)
- {
- GenericEvents.Trigger("BuildingPlaced", placedObjectType.title);
- StockpileManager.instance.RemoveResources(stockpileOwner, placedObjectType.cost);
- for (int i = 0; i < placedObjectType.cost.Count; i++)
- {
- var stock = placedObjectType.cost[i];
- float delay = 350f * i;
- Timer.Execute(delay, () => {
- string resource = stock.stockpileType.title.ToLower();
- if(resource == "mineral") resource = "minerals";
- string message = $"- {stock.ammount} <sprite name={resource}>";
- FloatingMessageEvents.Send(message, GetCurrentPlacebleObjectCenter(pos), 5, 1.3f, 20f);
- });
- }
- }
- }
- else
- {
- Vector3 finalPos = GetCurrentPlacebleObjectCenter(worldPos);
- DrawResourceErrorMessage(finalPos);
- GenericEvents.Trigger("CannotBuildError");
- }
- }
- else
- {
- Vector3 finalPos = new Vector3(worldPos.x, worldPos.y + 10, worldPos.z);
- DrawRulesetErrorMessage(finalPos, x, z);
- GenericEvents.Trigger("CannotBuildError");
- }
- }
- public void RemoveObjectFromGrid(Vector3 worldPos)
- {
- GridObject gridObject = grid.GetObject(worldPos);
- RemoveObjectFromGrid(gridObject);
- }
- public void RemoveObjectFromGrid(int x, int z)
- {
- GridObject gridObject = grid.GetObject(x, z);
- RemoveObjectFromGrid(gridObject);
- }
- public void RemoveObjectFromGrid(GridObject gridObject)
- {
- if(gridObject == null) return;
- PlacedObject placedObject = gridObject.GetPlacedObject();
- if(placedObject != null)
- {
- Vector3 worldPos = grid.GetWorldPosition(gridObject.GetPosition().x, gridObject.GetPosition().z);
- Vector3 finalPos = GetCurrentPlacebleObjectCenter(worldPos);
- if(!placedObject.placedObjectType.isDestructable)
- {
- FloatingMessageEvents.Send("Indestructable!", finalPos, 5, 2f, 20f);
- return;
- }
- if(!placedObject.destructable)
- {
- FloatingMessageEvents.Send("Cannot remove initial building", finalPos, 5, 2f, 20f);
- return;
- }
- GenericEvents.Trigger("BuildingRemoved", placedObject.placedObjectType.title, worldPos);
- placedObjects.Remove(placedObject);
- placedObject.DestroySelf();
- List<Vector2Int> gridPositionList = placedObject.GetGridPositionList();
- foreach (var gridPosition in gridPositionList)
- {
- grid.GetObject(gridPosition.x, gridPosition.y).ClearPlacedObject();
- }
-
- }
- }
- public void RotatePlacebableObject()
- {
- dir = PlacedObjectType.GetNextDir(dir);
- Vector3 pos = Utils.GetMouseWorldPosition(layerMask.value);
- Vector3 finalPos = new Vector3(pos.x, pos.y + 10, pos.z);
- //Utilities.CreateWorldTextPopup(null, "" + dir, pos, 18, Color.white, finalPos, 1.2f, true);
- FloatingMessageEvents.Send("" + dir, GetCurrentPlacebleObjectCenter(pos), 5, 1.2f, 20f);
- }
- public void ChangeSelectedPlacebleObject(int index)
- {
- placedObjectType = placeObjectTypeList[index];
- RefreshSelectedObjectType();
- }
- public void ChangeSelectedPlacebleObject(PlacedObjectType newPlacedObjectType)
- {
- placedObjectType = newPlacedObjectType;
- RefreshSelectedObjectType();
- }
- public bool IsPositionInsideGrid(Vector2Int gridPos)
- {
- if(grid == null) return false;
- return grid.IsPositionInsideGrid(gridPos);
- }
- public bool IsPositionInsideGrid(Vector3 worldPos)
- {
- if(grid == null) return false;
- return grid.IsPositionInsideGrid(worldPos);
- }
- public PlacedObject GetPlacedObjectInGrid(Vector2Int gridPosition)
- {
- if(grid == null) return null;
- GridObject gridObject = grid.GetObject(gridPosition.x, gridPosition.y);
- if(gridObject == null) return null;
- PlacedObject placedObject = gridObject.GetPlacedObject();
- return placedObject;
- }
- public bool HasResources() => StockpileManager.instance.HasResources(stockpileOwner, placedObjectType.cost);
- public bool HasResource(KairoEngine.Stockpiles.Stockpile stockpile) => StockpileManager.instance.HasResource(stockpileOwner, stockpile);
- public void RemovePlacedObjects()
- {
- for (int i = 0; i < placedObjects.Count; i++)
- {
- Destroy(placedObjects[i].gameObject);
- }
- placedObjects.Clear();
- }
- public Vector3 GetCurrentPlacebleObjectCenter(Vector3 worldPos)
- {
- if(dir == PlacedObjectType.Dir.Down || dir == PlacedObjectType.Dir.Up)
- {
- return new Vector3(
- worldPos.x + (placedObjectType.width * cellSize)/2,
- worldPos.y + 1,
- worldPos.z + (placedObjectType.height * cellSize)/2);
- }
- else
- {
- return new Vector3(
- worldPos.x + (placedObjectType.height * cellSize)/2,
- worldPos.y + 1,
- worldPos.z + (placedObjectType.width * cellSize)/2);
- }
-
- }
- private void DrawResourceErrorMessage(Vector3 finalPos)
- {
- List<string> sprites = new List<string>();
- bool missingResources = false;
- for (int i = 0; i < placedObjectType.cost.Count; i++)
- {
- if(!HasResource(placedObjectType.cost[i]))
- {
- sprites.Add(placedObjectType.cost[i].stockpileType.spriteText);
- missingResources = true;
- }
- }
- if(missingResources == false) return;
- switch (sprites.Count)
- {
- case 1:
- FloatingMessageEvents.Send($"Not enought {sprites[0]}", finalPos, 5, 1.5f, 20f);
- break;
- case 2:
- FloatingMessageEvents.Send($"Not enought {sprites[0]} and {sprites[1]}", finalPos, 5, 1.5f, 20f);
- break;
- case 3:
- FloatingMessageEvents.Send($"Not enought {sprites[0]}, {sprites[1]} and {sprites[2]}", finalPos, 5, 1.5f, 20f);
- break;
- case 4:
- FloatingMessageEvents.Send($"Not enought {sprites[0]}, {sprites[1]}, {sprites[2]} and {sprites[3]}", finalPos, 5, 1.5f, 20f);
- break;
- default:
- FloatingMessageEvents.Send("Not enought resources", finalPos, 5, 2f, 20f);
- break;
- }
- }
- private void DrawRulesetErrorMessage(Vector3 finalPos, int x, int y)
- {
- List<PlaceableObjectRule> brokenRules = placedObjectType.GetRulesetError(grid, x, y, dir);
- for (int i = 0; i < brokenRules.Count; i++)
- {
- string message = "";
- switch (brokenRules[i].GetRule())
- {
- case PlaceableObjectRule.Rule.EmptyCell:
- message = $"Area must be empty!";
- break;
- case PlaceableObjectRule.Rule.Connection:
- message = $"Invalid connection";
- //message += $" of type {brokenRules[i].GetConnector()}!";
- break;
- case PlaceableObjectRule.Rule.CellOcupied:
- message = $"Must be placed on a {brokenRules[i].GetTargetObject().title}";
- break;
- case PlaceableObjectRule.Rule.AdjacentCellOcupied:
- message = $"Adjacent cell need to be of type {brokenRules[i].GetTargetObject().title}";
- break;
- case PlaceableObjectRule.Rule.AdjacentEmptyCell:
- message = $"Adjacent cell must be empty";
- break;
- case PlaceableObjectRule.Rule.CellInRadius:
- message = $"No {brokenRules[i].GetTargetObject().title} in {brokenRules[i].GetRadius()} radius";
- break;
- case PlaceableObjectRule.Rule.EmptyArea:
- message = $"Area must be empty!";
- break;
- default:
- break;
- }
- Timer.Execute(350f * i, () => {
- FloatingMessageEvents.Send(message, finalPos, 5, 2f, 20f);
- });
- }
- Timer.Execute(350f * brokenRules.Count, () => {
- DrawResourceErrorMessage(finalPos);
- });
-
- }
- }
- }
|