256 lines
7.7 KiB
C#
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 "없음";
|
|
}
|
|
}
|
|
}
|