diff --git a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/Market.cs b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/Market.cs index d1ec35dd..3a68c1bd 100644 --- a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/Market.cs +++ b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/Market.cs @@ -1,13 +1,13 @@ using System; -using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Runtime.ExceptionServices; using MyGame.Scenes.marketing.Scripts; using MyGame.Scripts; -using TMPro; using UniRx; -using UniRx.Triggers; using UnityEngine; +using Debug = UnityEngine.Debug; using Random = UnityEngine.Random; public enum ShopState @@ -22,6 +22,7 @@ public class Market : MonoBehaviour // 購入時アニメーションタイミング private static readonly float waitSellTime = 1.5f; private static readonly float waitRefillTime = 1f; + private static readonly float DummyUsedCapacity = .5f; [SerializeField] private CustomerFlow customerFlow; [SerializeField] private GameObject orderPosisionObject; @@ -36,7 +37,14 @@ public class Market : MonoBehaviour private List displayFlavors = new List(); public List ShuffledOrder => shuffledOrder; private List shuffledOrder = new List(); - + + private List ShopStock => IsPartTimer ? dummyStock : cityGameData.ShopStock; + private readonly List dummyStock = new(); + private readonly List dummyStorageTank = new(); + + public bool IsPartTimer { get; private set; } + public bool IsLatestCity { get; private set; } + public IReadOnlyReactiveProperty CurrentShopState => shopState; private readonly ReactiveProperty shopState = new ReactiveProperty(); public IReadOnlyReactiveCollection CustomerControllerList => customerControllerList; @@ -60,7 +68,8 @@ public class Market : MonoBehaviour private int orderIndex; private int oneByOneIndex = 0; private int salesBonus = 0; - private GameData gameData; + private GameData globalGameData; + private GameData cityGameData; // Start is called before the first frame update void Start() @@ -72,33 +81,36 @@ public class Market : MonoBehaviour orderSubject.AddTo(this); IsPause.AddTo(this); isPromotion.AddTo(this); - - gameData = GameDataManager.GameData; - - UpdateBonus(ShopCustomize.GetBonusList(gameData.ShopCustomizeLevel)); + } + + public void Initialize(int cityId) + { + IsLatestCity = GameDataUtils.CheckLatestCity(cityId); + cityGameData = GameDataManager.GetCityGameData(cityId); + globalGameData = GameDataManager.GameData; + UpdateBonus(ShopCustomize.GetBonusList(globalGameData.ShopCustomizeLevel)); + customerFlow.SetCityGameData(cityGameData); -#if UNITY_EDITOR || DEVELOPMENT_BUILD CheckAndFixStock(); WorldMarketManager.StockFlavorLog(); -#endif // 陳列/売り順決定 - ReShuffle(gameData.ShopStock); + ReShuffle(ShopStock); Observable.Interval(TimeSpan.FromSeconds(1f)) .Where(_ => shuffledOrder.Count == 0) - .Where(_ => gameData.ShopStock.Count > 0) + .Where(_ => ShopStock.Count > 0) .Subscribe(_ => { #if UNITY_EDITOR || DEVELOPMENT_BUILD - Debug.Log("displayFlavors updated"); + Debug.LogWarning("displayFlavors updated"); #endif - ReShuffle(gameData.ShopStock); + ReShuffle(ShopStock); shopState.Value = ShopState.Open; - }); + }).AddTo(this); // お店の状態設定 - CheckStock(gameData.ShopStock); + UpdateShopState(); // 購入リクエスト var maxOrder = orderPosisionObject.transform.childCount; @@ -131,24 +143,10 @@ public class Market : MonoBehaviour requestSubject.BatchFrame().Subscribe(customers => { - // 来客数カウント - gameData.AddCustomerCount(customers.Count); - var orders = new List(); var dontBuyCustomerList = new List(); foreach (var controller in customers) - { - // 何も買わない - if (displayFlavors.Count == 0 || controller.OrderCount == 0) - { - controller.CallWaitForSeconds(1.5f, () => - { - controller.ChangeCustomerState(CustomerState.Leave); - }); - dontBuyCustomerList.Add(controller); - continue; - } - + { // 売り切れ if (shuffledOrder.Count == 0) { @@ -166,27 +164,22 @@ public class Market : MonoBehaviour var tmpOrderCount = Mathf.Min(controller.OrderCount, shuffledOrder.Count); var tmpOrders = shuffledOrder.GetRange(0, tmpOrderCount); shuffledOrder.RemoveRange(0, tmpOrderCount); - orders.AddRange(tmpOrders); - // コーンの味吹き出しを設定 try { - // 不正なオーダーの場合お客さん制御 - foreach (var t in tmpOrders) - { - if (gameData.ShopStock.Contains(displayFlavors[t])) - { - continue; - } - - if (controller.OrderCount >= 1) - { - controller.OrderCount--; - } - } + // 不正なオーダーチェック + var checkedOrders = tmpOrders.Where(order => ShopStock.Contains(displayFlavors[order])).ToList(); + controller.OrderCount = checkedOrders.Count; +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (tmpOrderCount != checkedOrders.Count) + throw new Exception($@"tmpOrder:{string.Join(".", tmpOrders)} +shuffledOrder:{shuffledOrder.OrderBy(x => x).Aggregate("", (s, num) => $"{s},{num}")} +shopStock:{ShopStock.Aggregate("", (s, data) => $"{s},{data.FlavorId}")} +display:{displayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId}")}"); +#endif // 購入しないお客さん扱いで退場 - if (controller.OrderCount == 0) + if (displayFlavors.Count == 0 || controller.OrderCount == 0) { controller.CallWaitForSeconds(1.5f, () => { @@ -195,17 +188,14 @@ public class Market : MonoBehaviour dontBuyCustomerList.Add(controller); continue; } - - controller.SetWantFlavor(displayFlavors[tmpOrders.RandomChoose()]); + // コーンの味吹き出しを設定 + controller.SetWantFlavor(displayFlavors[checkedOrders.RandomChoose()]); + orders.AddRange(checkedOrders); } catch (Exception e) { - /* - * 例外握りつぶし - * 存在しないorderを引いたのでそのまま処理せず逃がす - */ - Debug.LogError($"d:{displayFlavors.Count}, {string.Join("", tmpOrders)}" + - $"\nshuffled:{shuffledOrder.Count}, maxNum:{shuffledOrder.Max()}"); + // 動作止めずに例外スロー + Observable.NextFrame().Subscribe(_ => { ExceptionDispatchInfo.Capture(e).Throw();}); controller.CallWaitForSeconds(1.5f, () => { controller.ChangeCustomerState(CustomerState.Leave); @@ -217,7 +207,7 @@ public class Market : MonoBehaviour { customers.Remove(customerController); } - if (gameData.ShopStock.Count == 0) + if (ShopStock.Count == 0) { shopState.Value = ShopState.Close; } @@ -227,48 +217,63 @@ public class Market : MonoBehaviour } // 購入 - var flavors = orders.Select(x => displayFlavors[x]).ToList(); + var flavors = orders.Select(x => displayFlavors[x]).ToList(); var (coin, count) = SellPopcorn(flavors); - - // 獲得処理(遅延追加用変数に加算) - gameData.WaitAddCoin += coin; - gameData.WaitAddHeart += count; - gameData.AddVipCustomerCount(customers.Count(data => data.CustomerType == CustomerType.Vip)); - GameDataManager.SaveGameData(); - - // 商品補充 - RefillShopStockData(); - - // 表示データ更新 var isReorder = false; var refillList = new List(); - if (gameData.ShopStock.Count > shuffledOrder.Count) + if (IsPartTimer) { - refillList = RefillDisplayFlavors(gameData.ShopStock); + // 商品補充 + RefillDummyShopStockData(); + refillList = RefillDisplayFlavors(); + + // 在庫生成 + if (dummyStorageTank.Count <= 0) + { + GenerateDummyStock(); + } } else { - isReorder = CheckRemaining(gameData.ShopStock.Count); - if (isReorder) + // 獲得処理(遅延追加用変数に加算) + cityGameData.WaitAddCoin += coin; + cityGameData.WaitAddHeart += count; + cityGameData.AddCustomerCount(customers.Count); + cityGameData.AddVipCustomerCount(customers.Count(data => data.CustomerType == CustomerType.Vip)); + GameDataManager.SaveGameData(); + + // 商品補充 + RefillShopStockData(); + + // 表示データ更新 + if (ShopStock.Count > shuffledOrder.Count) { - ReShuffle(gameData.ShopStock); + refillList = RefillDisplayFlavors(); + } + else + { + isReorder = CheckRemaining(ShopStock.Count); + if (isReorder) + { + ReShuffle(ShopStock); + } } } this.CallWaitForSeconds(waitSellTime, () => { // 獲得処理 - gameData.MoveCoin(coin); + cityGameData.MoveCoin(coin); GameDataManager.SaveGameData(); sellObservable.OnNext(coin); sellOrderSubject.OnNext(orders); - CheckStock(gameData.ShopStock); + UpdateShopState(); this.CallWaitForSeconds(waitRefillTime, () => { // 獲得処理 - gameData.MoveHeart(count); + cityGameData.MoveHeart(count); GameDataManager.SaveGameData(); refillSubject.OnNext((isReorder, refillList)); @@ -300,6 +305,7 @@ public class Market : MonoBehaviour controller.ChangeCustomerState(CustomerState.Leave); }).AddTo(controller); + // ステートが変わるたびにオーダーチェック controller.State .Where(x => x != CustomerState.Order) .Subscribe(c => @@ -320,33 +326,24 @@ public class Market : MonoBehaviour } // チュートリアル中は抑制 - if (!gameData.FinishedFlags.HasFlag(TutorialFlag.FirstPlay)) + if (!globalGameData.FinishedFlags.HasFlag(TutorialFlag.FirstPlay)) { return; } // 一般客orセレブ - CustomerState customerState; - - switch (customerType) + + var customerState = customerType switch { - case CustomerType.Walker: - customerState = CustomerState.Walk; - break; - case CustomerType.Customer: - customerState = CustomerState.WalkShop; - break; - case CustomerType.Vip: - customerState = CustomerState.WalkShop; - break; - default: - throw new ArgumentOutOfRangeException(nameof(customerType), customerType, null); - } - + CustomerType.Walker => CustomerState.Walk, + CustomerType.Customer => CustomerState.WalkShop, + CustomerType.Vip => CustomerState.WalkShop, + _ => throw new ArgumentOutOfRangeException(nameof(customerType), customerType, null) + }; + var (isSpecial, orderCount) = customerSetting.GetCustomerData(customerType); var customerController = SpawnCustomer(); customerController.Setup(orderPosisionObject.transform.GetComponentsInChildren().ToList().Skip(1).ToList()); customerController.ChangeCustomerState(customerState); - // 複数パターンある場合ChooseRandom customerController.CustomerPrefab = isSpecial ? customerData.ChooseSpecialPrefab() : customerData.ChooseNormalPrefab(); customerController.OrderCount = orderCount; customerController.CustomerType = customerType; @@ -354,17 +351,11 @@ public class Market : MonoBehaviour customerController.TappedObservable .Take(1) - .Subscribe(_ => + .Subscribe(_ => customerController.ChangeCustomerState(shopState.Value switch { - if (shopState.Value == ShopState.Open) - { - customerController.ChangeCustomerState(CustomerState.TouchNotice); - } - else - { - customerController.ChangeCustomerState(CustomerState.TouchQuestion); - } - }).AddTo(customerController); + ShopState.Open => CustomerState.TouchNotice, + _ => CustomerState.TouchQuestion + })).AddTo(customerController); }).AddTo(this); // お客さんが少なくなったら弟が走る @@ -389,7 +380,7 @@ public class Market : MonoBehaviour else { BrotherPinkView.Instance.StopPromotion(); - if (gameData.TastingCount > 0 && shopState.Value == ShopState.Open) + if (cityGameData.TastingCount > 0 && shopState.Value == ShopState.Open) { BrotherPinkView.Instance.StartTasting(); } @@ -412,9 +403,7 @@ public class Market : MonoBehaviour { case CustomerMovingType.WalkSide: case CustomerMovingType.WalkSideEat: - customerList.Remove(customerController); - customerControllerList.Remove(customerController); - Destroy(customerController.gameObject); + DestroyCustomer(customerController); break; case CustomerMovingType.TouchNotice: customerList.Add(customerController); @@ -441,11 +430,17 @@ public class Market : MonoBehaviour return customerController; } + private void DestroyCustomer(CustomerController customerController) + { + customerControllerList.Remove(customerController); + customerList.Remove(customerController); + Destroy(customerController.gameObject); + } + private (int coin, int count) SellPopcorn(List stockDataList) { - var gameData = GameDataManager.GameData; // 品切れ - if (gameData.ShopStock.Count == 0) + if (ShopStock.Count == 0) { return (0, 0); } @@ -459,18 +454,20 @@ public class Market : MonoBehaviour { var productData = recipeList.First(data => data.id == stockData.FlavorId); var rarityData = rarityList.First(data => data.Rarity == stockData.Rarity); - var targetIndex = gameData.ShopStock.FindIndex(data => data.FlavorId == stockData.FlavorId && data.Rarity == stockData.Rarity); + var targetIndex = ShopStock.FindIndex(data => data.FlavorId == stockData.FlavorId && data.Rarity == stockData.Rarity); if (targetIndex == -1) { Debug.LogError($@"data -----stockData: {stockData.FlavorId}, {stockData.Rarity} ------shopStock: {gameData.ShopStock.Aggregate("", (s, data) => $"{s},{data.FlavorId}")} +-----shopStock: {ShopStock.Aggregate("", (s, data) => $"{s},{data.FlavorId}")} displayFlavors: {displayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId}")}"); Observable.NextFrame().Subscribe(_ => throw new Exception("DisplayFlavors Invalid")).AddTo(this); continue; } - gameData.ShopStock.RemoveAt(targetIndex); - gameData.AddSalesCount(stockData.FlavorId, 1, stockData.Rarity); + ShopStock.RemoveAt(targetIndex); + // バイトは削除処理のみ + if (IsPartTimer) continue; + cityGameData.AddSalesCount(stockData.FlavorId, 1, stockData.Rarity); coin += productData.GetRarityPrice(rarityData.Rarity); coin += salesBonus; count++; @@ -488,33 +485,32 @@ displayFlavors: {displayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId} { // 手前のタンクから出し多分stockをへらす // へらした分を店頭リストに追加する - var gameData = GameDataManager.GameData; - var shopSpace = WorldMarketManager.ShopStockCount - gameData.ShopStock.Count; - switch (gameData.RefillMode) + var shopSpace = WorldMarketManager.ShopStockCount - ShopStock.Count; + switch (cityGameData.RefillMode) { case ProductRefillMode.OneByOne: - while (shopSpace > 0 && gameData.StorageTanks.Sum(data => data.Stock) > 0) + while (shopSpace > 0 && cityGameData.StorageTanks.Sum(data => data.Stock) > 0) { - var tanks = gameData.StorageTanks.Where(tank => !tank.IsEmpty).ToList(); + var tanks = cityGameData.StorageTanks.Where(tank => !tank.IsEmpty).ToList(); if (oneByOneIndex >= tanks.Count) { oneByOneIndex = 0; } var stockList = tanks[oneByOneIndex].GetStock(1); - gameData.ShopStock.AddRange(stockList); + ShopStock.AddRange(stockList); shopSpace -= stockList.Count; oneByOneIndex++; } break; case ProductRefillMode.TankByTank: - foreach (var tank in gameData.StorageTanks.Where(tank => !tank.IsEmpty)) + foreach (var tank in cityGameData.StorageTanks.Where(tank => !tank.IsEmpty)) { if (shopSpace == 0) { break; } var stockList = tank.GetStock(shopSpace); - gameData.ShopStock.AddRange(stockList); + ShopStock.AddRange(stockList); shopSpace -= stockList.Count; } break; @@ -524,28 +520,32 @@ displayFlavors: {displayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId} GameDataManager.SaveGameData(); } - public List RefillDisplayFlavors(List shopStock) + /// + /// shopStockを確認して追加差分をDisplayFlavorsとShuffledOrderにAddする + /// + /// + public List RefillDisplayFlavors() { // 補充された場合店頭のフレーバー入れ替え - var refillCount = shopStock.Count - shuffledOrder.Count; + var refillCount = ShopStock.Count - shuffledOrder.Count; if (refillCount <= 0) { return new List(); } // 補充候補リスト - var orders = Enumerable.Range(0, shopStock.Count).Except(shuffledOrder).ToList(); + var orders = Enumerable.Range(0, ShopStock.Count).Except(shuffledOrder).ToList(); var refillList = orders.GetRange(0, refillCount).OrderBy(_ => Random.value).ToList(); shuffledOrder.AddRange(refillList); try { - var diffDisplayCount = shopStock.Count - displayFlavors.Count; + var diffDisplayCount = ShopStock.Count - displayFlavors.Count; if (diffDisplayCount > 0) { - displayFlavors.AddRange(shopStock.GetRange(displayFlavors.Count, diffDisplayCount)); + displayFlavors.AddRange(ShopStock.GetRange(displayFlavors.Count, diffDisplayCount)); } for (int i = 0; i < refillList.Count; i++) { - displayFlavors[refillList[i]] = shopStock[shopStock.Count - 1 - i]; + displayFlavors[refillList[i]] = ShopStock[ShopStock.Count - 1 - i]; } } catch (Exception e) @@ -569,15 +569,15 @@ displayFlavors: {displayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId} return false; } - public void ReShuffle(List shopStock) + private void ReShuffle(List shopStock) { displayFlavors = shopStock.ToList(); shuffledOrder = ShuffleOrder(displayFlavors.Count); } - public void CheckStock(List shopStock) + public void UpdateShopState() { - shopState.Value = shopStock.Count == 0 ? ShopState.Close : ShopState.Open; + shopState.Value = ShopStock.Count == 0 ? ShopState.Close : ShopState.Open; } public void AdClickAction() @@ -620,14 +620,72 @@ displayFlavors: {displayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId} return customerController; } + /// + /// 兄弟モードで在庫がなくなった場合にバイト君に切り替えるためのチェック + /// + public void CheckPartTimerMode() + { + var shopStock = cityGameData.ShopStock.Count; + var tankStock = cityGameData.StorageTanks.Sum(x => x.Stock); + if (IsLatestCity || shopStock + tankStock > 0) + { + if (!IsPartTimer) return; + ReShuffle(ShopStock); + IsPartTimer = false; + return; + } + IsPartTimer = true; + // バイト用ダミー生成処理 + if (dummyStorageTank.Count <= 0) GenerateDummyStock(); + RefillDummyShopStockData(); + ReShuffle(ShopStock); + UpdateShopState(); + } + + public void SetLatestCity(bool active) => IsLatestCity = active; + + /// + /// ダミー在庫生成 + /// ダミータンクが0の場合に入手済みレシピからランダムでフレーバー選ぶ + /// 1度の生成で10個(volume), 0になる度に全部で30くらいつくっておく + /// + private void GenerateDummyStock() + { + foreach (var recipeId in globalGameData.MyRecipes.RandomChoose(3)) + { + dummyStorageTank.AddRange(Enumerable.Repeat(new ProductStockData + { + FlavorId = recipeId, + Rarity = ProductRarity.Normal + }, 10)); + } + } + + private void RefillDummyShopStockData() + { + var shopSpace = WorldMarketManager.ShopStockCount - ShopStock.Count; + var refillCount = Mathf.Min(dummyStorageTank.Count, shopSpace); + ShopStock.AddRange(dummyStorageTank.GetRange(0, refillCount)); + dummyStorageTank.RemoveRange(0, refillCount); + } + + public float GetUsedStorageCapacity() + { + if (IsPartTimer) return DummyUsedCapacity; + var totalCapacity = cityGameData.StorageTanks.Sum(x => x.Capacity); + var totalStock = cityGameData.StorageTanks.Sum(x => x.Stock); + return (float)totalStock / totalCapacity; + } + + [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")] private void CheckAndFixStock() { - if (GameDataManager.GameData.ShopStock.Count > WorldMarketManager.ShopStockCount) + if (ShopStock.Count > WorldMarketManager.ShopStockCount) { - GameDataManager.GameData.ShopStock.RemoveRange(0, GameDataManager.GameData.ShopStock.Count - WorldMarketManager.ShopStockCount); + ShopStock.RemoveRange(0, ShopStock.Count - WorldMarketManager.ShopStockCount); } - foreach (var stockData in GameDataManager.GameData.ShopStock.Where(stockData => stockData.FlavorId < 1)) + foreach (var stockData in ShopStock.Where(stockData => stockData.FlavorId < 1)) { stockData.FlavorId = 1; } @@ -639,8 +697,8 @@ displayFlavors: {displayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId} /// public void ResetGameData(GameData newGameData) { - gameData = newGameData; - ReShuffle(gameData.ShopStock); - CheckStock(gameData.ShopStock); + cityGameData = newGameData; + ReShuffle(ShopStock); + UpdateShopState(); } } diff --git a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/MarketManager.cs b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/MarketManager.cs index 4622fbe3..88790495 100644 --- a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/MarketManager.cs +++ b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/MarketManager.cs @@ -27,6 +27,7 @@ public class MarketManager : MonoBehaviour [SerializeField] private TutorialObjectMask walkerMask; private Market market; List productDataList; + private bool isPartTimer; private readonly Subject customerRewardTimerUpdateSubject = new Subject(); private readonly Subject vipTimerUpdateSubject = new Subject(); @@ -38,17 +39,27 @@ public class MarketManager : MonoBehaviour customerRewardTimerUpdateSubject.AddTo(this); vipTimerUpdateSubject.AddTo(this); market = WorldMarketManager.Instance.GetCurrentCityMarket(); + market.CheckPartTimerMode(); + isPartTimer = market.IsPartTimer; SoundManager.Instance.PlayBGM("bgm_marketing"); - var gameData = GameDataManager.GameData; + var globalGameData = GameDataManager.GameData; + var cityGameData = GameDataManager.GetCurrentCityGameData(); // カスタマイズ読み込み marketView.SetAllItem(); stockView = marketView.GetTarget(ShopCustomizeCategory.Category4).GetComponentInChildren(); stockView.SetTextActive(true); - ShopCustomizeCoinManager.Instance.ChangeCoin(gameData.ShopCustomizeCoin); + ShopCustomizeCoinManager.Instance.ChangeCoin(globalGameData.ShopCustomizeCoin); + + if (isPartTimer) + { + partTimerView.StartAnimation(); + rewardButtonView.gameObject.SetActive(false); + vipCustomerButtonView.gameObject.SetActive(false); + } - if (!gameData.FinishedFlags.HasFlag(TutorialFlag.FirstPlay)) + if (!globalGameData.FinishedFlags.HasFlag(TutorialFlag.FirstPlay)) { if (TutorialManager.Instance.Index == 3) { @@ -78,7 +89,7 @@ public class MarketManager : MonoBehaviour .Subscribe(_ => { }, () => { // チュートリアル終了 - gameData.FinishTutorial(); + globalGameData.FinishTutorial(); GameDataManager.SaveGameData(); walkerMask.gameObject.SetActive(false); customerRewardTimerUpdateSubject.OnNext(Unit.Default); @@ -88,8 +99,8 @@ public class MarketManager : MonoBehaviour } } - CoinManager.Instance.ChangeCoin(gameData.Coin); - HeartMeter.Instance.Initialize(gameData.ViewedShopLevel, gameData.Heart); + CoinManager.Instance.ChangeCoin(cityGameData.Coin); + HeartMeter.Instance.Initialize(globalGameData.ViewedShopLevel, cityGameData.Heart); // ハートゲージがフルかつダイアログが開いていない場合レベルアップ HeartMeter.Instance.FulledHeart @@ -100,14 +111,14 @@ public class MarketManager : MonoBehaviour .Subscribe(_ => { market.IsPause.Value = true; - ShopLevelUp.ShowDialog(gameData.ViewedShopLevel + 1, () => + ShopLevelUp.ShowDialog(globalGameData.ViewedShopLevel + 1, () => { market.IsPause.Value = false; }); }).AddTo(this); productDataList = SpreadsheetDataManager.Instance.GetBaseDataList(Const.ProductDataSheet); - stockView.SetStock(gameData.StorageTanks); + stockView.SetStock(market.GetUsedStorageCapacity()); List<(int, ProductStockData)> startStocks; try { @@ -134,8 +145,9 @@ public class MarketManager : MonoBehaviour { vipCustomerButtonView.SetActive(isPause); // 兄弟非表示 - blueView.SetActive(!isPause); - BrotherPinkView.Instance.SetActive(!isPause); + blueView.SetActive(!isPartTimer && !isPause); + BrotherPinkView.Instance.SetActive(!isPartTimer && !isPause); + partTimerView.SetActive(isPartTimer && !isPause); }).AddTo(this); // 宣伝ボタン @@ -144,11 +156,11 @@ public class MarketManager : MonoBehaviour GetRewardDialog.ShowIncreaseCustomerDialog(() => { market.AdClickAction(); - gameData.increaseCustomerTime = DateTime.UtcNow.AddSeconds(refreshWaitTime).ToBinary(); + globalGameData.increaseCustomerTime = DateTime.UtcNow.AddSeconds(refreshWaitTime).ToBinary(); #if UNITY_EDITOR - gameData.increaseCustomerTime = DateTime.UtcNow.AddSeconds(10).ToBinary(); + globalGameData.increaseCustomerTime = DateTime.UtcNow.AddSeconds(10).ToBinary(); #endif - gameData.AddUseAdWalker(); + cityGameData.AddUseAdWalker(); GameDataManager.SaveGameData(); customerRewardTimerUpdateSubject.OnNext(Unit.Default); }); @@ -161,38 +173,37 @@ public class MarketManager : MonoBehaviour { market.VipAction(); // 現在時刻に設定して期限切れにする - gameData.vipCustomerLimitTime = DateTime.UtcNow.ToBinary(); + globalGameData.vipCustomerLimitTime = DateTime.UtcNow.ToBinary(); vipTimerUpdateSubject.OnNext(Unit.Default); }, () => { // 現在時刻に設定して期限切れにする - gameData.vipCustomerLimitTime = DateTime.UtcNow.ToBinary(); + globalGameData.vipCustomerLimitTime = DateTime.UtcNow.ToBinary(); vipTimerUpdateSubject.OnNext(Unit.Default); }); }).AddTo(this); // onNextをトリガーに実行 customerRewardTimerUpdateSubject - .Select(_ => (int) DateTime.FromBinary(gameData.increaseCustomerTime).Subtract(DateTime.UtcNow).TotalSeconds) + .StartWith() + .Select(_ => (int) DateTime.FromBinary(globalGameData.increaseCustomerTime).Subtract(DateTime.UtcNow).TotalSeconds) .Subscribe(time => { rewardButtonView.ResetTimer(time); }).AddTo(this); - if (DateTime.FromBinary(gameData.vipCustomerLimitTime) >= DateTime.UtcNow) + if (DateTime.FromBinary(globalGameData.vipCustomerLimitTime) >= DateTime.UtcNow) { - vipCustomerButtonView.ShowButton(gameData.vipCustomerFirstOpen); - gameData.vipCustomerFirstOpen = false; + vipCustomerButtonView.ShowButton(globalGameData.vipCustomerFirstOpen); + globalGameData.vipCustomerFirstOpen = false; vipTimerUpdateSubject - .Select(_ => (int) DateTime.FromBinary(gameData.vipCustomerLimitTime).Subtract(DateTime.UtcNow).TotalSeconds) + .StartWith() + .Select(_ => (int) DateTime.FromBinary(globalGameData.vipCustomerLimitTime).Subtract(DateTime.UtcNow).TotalSeconds) .Subscribe(time => { vipCustomerButtonView.ResetTimer(time); }).AddTo(this); } - - customerRewardTimerUpdateSubject.OnNext(Unit.Default); - vipTimerUpdateSubject.OnNext(Unit.Default); // アプリ復帰時に残り時間更新 Observable.EveryApplicationPause() @@ -222,11 +233,12 @@ public class MarketManager : MonoBehaviour market.SellObservable.Subscribe(coin => { // コイン獲得エフェクト + blueView.SellAction(); + if (coin == 0) return; CoinEffect(coin, pos => { CoinManager.Instance.AddCoinWithEffect(coin, pos); }); - blueView.SellAction(); }).AddTo(this); market.SellOrderSubject.Subscribe(orders => @@ -240,37 +252,32 @@ public class MarketManager : MonoBehaviour market.RefillSubject.Subscribe(x => { - stockView.SetStock(gameData.StorageTanks); + stockView.SetStock(market.GetUsedStorageCapacity()); if (x.isReorder) { // 陳列表示更新(陳列13=650ms,7=350ms) var stocks = market.ShuffledOrder.Select(i => (i, market.DisplayFlavors[i])).ToList(); cartView.SetStock(stocks, true); + return; } - else - { - var isError = false; - // 補充したフレーバーのスキンを設定 - foreach (var order in x.refillList) - { - if (order >= market.DisplayFlavors.Count) - { - isError = true; - Debug.LogError($@"mismatch order:{order}, displayFlavors:{market.DisplayFlavors.Count}"); - continue; - } - cartView.Refill(order, market.DisplayFlavors[order]); - } - if (isError) + // 補充したフレーバーのスキンを設定 + foreach (var order in x.refillList) + { + if (order >= market.DisplayFlavors.Count) { - Debug.LogError($@"list - shopStock: {gameData.ShopStock.Aggregate("", (s, data) => $"{s},{data.FlavorId}")} + continue; + } + cartView.Refill(order, market.DisplayFlavors[order]); + } + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + if (x.refillList.DefaultIfEmpty().Max() < market.DisplayFlavors.Count) return; + Debug.LogError($@"list displayFlavors: {market.DisplayFlavors.Aggregate("", (s, data) => $"{s},{data.FlavorId}")} refillList: {x.refillList.Aggregate("", (s, order) => $"{s},{order}")}"); - throw new Exception("RefillList Invalid"); - } - } + throw new Exception("RefillList Invalid"); +#endif }).AddTo(this); // 開閉店 @@ -281,58 +288,66 @@ displayFlavors: {market.DisplayFlavors.Aggregate("", (s, data) => $"{s},{data.Fl }).AddTo(this); // 試食看板はStart時非表示 - signBoardView.SetActiveTastingBoard(false); + // signBoardView.SetActiveTastingBoard(false); // 宣伝ボタン/試食表示切替 var tastingComplete = new Subject().AddTo(this); + IDisposable tastingDisposable = null; market.CurrentShopState - .SkipWhile(_ => !gameData.FinishedFlags.HasFlag(TutorialFlag.FirstPlay)) - .CombineLatest(market.IsPromotion, tastingComplete, (shopState, isPromotion, _) => (shopState == ShopState.Open, isPromotion)) + .SkipWhile(_ => !globalGameData.FinishedFlags.HasFlag(TutorialFlag.FirstPlay)) + .CombineLatest(market.IsPromotion, tastingComplete, (shopState, isPromotion, _) => (shopState == ShopState.Close, isPromotion)) .Subscribe(x => { - var (isOpen, isPromotion) = x; - if (isOpen) + var (isClose, isPromotion) = x; + if (isClose || isPartTimer) { - if (isPromotion) - { - signBoardView.SetActiveTastingBoard(false); - // 宣伝ボタン表示 - rewardButtonView.gameObject.SetActive(true); - BrotherPinkView.Instance.StartPromotion(); - } - else if (gameData.TastingCount > 0) - { - rewardButtonView.gameObject.SetActive(false); - // 試食表示 - signBoardView.SetActiveTastingBoard(true); - BrotherPinkView.Instance.StartTasting(); - BrotherPinkView.Instance.SetTastingCount(gameData.TastingCount); - signBoardView.SetTimer(gameData.TastingCount * (int)market.TastingCustomerInterval, () => - { - BrotherPinkView.Instance.SetTastingCount(gameData.TastingCount); - }, () => + BrotherPinkView.Instance.StopTasting(); + rewardButtonView.gameObject.SetActive(false); + // signBoardView.CancelTasting(); + tastingDisposable?.Dispose(); + + // VIP宣伝を非表示 + globalGameData.vipCustomerLimitTime = DateTime.UtcNow.ToBinary(); + vipTimerUpdateSubject.OnNext(Unit.Default); + return; + } + if (isPromotion) + { + // signBoardView.SetActiveTastingBoard(false); + // 宣伝ボタン表示 + rewardButtonView.gameObject.SetActive(true); + BrotherPinkView.Instance.StartPromotion(); + return; + } + if (cityGameData.TastingCount > 0) + { + rewardButtonView.gameObject.SetActive(false); + // 試食表示 + // signBoardView.SetActiveTastingBoard(true); + BrotherPinkView.Instance.StartTasting(); + BrotherPinkView.Instance.SetTastingCount(cityGameData.TastingCount); + var remaining = cityGameData.TastingCount * (int)market.TastingCustomerInterval; + tastingDisposable = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1f)) + .TakeWhile(x => (int)(remaining - x) >= 0) + .Subscribe(_ => BrotherPinkView.Instance.SetTastingCount(cityGameData.TastingCount), () => { // 試食タイマーが終わったら表示更新トリガー tastingComplete.OnNext(Unit.Default); BrotherPinkView.Instance.StopTasting(); - }); - } - else // 宣伝も試食も未発動 - { - BrotherPinkView.Instance.StopTasting(); - rewardButtonView.gameObject.SetActive(true); - } - } - else // 閉店 - { - BrotherPinkView.Instance.StopTasting(); - rewardButtonView.gameObject.SetActive(false); - signBoardView.CancelTasting(); - - // VIP宣伝を非表示 - gameData.vipCustomerLimitTime = DateTime.UtcNow.ToBinary(); - vipTimerUpdateSubject.OnNext(Unit.Default); + }).AddTo(this); + // signBoardView.SetTimer(gameData.TastingCount * (int)market.TastingCustomerInterval, + // () => { BrotherPinkView.Instance.SetTastingCount(gameData.TastingCount); }, () => + // { + // // 試食タイマーが終わったら表示更新トリガー + // tastingComplete.OnNext(Unit.Default); + // BrotherPinkView.Instance.StopTasting(); + // }); + return; } + // 宣伝も試食も未発動 + BrotherPinkView.Instance.StopTasting(); + rewardButtonView.gameObject.SetActive(true); + }).AddTo(this); // CombineLatest動かすのに必要 tastingComplete.OnNext(Unit.Default); @@ -462,6 +477,7 @@ displayFlavors: {market.DisplayFlavors.Aggregate("", (s, data) => $"{s},{data.Fl }).AddTo(customerAnimator); var eventTrigger = customerAnimator.gameObject.AddComponent(); eventTrigger.OnPointerClickAsObservable() + .Where(_ => !isPartTimer) .Take(1) .Subscribe(_ => { diff --git a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/ShopStockView.cs b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/ShopStockView.cs index 9245ba56..62dee225 100644 --- a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/ShopStockView.cs +++ b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/ShopStockView.cs @@ -14,12 +14,10 @@ public class ShopStockView : MonoBehaviour textObject.SetActive(false); } - public void SetStock(List tanks) + public void SetStock(float value) { - var totalCapacity = tanks.Sum(x => x.Capacity); - var totalStock = tanks.Sum(x => x.Stock); var newPos = popcornImage.transform.localPosition; - newPos.y = Mathf.Lerp(minPosision, maxPosision, (float) totalStock / totalCapacity); + newPos.y = Mathf.Lerp(minPosision, maxPosision, value); popcornImage.transform.localPosition = newPos; } diff --git a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/WorldMarketManager.cs b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/WorldMarketManager.cs index 226163cb..0d67ad30 100644 --- a/popcorn/Assets/MyGame/Scenes/marketing/Scripts/WorldMarketManager.cs +++ b/popcorn/Assets/MyGame/Scenes/marketing/Scripts/WorldMarketManager.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using MyGame.Scripts; using UniRx; using UnityEngine; +using Debug = UnityEngine.Debug; namespace MyGame.Scenes.marketing.Scripts { @@ -19,18 +22,63 @@ namespace MyGame.Scenes.marketing.Scripts private readonly Dictionary cityMarketDict = new(); private void Start() { +#if UNITY_EDITOR + var newGameData = GameDataUtils.CreateCityData(2); + newGameData.IsFundingCompleted = true; + newGameData.Heart = 0; +#endif + + // 各都市マーケット生成 + var latestCityId = GameDataUtils.GetLatestCityId(); + CreateMarket(Const.DefaultCityId).CheckPartTimerMode(); + foreach (var (cityId, gameData) in GameDataManager.GameData.CityGameDataDict) + { + if (!gameData.IsFundingCompleted) return; + var market = CreateMarket(cityId); + market.CheckPartTimerMode(); + market.SetLatestCity(cityId == latestCityId); + } + } + + private Market CreateMarket(int cityId) + { var market = Instantiate(marketPrefab, transform); - cityMarketDict.Add(Const.DefaultCityId, market); + market.Initialize(cityId); + cityMarketDict.Add(cityId, market); + return market; } public Market GetMarket(int cityId) { - return cityMarketDict[Const.DefaultCityId]; + return cityMarketDict[cityId]; } public Market GetCurrentCityMarket() { - return cityMarketDict[Const.DefaultCityId]; + return cityMarketDict[GameDataManager.GameData.CurrentCityId]; + } + + /// + /// 選択中の都市と、最新の都市以外のMarketの動きを止める + /// + /// + public void UpdateCurrentCity(int currentCityId) + { + var latestCityId = GameDataUtils.GetLatestCityId(); + foreach (var (cityId, market) in cityMarketDict) + { + if (cityId == currentCityId || cityId == latestCityId) + { + market.IsPause.Value = false; + continue; + } + market.IsPause.Value = true; + } + } + + public void SetActiveMarket(int cityId, bool active) + { + cityMarketDict[cityId].IsPause.Value = !active; } /// @@ -39,7 +87,10 @@ namespace MyGame.Scenes.marketing.Scripts /// public void UpdateBonus(Dictionary bonusList) { - cityMarketDict[Const.DefaultCityId].UpdateBonus(bonusList); + foreach (var (_, market) in cityMarketDict) + { + market.UpdateBonus(bonusList); + } } public void ResetGameData(GameData gameData) @@ -47,6 +98,7 @@ namespace MyGame.Scenes.marketing.Scripts cityMarketDict[Const.DefaultCityId].ResetGameData(gameData); } + [Conditional("UNITY_EDITOR"), Conditional("DEVELOPMENT_BUILD")] public static void StockFlavorLog(int cityId = -1) { if (GameDataManager.GetCityGameData(cityId) is not {} cityGameData)