using System; using System.Collections.Generic; using System.Diagnostics; using CIGEnums; using SUISS.Core; using UnityEngine; namespace SUISSEngine { public class Builder : MonoBehaviour { //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public event Builder.TileBuilt OnTileBuild; //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public event Builder.TileDestroyed OnTileDestroyed; protected virtual void Awake() { this._isBuilding = false; this._currentTile = null; this._isBuildingRoad = false; this._currentRoadPrefab = null; this._currentRoadType = -1; this._currentRoadTiles = new List(); this._removedRoadTiles = new List>(); this._originalIndex = GridIndex.invalid; this._tilesHidden = false; this._roadsHidden = false; } protected virtual void OnGridDeserialized() { } private void OnDestroy() { this.OnTileBuild = null; this.OnTileDestroyed = null; if (SingletonMonobehaviour.IsAvailable) { SingletonMonobehaviour.Instance.EnableInteractionRequest(this._hideOverlayRequest); SingletonMonobehaviour.Instance.EnableInteractionRequest(this._usingOverlayRequest); } } public bool isBuilding { get { return this._isBuilding; } } public GridTile currentTile { get { return this._currentTile; } } public bool isBuildingRoad { get { return this._isBuildingRoad; } } public int currentRoadType { get { return this._currentRoadType; } } public virtual bool TilesHidden { get { return this._tilesHidden; } set { if (value != this._tilesHidden) { this._tilesHidden = value; if (this.grid != null) { GridSize size = this.grid.Size; for (int i = 0; i < size.v; i++) { for (int j = 0; j < size.u; j++) { GridTile tile = this.grid[j, i].Tile; if (tile != null && tile.GetComponent() == null && tile.GetComponent() == null) { tile.hidden = this._tilesHidden; } } } if (this._tilesHidden) { SingletonMonobehaviour.Instance.DisableInteractionRequest(this._hideOverlayRequest); } else { SingletonMonobehaviour.Instance.EnableInteractionRequest(this._hideOverlayRequest); } } } } } public virtual bool roadsHidden { get { return this._roadsHidden; } set { if (value != this._roadsHidden) { this._roadsHidden = value; if (this.grid != null) { GridSize size = this.grid.Size; for (int i = 0; i < size.v; i++) { for (int j = 0; j < size.u; j++) { GridTile tile = this.grid[j, i].Tile; if (tile != null && tile.GetComponent() != null) { tile.hidden = this._roadsHidden; } } } } } } } public void BeginBuild(GameObject prefab) { this.BeginBuild(prefab, GridIndex.invalid, false); } public void BeginBuild(GameObject prefab, bool mirrored) { this.BeginBuild(prefab, GridIndex.invalid, mirrored); } public void BeginBuild(GameObject prefab, GridIndex indexHint) { this.BeginBuild(prefab, indexHint, false); } public void BeginBuild(GameObject prefab, GridIndex indexHint, bool mirrored) { if (this._isBuilding) { UnityEngine.Debug.LogWarning("Can't begin building because this Builder is already building."); return; } if (this.grid == null) { UnityEngine.Debug.LogError("Can't begin building because no grid could be found."); return; } GameObject gameObject = UnityEngine.Object.Instantiate(prefab); GridTile component = gameObject.GetComponent(); if (component == null) { UnityEngine.Debug.LogError("Can't build " + prefab + " because it has no GridTile component."); UnityEngine.Object.Destroy(gameObject); return; } gameObject.name = prefab.name; GridSize size = component.size; if (mirrored) { size = new GridSize(size.v, size.u); } if (indexHint.isInvalid) { indexHint = this.grid.ConvertIslandCoordinateToGridIndex(this.island.islandCamera.transform.position); if (indexHint.isInvalid) { indexHint.u = this.grid.Size.u / 2; indexHint.v = this.grid.Size.v / 2; } } indexHint.u += size.u / 2; if (indexHint.u >= this.grid.Size.u) { indexHint.u = this.grid.Size.u - 1; } indexHint.v += size.v / 2; if (indexHint.v >= this.grid.Size.v) { indexHint.v = this.grid.Size.v - 1; } GridIndex index = indexHint; if (!this.CanBuildTile(component, this.grid, index, mirrored, false)) { float num = (float)(this.grid.Size.u + this.grid.Size.v); bool flag = false; for (int i = 1; i < this.grid.Size.u + this.grid.Size.v; i++) { GridIndex gridIndex; for (int j = -i; j <= i; j++) { gridIndex.u = indexHint.u + j; gridIndex.v = indexHint.v - i; float num2 = Mathf.Sqrt((float)((indexHint.u - gridIndex.u) * (indexHint.u - gridIndex.u) + (indexHint.v - gridIndex.v) * (indexHint.v - gridIndex.v))); if (num2 < num && this.CanBuildTile(component, this.grid, gridIndex, mirrored, false)) { num = num2; index = gridIndex; flag = true; } gridIndex.v = indexHint.v + i; num2 = Mathf.Sqrt((float)((indexHint.u - gridIndex.u) * (indexHint.u - gridIndex.u) + (indexHint.v - gridIndex.v) * (indexHint.v - gridIndex.v))); if (num2 < num && this.CanBuildTile(component, this.grid, gridIndex, mirrored, false)) { num = num2; index = gridIndex; flag = true; } } for (int k = -i + 1; k <= i - 1; k++) { gridIndex.v = indexHint.v + k; gridIndex.u = indexHint.u - i; float num2 = Mathf.Sqrt((float)((indexHint.u - gridIndex.u) * (indexHint.u - gridIndex.u) + (indexHint.v - gridIndex.v) * (indexHint.v - gridIndex.v))); if (num2 < num && this.CanBuildTile(component, this.grid, gridIndex, mirrored, false)) { num = num2; index = gridIndex; flag = true; } gridIndex.u = indexHint.u + i; num2 = Mathf.Sqrt((float)((indexHint.u - gridIndex.u) * (indexHint.u - gridIndex.u) + (indexHint.v - gridIndex.v) * (indexHint.v - gridIndex.v))); if (num2 < num && this.CanBuildTile(component, this.grid, gridIndex, mirrored, false)) { num = num2; index = gridIndex; flag = true; } } if (flag) { break; } } } this._isBuilding = true; this._currentTile = component; component.status = GridTile.Status.Preview; this.UpdateCurrentTile(this._currentTile, index, mirrored); if (this.island.input != null) { this.island.input.CenterViewOn(this._currentTile.gameObject, true); } SingletonMonobehaviour.Instance.DisableInteractionRequest(this._usingOverlayRequest); } public void BeginMove(GameObject clone) { if (this._isBuilding) { UnityEngine.Debug.LogWarning("Can't moving building because this Builder is already building."); return; } if (this.grid == null) { UnityEngine.Debug.LogError("Can't begin moving because no grid could be found."); return; } GridTile component = clone.GetComponent(); if (component == null) { UnityEngine.Debug.LogError("Can't move " + clone + " because it has no GridTile component."); UnityEngine.Object.Destroy(clone); return; } GridIndex index = component.index; this.WillDestroyTile(component, index, component.size); this.grid.RemoveAtIndex(index, component.size, false); if (this.TilesHidden) { component.hidden = false; } this._originalIndex = index; this._isBuilding = true; this._currentTile = component; component.status = GridTile.Status.Moving; this.UpdateCurrentTile(this._currentTile, index, component.mirrored); this.DidDestroyTile(component, index, component.size); if (this.island.input != null) { this.island.input.CenterViewOn(this._currentTile.gameObject, true); } SingletonMonobehaviour.Instance.DisableInteractionRequest(this._usingOverlayRequest); } public void UpdateBuild(GridIndex newIndex) { if (!this._isBuilding) { return; } this.UpdateBuild(newIndex, this._currentTile.mirrored); } public void UpdateBuild(bool mirrored) { if (!this._isBuilding) { return; } this.UpdateBuild(this._currentTile.index, mirrored); } public void UpdateBuild(GridIndex newIndex, bool mirrored) { if (!this._isBuilding) { return; } if (newIndex.isInvalid) { newIndex = this._currentTile.index; } if (mirrored && !this._currentTile.canMirror) { mirrored = false; } this.UpdateCurrentTile(this._currentTile, newIndex, mirrored); } public void CancelBuild() { if (!this._isBuilding) { return; } SingletonMonobehaviour.Instance.EnableInteractionRequest(this._usingOverlayRequest); bool flag = true; if (this._currentTile.status == GridTile.Status.Moving && this.BuildAt(this._currentTile, this._originalIndex, this._currentTile.mirrored, false)) { flag = false; } if (flag) { this.DestroyTile(this._currentTile); } this._currentTile = null; this._isBuilding = false; this._originalIndex = GridIndex.invalid; } public GridTile FinishBuild() { if (!this._isBuilding) { return null; } SingletonMonobehaviour.Instance.EnableInteractionRequest(this._usingOverlayRequest); if (this.BuildAt(this._currentTile, this._currentTile.index, this._currentTile.mirrored, false)) { GridTile currentTile = this._currentTile; this._currentTile = null; this._isBuilding = false; this._originalIndex = GridIndex.invalid; return currentTile; } this.CancelBuild(); return null; } public void BeginRoad(GameObject prefab) { if (this._isBuildingRoad) { UnityEngine.Debug.LogWarning("Can't begin building roads because this Builder is already building roads."); return; } GameObject gameObject = UnityEngine.Object.Instantiate(prefab); Road component = gameObject.GetComponent(); if (component == null) { UnityEngine.Object.Destroy(gameObject); UnityEngine.Debug.LogWarning("Can't begin building road " + prefab + " because it has no Road component."); return; } this._currentRoadType = component.type; UnityEngine.Object.Destroy(gameObject); this._currentRoadPrefab = prefab; this._currentRoadTiles.Clear(); this._isBuildingRoad = true; VehicleManager vehicleManager = this.island.vehicleManager; if (vehicleManager != null) { vehicleManager.WillBeginBuildingRoads(this._currentRoadType); } SingletonMonobehaviour.Instance.DisableInteractionRequest(this._usingOverlayRequest); } public void UpdateRoad(GridIndex index) { if (!this._isBuildingRoad) { return; } if (this.grid == null) { return; } if (index.isInvalid || index.u >= this.grid.Size.u || index.v >= this.grid.Size.v) { return; } GameObject gameObject = this.createRoadObject(this._currentRoadPrefab); if (gameObject == null) { return; } GridTile component = gameObject.GetComponent(); Road component2 = component.GetComponent(); GridElement gridElement = this.grid[index.u, index.v]; if (gridElement.Tile == null) { if (!this.BuildAt(component, index, false, false)) { UnityEngine.Object.Destroy(component.gameObject); } else { this._currentRoadTiles.Add(component); SingletonMonobehaviour.Instance.PlayClip(Clip.ButtonClick); } } else if (gridElement.Tile.GetComponent() != null) { GridTile tile = gridElement.Tile; if (component2.canBuildBridgeOver(tile.GetComponent().type)) { GameObject bridgePrefab = component2.getBridgePrefab(tile.GetComponent().type); GameObject gameObject2 = this.createRoadObject(bridgePrefab); if (gameObject2 != null) { this.grid.RemoveAtIndex(index, tile.currentSize, false); tile.gameObject.SetActive(false); this._removedRoadTiles.Add(new KeyValuePair(tile, index)); GridTile component3 = gameObject2.GetComponent(); this.BuildAt(component3, index, false, true); this._currentRoadTiles.Add(component3); SingletonMonobehaviour.Instance.PlayClip(Clip.ButtonClick); } } component.status = GridTile.Status.Destroyed; UnityEngine.Object.Destroy(component.gameObject); } else { component.status = GridTile.Status.Destroyed; UnityEngine.Object.Destroy(component.gameObject); } } private GameObject createRoadObject(GameObject prefab) { GameObject gameObject = UnityEngine.Object.Instantiate(prefab); GridTile component = gameObject.GetComponent(); if (component == null) { UnityEngine.Debug.LogError("Can't build " + prefab + " because it has no GridTile component."); UnityEngine.Object.Destroy(gameObject); return null; } Road component2 = component.GetComponent(); if (component2 == null) { UnityEngine.Debug.LogError("Can't build " + prefab + " because it has no Road component."); component.status = GridTile.Status.Destroyed; UnityEngine.Object.Destroy(gameObject); return null; } gameObject.name = prefab.name; return gameObject; } public void CancelRoad() { if (!this._isBuildingRoad) { return; } SingletonMonobehaviour.Instance.EnableInteractionRequest(this._usingOverlayRequest); foreach (GridTile tile in this._currentRoadTiles) { this.DestroyTile(tile); } foreach (KeyValuePair keyValuePair in this._removedRoadTiles) { if (this.grid == null) { return; } if (keyValuePair.Key != null) { keyValuePair.Key.gameObject.SetActive(true); this.grid.AddTileAt(keyValuePair.Key, keyValuePair.Value, true); this.NotifyRoadsOfRoadChange(keyValuePair.Key); } else { UnityEngine.Debug.LogWarning("tile.Key == null"); } } VehicleManager vehicleManager = this.island.vehicleManager; if (vehicleManager != null) { vehicleManager.DidFinishBuildingRoads(this._currentRoadType); } this._currentRoadPrefab = null; this._currentRoadType = -1; this._currentRoadTiles.Clear(); this._removedRoadTiles.Clear(); this._isBuildingRoad = false; } public void FinishRoad() { if (!this._isBuildingRoad) { return; } SingletonMonobehaviour.Instance.EnableInteractionRequest(this._usingOverlayRequest); VehicleManager vehicleManager = this.island.vehicleManager; if (vehicleManager != null) { vehicleManager.DidFinishBuildingRoads(this._currentRoadType); } foreach (KeyValuePair keyValuePair in this._removedRoadTiles) { if (keyValuePair.Key != null) { keyValuePair.Key.status = GridTile.Status.Destroyed; UnityEngine.Object.Destroy(keyValuePair.Key.gameObject); } else { UnityEngine.Debug.LogWarning("tile.Key == null"); } } this._currentRoadPrefab = null; this._currentRoadType = -1; this._currentRoadTiles.Clear(); this._removedRoadTiles.Clear(); this._isBuildingRoad = false; } public bool BuildAt(GameObject prefab, GridIndex index, bool mirrored, bool forced) { GameObject gameObject = UnityEngine.Object.Instantiate(prefab); GridTile component = gameObject.GetComponent(); if (component == null) { UnityEngine.Debug.LogError("Can't build " + prefab + " because it has no GridTile component."); UnityEngine.Object.Destroy(gameObject); return false; } gameObject.name = prefab.name; bool flag = this.BuildAt(component, index, mirrored, forced); if (!flag && component.status == GridTile.Status.Moving) { flag = this.BuildAt(component, this._originalIndex, mirrored, forced); } if (!flag) { this.DestroyTile(component); } return flag; } public bool BuildAt(GridTile tile, GridIndex index, bool mirrored, bool forced) { if (this.grid == null) { UnityEngine.Debug.LogError("Can't build anything because no grid could be found."); return false; } if (!this.CanBuildTile(tile, this.grid, index, mirrored, forced)) { return false; } GridSize size = tile.size; if (mirrored) { size = new GridSize(size.v, size.u); } Road component = tile.GetComponent(); VehicleManager vehicleManager = this.island.vehicleManager; this.WillBuildTile(tile, index, size, mirrored); tile.transform.parent = this.grid.transform; tile.index = index; if (component == null) { tile.hidden = this._tilesHidden; } else { tile.hidden = this._roadsHidden; } tile.mirrored = mirrored; if (tile.status == GridTile.Status.Moving) { this.grid.MoveTileFrom(tile, this._originalIndex, true); } else { this.grid.AddTileAt(tile, index, true); } if (component != null && vehicleManager != null) { vehicleManager.DidBuildRoadAt(index, component); } tile.UpdateTransform(); if (component == null && vehicleManager != null) { vehicleManager.DidBuildTileAt(index, tile); } SpriteRenderer component2 = tile.GetComponent(); if (component2 != null) { component2.color = Color.white; } if (this.OnTileBuild != null) { this.OnTileBuild(tile); } tile.status = GridTile.Status.Created; this.NotifyRoadsOfRoadChange(tile); this.DidBuildTile(tile, index, size, mirrored); return true; } public void DestroyTile(GridTile tile) { if (tile == null) { return; } GridIndex index = tile.index; GridSize currentSize = tile.currentSize; this.WillDestroyTile(tile, index, currentSize); if (tile.status != GridTile.Status.Preview) { GridElement element = tile.element; if (element != null) { IsometricGrid isometricGrid = element.Grid; if (isometricGrid != null) { Road component = tile.GetComponent(); VehicleManager vehicleManager = this.island.vehicleManager; if (component == null && vehicleManager != null) { vehicleManager.WillDestroyTileAt(element.Index, tile); } if (component != null && vehicleManager != null) { vehicleManager.WillDestroyRoadAt(element.Index, component); } isometricGrid.RemoveAtIndex(element.Index, currentSize, true); if (component != null) { this.NotifyRoadsOfRoadChange(tile); } } else { element.Tile = null; } } } GridTile.Status status = tile.status; tile.status = GridTile.Status.Destroyed; if (this.OnTileDestroyed != null) { this.OnTileDestroyed(tile, status); } UnityEngine.Object.Destroy(tile.gameObject); this.DidDestroyTile(tile, index, currentSize); } public bool CanBuild() { return this.CanBuildTile(this._currentTile, this._currentTile.grid, this._currentTile.index, false, false); } protected virtual bool CanBuildTile(GridTile tile, IsometricGrid grid, GridIndex index, bool mirrored, bool forced) { if (index.isInvalid || index.u >= grid.Size.u || index.v >= grid.Size.v) { return false; } if (mirrored && !tile.canMirror) { return false; } GridSize size = tile.size; if (mirrored) { size = new GridSize(size.v, size.u); } if (size.u > index.u + 1 || size.v > index.v + 1) { return false; } for (int i = index.v; i > index.v - size.v; i--) { for (int j = index.u; j > index.u - size.u; j--) { GridElement gridElement = grid[j, i]; if (gridElement.Tile != null) { if (!forced || !(gridElement.Tile.GetComponent() == null)) { return false; } UnityEngine.Debug.LogWarning(string.Format("In order to build {0} at {1}, we need to remove {2} at ({3},{4})", new object[] { tile.name, index, gridElement.Tile.name, j, i })); this.DestroyTile(gridElement.Tile); } if (!forced && !this.CanBuildTileOnElement(tile, grid, gridElement)) { return false; } } } return true; } protected virtual bool IsElementTypeCompatible(int type, int required) { return type == required; } protected virtual bool CanBuildTileOnElement(GridTile tile, IsometricGrid grid, GridElement element) { return this.IsElementTypeCompatible(element.Type, tile.requiredGridType); } protected void UpdateCurrentTile(GridTile tile, GridIndex index, bool mirrored) { if (this.grid == null) { return; } if (index.u < tile.size.u - 1) { index.u = tile.size.u - 1; } if (index.u >= this.grid.Size.u) { index.u = this.grid.Size.u - 1; } if (index.v < tile.size.v - 1) { index.v = tile.size.v - 1; } if (index.v >= this.grid.Size.v) { index.v = tile.size.v - 1; } tile.transform.parent = this.grid.transform; tile.index = index; tile.mirrored = mirrored; tile.UpdateTransform(); Vector3 localPosition = tile.transform.localPosition; localPosition.z = this.grid.zNear; tile.transform.localPosition = localPosition; SpriteRenderer component = tile.GetComponent(); if (component != null) { Color color; if (this.CanBuildTile(tile, this.grid, index, tile.mirrored, false)) { color = Color.white; } else { color = Color.red; } color.a *= 0.5f; component.color = color; } } protected virtual void WillBuildTile(GridTile tile, GridIndex index, GridSize size, bool mirrored) { } protected virtual void DidBuildTile(GridTile tile, GridIndex index, GridSize size, bool mirrored) { } protected virtual void WillDestroyTile(GridTile tile, GridIndex index, GridSize size) { } protected virtual void DidDestroyTile(GridTile tile, GridIndex index, GridSize size) { } private static void TryUpdateRoadAt(Road original, IsometricGrid grid, GridIndex index) { if (index.isInvalid || index.u >= grid.Size.u || index.v >= grid.Size.v) { return; } GridTile tile = grid[index].Tile; if (tile != null) { Road component = tile.GetComponent(); if (component != null && Road.RoadsMatch(component.type, original.type, true)) { component.UpdateSprite(); } } } private void NotifyBuildingsOfRoadChange(GridTile roadTile) { if (roadTile != null && roadTile.grid != null) { foreach (GridTile gridTile in roadTile.grid.GetNeighbourTiles(roadTile)) { Building component = gridTile.GetComponent(); if (component != null && component.checkForRoad) { component.OnAdjacentRoadsChanged(roadTile); } } } } private void NotifyRoadsOfRoadChange(GridTile tile) { if (this.grid == null) { return; } Road component = tile.GetComponent(); if (component != null) { component.UpdateSprite(); GridIndex index = tile.index; index.v--; Builder.TryUpdateRoadAt(component, this.grid, index); index.v++; index.u++; Builder.TryUpdateRoadAt(component, this.grid, index); index.u--; index.v++; Builder.TryUpdateRoadAt(component, this.grid, index); index.v--; index.u--; Builder.TryUpdateRoadAt(component, this.grid, index); index.u++; this.NotifyBuildingsOfRoadChange(tile); } } [SelfReference] public IsometricIsland island; [ChildReference] public IsometricGrid grid; private bool _isBuilding; private GridTile _currentTile; private bool _isBuildingRoad; private GameObject _currentRoadPrefab; private int _currentRoadType; private List _currentRoadTiles; private List> _removedRoadTiles; private GridIndex _originalIndex; private bool _tilesHidden; private bool _roadsHidden; private object _hideOverlayRequest = new object(); private object _usingOverlayRequest = new object(); public delegate void TileBuilt(GridTile tile); public delegate void TileDestroyed(GridTile tile, GridTile.Status priorStatus); } }