From 5af98a69a2a5fab3130de21a8a04731605c805c7 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Wed, 14 Jan 2026 23:20:56 -0600 Subject: [PATCH] Refactor conversation stuff --- cutscene/Cutscene.gd | 19 +++++++++++----- cutscene/conversation/ConversationAction.gd | 12 ++++++++++ .../conversation/ConversationAction.gd.uid | 1 + cutscene/conversation/ConversationElement.gd | 9 -------- cutscene/conversation/ConversationResource.gd | 9 ++++++++ .../conversation/ConversationResource.gd.uid | 1 + cutscene/item/ItemAction.gd | 16 ++++++++++++++ cutscene/item/ItemAction.gd.uid | 1 + item/Inventory.gd | 21 ++++++++++-------- item/Item.gd | 15 +++++++++++-- item/ItemResource.gd | 13 +++++++++++ item/ItemResource.gd.uid | 1 + item/ItemStack.gd | 3 +-- overworld/entity/Entity.gd | 6 ++++- overworld/entity/Entity.tscn | 1 + overworld/entity/EntityInteractableArea.gd | 22 ++++++++++++++++++- overworld/map/TestMap.tscn | 20 ++++++++++++----- ui/component/VNTextbox.gd | 1 + 18 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 cutscene/conversation/ConversationAction.gd create mode 100644 cutscene/conversation/ConversationAction.gd.uid delete mode 100644 cutscene/conversation/ConversationElement.gd create mode 100644 cutscene/conversation/ConversationResource.gd create mode 100644 cutscene/conversation/ConversationResource.gd.uid create mode 100644 cutscene/item/ItemAction.gd create mode 100644 cutscene/item/ItemAction.gd.uid create mode 100644 item/ItemResource.gd create mode 100644 item/ItemResource.gd.uid diff --git a/cutscene/Cutscene.gd b/cutscene/Cutscene.gd index 6bfb04e..2170009 100644 --- a/cutscene/Cutscene.gd +++ b/cutscene/Cutscene.gd @@ -34,12 +34,21 @@ func addCallable(params:Dictionary) -> int: return params["position"] -func addConversation(conversation:Array[ConversationElement]) -> Array[int]: +func addCallables(params:Dictionary) -> Array[int]: + assert(params.has("functions")) var indexes:Array[int] = [] - for element in conversation: - indexes.append(addCallable({ 'function': element.start })) + for element in params['functions']: + var newDict = element.merged(params, false) + newDict.erase('functions') + indexes.append(addCallable(newDict)) return indexes +func addConversation(resources:Array[ConversationResource]) -> Array[int]: + var callables:Array[Dictionary] = [] + for resource in resources: + callables.append(resource.toCallable()) + return addCallables({ 'functions': callables }) + func start() -> void: if queue.size() == 0: return @@ -47,7 +56,7 @@ func start() -> void: assert(!running) running = true index = 0 - while true: + while index < queue.size(): var queueItem = queue[index] var result = await queueItem['function'].call(queueItem) @@ -61,7 +70,7 @@ func start() -> void: _: index = result - if index >= queue.size() || index < 0: + if index < 0: break running = false diff --git a/cutscene/conversation/ConversationAction.gd b/cutscene/conversation/ConversationAction.gd new file mode 100644 index 0000000..3eb788d --- /dev/null +++ b/cutscene/conversation/ConversationAction.gd @@ -0,0 +1,12 @@ +class_name ConversationAction + +static func textboxCallable(params:Dictionary) -> int: + assert(params.has('label')) + await UI.TEXTBOX.setTextAndWait(params['label']) + return Cutscene.CUTSCENE_CONTINUE + +static func getTextboxCallable(label:String) -> Dictionary: + return { + "function": textboxCallable, + "label": label + } \ No newline at end of file diff --git a/cutscene/conversation/ConversationAction.gd.uid b/cutscene/conversation/ConversationAction.gd.uid new file mode 100644 index 0000000..7cb739f --- /dev/null +++ b/cutscene/conversation/ConversationAction.gd.uid @@ -0,0 +1 @@ +uid://dng7tgnex55wp diff --git a/cutscene/conversation/ConversationElement.gd b/cutscene/conversation/ConversationElement.gd deleted file mode 100644 index 17a7a87..0000000 --- a/cutscene/conversation/ConversationElement.gd +++ /dev/null @@ -1,9 +0,0 @@ -extends Resource -class_name ConversationElement - -@export_node_path("Entity") var entity:NodePath -@export_multiline var label: String - -func start(_params:Dictionary) -> int: - await UI.TEXTBOX.setTextAndWait(label) - return Cutscene.CUTSCENE_CONTINUE diff --git a/cutscene/conversation/ConversationResource.gd b/cutscene/conversation/ConversationResource.gd new file mode 100644 index 0000000..b230c61 --- /dev/null +++ b/cutscene/conversation/ConversationResource.gd @@ -0,0 +1,9 @@ +extends Resource +class_name ConversationResource +const ConversationAction = preload("res://cutscene/conversation/ConversationAction.gd") + +@export_node_path("Entity") var entity:NodePath +@export_multiline var label: String + +func toCallable() -> Dictionary: + return ConversationAction.getTextboxCallable(label) diff --git a/cutscene/conversation/ConversationResource.gd.uid b/cutscene/conversation/ConversationResource.gd.uid new file mode 100644 index 0000000..a9762f2 --- /dev/null +++ b/cutscene/conversation/ConversationResource.gd.uid @@ -0,0 +1 @@ +uid://yn7kxdargafx diff --git a/cutscene/item/ItemAction.gd b/cutscene/item/ItemAction.gd new file mode 100644 index 0000000..be4bcb3 --- /dev/null +++ b/cutscene/item/ItemAction.gd @@ -0,0 +1,16 @@ +class_name ItemAction +const ConversationAction = preload("res://cutscene/conversation/ConversationAction.gd") + +static func itemGetCallable(params:Dictionary) -> int: + assert(params.has('stack')) + PARTY.BACKPACK.addStack(params['stack']) + params['cutscene'].addCallable(ConversationAction.getTextboxCallable('TEST').merged({ + 'position': Cutscene.CUTSCENE_ADD_NEXT, + })) + return Cutscene.CUTSCENE_CONTINUE + +static func getItemCallable(itemStack:ItemStack) -> Dictionary: + return { + "function": itemGetCallable, + "stack": itemStack + } diff --git a/cutscene/item/ItemAction.gd.uid b/cutscene/item/ItemAction.gd.uid new file mode 100644 index 0000000..df1eca3 --- /dev/null +++ b/cutscene/item/ItemAction.gd.uid @@ -0,0 +1 @@ +uid://de04o21rytdqk diff --git a/item/Inventory.gd b/item/Inventory.gd index d5ce0ec..76c69fb 100644 --- a/item/Inventory.gd +++ b/item/Inventory.gd @@ -9,12 +9,12 @@ enum InventorySortType { ITEM_KEY } -signal itemAdded(item:Item) -signal itemRemoved(item:Item) -signal itemQuantityChanged(item:Item, quantity:int) +signal itemAdded(item:Item.ItemId) +signal itemRemoved(item:Item.ItemId) +signal itemQuantityChanged(item:Item.ItemId, quantity:int) signal inventorySorted(sortBy:InventorySortType, reverse:bool) -func setItem(item:Item, quantity:int) -> void: +func setItem(item:Item.ItemId, quantity:int) -> void: if quantity < 0: push_error("Cannot set item quantity to negative value, using 0") quantity = 0 @@ -42,20 +42,23 @@ func setItem(item:Item, quantity:int) -> void: itemAdded.emit(item) itemQuantityChanged.emit(item, quantity) -func getItemQuantity(item:Item) -> int: +func getItemQuantity(item:Item.ItemId) -> int: for itemStack in items: if itemStack.item == item: return itemStack.quantity return 0 -func addItem(item:Item, quantity:int = 1) -> void: +func addItem(item:Item.ItemId, quantity:int = 1) -> void: # Add can only take positive quantities, otherwise use set or remove if quantity <= 0: push_error("Cannot add non-positive item quantity") return self.setItem(item, self.getItemQuantity(item) + quantity) -func removeItem(item:Item) -> void: +func addStack(stack:ItemStack) -> void: + self.addItem(stack.item, stack.quantity) + +func removeItem(item:Item.ItemId) -> void: self.setItem(item, 0) func sort(sortBy:InventorySortType, reverse:bool = false) -> void: @@ -72,7 +75,7 @@ func sort(sortBy:InventorySortType, reverse:bool = false) -> void: # Sorters func _sortByItemType(a:ItemStack, b:ItemStack) -> int: - return int(a.item.itemType) - int(b.item.itemType) + return int(Item.getItemById(a.item).itemType) - int(Item.getItemById(b.item).itemType) func _sortByItemKey(a:ItemStack, b:ItemStack) -> int: - return a.item.key.casecmp_to(b.item.key) \ No newline at end of file + return Item.getItemById(a.item).key.casecmp_to(Item.getItemById(b.item).key) \ No newline at end of file diff --git a/item/Item.gd b/item/Item.gd index 66d9ef8..7c69b27 100644 --- a/item/Item.gd +++ b/item/Item.gd @@ -8,6 +8,11 @@ enum ItemType { KEY_ITEM, } +enum ItemId { + NULL, + POTION, +} + # Properties var itemType:ItemType var key:String @@ -22,5 +27,11 @@ func getName() -> String: return self.key # Item Table -static var NULL:Item = Item.new("NULL", ItemType.NULL) -static var POTION:Item = Item.new("POTION", ItemType.MEDICINE) \ No newline at end of file +static var ITEM_DEFINITIONS = { + [ItemId.NULL]: Item.new("NULL", ItemType.NULL), + [ItemId.POTION]: Item.new("POTION", ItemType.MEDICINE), +} + +static func getItemById(itemId:ItemId) -> Item: + assert(ITEM_DEFINITIONS.has(itemId)) + return ITEM_DEFINITIONS[itemId] \ No newline at end of file diff --git a/item/ItemResource.gd b/item/ItemResource.gd new file mode 100644 index 0000000..bfd4e1d --- /dev/null +++ b/item/ItemResource.gd @@ -0,0 +1,13 @@ +extends Resource +class_name ItemResource +const Item = preload("res://item/Item.gd") +const ItemStack = preload("res://item/ItemStack.gd") + +@export var item:Item.ItemId = Item.ItemId.NULL +@export var quantity:int = 0 + +func toItemStack() -> ItemStack: + var stack = ItemStack.new() + stack.item = item + stack.quantity = quantity + return stack \ No newline at end of file diff --git a/item/ItemResource.gd.uid b/item/ItemResource.gd.uid new file mode 100644 index 0000000..769ebf8 --- /dev/null +++ b/item/ItemResource.gd.uid @@ -0,0 +1 @@ +uid://38ya6vphm5bu diff --git a/item/ItemStack.gd b/item/ItemStack.gd index a9dc45e..ff07cb6 100644 --- a/item/ItemStack.gd +++ b/item/ItemStack.gd @@ -1,6 +1,5 @@ class_name ItemStack - const Item = preload("res://item/Item.gd") -var item:Item = Item.NULL +var item:Item.ItemId = Item.ItemId.NULL var quantity:int = 0 \ No newline at end of file diff --git a/overworld/entity/Entity.gd b/overworld/entity/Entity.gd index 9da524c..c5a47d2 100644 --- a/overworld/entity/Entity.gd +++ b/overworld/entity/Entity.gd @@ -11,6 +11,7 @@ enum MovementType { enum InteractType { NONE, CONVERSATION, + ONE_TIME_ITEM, TEST_BATTLE }; @@ -27,7 +28,10 @@ var button := func(): # Interaction settings @export_category("Interactions") @export var interactType:InteractType = InteractType.NONE -@export var conversation:Array[ConversationElement] = [] +@export var conversation:Array[ConversationResource] = [] + +@export_category("One-Time Item") +@export var oneTimeItem:ItemResource = null # TEST BATTLE @export_category("Test Battle") diff --git a/overworld/entity/Entity.tscn b/overworld/entity/Entity.tscn index bc6ee62..9fe5fab 100644 --- a/overworld/entity/Entity.tscn +++ b/overworld/entity/Entity.tscn @@ -27,6 +27,7 @@ size = Vector3(1.3, 1.3, 1.3) [node name="Entity" type="CharacterBody3D"] script = ExtResource("1_8e8ef") +entityId = "35ce980f-3df9-4e09-b365-1a228948cf78" metadata/_custom_type_script = "uid://c8146flooxeue" [node name="CollisionShape3D" type="CollisionShape3D" parent="."] diff --git a/overworld/entity/EntityInteractableArea.gd b/overworld/entity/EntityInteractableArea.gd index be374f1..7df04c1 100644 --- a/overworld/entity/EntityInteractableArea.gd +++ b/overworld/entity/EntityInteractableArea.gd @@ -1,5 +1,5 @@ class_name EntityInteractableArea extends Area3D -# const BattleStartAction = preload("res://cutscene/battle/BattleStartAction.gd") +const ItemAction = preload("res://cutscene/item/ItemAction.gd") @export var entity:Entity @@ -16,6 +16,15 @@ func isInteractable() -> bool: if entity.interactType == Entity.InteractType.TEST_BATTLE: return true + + if entity.interactType == Entity.InteractType.ONE_TIME_ITEM: + if entity.oneTimeItem == null: + return false + if entity.oneTimeItem.quantity <= 0: + return false + if entity.oneTimeItem.item == Item.ItemId.NULL: + return false + return true return false @@ -24,6 +33,13 @@ func _onConversationInteract(_other:Entity) -> void: cutscene.addConversation(entity.conversation) cutscene.start() +func _onItemInteract(_other:Entity) -> void: + assert(entity.oneTimeItem != null) + var cutscene:Cutscene = Cutscene.new() + cutscene.addCallable(ItemAction.getItemCallable(entity.oneTimeItem.toItemStack())) + cutscene.addCallable(ConversationAction.getTextboxCallable('This should be last')) + cutscene.start() + func onInteract(other:Entity) -> void: if entity.interactType == Entity.InteractType.NONE: return @@ -33,6 +49,10 @@ func onInteract(other:Entity) -> void: _onConversationInteract(other) return + Entity.InteractType.ONE_TIME_ITEM: + _onItemInteract(other) + return + Entity.InteractType.TEST_BATTLE: var cutscene:Cutscene = Cutscene.new() cutscene.addCallable(BattleStartAction.getStartBattleCallable({ diff --git a/overworld/map/TestMap.tscn b/overworld/map/TestMap.tscn index a5c816f..5569685 100644 --- a/overworld/map/TestMap.tscn +++ b/overworld/map/TestMap.tscn @@ -1,15 +1,22 @@ -[gd_scene load_steps=6 format=3 uid="uid://d0ywgijpuqy0r"] +[gd_scene load_steps=8 format=3 uid="uid://d0ywgijpuqy0r"] [ext_resource type="Script" uid="uid://xe6pcuq741xi" path="res://overworld/map/TestMap.gd" id="1_6ms5s"] [ext_resource type="PackedScene" uid="uid://cluuhtfjeodwb" path="res://overworld/map/TestMapBase.tscn" id="1_ox0si"] [ext_resource type="PackedScene" uid="uid://by4a0r2hp0w6s" path="res://overworld/entity/Entity.tscn" id="2_jmygs"] -[ext_resource type="Script" uid="uid://b40rstjkpompc" path="res://cutscene/conversation/ConversationElement.gd" id="3_p7git"] +[ext_resource type="Script" uid="uid://yn7kxdargafx" path="res://cutscene/conversation/ConversationResource.gd" id="3_p7git"] +[ext_resource type="Script" uid="uid://38ya6vphm5bu" path="res://item/ItemResource.gd" id="4_xf0pb"] -[sub_resource type="Resource" id="Resource_p7git"] +[sub_resource type="Resource" id="Resource_xf0pb"] script = ExtResource("3_p7git") entity = NodePath(".") -label = "Hello!" -metadata/_custom_type_script = "uid://b40rstjkpompc" +label = "Test" +metadata/_custom_type_script = "uid://yn7kxdargafx" + +[sub_resource type="Resource" id="Resource_125nt"] +script = ExtResource("4_xf0pb") +item = 1 +quantity = 2 +metadata/_custom_type_script = "uid://38ya6vphm5bu" [node name="TestMap" type="Node3D"] script = ExtResource("1_6ms5s") @@ -18,12 +25,13 @@ script = ExtResource("1_6ms5s") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00883961, 1.11219, 0.0142021) entityId = "bcabec96-8d33-4c16-a997-3bb3b0562b33" interactType = 1 -conversation = Array[ExtResource("3_p7git")]([SubResource("Resource_p7git")]) +conversation = Array[ExtResource("3_p7git")]([SubResource("Resource_xf0pb")]) [node name="NotPlayer2" parent="." instance=ExtResource("2_jmygs")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00883961, 1.11219, 4.34543) entityId = "ad5a1504-7fbf-45d6-b1bf-6e7af6314066" interactType = 2 +oneTimeItem = SubResource("Resource_125nt") [node name="TestMapBase" parent="." instance=ExtResource("1_ox0si")] diff --git a/ui/component/VNTextbox.gd b/ui/component/VNTextbox.gd index f6f04f2..201b523 100644 --- a/ui/component/VNTextbox.gd +++ b/ui/component/VNTextbox.gd @@ -93,3 +93,4 @@ func setText(text:String) -> void: func setTextAndWait(text:String) -> void: self.setText(text); await self.textboxClosing + await get_tree().process_frame