Files
2026-07-09 02:50:48 +09:00

391 lines
20 KiB
C#

using TMPro;
using UnityEngine;
using UnityEngine.UI;
public partial class GameFlowManager {
private void ShowDutyFreeShop() {
currentScreen = FlowScreen.DutyFreeShop;
gameplayActive = false;
pendingStartGameplay = false;
if(TryLoadFlowScene(DutyFreeShopSceneName))
{
return;
}
EnsureOverlay();
ClearOverlay();
SetOverlayVisible(true);
BuildDutyFreeShopScreen();
}
private void BuildDutyFreeShopScreen() {
EnsureDutyFreeStagePurchaseLimits();
ApplyDutyFreeShopBackground();
RectTransform boardRect = AddDutyFreeBoard();
AddDutyFreeHeader(boardRect);
AddDutyFreeItemCard(
boardRect,
"도시락",
DutyFreeItemType.Lunchbox,
LunchboxCost,
saveData.lunchboxStock,
LoadUiSprite("", DutyFreeLunchboxAssetPath),
BuyLunchbox,
new Vector2(75f, -135f));
AddDutyFreeSupplementCard(
boardRect,
"영양제",
SupplementCost,
saveData.supplementPurchases,
LoadUiSprite("", DutyFreeSupplementAssetPath),
BuySupplement,
new Vector2(303f, -135f));
AddDutyFreeItemCard(
boardRect,
"마일리지 카드",
DutyFreeItemType.MileageCard,
MileageCardCost,
saveData.mileageCardStock,
LoadUiSprite("", DutyFreeMileageCardAssetPath),
BuyMileageCard,
new Vector2(760f, -135f));
AddDutyFreeNextTravelButton();
}
private void ApplyDutyFreeShopBackground() {
if(overlayBackground != null)
{
overlayBackground.sprite = null;
overlayBackground.preserveAspect = false;
overlayBackground.color = new Color(0.018f, 0.041f, 0.052f, 0.98f);
}
if(flowCamera != null)
{
flowCamera.backgroundColor = new Color(0.018f, 0.041f, 0.052f, 1f);
}
AddDutyFreeBackdropImage(
"Duty Free Shop Interior",
LoadUiSprite(DutyFreeBackgroundResourcePath, DutyFreeBackgroundAssetPath),
Vector2.zero,
new Vector2(1378f, 724f),
true,
Color.white);
GameObject scrimObject = CreateUiObject("Duty Free Background Scrim", overlayRoot, typeof(Image));
RectTransform scrimRect = scrimObject.GetComponent<RectTransform>();
scrimRect.anchorMin = Vector2.zero;
scrimRect.anchorMax = Vector2.one;
scrimRect.offsetMin = Vector2.zero;
scrimRect.offsetMax = Vector2.zero;
Image scrimImage = scrimObject.GetComponent<Image>();
scrimImage.color = new Color(0.01f, 0.012f, 0.014f, 0.22f);
scrimImage.raycastTarget = false;
}
private Image AddDutyFreeBackdropImage(string objectName, Sprite sprite, Vector2 position, Vector2 size, bool preserveAspect, Color color) {
GameObject imageObject = CreateUiObject(objectName, overlayRoot, typeof(Image));
RectTransform imageRect = imageObject.GetComponent<RectTransform>();
imageRect.anchorMin = new Vector2(0.5f, 0.5f);
imageRect.anchorMax = new Vector2(0.5f, 0.5f);
imageRect.pivot = new Vector2(0.5f, 0.5f);
imageRect.anchoredPosition = position;
imageRect.sizeDelta = size;
Image image = imageObject.GetComponent<Image>();
image.sprite = sprite;
image.color = sprite != null ? color : new Color(0.30f, 0.46f, 0.54f, 0.28f);
image.preserveAspect = preserveAspect;
image.raycastTarget = false;
return image;
}
private RectTransform AddDutyFreeBoard() {
GameObject boardObject = CreateUiObject("Duty Free Product Board", overlayRoot, typeof(Image));
RectTransform boardRect = boardObject.GetComponent<RectTransform>();
boardRect.anchorMin = new Vector2(0.5f, 0.5f);
boardRect.anchorMax = new Vector2(0.5f, 0.5f);
boardRect.pivot = new Vector2(0.5f, 0.5f);
boardRect.anchoredPosition = new Vector2(0f, 20f);
boardRect.sizeDelta = new Vector2(1038f, 552f);
Image boardImage = boardObject.GetComponent<Image>();
boardImage.sprite = LoadUiSprite(DutyFreeWindowPanelResourcePath, DutyFreeWindowPanelAssetPath);
boardImage.color = boardImage.sprite != null
? Color.white
: new Color(0.92f, 0.98f, 1f, 0.78f);
boardImage.preserveAspect = false;
boardImage.raycastTarget = false;
return boardRect;
}
private void AddDutyFreeHeader(RectTransform parent) {
AddResultImage(parent, "Duty Free Equip Slots Panel", LoadUiSprite(DutyFreeEquipSlotPanelResourcePath, "Assets/Resources/UI_DutyFreeBagSlotPanel.png"), new Vector2(50f, -570f), new Vector2(276f, 124f), true, Color.white);
for(int i = 0; i < 3; i++)
{
AddDutyFreeEquipSlot(parent, i, new Vector2(-65f + (i * 82f), -540f));
}
AddDutyFreeBagUpgradeButton(parent, new Vector2(190f, -560f));
AddResultImage(parent, "Duty Free Mileage Price Tag", LoadDutyFreeResourceSprite(DutyFreePriceTagResourcePath), new Vector2(1000f, -48f), new Vector2(230f, 100f), false, Color.white);
AddResultText(parent, "Duty Free Mileage Label", "보유 마일리지", new Vector2(990f, -26f), new Vector2(118f, 20f), 14f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 0.96f), TextAlignmentOptions.MidlineLeft);
AddResultText(parent, "Duty Free Mileage Value", saveData.totalMileage + " M", new Vector2(1000f, -45f), new Vector2(122f, 28f), 21f, FontStyles.Bold, new Color(1f, 0.90f, 0.38f, 1f), TextAlignmentOptions.MidlineLeft);
}
private void AddDutyFreeEquipSlot(RectTransform parent, int slotIndex, Vector2 topLeftPosition) {
bool unlocked = slotIndex < saveData.bagSlots;
DutyFreeItemType itemType = unlocked ? GetEquippedDutyFreeItem(slotIndex) : DutyFreeItemType.None;
bool hasItem = itemType != DutyFreeItemType.None;
GameObject slotObject = CreateUiObject("Duty Free Equip Slot " + (slotIndex + 1), parent, typeof(Image), typeof(Button));
RectTransform slotRect = slotObject.GetComponent<RectTransform>();
slotRect.anchorMin = new Vector2(0f, 1f);
slotRect.anchorMax = new Vector2(0f, 1f);
slotRect.pivot = new Vector2(0f, 1f);
slotRect.anchoredPosition = topLeftPosition;
slotRect.sizeDelta = new Vector2(64f, 64f);
Image slotImage = slotObject.GetComponent<Image>();
if(hasItem)
{
slotImage.sprite = LoadDutyFreeResourceSprite(DutyFreeOccupiedSlotResourcePath);
slotImage.color = slotImage.sprite != null ? Color.white : new Color(0.05f, 0.16f, 0.20f, 0.88f);
}
else if(unlocked)
{
slotImage.sprite = LoadDutyFreeResourceSprite(DutyFreeActiveSlotResourcePath);
slotImage.color = slotImage.sprite != null ? Color.white : new Color(0.58f, 0.36f, 0.18f, 0.88f);
}
else
{
slotImage.sprite = LoadDutyFreeResourceSprite(DutyFreeInactiveSlotResourcePath);
slotImage.color = slotImage.sprite != null ? Color.white : new Color(0.35f, 0.35f, 0.35f, 0.78f);
}
slotImage.preserveAspect = true;
slotImage.raycastTarget = hasItem;
Button slotButton = slotObject.GetComponent<Button>();
slotButton.targetGraphic = slotImage;
slotButton.interactable = hasItem;
slotButton.navigation = new Navigation {
mode = Navigation.Mode.None
};
if(hasItem)
{
int capturedSlotIndex = slotIndex;
slotButton.onClick.AddListener(delegate { UnequipDutyFreeSlot(capturedSlotIndex); });
}
AddResultText(slotRect, "Duty Free Slot Number", (slotIndex + 1).ToString(), new Vector2(3f, -3f), new Vector2(18f, 18f), 10f, FontStyles.Bold, new Color(0.78f, 0.92f, 0.97f, 0.94f), TextAlignmentOptions.Center);
if(hasItem)
{
AddResultImage(slotRect, "Duty Free Slot Icon", GetDutyFreeItemSprite(itemType), new Vector2(32f, -31f), new Vector2(36f, 36f), true, Color.white);
AddResultText(slotRect, "Duty Free Slot Name", GetDutyFreeItemShortName(itemType), new Vector2(5f, -50f), new Vector2(54f, 12f), 8f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 0.96f), TextAlignmentOptions.Center);
}
}
private void AddDutyFreeBagUpgradeButton(RectTransform parent, Vector2 topLeftPosition) {
bool isMax = saveData.bagSlots >= 3;
bool canBuy = !isMax && saveData.totalMileage >= BagSlotUpgradeCost;
GameObject buttonObject = CreateUiObject("Duty Free Bag Upgrade", parent, typeof(Image), typeof(Button));
RectTransform buttonRect = buttonObject.GetComponent<RectTransform>();
buttonRect.anchorMin = new Vector2(0f, 1f);
buttonRect.anchorMax = new Vector2(0f, 1f);
buttonRect.pivot = new Vector2(0f, 1f);
buttonRect.anchoredPosition = topLeftPosition;
buttonRect.sizeDelta = new Vector2(160f, 64f);
Image buttonImage = buttonObject.GetComponent<Image>();
buttonImage.sprite = LoadUiSprite(
canBuy ? DutyFreeButtonPrimaryResourcePath : DutyFreeButtonDisabledResourcePath,
canBuy ? "Assets/Resources/UI_DutyFreeButton_PrimaryYellow.png" : "Assets/Resources/UI_DutyFreeButton_DisabledGray.png");
buttonImage.color = canBuy
? Color.white
: (buttonImage.sprite != null ? Color.white : new Color(0.36f, 0.43f, 0.47f, 0.76f));
buttonImage.preserveAspect = false;
buttonImage.raycastTarget = canBuy;
Button button = buttonObject.GetComponent<Button>();
button.targetGraphic = buttonImage;
button.interactable = canBuy;
button.navigation = new Navigation {
mode = Navigation.Mode.None
};
button.onClick.AddListener(BuyBagSlotUpgrade);
AddResultImage(buttonRect, "Duty Free Bag Upgrade Icon", LoadUiSprite("", DutyFreeBackpackAssetPath), new Vector2(45f, -32f), new Vector2(42f, 42f), true, canBuy ? Color.white : new Color(1f, 1f, 1f, 0.48f));
AddResultText(buttonRect, "Duty Free Bag Upgrade Label", isMax ? "가방 MAX" : "가방 +1", new Vector2(75f, -11f), new Vector2(66f, 24f), 16f, FontStyles.Bold, canBuy ? new Color(0.06f, 0.16f, 0.22f, 1f) : new Color(0.72f, 0.80f, 0.84f, 0.92f), TextAlignmentOptions.MidlineLeft);
AddResultText(buttonRect, "Duty Free Bag Upgrade Cost", isMax ? "" : BagSlotUpgradeCost + " M", new Vector2(85f, -36f), new Vector2(66f, 18f), 14f, FontStyles.Bold, canBuy ? new Color(0.87f, 0.55f, 0.08f, 1f) : new Color(0.62f, 0.68f, 0.70f, 0.92f), TextAlignmentOptions.MidlineLeft);
}
private void AddDutyFreeItemCard(RectTransform parent, string itemName, DutyFreeItemType itemType, int cost, int stock, Sprite itemSprite, UnityEngine.Events.UnityAction buyAction, Vector2 topLeftPosition) {
bool canBuy = CanBuyDutyFreeItem(itemType, cost);
bool hasFreeSlot = HasFreeDutyFreeSlot();
int equippedCount = GetEquippedDutyFreeItemCount(itemType);
bool canEquip = stock > equippedCount && hasFreeSlot;
bool canInteract = canEquip || canBuy;
GameObject cardObject = CreateUiObject("Duty Free Item " + itemName, parent, typeof(Image));
RectTransform cardRect = cardObject.GetComponent<RectTransform>();
cardRect.anchorMin = new Vector2(0f, 1f);
cardRect.anchorMax = new Vector2(0f, 1f);
cardRect.pivot = new Vector2(0f, 1f);
cardRect.anchoredPosition = topLeftPosition;
cardRect.sizeDelta = new Vector2(206f, 288f);
Image cardImage = cardObject.GetComponent<Image>();
cardImage.sprite = GetDutyFreeProductCardSprite(itemType);
cardImage.color = cardImage.sprite != null
? (canInteract ? Color.white : new Color(0.68f, 0.70f, 0.72f, 0.92f))
: canInteract
? new Color(0.97f, 0.91f, 0.78f, 0.96f)
: new Color(0.40f, 0.45f, 0.48f, 0.88f);
cardImage.preserveAspect = false;
cardImage.raycastTarget = false;
Color textColor = canInteract
? new Color(0.06f, 0.16f, 0.22f, 1f)
: new Color(0.78f, 0.84f, 0.86f, 1f);
AddResultImage(cardRect, "Duty Free " + itemName + " Image", itemSprite, new Vector2(103f, -107f), new Vector2(92f, 96f), true, canInteract ? Color.white : new Color(1f, 1f, 1f, 0.54f));
Image priceTagImage = AddResultImage(cardRect, "Duty Free " + itemName + " Price Tag", LoadDutyFreeResourceSprite(DutyFreeProductPriceTagResourcePath), new Vector2(151f, -150f), new Vector2(52f, 78f), true, canInteract ? Color.white : new Color(1f, 1f, 1f, 0.62f));
priceTagImage.rectTransform.localEulerAngles = new Vector3(0f, 0f, 110f);
TextMeshProUGUI priceText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Price", cost + "M", new Vector2(153f, -150f), new Vector2(40f, 18f), 11f, FontStyles.Bold, canInteract ? new Color(0.03f, 0.03f, 0.028f, 1f) : new Color(0.36f, 0.36f, 0.34f, 0.92f), TextAlignmentOptions.Center);
priceText.rectTransform.pivot = new Vector2(0.5f, 0.5f);
priceText.rectTransform.anchoredPosition = new Vector2(155f, -150f);
priceText.rectTransform.localEulerAngles = new Vector3(0f, 0f, 20f);
TextMeshProUGUI nameText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Name", itemName + "\n" + GetDutyFreeItemEffectText(itemType), new Vector2(103f, -199f), new Vector2(126f, 34f), 13f, FontStyles.Bold, textColor, TextAlignmentOptions.Center);
nameText.lineSpacing = -8f;
GameObject buyObject = CreateUiObject("Duty Free " + itemName + " Buy Area", cardRect, typeof(Image), typeof(Button));
RectTransform buyRect = buyObject.GetComponent<RectTransform>();
buyRect.anchorMin = new Vector2(0f, 1f);
buyRect.anchorMax = new Vector2(0f, 1f);
buyRect.pivot = new Vector2(0f, 1f);
buyRect.anchoredPosition = new Vector2(39f, -232f);
buyRect.sizeDelta = new Vector2(128f, 22f);
Image buyImage = buyObject.GetComponent<Image>();
buyImage.color = Color.clear;
buyImage.raycastTarget = canInteract;
Button buyButton = buyObject.GetComponent<Button>();
buyButton.targetGraphic = buyImage;
buyButton.interactable = canInteract;
buyButton.transition = Selectable.Transition.None;
buyButton.navigation = new Navigation {
mode = Navigation.Mode.None
};
buyButton.onClick.AddListener(buyAction);
TextMeshProUGUI buyText = AddResultText(buyRect, "Duty Free " + itemName + " Buy Label", GetDutyFreePurchaseLabel(itemType, canEquip, canBuy, hasFreeSlot, stock, equippedCount), Vector2.zero, new Vector2(128f, 22f), 11f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 1f), TextAlignmentOptions.Center);
buyText.outlineColor = new Color(0f, 0.04f, 0.07f, 0.98f);
buyText.outlineWidth = 0.12f;
}
private void AddDutyFreeSupplementCard(RectTransform parent, string itemName, int cost, int purchaseCount, Sprite itemSprite, UnityEngine.Events.UnityAction buyAction, Vector2 topLeftPosition) {
bool isMax = purchaseCount >= MaxSupplementPurchases;
bool alreadyPurchasedThisStage = HasPurchasedSupplementInDutyFreeStage();
bool canBuy = CanBuySupplement();
GameObject cardObject = CreateUiObject("Duty Free Item " + itemName, parent, typeof(Image));
RectTransform cardRect = cardObject.GetComponent<RectTransform>();
cardRect.anchorMin = new Vector2(0f, 1f);
cardRect.anchorMax = new Vector2(0f, 1f);
cardRect.pivot = new Vector2(0f, 1f);
cardRect.anchoredPosition = topLeftPosition;
cardRect.sizeDelta = new Vector2(206f, 288f);
Image cardImage = cardObject.GetComponent<Image>();
cardImage.sprite = GetDutyFreeProductCardSprite(DutyFreeItemType.Supplement);
cardImage.color = cardImage.sprite != null
? (canBuy || isMax ? Color.white : new Color(0.68f, 0.70f, 0.72f, 0.92f))
: canBuy
? new Color(0.97f, 0.91f, 0.78f, 0.96f)
: new Color(0.40f, 0.45f, 0.48f, 0.88f);
cardImage.preserveAspect = false;
cardImage.raycastTarget = false;
Color textColor = canBuy || isMax
? new Color(0.06f, 0.16f, 0.22f, 1f)
: new Color(0.78f, 0.84f, 0.86f, 1f);
AddResultImage(cardRect, "Duty Free " + itemName + " Image", itemSprite, new Vector2(103f, -107f), new Vector2(92f, 96f), true, canBuy || isMax ? Color.white : new Color(1f, 1f, 1f, 0.54f));
Image priceTagImage = AddResultImage(cardRect, "Duty Free " + itemName + " Price Tag", LoadDutyFreeResourceSprite(DutyFreeProductPriceTagResourcePath), new Vector2(151f, -150f), new Vector2(52f, 78f), true, canBuy || isMax ? Color.white : new Color(1f, 1f, 1f, 0.62f));
priceTagImage.rectTransform.localEulerAngles = new Vector3(0f, 0f, 110f);
TextMeshProUGUI priceText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Price", isMax ? "MAX" : cost + "M", new Vector2(153f, -150f), new Vector2(40f, 18f), 11f, FontStyles.Bold, canBuy || isMax ? new Color(0.03f, 0.03f, 0.028f, 1f) : new Color(0.36f, 0.36f, 0.34f, 0.92f), TextAlignmentOptions.Center);
priceText.rectTransform.pivot = new Vector2(0.5f, 0.5f);
priceText.rectTransform.anchoredPosition = new Vector2(155f, -150f);
priceText.rectTransform.localEulerAngles = new Vector3(0f, 0f, 20f);
TextMeshProUGUI nameText = AddResultCenteredText(cardRect, "Duty Free " + itemName + " Name", itemName + "\n" + GetDutyFreeSupplementEffectText(purchaseCount), new Vector2(103f, -199f), new Vector2(126f, 34f), 13f, FontStyles.Bold, textColor, TextAlignmentOptions.Center);
nameText.lineSpacing = -8f;
GameObject buyObject = CreateUiObject("Duty Free " + itemName + " Buy Area", cardRect, typeof(Image), typeof(Button));
RectTransform buyRect = buyObject.GetComponent<RectTransform>();
buyRect.anchorMin = new Vector2(0f, 1f);
buyRect.anchorMax = new Vector2(0f, 1f);
buyRect.pivot = new Vector2(0f, 1f);
buyRect.anchoredPosition = new Vector2(39f, -232f);
buyRect.sizeDelta = new Vector2(128f, 22f);
Image buyImage = buyObject.GetComponent<Image>();
buyImage.color = Color.clear;
buyImage.raycastTarget = canBuy;
Button buyButton = buyObject.GetComponent<Button>();
buyButton.targetGraphic = buyImage;
buyButton.interactable = canBuy;
buyButton.transition = Selectable.Transition.None;
buyButton.navigation = new Navigation {
mode = Navigation.Mode.None
};
buyButton.onClick.AddListener(buyAction);
TextMeshProUGUI buyText = AddResultText(buyRect, "Duty Free " + itemName + " Buy Label", GetDutyFreeSupplementPurchaseLabel(canBuy, isMax, alreadyPurchasedThisStage), Vector2.zero, new Vector2(128f, 22f), 11f, FontStyles.Bold, new Color(0.94f, 0.99f, 1f, 1f), TextAlignmentOptions.Center);
buyText.outlineColor = new Color(0f, 0.04f, 0.07f, 0.98f);
buyText.outlineWidth = 0.12f;
}
private void AddDutyFreeNextTravelButton() {
GameObject buttonObject = CreateUiObject("Duty Free Next Travel Sign", overlayRoot, typeof(Image), typeof(Button));
RectTransform buttonRect = buttonObject.GetComponent<RectTransform>();
buttonRect.anchorMin = new Vector2(0.5f, 0.5f);
buttonRect.anchorMax = new Vector2(0.5f, 0.5f);
buttonRect.pivot = new Vector2(0.5f, 0.5f);
buttonRect.anchoredPosition = new Vector2(548f, -247f);
buttonRect.sizeDelta = new Vector2(200f, 160f);
Image buttonImage = buttonObject.GetComponent<Image>();
buttonImage.sprite = LoadDutyFreeResourceSprite(DutyFreeDirectionSignResourcePath);
buttonImage.color = buttonImage.sprite != null ? Color.white : new Color(0.82f, 0.91f, 0.96f, 0.90f);
buttonImage.preserveAspect = true;
buttonImage.raycastTarget = true;
Button button = buttonObject.GetComponent<Button>();
button.targetGraphic = buttonImage;
button.onClick.AddListener(ShowMapPreview);
button.navigation = new Navigation {
mode = Navigation.Mode.None
};
}
}