Files
WhaleAdventure_VR/Assets/My project/Fishing Scripts/UI/FishingRewardSystem.cs
2026-06-25 17:39:42 +09:00

256 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
public class FishingRewardSystem : MonoBehaviour
{
[Serializable]
public class LootEntry
{
public FishingItemType itemType = FishingItemType.Fish;
public string displayName = "생선";
[Min(0f)] public float weight = 1f;
public LootEntry(FishingItemType itemType, string displayName, float weight)
{
this.itemType = itemType;
this.displayName = displayName;
this.weight = Mathf.Max(0f, weight);
}
}
public struct CatchResult
{
public FishingItemType ItemType;
public string DisplayName;
public bool CountsAsCleanupItem;
public bool IsMemoryPiece;
public CatchResult(FishingItemType itemType, string displayName, bool countsAsCleanupItem, bool isMemoryPiece)
{
ItemType = itemType;
DisplayName = displayName;
CountsAsCleanupItem = countsAsCleanupItem;
IsMemoryPiece = isMemoryPiece;
}
}
[Header("Loot Table - Dirty Pond")]
[Tooltip("연못이 정화되기 전 낚이는 아이템 목록입니다. 기억의 조각은 이 테이블에 있어도 자동 제외됩니다.")]
[SerializeField] private List<LootEntry> dirtyPondLootTable = new List<LootEntry>();
[Header("Loot Table - Clean Pond")]
[Tooltip("연못이 정화된 뒤 낚이는 아이템 목록입니다. 기억의 조각을 포함할 수 있습니다.")]
[SerializeField] private List<LootEntry> cleanPondLootTable = new List<LootEntry>();
[Header("Debug")]
[SerializeField] private bool showDebugLog = true;
public IReadOnlyList<LootEntry> DirtyPondLootTable => dirtyPondLootTable;
public IReadOnlyList<LootEntry> CleanPondLootTable => cleanPondLootTable;
private void Reset()
{
SetDefaultLootTables();
}
private void Awake()
{
EnsureLootTables();
}
private void OnValidate()
{
EnsureLootTables();
ClampLootTable(dirtyPondLootTable);
ClampLootTable(cleanPondLootTable);
}
private void EnsureLootTables()
{
if (dirtyPondLootTable == null)
dirtyPondLootTable = new List<LootEntry>();
if (cleanPondLootTable == null)
cleanPondLootTable = new List<LootEntry>();
if (dirtyPondLootTable.Count == 0)
SetDefaultDirtyLootTable();
if (cleanPondLootTable.Count == 0)
SetDefaultCleanLootTable();
}
private void SetDefaultLootTables()
{
SetDefaultDirtyLootTable();
SetDefaultCleanLootTable();
}
private void SetDefaultDirtyLootTable()
{
dirtyPondLootTable = new List<LootEntry>
{
new LootEntry(FishingItemType.Fish, "생선", 25f),
new LootEntry(FishingItemType.RottenFish, "상한 생선", 8f),
new LootEntry(FishingItemType.Trash, "쓰레기", 28f),
new LootEntry(FishingItemType.Bottle, "병", 18f),
new LootEntry(FishingItemType.PlasticBag, "봉지", 18f),
new LootEntry(FishingItemType.JellyfishPowder, "해파리 가루", 6f),
new LootEntry(FishingItemType.OldCompass, "낡은 나침반", 4f)
};
}
private void SetDefaultCleanLootTable()
{
cleanPondLootTable = new List<LootEntry>
{
new LootEntry(FishingItemType.MemoryPiece, "기억의 조각", 30f),
new LootEntry(FishingItemType.Fish, "생선", 30f),
new LootEntry(FishingItemType.OldCompass, "낡은 나침반", 15f),
new LootEntry(FishingItemType.JellyfishPowder, "해파리 가루", 15f),
new LootEntry(FishingItemType.RottenFish, "상한 생선", 4f)
};
}
private void ClampLootTable(List<LootEntry> table)
{
if (table == null)
return;
for (int i = 0; i < table.Count; i++)
{
if (table[i] == null)
{
table[i] = new LootEntry(FishingItemType.Fish, "생선", 1f);
continue;
}
table[i].weight = Mathf.Max(0f, table[i].weight);
if (string.IsNullOrWhiteSpace(table[i].displayName))
table[i].displayName = GetDefaultDisplayName(table[i].itemType);
}
}
public CatchResult RollCatch(bool pondCleaned, bool forceMemoryPiece)
{
if (forceMemoryPiece)
return CreateCatchResult(FishingItemType.MemoryPiece, GetDefaultDisplayName(FishingItemType.MemoryPiece));
List<LootEntry> table = pondCleaned ? cleanPondLootTable : dirtyPondLootTable;
LootEntry selectedEntry = RollFromTable(table, pondCleaned);
if (selectedEntry == null)
return CreateCatchResult(FishingItemType.Fish, GetDefaultDisplayName(FishingItemType.Fish));
return CreateCatchResult(selectedEntry.itemType, selectedEntry.displayName);
}
private LootEntry RollFromTable(List<LootEntry> table, bool pondCleaned)
{
if (table == null || table.Count == 0)
return null;
float totalWeight = 0f;
for (int i = 0; i < table.Count; i++)
{
LootEntry entry = table[i];
if (!IsRollableEntry(entry, pondCleaned))
continue;
totalWeight += entry.weight;
}
if (totalWeight <= 0f)
return null;
float roll = UnityEngine.Random.Range(0f, totalWeight);
float current = 0f;
for (int i = 0; i < table.Count; i++)
{
LootEntry entry = table[i];
if (!IsRollableEntry(entry, pondCleaned))
continue;
current += entry.weight;
if (roll <= current)
return entry;
}
return null;
}
private bool IsRollableEntry(LootEntry entry, bool pondCleaned)
{
if (entry == null)
return false;
if (entry.weight <= 0f)
return false;
if (!pondCleaned && entry.itemType == FishingItemType.MemoryPiece)
return false;
return entry.itemType != FishingItemType.None;
}
private CatchResult CreateCatchResult(FishingItemType itemType, string displayName)
{
string finalDisplayName = string.IsNullOrWhiteSpace(displayName) ? GetDefaultDisplayName(itemType) : displayName;
bool countsAsCleanupItem = IsCleanupItem(itemType);
bool isMemoryPiece = itemType == FishingItemType.MemoryPiece;
if (showDebugLog)
Debug.Log($"낚시 획득: {finalDisplayName}");
return new CatchResult(itemType, finalDisplayName, countsAsCleanupItem, isMemoryPiece);
}
public bool IsCleanupItem(FishingItemType itemType)
{
return itemType == FishingItemType.Trash ||
itemType == FishingItemType.Bottle ||
itemType == FishingItemType.PlasticBag;
}
public string GetDefaultDisplayName(FishingItemType itemType)
{
switch (itemType)
{
case FishingItemType.Fish:
return "생선";
case FishingItemType.RottenFish:
return "상한 생선";
case FishingItemType.Trash:
return "쓰레기";
case FishingItemType.Bottle:
return "병";
case FishingItemType.PlasticBag:
return "봉지";
case FishingItemType.JellyfishPowder:
return "해파리 가루";
case FishingItemType.OldCompass:
return "낡은 나침반";
case FishingItemType.MemoryPiece:
return "기억의 조각";
case FishingItemType.None:
default:
return "없음";
}
}
}