From d0663d569af26cf760f0510f844f0a5252646ad5 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Sun, 23 Nov 2025 00:03:18 -0600 Subject: [PATCH] Fix storage slot filtering with parent tag system and add F10 spawn window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CardSets/ExampleSet/cards.txt | 21 -- CardSets/ExampleSet/images/bread_seeker.png | Bin 3335 -> 0 bytes CardSets/ExampleSet/images/duck_hero.png | Bin 3403 -> 0 bytes CardSets/ExampleSet/images/feathered_fury.png | Bin 3023 -> 0 bytes CardSets/ExampleSet/images/golden_quacker.png | Bin 3226 -> 0 bytes CardSets/ExampleSet/images/pack.png | Bin 3762 -> 0 bytes CardSets/ExampleSet/images/pond_guardian.png | Bin 3571 -> 0 bytes TradingCardMod.csproj | 3 + src/ModBehaviour.cs | 182 +++++++++++++++--- src/TagHelper.cs | 10 + 10 files changed, 163 insertions(+), 53 deletions(-) delete mode 100644 CardSets/ExampleSet/cards.txt delete mode 100644 CardSets/ExampleSet/images/bread_seeker.png delete mode 100644 CardSets/ExampleSet/images/duck_hero.png delete mode 100644 CardSets/ExampleSet/images/feathered_fury.png delete mode 100644 CardSets/ExampleSet/images/golden_quacker.png delete mode 100644 CardSets/ExampleSet/images/pack.png delete mode 100644 CardSets/ExampleSet/images/pond_guardian.png diff --git a/CardSets/ExampleSet/cards.txt b/CardSets/ExampleSet/cards.txt deleted file mode 100644 index 9330b1b..0000000 --- a/CardSets/ExampleSet/cards.txt +++ /dev/null @@ -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 diff --git a/CardSets/ExampleSet/images/bread_seeker.png b/CardSets/ExampleSet/images/bread_seeker.png deleted file mode 100644 index e2548c57ac09397cd9b3047d0f2a9f37633a6be9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3335 zcmd5$VxwilSTOg{*M1f3DKhf9L zxcui_vnKu`XJ|rn4K-<2=~-@zgSqC?GXMbk6dsfb4wC%`Ye+jSt#FjiiT zByk&oAsw+|)1FC*Y*jNMgQVnILo`8)p0mq99qpiQVq+Rd&@;a`9a7`glTNa2A`-h- zi3$qk=N@_XxRw0~(kL`?Kz0Udw4JxzuP7-u-KM4$&qKuwtQL%60=WQaB^dzE;wg9r z!2l{w>KK)F0Fx&>fRgcwO2NO9q;NEjA;t-J(D38o7nyG?WWT(czXfHumird!-av-} zq-gD9ETUKs-(~O`DczOIMsCvimbFNCI!Fsuvd!?d=mjZB<%Pdyu-*SMhL77C;p`X3 zQs!{MVuLYyVK3_WWfoW2MW?q%aEliyv8Bh2Cfr@vYGst}Nu_+76>GJVQprN5csSPM z%lV*tJsQtFr~nLut#2pNn9*mrwm-)K6+GT9Ajt1Sv#imO_By@TwseN!sUDo|mdWUQ&rf|yiJU7N3 zZYIUcl9uKm#g#tweuhSV$FC8@{@T!f{_#Fx-;`0hyB>?F3pidZZQ2`4$+xB+(xd%n zfdudOPW*+-op*K*F*$AP@`{$T%!HyxUfbN%t-`|1L4?ABaE$rKHoA+(=M`!+$}MaN zRfuzrYG)^k)Z?&Vwm6{&y6oqsdZEGJv0OgE6%G>BXJrV)H(Pn1@e4|U%D3P2j##BE z()x)U8l$H|ocI)BkKNAPOFx<_U6!TvY0} z2@1SAUu%+|8I#Pt1?NywPp}CM*wc}E&@FcF^qO4c|ZM+ zbPeeTE<{l|EF6ke{iqA6bU&{$Z?-pIrce^Bu>?8qyWe$Ps%MuXi3gN?PS zY%ISJmmE6kuVr5wFfNwx=<4uZ7yZ>L0O8kWQ4sOH*Ay9iW+zBk$w2e+tLik9N#!e++DCqO$M)PEo$5bWst>}q`S9|13 zXQh5+*sz^^)Lh*_6f-+S5D`$=TwF^$7$kIY42&xmj^|iNX4o$sM%@t(ye8R^Y4~ZS zm&hb1wxT!8>7^8DAYFOylavH98qcS)T(>vOrupQatkL?Plc&8p>etTr1}4ELRhQu~cZ&qm)AK&ZOshpn_(V(ull-D0f08+~XPpkWn8Q(9GVetRKwc{%lK zK9Tsd_8X?Em~3&0S?EBf9*z~M_XJYbq7u{GWmK-CH6o(O;uZdDH&Fm)Q;#+S%~J)` zI!am;z-+Tr&ZxYT57diaa|)#BK6B|&#;+m?j~;(vc5$2Dn)r3o><~6P%LbzcHsX-e z_}r%+3u~I*lt9E#0^FoTrqRbM=QL^Qs!u?b@eRe?`3&Wc^~Oa+$?E(8&nve8m1)cB zu2qS$a0Pf!kbio>ajeh7=oT(((*2fFxGCf5#-zfYAMwrTC3)Vg3}AiDQj@Ivlt-!7z@2C%K(B z^lml+%fwW_Wp)Z_L1zLFWPul!u(uF+iC3iEhLArRKz0jsvNTQuC+NF=gJQ?S(p{t304(Dl_C@qU`wd({yg9l9+~BZY|A1 zZR>ON;`};nB!c7?e#IUTrHx>~3T;6&10GofIo;1j(cQex0!$5;$Myubn#C3kCHA?M z&diVkRh3)(qS{xz>AkCst5y>l6E4?}6Rtg#y145gF0s@NeddFt)^(JT>V=vTGkaTZ za?Hu}SwzlDeA$|-lH(uuD5WlPLMql_W0;t=ziM0&X>W9|N04BhR$|*rhK7s<_{iDA zeGb2vOcen6PXnXyTo!9$Qy7r6mcrLABh6i zG3cM|c5vLFS7cdd;W`xT@*G1#%B0A|BP*aC9bvl7 zyqJd+I=Y&HCzxQhsX=vj1iohlV#K6qS+11_e^T^3q-nb@fQ2k%R zW%>SSqX}~sP4*6yeBbT>*0Tf4%5{*2|w*VW8?Caz$;C_gvb%>iwh`XF?usaz5;$U$p5iv0l zFHdwG5`Po diff --git a/CardSets/ExampleSet/images/duck_hero.png b/CardSets/ExampleSet/images/duck_hero.png deleted file mode 100644 index 2b05e33b1cba81cdb216b9f77d09be4edb0ba979..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3403 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 diff --git a/CardSets/ExampleSet/images/feathered_fury.png b/CardSets/ExampleSet/images/feathered_fury.png deleted file mode 100644 index 9fc5e6d5a6626dbee97094f25a4bb3494f9768af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3023 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 PGyvMr3{`o>^|yZjccjyS diff --git a/CardSets/ExampleSet/images/pack.png b/CardSets/ExampleSet/images/pack.png deleted file mode 100644 index b343c3fb2a9a73c7b2738bfbe957222320140756..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3762 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 diff --git a/CardSets/ExampleSet/images/pond_guardian.png b/CardSets/ExampleSet/images/pond_guardian.png deleted file mode 100644 index 082ac9f0d9a7e963e2766120bcf36ca9b399c746..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3571 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 diff --git a/TradingCardMod.csproj b/TradingCardMod.csproj index f41943c..3cbf532 100644 --- a/TradingCardMod.csproj +++ b/TradingCardMod.csproj @@ -50,6 +50,9 @@ $(DuckovPath)$(SubPath)UnityEngine.InputLegacyModule.dll + + $(DuckovPath)$(SubPath)UnityEngine.IMGUIModule.dll + $(DuckovPath)$(SubPath)UniTask.dll diff --git a/src/ModBehaviour.cs b/src/ModBehaviour.cs index 498005c..76999fc 100644 --- a/src/ModBehaviour.cs +++ b/src/ModBehaviour.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Collections.Generic; +using System.Linq; using UnityEngine; using ItemStatsSystem; using SodaCraft.Localizations; @@ -72,6 +73,7 @@ namespace TradingCardMod private List _createdGameObjects = new List(); private Tag? _tradingCardTag; private Tag? _binderSheetTag; + private Tag? _cardBinderContentTag; private Item? _binderItem; private Item? _cardBoxItem; @@ -84,9 +86,10 @@ namespace TradingCardMod // Store pack definitions for runtime lookup (key = "SetName|PackName") private Dictionary _packDefinitions = new Dictionary(); - // Debug: track spawn cycling - private int _debugSpawnIndex = 0; - private List _allSpawnableItems = new List(); + // Debug spawn window + private bool _showSpawnWindow = false; + private Rect _spawnWindowRect = new Rect(20, 250, 350, 450); + private System.Random _random = new System.Random(); /// /// 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 _tradingCardTag = TagHelper.GetOrCreateTradingCardTag(); _binderSheetTag = TagHelper.GetOrCreateBinderSheetTag(); + _cardBinderContentTag = TagHelper.GetOrCreateCardBinderContentTag(); // Load and register cards - do this early so saves can load them LoadCardSets(); @@ -122,12 +126,6 @@ namespace TradingCardMod // Create card packs 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!"); } catch (Exception ex) @@ -299,7 +297,7 @@ namespace TradingCardMod Debug.Log($"[TradingCardMod] Total cards loaded: {_loadedCards.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 ClearSearchCache(); @@ -335,7 +333,7 @@ namespace TradingCardMod /// 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!"); return; @@ -352,14 +350,17 @@ namespace TradingCardMod new List { _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) { _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( CARD_BINDER_ITEM_ID, "Card Binder", @@ -367,7 +368,7 @@ namespace TradingCardMod 12, 1.5f, // weight 12500, // value - new List { _tradingCardTag, _binderSheetTag } // Cards and binder sheets allowed + new List { _cardBinderContentTag } // Only CardBinderContent tag required ); } @@ -431,46 +432,158 @@ namespace TradingCardMod /// void Update() { - // Debug: Press F9 to spawn an item - if (Input.GetKeyDown(KeyCode.F9)) + // Debug: Press F10 to toggle spawn menu + if (Input.GetKeyDown(KeyCode.F10)) { - SpawnDebugItem(); + _showSpawnWindow = !_showSpawnWindow; + Debug.Log($"[TradingCardMod] Spawn window {(_showSpawnWindow ? "opened" : "closed")}"); } } /// - /// Spawns items for testing - cycles through cards, then storage items. + /// OnGUI is called for rendering and handling GUI events. /// - 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); + } + + /// + /// Draws the spawn window contents. + /// + 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(); + } + + /// + /// Spawns a storage item (binder or binder sheet). + /// + private void SpawnStorageItem(Item? prefab, string itemName) + { + if (prefab == null) + { + Debug.LogWarning($"[TradingCardMod] {itemName} not available!"); return; } - // Cycle through all spawnable items - Item prefab = _allSpawnableItems[_debugSpawnIndex % _allSpawnableItems.Count]; - _debugSpawnIndex++; - try { - // Instantiate a fresh copy of the item (don't send prefab directly) Item instance = ItemAssetsCollection.InstantiateSync(prefab.TypeID); if (instance != null) { - // Use game's utility to give item to player ItemUtilities.SendToPlayer(instance); - Debug.Log($"[TradingCardMod] Spawned: {instance.DisplayName} (ID: {instance.TypeID})"); + Debug.Log($"[TradingCardMod] Spawned: {itemName}"); } else { - Debug.LogError($"[TradingCardMod] Failed to instantiate {prefab.DisplayName} (ID: {prefab.TypeID})"); + Debug.LogError($"[TradingCardMod] Failed to instantiate {itemName}"); } } catch (Exception ex) { - Debug.LogError($"[TradingCardMod] Failed to spawn item: {ex.Message}"); + Debug.LogError($"[TradingCardMod] Failed to spawn {itemName}: {ex.Message}"); + } + } + + /// + /// Spawns a random card of the specified rarity. + /// + 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); } + // Add CardBinderContent tag so cards can be stored in Card Binders + if (_cardBinderContentTag != null) + { + item.Tags.Add(_cardBinderContentTag); + } + // Load and set icon Sprite? cardSprite = LoadSpriteFromFile(card.ImagePath, typeId); if (cardSprite != null) @@ -793,7 +912,6 @@ namespace TradingCardMod _cardNameToTypeId.Clear(); _registeredPacks.Clear(); _packDefinitions.Clear(); - _allSpawnableItems.Clear(); Debug.Log("[TradingCardMod] Cleanup complete."); } diff --git a/src/TagHelper.cs b/src/TagHelper.cs index c640369..537010d 100644 --- a/src/TagHelper.cs +++ b/src/TagHelper.cs @@ -92,6 +92,16 @@ namespace TradingCardMod return CreateOrCloneTag("BinderSheet", "Binder Sheet"); } + /// + /// 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. + /// + /// The CardBinderContent tag. + public static Tag GetOrCreateCardBinderContentTag() + { + return CreateOrCloneTag("CardBinderContent", "Card Binder Content"); + } + /// /// Gets all tags created by this mod. ///