using System; using System.Collections.Generic; using CIGEnums; using SUISS.Core; using SUISS.Scheduling; using SUISS.Storage; using SUISSEngine; using UnityEngine; public class CIGExpansions : MonoBehaviour { private void Awake() { foreach (CIGExpansionDefinition cigexpansionDefinition in this.blockDefinitions) { if (cigexpansionDefinition.initiallyUnlocked) { this._initiallyUnlockedBlocks++; } } this.constants = UnityEngine.Object.FindObjectOfType(); if (this.constants == null) { UnityEngine.Debug.LogWarning(string.Format("{0}: unable to find a CIGGameConstants object", base.name)); } if (this.blockSizeU <= 0 || this.blockSizeV <= 0) { throw new ArgumentException("Block size must be at least 1x1.", (this.blockSizeU > 0) ? "blockSizeV" : "blockSizeU"); } if (this.grid == null) { UnityEngine.Debug.LogError(string.Format("{0}::Grid: No grid.", base.name)); return; } } private void OnGridDeserialized() { this.CreateBlocks(); this.CalculateUnlockedTileCountByType(); this.NewBlockUnlocked = new Action(SingletonMonobehaviour.Instance.OnNewBlockUnlocked); SingletonMonobehaviour.Instance.ExecuteNextFrame(base.gameObject, delegate () { this.PlaceBuySigns(); }); } public int NumberOfInitiallyUnlockedBlocks { get; protected set; } public int GoldCostCounter { get { Dictionary root = Storage.Get(StorageLifecycle.Game).Root; if (root.ContainsKey(this.GoldCostCounterKey)) { return (int)root[this.GoldCostCounterKey]; } return 0; } protected set { Dictionary root = Storage.Get(StorageLifecycle.Game).Root; root[this.GoldCostCounterKey] = value; } } public int BlocksU { get { return this.blocksU; } } public int BlocksV { get { return this.blocksV; } } public int UnlockedBlocks { get { return this.unlockedBlocks; } private set { this.unlockedBlocks = value; } } public int UnlockedBlocksWithGold { get { return this.unlockedBlocksWithGold; } private set { this.unlockedBlocksWithGold = value; } } public bool ExpansionsAreOnSale { get { return false; } } public decimal BaseRoiExpansion { get { if (this.constants != null) { return this.constants.baseRoiExpansion; } return 0.75m; } } public decimal ExtraRoiExpansion { get { if (this.constants != null) { return this.constants.extraRoiExpansion; } return 0.22m; } } public decimal MinProfitPerHourForCashCost { get { if (this.constants != null) { return this.constants.minProfitPerHourForCashCost; } return 100000m; } } public decimal BaseGoldCost { get { if (this.constants != null) { return this.constants.baseGoldCost; } return 25m; } } public decimal ExtraGoldCost { get { if (this.constants != null) { return this.constants.extraGoldCost; } return 5m; } } public bool HaveExpansionsLeft { get { return this.unlockableBlocks.Count > 0; } } public decimal ProfitPerHour { get { if (this.profitPerHour == -1m) { this.CalculatePriceVariables(); } if (SingletonMonobehaviour.IsAvailable) { this.profitPerHour = SingletonMonobehaviour.Instance.GlobalProfitPerHour.GetValue("Cash"); } return this.profitPerHour; } private set { this.profitPerHour = value; } } public int UsedElements { get { if (this.usedElems == -1) { this.CalculatePriceVariables(); } return this.usedElems; } private set { this.usedElems = value; } } public int UnusedElements { get { if (this.unusedElems == -1) { this.CalculatePriceVariables(); } return this.unusedElems; } private set { this.unusedElems = value; } } public int GetUnlockedElementCount(int type) { if (this.unlockedTileCountByType.ContainsKey(type)) { return this.unlockedTileCountByType[type]; } return 0; } public CIGExpansions.ExpansionBlock GetBlock(int u, int v) { if (u < 0 || u >= this.blocksU || v < 0 || v >= this.blocksV) { return null; } return this.blocks[u, v]; } public bool HasBuySign(GridIndex index) { CIGExpansions.ExpansionBlock blockForIndex = this.GetBlockForIndex(index); return blockForIndex != null && blockForIndex.CanUnlock; } public IEnumerable AllBlocks { get { if (this.blocks == null && !this.CreateBlocks()) { UnityEngine.Debug.LogWarning("Couldn't create expansion blocks."); yield break; } CIGExpansions.ExpansionBlock[,] array = this.blocks; int length = array.GetLength(0); int length2 = array.GetLength(1); for (int i = 0; i < length; i++) { for (int j = 0; j < length2; j++) { CIGExpansions.ExpansionBlock b = array[i, j]; yield return b; } } yield break; } } public void DidUnlockTileWithType(int type) { if (this.unlockedTileCountByType.ContainsKey(type)) { (this.unlockedTileCountByType)[type] = this.unlockedTileCountByType[type] + 1; } else { this.unlockedTileCountByType.Add(type, 1); } } public CIGExpansions.ExpansionBlock GetBlockForIndex(GridIndex index) { if (this.blocks == null && !this.CreateBlocks()) { UnityEngine.Debug.LogWarning("Couldn't create expansion blocks."); return null; } int num = index.u / this.blockSizeU; if (num < 0 || num >= this.blocksU) { if (index.u >= this.grid.Size.u) { UnityEngine.Debug.LogWarning("Out of bounds"); } return null; } int num2 = index.v / this.blockSizeV; if (num2 < 0 || num2 >= this.blocksV) { if (index.v >= this.grid.Size.v) { UnityEngine.Debug.LogWarning("Out of bounds"); } return null; } return this.blocks[num, num2]; } public void UnlockBlock(CIGExpansions.ExpansionBlock block, Currencies price) { if (block.Unlock(price)) { int num = Mathf.RoundToInt((float)price.GetValue("Gold")); if (num > 0) { SingletonMonobehaviour.Instance.AddGoldSpent_Expansions(num); } if (this.NewBlockUnlocked != null) { this.NewBlockUnlocked(this.grid, block); } } } private bool CreateBlocks() { if (this.blocks != null) { return true; } if (this.grid == null) { UnityEngine.Debug.LogWarning("this.grid == null"); return false; } if (this.blockDefinitions == null) { UnityEngine.Debug.LogWarning("this.blockDefinitions == null"); return false; } this.blocksU = (this.blocksV = 0); this.NumberOfInitiallyUnlockedBlocks = 0; foreach (CIGExpansionDefinition cigexpansionDefinition in this.blockDefinitions) { this.blocksU = Mathf.Max(this.blocksU, cigexpansionDefinition.u + 1); this.blocksV = Mathf.Max(this.blocksV, cigexpansionDefinition.v + 1); if (cigexpansionDefinition.initiallyUnlocked) { this.NumberOfInitiallyUnlockedBlocks++; } } if (this.blocksU * this.blockSizeU > this.grid.sizeU || this.blocksV * this.blockSizeV > this.grid.sizeV) { UnityEngine.Debug.LogWarning(string.Format("Grid size mismatch: {0} x {1} > {2} or {3} x {4} > {5}", new object[] { this.blocksU, this.blockSizeU, this.grid.sizeU, this.blocksV, this.blockSizeV, this.grid.sizeV })); } this.blocks = new CIGExpansions.ExpansionBlock[this.blocksU, this.blocksV]; foreach (CIGExpansionDefinition cigexpansionDefinition2 in this.blockDefinitions) { GridIndex index = cigexpansionDefinition2.Index; index.u *= this.blockSizeU; index.v *= this.blockSizeV; GridSize size = new GridSize(this.blockSizeU, this.blockSizeV); CIGExpansions.ExpansionBlock expansionBlock = new CIGExpansions.ExpansionBlock(this, cigexpansionDefinition2, index, size); this.blocks[cigexpansionDefinition2.u, cigexpansionDefinition2.v] = expansionBlock; } return true; } protected void PlaceBuySigns() { for (int i = 0; i < this.blocksV; i++) { for (int j = 0; j < this.blocksU; j++) { CIGExpansions.ExpansionBlock expansionBlock = this.blocks[j, i]; if (expansionBlock != null) { expansionBlock.UpdateCanUnlock(); } } } } private void OnSerialize(Dictionary values) { values["CIGExpansions.profitPerHour"] = this.profitPerHour; values["CIGExpansions.usedElems"] = this.usedElems; values["CIGExpansions.unusedElems"] = this.unusedElems; } private void OnDeserialize(Dictionary values) { this.ProfitPerHour = (decimal)values.Get("CIGExpansions.profitPerHour", -1m); this.UsedElements = (int)values.Get("CIGExpansions.usedElems", -1); this.UnusedElements = (int)values.Get("CIGExpansions.unusedElems", -1); } private void CalculatePriceVariables() { CIGGameStats instance = SingletonMonobehaviour.Instance; this.ProfitPerHour = Math.Floor(instance.GlobalProfitPerHour.GetValue("Cash")); int num = 0; int num2 = 0; for (int i = 0; i < this.BlocksU; i++) { for (int j = 0; j < this.BlocksV; j++) { CIGExpansions.ExpansionBlock block = this.GetBlock(i, j); if (block != null && block.Unlocked) { for (int k = block.Origin.u; k < block.Origin.u + block.Size.u; k++) { for (int l = block.Origin.v; l < block.Origin.v + block.Size.v; l++) { GridElement gridElement = this.grid[k, l]; if (gridElement.Type != -1 && gridElement.IsFullyVisible) { num++; if (gridElement.Tile != null) { num2++; } } } } } } } this.UsedElements = num2; this.UnusedElements = num - num2; this.serializing.Serialize(); } private void CalculateUnlockedTileCountByType() { int[] array = new int[10]; for (int i = 0; i < this.BlocksU; i++) { for (int j = 0; j < this.BlocksV; j++) { CIGExpansions.ExpansionBlock block = this.GetBlock(i, j); if (block != null && block.Unlocked) { for (int k = block.Origin.u; k < block.Origin.u + block.Size.u; k++) { for (int l = block.Origin.v; l < block.Origin.v + block.Size.v; l++) { GridElement gridElement = this.grid[k, l]; int type = gridElement.Type; if (type >= 0 && type < 100) { if (type >= array.Length) { Array.Resize(ref array, type + 1); } array[type]++; } } } } } } this.unlockedTileCountByType = new Dictionary(); for (int m = 1; m < array.Length; m++) { if (array[m] > 0) { this.unlockedTileCountByType[m] = array[m]; } } } public int blockSizeU = 8; public int blockSizeV = 8; public GameObject buySignPrefab; [SelfReference] public IsometricIsland island; [ChildReference] public IsometricGrid grid; [SelfReference] public Serializing serializing; public CIGExpansionDefinition[] blockDefinitions; private const decimal DefaultProfitPerHour = -1m; private const int DefaultUsedElems = -1; private const int DefaultUnusedElems = -1; private CIGGameConstants constants; private int blocksU; private int blocksV; private CIGExpansions.ExpansionBlock[,] blocks; private int unlockedBlocks; private int unlockedBlocksWithGold; private decimal profitPerHour = -1m; private int usedElems = -1; private int unusedElems = -1; private Dictionary unlockedTileCountByType = new Dictionary(); private HashSet unlockableBlocks = new HashSet(); public Action NewBlockUnlocked; protected int _initiallyUnlockedBlocks; private readonly string GoldCostCounterKey = "ExpansionsGoldCostCounter"; private const string ProfitPerHourKey = "CIGExpansions.profitPerHour"; private const string UsedElemsKey = "CIGExpansions.usedElems"; private const string UnusedElemsKey = "CIGExpansions.unusedElems"; public class ExpansionBlock { public ExpansionBlock(CIGExpansions parent, CIGExpansionDefinition def, GridIndex origin, GridSize size) { this.parent = parent; this.u = def.u; this.v = def.v; this.origin = origin; this.size = size; this.unlockByDefault = def.initiallyUnlocked; this.automaticUnlock = def.automaticUnlock; this.defName = def.name; string key = string.Concat(new object[] { parent.grid.serializing.StorageKey, "_Expansion[", this.u, ",", this.v, "]" }); this.state = Storage.Get(StorageLifecycle.Game).GetDictionary(key); if (!this.state.ContainsKey("Unlocked")) { this.state["Unlocked"] = false; } if (!this.state.ContainsKey("BoughtFor")) { this.state["BoughtFor"] = null; } this.CanUnlock = false; this.buySign = null; if (this.Unlocked) { parent.UnlockedBlocks++; if (this.UnlockedWithGold) { parent.UnlockedBlocksWithGold++; } for (int i = this.origin.v; i < this.origin.v + this.size.v; i++) { for (int j = this.origin.u; j < this.origin.u + this.size.u; j++) { parent.grid[j, i].Unlocked = true; } } } else if (this.unlockByDefault) { this.CanUnlock = true; if (!this.CanUnlock) { UnityEngine.Debug.LogWarning(string.Format("Unable to unlock by default, visfrac = {0}", this.VisibleFraction)); } this.Unlock(null); } } public Currencies Price { get { Currencies currencies = null; if (state.ContainsKey("Price")) { currencies = (state["Price"] as Currencies); } if (currencies == null || currencies.IsEmpty()) { currencies = (Currencies)(state["Price"] = CalculatePrice()); } return currencies; } } public int U { get { return this.u; } } public int V { get { return this.v; } } public GridIndex Origin { get { return this.origin; } } public GridSize Size { get { return this.size; } } public bool Unlocked { get { return (bool)this.state["Unlocked"]; } } public bool CanUnlock { get { if (this.canUnlock && this.VisibleFraction >= 0.5f) { this.parent.unlockableBlocks.Add(this); return true; } this.parent.unlockableBlocks.Remove(this); return false; } set { this.canUnlock = value; if (value && !this.Unlocked && this.VisibleFraction >= 0.5f) { this.parent.unlockableBlocks.Add(this); } else { this.parent.unlockableBlocks.Remove(this); } } } public bool UnlockedWithGold { get { Currencies currencies = (Currencies)this.state["BoughtFor"]; return !(currencies == null) && currencies.ContainsPositive("Gold"); } } public int AvailableElements { get { if (this.availableElements == -1) { this.CalculateElementStats(); } return this.availableElements; } } public int VisibleElements { get { if (this.visibleElements == -1) { this.CalculateElementStats(); } return this.visibleElements; } } public float AvailableFraction { get { return (float)this.AvailableElements / (float)(this.Size.u * this.Size.v); } } public float VisibleFraction { get { return (float)this.VisibleElements / (float)(this.Size.u * this.Size.v); } } public void UpdateCanUnlock() { bool flag = false; if (!this.Unlocked) { if (this.parent.GetBlock(this.u, this.v - 1) != null && this.parent.GetBlock(this.u, this.v - 1).Unlocked) { flag = true; } if (this.parent.GetBlock(this.u + 1, this.v) != null && this.parent.GetBlock(this.u + 1, this.v).Unlocked) { flag = true; } if (this.parent.GetBlock(this.u, this.v + 1) != null && this.parent.GetBlock(this.u, this.v + 1).Unlocked) { flag = true; } if (this.parent.GetBlock(this.u - 1, this.v) != null && this.parent.GetBlock(this.u - 1, this.v).Unlocked) { flag = true; } } bool flag2 = this.canUnlock; this.CanUnlock = flag; if (this.CanUnlock) { if (!flag2 && this.automaticUnlock) { this.Unlock(Currencies.Zero); } else if (this.buySign == null) { IsometricIsland island = this.parent.island; IsometricGrid grid = island.grid; bool flag3 = false; List list = new List(); GridIndex gridIndex = new GridIndex(int.MinValue, int.MinValue); GridIndex gridIndex2 = new GridIndex(int.MaxValue, int.MaxValue); for (int i = this.origin.v; i < this.origin.v + this.size.v; i++) { for (int j = this.origin.u; j < this.origin.u + this.size.u; j++) { if (grid.IsWithinBounds(j, i)) { if (grid[j, i].Tile != null && grid[j, i].Tile.GetComponent() != null) { flag3 = true; } if (grid[j, i].Type > 0) { gridIndex.u = Math.Max(j, gridIndex.u); gridIndex.v = Math.Max(i, gridIndex.v); gridIndex2.u = Math.Min(j, gridIndex2.u); gridIndex2.v = Math.Min(i, gridIndex2.v); list.Add(new GridIndex(j, i)); } } } } GridIndex centre = new GridIndex(gridIndex2.u + (gridIndex.u - gridIndex2.u) / 2, gridIndex2.v + (gridIndex.v - gridIndex2.v) / 2); list.Sort(delegate (GridIndex lhs, GridIndex rhs) { int num = lhs.u - centre.u; int num2 = lhs.v - centre.v; int num3 = rhs.u - centre.u; int num4 = rhs.v - centre.v; int num5 = num * num + num2 * num2; int num6 = num3 * num3 + num4 * num4; if (num5 < num6) { return -1; } if (num5 > num6) { return 1; } return 0; }); if (list.Count > 0) { for (int k = 0; k < list.Count; k++) { GridIndex index = list[k]; GridTile gridTile = grid[index].Tile; if (gridTile != null && gridTile.GetComponent() != null) { island.builder.DestroyTile(gridTile); gridTile = null; } GridIndex index2 = new GridIndex(index.u, index.v + 1); if (!index2.isInvalid && grid.IsWithinBounds(index2)) { GridTile tile = grid[index2].Tile; if (tile != null && tile.GetComponent() != null) { island.builder.DestroyTile(tile); } } if (gridTile == null && island.builder.BuildAt(this.parent.buySignPrefab, index, false, true)) { this.buySign = island.grid[index].Tile; Clickable.Instance(this.buySign).OnClickEvent += this.OnBuySignClick; if (flag3) { CIGBuySign component = this.buySign.GetComponent(); if (component != null) { component.EnableChest(); } } break; } } } else if (this.AvailableElements > 0) { UnityEngine.Debug.LogError(string.Format("No sign index count on {0} (has {1} available elements)", this.defName, this.AvailableElements)); } } } else if (this.buySign != null) { Clickable.Instance(this.buySign).OnClickEvent -= this.OnBuySignClick; this.parent.island.builder.DestroyTile(this.buySign); this.buySign = null; } } public bool Unlock(Currencies spent) { if (this.Unlocked || !this.CanUnlock) { UnityEngine.Debug.LogWarning(string.Format("Unlocked || !CanUnlock ({0} {1})", this.Unlocked, this.CanUnlock)); return false; } IsometricIsland island = this.parent.island; this.state["Unlocked"] = true; this.state["BoughtFor"] = spent; this.parent.UnlockedBlocks++; if (spent != null) { decimal num = UnityEngine.Random.Range(2, 6); int num2 = Mathf.Max(0, this.parent.UnlockedBlocks - this.parent.NumberOfInitiallyUnlockedBlocks); if (num2 == 1 || num2 % 10 == 0) { num = 10m; } if (spent.ContainsPositive("Gold")) { this.parent.UnlockedBlocksWithGold++; this.parent.GoldCostCounter = Math.Max(-3, this.parent.GoldCostCounter + 1); num *= 2m; } else { this.parent.GoldCostCounter = this.parent.GoldCostCounter - 1; } bool flag = false; if (this.buySign != null) { CIGBuySign component = this.buySign.GetComponent(); if (component != null) { component.Buy(PlingType.Gold, "Gold", num); flag = true; } } if (!flag) { UnityEngine.Debug.LogWarning("No sign found."); } } this.UpdateCanUnlock(); int num3 = this.u; int num4 = this.v; num4--; CIGExpansions.ExpansionBlock block = this.parent.GetBlock(num3, num4); if (block != null) { block.UpdateCanUnlock(); } num4++; num3++; block = this.parent.GetBlock(num3, num4); if (block != null) { block.UpdateCanUnlock(); } num3--; num4++; block = this.parent.GetBlock(num3, num4); if (block != null) { block.UpdateCanUnlock(); } num4--; num3--; block = this.parent.GetBlock(num3, num4); if (block != null) { block.UpdateCanUnlock(); } num3++; ((CIGBuilder)island.builder).ExpansionBlockDidUnlock(this.parent, this); this.parent.serializing.Serialize(); this.parent.unlockableBlocks.Remove(this); return true; } private void OnBuySignClick(GameObject target) { SingletonMonobehaviour.Instance.RequestFirstPopup(delegate (State state) { SingletonMonobehaviour.Instance.AddScreenViewed("buy_expansion"); ((BuyExpansionPopupState)state).Block = this; }); } private void CalculateElementStats() { this.availableElements = 0; this.visibleElements = 0; for (int i = this.origin.u; i < this.origin.u + this.size.u; i++) { for (int j = this.origin.v; j < this.origin.v + this.size.v; j++) { GridElement gridElement = this.parent.grid[i, j]; if (gridElement.Type > 0) { this.availableElements++; } if (gridElement.IsVisible) { this.visibleElements++; } } } } public Currencies CalculatePrice() { if (this.AvailableElements == 0) { return Currencies.Zero; } string text = "Cash"; string text2 = "Gold"; decimal num = (decimal)this.AvailableFraction; int usedElements = this.parent.UsedElements; int num2 = this.parent.UnusedElements / 2; decimal profitPerHour = this.parent.ProfitPerHour; long value = (long)this.parent.MinProfitPerHourForCashCost; if (profitPerHour > value && usedElements > 0) { value = (long)profitPerHour / (long)usedElements * (long)(usedElements + num2); } decimal baseRoiExpansion = this.parent.BaseRoiExpansion; decimal extraRoiExpansion = this.parent.ExtraRoiExpansion; decimal d = baseRoiExpansion + extraRoiExpansion * Mathf.Max(0, this.parent.UnlockedBlocks - this.parent._initiallyUnlockedBlocks); decimal factorForExpansionCostsCash = SingletonMonobehaviour.Instance.FactorForExpansionCostsCash; decimal num3 = value * d * num * factorForExpansionCostsCash; decimal num4 = 5m * (decimal)Math.Pow(10.0, Math.Floor(Math.Log10((double)num3)) - 2.0); decimal num5 = num4 * Math.Ceiling(num3 / num4); if (num5 < 50000m) { num5 = 50000m; } decimal d2 = num * Math.Max(10, 25 + 5 * this.parent.GoldCostCounter); decimal num6 = 5m * Math.Ceiling(d2 / 5m); if (this.parent.ExpansionsAreOnSale) { num3 = Math.Ceiling(num3 / 2m); d2 = Math.Ceiling(d2 / 2m); } return new Currencies(new object[] { text, num5, text2, num6 }); } public string ToString() { return string.Format("[ExpansionBlock: U={0}, V={1}, Origin={2}, Size={3}, Unlocked={4}]", new object[] { this.u, this.v, this.origin, this.size, this.Unlocked }); } private const string UnlockedKey = "Unlocked"; private const string BoughtForKey = "BoughtFor"; private const string PriceKey = "Price"; private CIGExpansions parent; private int u; private int v; private GridIndex origin; private GridSize size; private Dictionary state; private bool canUnlock; private GridTile buySign; private int availableElements = -1; private int visibleElements = -1; private bool unlockByDefault; private bool automaticUnlock; private string defName; } }