Fix storage slot filtering with parent tag system and add F10 spawn window
Storage Fix: - Implemented CardBinderContent parent tag shared by cards and binder sheets - Fixed Card Binder slots to use single tag requirement (CardBinderContent) - Unity's requireTags uses AND logic, not OR - previous approach required items to have ALL tags - Storage hierarchy now works correctly: * Cards can be stored in Binder Sheets (requires TradingCard tag) * Cards can be stored in Card Binders (requires CardBinderContent tag) * Binder Sheets can be stored in Card Binders (requires CardBinderContent tag) * Binder Sheets cannot be stored in other Binder Sheets (lacks TradingCard tag) F10 Spawn Window: - Replaced F9 key cycling with OnGUI floating window (changed to F10 to avoid mod conflicts) - Added buttons for spawning Card Binder and Binder Sheet - Added buttons for spawning random cards by rarity (Common, Uncommon, Rare, Very Rare, Ultra Rare) - Window is draggable and positioned to avoid UI overlap Cleanup: - Removed ExampleSet placeholder card data 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
1050d4f018
commit
d0663d569a
@ -1,21 +0,0 @@
|
|||||||
# Example Card Set - Trading Card Mod for Escape from Duckov
|
|
||||||
# Format: CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value | Description (optional)
|
|
||||||
#
|
|
||||||
# Fields:
|
|
||||||
# CardName - Display name of the card
|
|
||||||
# SetName - Name of the card collection
|
|
||||||
# SetNumber - Number within the set (for sorting)
|
|
||||||
# ImageFile - Filename of the card image (must be in images/ subfolder)
|
|
||||||
# Rarity - Card rarity. Valid values: Common, Uncommon, Rare, Very Rare, Ultra Rare, Legendary
|
|
||||||
# Weight - Physical weight in game units
|
|
||||||
# Value - In-game currency value
|
|
||||||
# Description - (Optional) Custom tooltip text. If omitted, auto-generates as "SetName #SetNumber - Rarity"
|
|
||||||
#
|
|
||||||
# Add your own cards below! Just follow the format above.
|
|
||||||
# Place corresponding images in the images/ subfolder.
|
|
||||||
|
|
||||||
Duck Hero | Example Set | 001 | duck_hero.png | Rare | 0.05 | 500 | The brave defender of all ponds
|
|
||||||
Golden Quacker | Example Set | 002 | golden_quacker.png | Ultra Rare | 0.05 | 12500 | A legendary duck made of pure gold
|
|
||||||
Pond Guardian | Example Set | 003 | pond_guardian.png | Uncommon | 0.05 | 100
|
|
||||||
Bread Seeker | Example Set | 004 | bread_seeker.png | Common | 0.05 | 25
|
|
||||||
Feathered Fury | Example Set | 005 | feathered_fury.png | Rare | 0.05 | 500 | Known for its fierce battle cry
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
@ -50,6 +50,9 @@
|
|||||||
<Reference Include="UnityEngine.InputLegacyModule">
|
<Reference Include="UnityEngine.InputLegacyModule">
|
||||||
<HintPath>$(DuckovPath)$(SubPath)UnityEngine.InputLegacyModule.dll</HintPath>
|
<HintPath>$(DuckovPath)$(SubPath)UnityEngine.InputLegacyModule.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.IMGUIModule">
|
||||||
|
<HintPath>$(DuckovPath)$(SubPath)UnityEngine.IMGUIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="UniTask">
|
<Reference Include="UniTask">
|
||||||
<HintPath>$(DuckovPath)$(SubPath)UniTask.dll</HintPath>
|
<HintPath>$(DuckovPath)$(SubPath)UniTask.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using ItemStatsSystem;
|
using ItemStatsSystem;
|
||||||
using SodaCraft.Localizations;
|
using SodaCraft.Localizations;
|
||||||
@ -72,6 +73,7 @@ namespace TradingCardMod
|
|||||||
private List<GameObject> _createdGameObjects = new List<GameObject>();
|
private List<GameObject> _createdGameObjects = new List<GameObject>();
|
||||||
private Tag? _tradingCardTag;
|
private Tag? _tradingCardTag;
|
||||||
private Tag? _binderSheetTag;
|
private Tag? _binderSheetTag;
|
||||||
|
private Tag? _cardBinderContentTag;
|
||||||
private Item? _binderItem;
|
private Item? _binderItem;
|
||||||
private Item? _cardBoxItem;
|
private Item? _cardBoxItem;
|
||||||
|
|
||||||
@ -84,9 +86,10 @@ namespace TradingCardMod
|
|||||||
// Store pack definitions for runtime lookup (key = "SetName|PackName")
|
// Store pack definitions for runtime lookup (key = "SetName|PackName")
|
||||||
private Dictionary<string, CardPack> _packDefinitions = new Dictionary<string, CardPack>();
|
private Dictionary<string, CardPack> _packDefinitions = new Dictionary<string, CardPack>();
|
||||||
|
|
||||||
// Debug: track spawn cycling
|
// Debug spawn window
|
||||||
private int _debugSpawnIndex = 0;
|
private bool _showSpawnWindow = false;
|
||||||
private List<Item> _allSpawnableItems = new List<Item>();
|
private Rect _spawnWindowRect = new Rect(20, 250, 350, 450);
|
||||||
|
private System.Random _random = new System.Random();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the GameObject is created. Initialize early to register items before saves load.
|
/// Called when the GameObject is created. Initialize early to register items before saves load.
|
||||||
@ -112,6 +115,7 @@ namespace TradingCardMod
|
|||||||
// Create our custom tags first
|
// Create our custom tags first
|
||||||
_tradingCardTag = TagHelper.GetOrCreateTradingCardTag();
|
_tradingCardTag = TagHelper.GetOrCreateTradingCardTag();
|
||||||
_binderSheetTag = TagHelper.GetOrCreateBinderSheetTag();
|
_binderSheetTag = TagHelper.GetOrCreateBinderSheetTag();
|
||||||
|
_cardBinderContentTag = TagHelper.GetOrCreateCardBinderContentTag();
|
||||||
|
|
||||||
// Load and register cards - do this early so saves can load them
|
// Load and register cards - do this early so saves can load them
|
||||||
LoadCardSets();
|
LoadCardSets();
|
||||||
@ -122,12 +126,6 @@ namespace TradingCardMod
|
|||||||
// Create card packs
|
// Create card packs
|
||||||
CreateCardPacks();
|
CreateCardPacks();
|
||||||
|
|
||||||
// Build spawnable items list (cards + storage + packs)
|
|
||||||
_allSpawnableItems.AddRange(_registeredItems);
|
|
||||||
if (_binderItem != null) _allSpawnableItems.Add(_binderItem);
|
|
||||||
if (_cardBoxItem != null) _allSpawnableItems.Add(_cardBoxItem);
|
|
||||||
_allSpawnableItems.AddRange(_registeredPacks);
|
|
||||||
|
|
||||||
Debug.Log("[TradingCardMod] Mod initialized successfully!");
|
Debug.Log("[TradingCardMod] Mod initialized successfully!");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -299,7 +297,7 @@ namespace TradingCardMod
|
|||||||
|
|
||||||
Debug.Log($"[TradingCardMod] Total cards loaded: {_loadedCards.Count}");
|
Debug.Log($"[TradingCardMod] Total cards loaded: {_loadedCards.Count}");
|
||||||
Debug.Log($"[TradingCardMod] Total items registered: {_registeredItems.Count}");
|
Debug.Log($"[TradingCardMod] Total items registered: {_registeredItems.Count}");
|
||||||
Debug.Log("[TradingCardMod] DEBUG: Press F9 to spawn items (cycles through cards, then binder, then box)");
|
Debug.Log("[TradingCardMod] DEBUG: Press F10 to open spawn menu (storage items & random cards by rarity)");
|
||||||
|
|
||||||
// Clear the search cache so our items can be found
|
// Clear the search cache so our items can be found
|
||||||
ClearSearchCache();
|
ClearSearchCache();
|
||||||
@ -335,7 +333,7 @@ namespace TradingCardMod
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void CreateStorageItems()
|
private void CreateStorageItems()
|
||||||
{
|
{
|
||||||
if (_tradingCardTag == null || _binderSheetTag == null)
|
if (_tradingCardTag == null || _binderSheetTag == null || _cardBinderContentTag == null)
|
||||||
{
|
{
|
||||||
Debug.LogError("[TradingCardMod] Cannot create storage items - Required tags not created!");
|
Debug.LogError("[TradingCardMod] Cannot create storage items - Required tags not created!");
|
||||||
return;
|
return;
|
||||||
@ -352,14 +350,17 @@ namespace TradingCardMod
|
|||||||
new List<Tag> { _tradingCardTag } // Only trading cards allowed
|
new List<Tag> { _tradingCardTag } // Only trading cards allowed
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add BinderSheet tag to the binder sheet item itself so it can be stored in Card Binders
|
// Add BinderSheet and CardBinderContent tags to the binder sheet item itself
|
||||||
|
// so it can be stored in Card Binders
|
||||||
if (_binderItem != null)
|
if (_binderItem != null)
|
||||||
{
|
{
|
||||||
_binderItem.Tags.Add(_binderSheetTag);
|
_binderItem.Tags.Add(_binderSheetTag);
|
||||||
Debug.Log("[TradingCardMod] Added BinderSheet tag to Binder Sheet item");
|
_binderItem.Tags.Add(_cardBinderContentTag);
|
||||||
|
Debug.Log("[TradingCardMod] Added BinderSheet and CardBinderContent tags to Binder Sheet item");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Card Binder (12 slots, stores cards AND binder sheets)
|
// Create Card Binder (12 slots, stores items with CardBinderContent tag)
|
||||||
|
// This allows both cards and binder sheets (which both have CardBinderContent tag)
|
||||||
_cardBoxItem = StorageHelper.CreateCardStorage(
|
_cardBoxItem = StorageHelper.CreateCardStorage(
|
||||||
CARD_BINDER_ITEM_ID,
|
CARD_BINDER_ITEM_ID,
|
||||||
"Card Binder",
|
"Card Binder",
|
||||||
@ -367,7 +368,7 @@ namespace TradingCardMod
|
|||||||
12,
|
12,
|
||||||
1.5f, // weight
|
1.5f, // weight
|
||||||
12500, // value
|
12500, // value
|
||||||
new List<Tag> { _tradingCardTag, _binderSheetTag } // Cards and binder sheets allowed
|
new List<Tag> { _cardBinderContentTag } // Only CardBinderContent tag required
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,46 +432,158 @@ namespace TradingCardMod
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
// Debug: Press F9 to spawn an item
|
// Debug: Press F10 to toggle spawn menu
|
||||||
if (Input.GetKeyDown(KeyCode.F9))
|
if (Input.GetKeyDown(KeyCode.F10))
|
||||||
{
|
{
|
||||||
SpawnDebugItem();
|
_showSpawnWindow = !_showSpawnWindow;
|
||||||
|
Debug.Log($"[TradingCardMod] Spawn window {(_showSpawnWindow ? "opened" : "closed")}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spawns items for testing - cycles through cards, then storage items.
|
/// OnGUI is called for rendering and handling GUI events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SpawnDebugItem()
|
void OnGUI()
|
||||||
{
|
{
|
||||||
if (_allSpawnableItems.Count == 0)
|
if (!_showSpawnWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Set depth to ensure window is on top
|
||||||
|
UnityEngine.GUI.depth = -1000;
|
||||||
|
|
||||||
|
// Draw window and bring to front
|
||||||
|
_spawnWindowRect = UnityEngine.GUI.Window(12345, _spawnWindowRect, DrawSpawnWindow, "Spawn Items (F10 to close)");
|
||||||
|
UnityEngine.GUI.BringWindowToFront(12345);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws the spawn window contents.
|
||||||
|
/// </summary>
|
||||||
|
private void DrawSpawnWindow(int windowID)
|
||||||
|
{
|
||||||
|
UnityEngine.GUILayout.BeginVertical();
|
||||||
|
|
||||||
|
// Storage items
|
||||||
|
UnityEngine.GUILayout.Label("Storage Items:", UnityEngine.GUI.skin.box);
|
||||||
|
|
||||||
|
if (UnityEngine.GUILayout.Button("Card Binder"))
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[TradingCardMod] No items registered to spawn!");
|
SpawnStorageItem(_cardBoxItem, "Card Binder");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UnityEngine.GUILayout.Button("Binder Sheet"))
|
||||||
|
{
|
||||||
|
SpawnStorageItem(_binderItem, "Binder Sheet");
|
||||||
|
}
|
||||||
|
|
||||||
|
UnityEngine.GUILayout.Space(10);
|
||||||
|
|
||||||
|
// Random cards by rarity
|
||||||
|
UnityEngine.GUILayout.Label("Spawn Random Card:", UnityEngine.GUI.skin.box);
|
||||||
|
|
||||||
|
if (UnityEngine.GUILayout.Button("Random Common Card"))
|
||||||
|
{
|
||||||
|
SpawnRandomCardByRarity("Common");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UnityEngine.GUILayout.Button("Random Uncommon Card"))
|
||||||
|
{
|
||||||
|
SpawnRandomCardByRarity("Uncommon");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UnityEngine.GUILayout.Button("Random Rare Card"))
|
||||||
|
{
|
||||||
|
SpawnRandomCardByRarity("Rare");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UnityEngine.GUILayout.Button("Random Very Rare Card"))
|
||||||
|
{
|
||||||
|
SpawnRandomCardByRarity("Very Rare");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UnityEngine.GUILayout.Button("Random Ultra Rare Card"))
|
||||||
|
{
|
||||||
|
SpawnRandomCardByRarity("Ultra Rare");
|
||||||
|
}
|
||||||
|
|
||||||
|
UnityEngine.GUILayout.EndVertical();
|
||||||
|
|
||||||
|
// Make window draggable
|
||||||
|
UnityEngine.GUI.DragWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spawns a storage item (binder or binder sheet).
|
||||||
|
/// </summary>
|
||||||
|
private void SpawnStorageItem(Item? prefab, string itemName)
|
||||||
|
{
|
||||||
|
if (prefab == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[TradingCardMod] {itemName} not available!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cycle through all spawnable items
|
|
||||||
Item prefab = _allSpawnableItems[_debugSpawnIndex % _allSpawnableItems.Count];
|
|
||||||
_debugSpawnIndex++;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Instantiate a fresh copy of the item (don't send prefab directly)
|
|
||||||
Item instance = ItemAssetsCollection.InstantiateSync(prefab.TypeID);
|
Item instance = ItemAssetsCollection.InstantiateSync(prefab.TypeID);
|
||||||
if (instance != null)
|
if (instance != null)
|
||||||
{
|
{
|
||||||
// Use game's utility to give item to player
|
|
||||||
ItemUtilities.SendToPlayer(instance);
|
ItemUtilities.SendToPlayer(instance);
|
||||||
Debug.Log($"[TradingCardMod] Spawned: {instance.DisplayName} (ID: {instance.TypeID})");
|
Debug.Log($"[TradingCardMod] Spawned: {itemName}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError($"[TradingCardMod] Failed to instantiate {prefab.DisplayName} (ID: {prefab.TypeID})");
|
Debug.LogError($"[TradingCardMod] Failed to instantiate {itemName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogError($"[TradingCardMod] Failed to spawn item: {ex.Message}");
|
Debug.LogError($"[TradingCardMod] Failed to spawn {itemName}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spawns a random card of the specified rarity.
|
||||||
|
/// </summary>
|
||||||
|
private void SpawnRandomCardByRarity(string rarity)
|
||||||
|
{
|
||||||
|
// Find all cards of this rarity
|
||||||
|
var matchingCards = _loadedCards
|
||||||
|
.Where(c => c.Rarity.Equals(rarity, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (matchingCards.Count == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[TradingCardMod] No {rarity} cards found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick a random card
|
||||||
|
TradingCard randomCard = matchingCards[_random.Next(matchingCards.Count)];
|
||||||
|
|
||||||
|
// Get the item ID for this card
|
||||||
|
if (!_cardNameToTypeId.TryGetValue(randomCard.CardName, out int typeId))
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TradingCardMod] Card '{randomCard.CardName}' not registered!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Item instance = ItemAssetsCollection.InstantiateSync(typeId);
|
||||||
|
if (instance != null)
|
||||||
|
{
|
||||||
|
ItemUtilities.SendToPlayer(instance);
|
||||||
|
Debug.Log($"[TradingCardMod] Spawned random {rarity}: {randomCard.CardName}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TradingCardMod] Failed to instantiate card: {randomCard.CardName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TradingCardMod] Failed to spawn card: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,6 +717,12 @@ namespace TradingCardMod
|
|||||||
item.Tags.Add(_tradingCardTag);
|
item.Tags.Add(_tradingCardTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add CardBinderContent tag so cards can be stored in Card Binders
|
||||||
|
if (_cardBinderContentTag != null)
|
||||||
|
{
|
||||||
|
item.Tags.Add(_cardBinderContentTag);
|
||||||
|
}
|
||||||
|
|
||||||
// Load and set icon
|
// Load and set icon
|
||||||
Sprite? cardSprite = LoadSpriteFromFile(card.ImagePath, typeId);
|
Sprite? cardSprite = LoadSpriteFromFile(card.ImagePath, typeId);
|
||||||
if (cardSprite != null)
|
if (cardSprite != null)
|
||||||
@ -793,7 +912,6 @@ namespace TradingCardMod
|
|||||||
_cardNameToTypeId.Clear();
|
_cardNameToTypeId.Clear();
|
||||||
_registeredPacks.Clear();
|
_registeredPacks.Clear();
|
||||||
_packDefinitions.Clear();
|
_packDefinitions.Clear();
|
||||||
_allSpawnableItems.Clear();
|
|
||||||
|
|
||||||
Debug.Log("[TradingCardMod] Cleanup complete.");
|
Debug.Log("[TradingCardMod] Cleanup complete.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,6 +92,16 @@ namespace TradingCardMod
|
|||||||
return CreateOrCloneTag("BinderSheet", "Binder Sheet");
|
return CreateOrCloneTag("BinderSheet", "Binder Sheet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the "CardBinderContent" tag, creating it if it doesn't exist.
|
||||||
|
/// This is a parent tag shared by both cards and binder sheets, allowing both to be stored in card binders.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The CardBinderContent tag.</returns>
|
||||||
|
public static Tag GetOrCreateCardBinderContentTag()
|
||||||
|
{
|
||||||
|
return CreateOrCloneTag("CardBinderContent", "Card Binder Content");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all tags created by this mod.
|
/// Gets all tags created by this mod.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user