From 6ecbc33cc2954bb9ec725d217365d6649d35ee5f Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sun, 11 Jan 2026 16:40:54 -0600 Subject: [PATCH] Refactor cutscene queue --- battle/Battle.gd | 7 +-- battle/BattleScene.gd | 52 ++++++++++++++++++-- battle/BattleScene.tscn | 21 +++++--- battle/fighter/BattleMove.gd | 4 ++ battle/fighter/BattleMove.gd.uid | 1 + battle/ui/ActionBox.gd | 26 ++++++++++ battle/ui/ActionBox.gd.uid | 1 + battle/ui/ActionBox.tscn | 36 ++++++++++++++ cutscene/Cutscene.gd | 52 +++++++++++++++----- cutscene/CutsceneSingleton.gd | 1 + cutscene/CutsceneSingleton.gd.uid | 1 + cutscene/battle/CutsceneBattleAction.gd | 7 +++ cutscene/battle/CutsceneBattleAction.gd.uid | 1 + cutscene/conversation/ConversationElement.gd | 4 +- project.godot | 4 +- ui/mainmenu/MainMenu.gd | 4 +- 16 files changed, 190 insertions(+), 32 deletions(-) create mode 100644 battle/fighter/BattleMove.gd.uid create mode 100644 battle/ui/ActionBox.gd create mode 100644 battle/ui/ActionBox.gd.uid create mode 100644 battle/ui/ActionBox.tscn create mode 100644 cutscene/CutsceneSingleton.gd create mode 100644 cutscene/CutsceneSingleton.gd.uid create mode 100644 cutscene/battle/CutsceneBattleAction.gd create mode 100644 cutscene/battle/CutsceneBattleAction.gd.uid diff --git a/battle/Battle.gd b/battle/Battle.gd index 1d52a75..403091b 100644 --- a/battle/Battle.gd +++ b/battle/Battle.gd @@ -2,9 +2,6 @@ class_name BattleSingleton extends Node var battleScene:BattleScene = null -func startBattle( - fighters:Dictionary[BattleScene.BattlePosition, BattleFighter] -) -> void: +func startBattle(params) -> void: assert(battleScene != null) - battleScene.startBatle(fighters -) + battleScene.startBattle(params) diff --git a/battle/BattleScene.gd b/battle/BattleScene.gd index 9e14cb5..9da6b28 100644 --- a/battle/BattleScene.gd +++ b/battle/BattleScene.gd @@ -1,4 +1,5 @@ class_name BattleScene extends BattleFighterScene +const CutsceneBattleAction = preload("res://cutscene/battle/CutsceneBattleAction.gd") enum BattlePosition { LEFT_TOP_BACK, @@ -16,8 +17,11 @@ enum BattlePosition { RIGHT_BOTTOM_FRONT } +var active:bool = false var fighterMap:Dictionary[BattlePosition, BattleFighterScene] = {} +@export var actionBox:ActionBox = null + @export var fighterTopLeftBack:BattleFighterScene = null: get: return fighterMap.get(BattlePosition.LEFT_TOP_BACK, null) @@ -94,8 +98,48 @@ func _init() ->void: BATTLE.battleScene = self pass -func startBatle(fighters:Dictionary[BattlePosition, BattleFighter]) -> void: - for position in fighters.keys(): - var fighterScene:BattleFighterScene = fighterMap.get(position, null) +func getFigheterAtPosition(battlePos:BattlePosition) -> BattleFighterScene: + return fighterMap.get(battlePos, null) + +func getPositionForFighterScene(fighterScene:BattleFighterScene) -> BattlePosition: + for battlePos in fighterMap.keys(): + var scene:BattleFighterScene = fighterMap[battlePos] + if scene == fighterScene: + return battlePos + assert(false) + return BattlePosition.LEFT_TOP_BACK + +func getPositionForFighter(fighter:BattleFighter) -> BattlePosition: + for battlePos in fighterMap.keys(): + var fighterScene:BattleFighterScene = fighterMap[battlePos] + if fighterScene.fighter == fighter: + return battlePos + assert(false) + return BattlePosition.LEFT_TOP_BACK + +func getFighterSceneForFighter(fighter:BattleFighter) -> BattleFighterScene: + for battlePos in fighterMap.keys(): + var fighterScene:BattleFighterScene = fighterMap[battlePos] + if fighterScene.fighter == fighter: + return fighterScene + return null + +func startBattle(params:Dictionary) -> void: + assert(params.has('fighters')) + assert(!active) + + var cutscene:Cutscene = params.get('cutscene', Cutscene.new()) + + for battlePos in params['fighters'].keys(): + var fighterScene:BattleFighterScene = fighterMap.get(battlePos, null) assert(fighterScene != null) - fighterScene.setFighter(fighters[position]) + fighterScene.setFighter(params['fighters'][battlePos]) + + # Initial cutscene elements. In future I may need to make this editable + # somehow? + cutscene.addCallable({ "function": CutsceneBattleAction.playerDecision }) + + if !cutscene.running: + cutscene.start() + + active = true diff --git a/battle/BattleScene.tscn b/battle/BattleScene.tscn index 11a7e01..0046535 100644 --- a/battle/BattleScene.tscn +++ b/battle/BattleScene.tscn @@ -1,10 +1,12 @@ -[gd_scene load_steps=3 format=3 uid="uid://dy54m7dvjgqta"] +[gd_scene load_steps=4 format=3 uid="uid://dy54m7dvjgqta"] [ext_resource type="PackedScene" uid="uid://d1xyb0hdf1yeh" path="res://battle/fighter/BattleFighterScene.tscn" id="1_abr1f"] [ext_resource type="Script" uid="uid://dihfp05x6pktn" path="res://battle/BattleScene.gd" id="1_acaen"] +[ext_resource type="PackedScene" uid="uid://ktmvnapibv2q" path="res://battle/ui/ActionBox.tscn" id="2_c3ndu"] -[node name="BattleScene" type="Node3D" node_paths=PackedStringArray("fighterTopLeftBack", "fighterTopLeftFront", "fighterMiddleLeftBack", "fighterMiddleLeftFront", "fighterBottomLeftBack", "fighterBottomLeftFront", "fighterTopRightBack", "fighterTopRightFront", "fighterMiddleRightBack", "fighterMiddleRightFront", "fighterBottomRightBack", "fighterBottomRightFront")] +[node name="BattleScene" type="Node3D" node_paths=PackedStringArray("actionBox", "fighterTopLeftBack", "fighterTopLeftFront", "fighterMiddleLeftBack", "fighterMiddleLeftFront", "fighterBottomLeftBack", "fighterBottomLeftFront", "fighterTopRightBack", "fighterTopRightFront", "fighterMiddleRightBack", "fighterMiddleRightFront", "fighterBottomRightBack", "fighterBottomRightFront")] script = ExtResource("1_acaen") +actionBox = NodePath("UI/ActionBox") fighterTopLeftBack = NodePath("Fighters/LeftTopBack") fighterTopLeftFront = NodePath("Fighters/LeftTopFront") fighterMiddleLeftBack = NodePath("Fighters/LeftMiddleBack") @@ -19,13 +21,18 @@ fighterBottomRightBack = NodePath("Fighters/RightBottomBack") fighterBottomRightFront = NodePath("Fighters/RightBottomFront") metadata/_custom_type_script = "uid://dihfp05x6pktn" -[node name="Control" type="Control" parent="."] +[node name="UI" type="Control" parent="."] layout_mode = 3 -anchors_preset = 0 -offset_right = 40.0 -offset_bottom = 40.0 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 -[node name="Label" type="Label" parent="Control"] +[node name="ActionBox" parent="UI" instance=ExtResource("2_c3ndu")] +layout_mode = 1 + +[node name="Battle" type="Label" parent="UI"] layout_mode = 0 offset_right = 40.0 offset_bottom = 12.0 diff --git a/battle/fighter/BattleMove.gd b/battle/fighter/BattleMove.gd index 0d2f634..bcf4898 100644 --- a/battle/fighter/BattleMove.gd +++ b/battle/fighter/BattleMove.gd @@ -23,6 +23,10 @@ func _init(params:Dictionary) -> void: self.moveType = params.get("moveType", MoveType.PHYSICAL) self.fieldUse = params.get("fieldUse", false) +func start(_params:Dictionary) -> void: + # Implement move execution logic here + await UI.TEXTBOX.setTextAndWait("Action") + # Moves static var MOVE_PUNCH = BattleMove.new({ "name": "Punch", diff --git a/battle/fighter/BattleMove.gd.uid b/battle/fighter/BattleMove.gd.uid new file mode 100644 index 0000000..c6ea759 --- /dev/null +++ b/battle/fighter/BattleMove.gd.uid @@ -0,0 +1 @@ +uid://gb08hhwk0paw diff --git a/battle/ui/ActionBox.gd b/battle/ui/ActionBox.gd new file mode 100644 index 0000000..c6eaaad --- /dev/null +++ b/battle/ui/ActionBox.gd @@ -0,0 +1,26 @@ +class_name ActionBox extends GridContainer +const BattleMove = preload("res://battle/fighter/BattleMove.gd") + +@export var btnAttack:Button +@export var btnMagic:Button +@export var btnItem:Button + +signal decisionMade(move:BattleMove) + +func _ready() -> void: + btnAttack.pressed.connect(onAttackPressed) + btnMagic.pressed.connect(onMagicPressed) + btnItem.pressed.connect(onItemPressed) + self.visible = false + +func onAttackPressed() -> void: + print("Attack button pressed") + decisionMade.emit(null) + +func onMagicPressed() -> void: + print("Magic button pressed") + decisionMade.emit(null) + +func onItemPressed() -> void: + print("Item button pressed") + decisionMade.emit(null) diff --git a/battle/ui/ActionBox.gd.uid b/battle/ui/ActionBox.gd.uid new file mode 100644 index 0000000..bc39853 --- /dev/null +++ b/battle/ui/ActionBox.gd.uid @@ -0,0 +1 @@ +uid://27274005hbgh diff --git a/battle/ui/ActionBox.tscn b/battle/ui/ActionBox.tscn new file mode 100644 index 0000000..04ca711 --- /dev/null +++ b/battle/ui/ActionBox.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=2 format=3 uid="uid://ktmvnapibv2q"] + +[ext_resource type="Script" uid="uid://27274005hbgh" path="res://battle/ui/ActionBox.gd" id="1_w5s71"] + +[node name="ActionBox" type="GridContainer" node_paths=PackedStringArray("btnAttack", "btnMagic", "btnItem")] +anchors_preset = 3 +anchor_left = 1.0 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -86.0 +offset_top = -44.0 +grow_horizontal = 0 +grow_vertical = 0 +columns = 2 +script = ExtResource("1_w5s71") +btnAttack = NodePath("Attack") +btnMagic = NodePath("Magic") +btnItem = NodePath("Items") +metadata/_custom_type_script = "uid://27274005hbgh" + +[node name="Attack" type="Button" parent="."] +layout_mode = 2 +text = "Attack" + +[node name="Magic" type="Button" parent="."] +layout_mode = 2 +text = "Magic" + +[node name="Items" type="Button" parent="."] +layout_mode = 2 +text = "Items" + +[node name="idk" type="Button" parent="."] +layout_mode = 2 +text = "idk" diff --git a/cutscene/Cutscene.gd b/cutscene/Cutscene.gd index 4e35aa4..6bfb04e 100644 --- a/cutscene/Cutscene.gd +++ b/cutscene/Cutscene.gd @@ -1,25 +1,55 @@ -class_name CutsceneSingleton extends Node +class_name Cutscene const CUTSCENE_CONTINUE = -1 const CUTSCENE_END = -2 +const CUTSCENE_ADD_END = -1 +const CUTSCENE_ADD_NEXT = -2 + var running:bool = false +var index:int = 0 +var queue:Array[Dictionary] = [] -func setConversation(conversation:Array[ConversationElement]) -> void: - var functions:Array[Callable] = [] +# Accepts; +# function:Callable - The function to add +# position:int - Where to add the function (default: end) +# data:Dictionary - Data to pass to the function when called +func addCallable(params:Dictionary) -> int: + assert(params.has("function")) + + if !params.has("position"): + params["position"] = CUTSCENE_ADD_END + + params['cutscene'] = self + + if params["position"] == CUTSCENE_ADD_END || params["position"] >= queue.size(): + queue.append(params) + return queue.size() - 1 + + elif params["position"] == CUTSCENE_ADD_NEXT: + queue.insert(index + 1, params) + return index + 1 + + queue.insert(params["position"], params) + return params["position"] + + +func addConversation(conversation:Array[ConversationElement]) -> Array[int]: + var indexes:Array[int] = [] for element in conversation: - functions.append(element.sceneItem) - setScene(functions) + indexes.append(addCallable({ 'function': element.start })) + return indexes -func setScene(functions:Array[Callable]) -> void: - if functions.size() == 0: +func start() -> void: + if queue.size() == 0: return + assert(!running) running = true - - var index = 0 + index = 0 while true: - var result = await functions[index].call() + var queueItem = queue[index] + var result = await queueItem['function'].call(queueItem) match result: CUTSCENE_CONTINUE: @@ -31,7 +61,7 @@ func setScene(functions:Array[Callable]) -> void: _: index = result - if index >= functions.size() || index < 0: + if index >= queue.size() || index < 0: break running = false diff --git a/cutscene/CutsceneSingleton.gd b/cutscene/CutsceneSingleton.gd new file mode 100644 index 0000000..f135cf3 --- /dev/null +++ b/cutscene/CutsceneSingleton.gd @@ -0,0 +1 @@ +class_name CutsceneSingleton extends Node \ No newline at end of file diff --git a/cutscene/CutsceneSingleton.gd.uid b/cutscene/CutsceneSingleton.gd.uid new file mode 100644 index 0000000..dc30100 --- /dev/null +++ b/cutscene/CutsceneSingleton.gd.uid @@ -0,0 +1 @@ +uid://dtq6p6mop3xfo diff --git a/cutscene/battle/CutsceneBattleAction.gd b/cutscene/battle/CutsceneBattleAction.gd new file mode 100644 index 0000000..7889e4f --- /dev/null +++ b/cutscene/battle/CutsceneBattleAction.gd @@ -0,0 +1,7 @@ +class_name CutsceneBattleAction + +static func playerDecision(_params:Dictionary) -> int: + BATTLE.battleScene.actionBox.visible = true + var move = await BATTLE.battleScene.actionBox.decisionMade + BATTLE.battleScene.actionBox.visible = false + return Cutscene.CUTSCENE_CONTINUE \ No newline at end of file diff --git a/cutscene/battle/CutsceneBattleAction.gd.uid b/cutscene/battle/CutsceneBattleAction.gd.uid new file mode 100644 index 0000000..7adab66 --- /dev/null +++ b/cutscene/battle/CutsceneBattleAction.gd.uid @@ -0,0 +1 @@ +uid://cj38yci04aylm diff --git a/cutscene/conversation/ConversationElement.gd b/cutscene/conversation/ConversationElement.gd index 812ff65..17a7a87 100644 --- a/cutscene/conversation/ConversationElement.gd +++ b/cutscene/conversation/ConversationElement.gd @@ -4,6 +4,6 @@ class_name ConversationElement @export_node_path("Entity") var entity:NodePath @export_multiline var label: String -func sceneItem() -> int: +func start(_params:Dictionary) -> int: await UI.TEXTBOX.setTextAndWait(label) - return CutsceneSingleton.CUTSCENE_CONTINUE + return Cutscene.CUTSCENE_CONTINUE diff --git a/project.godot b/project.godot index 45b80fd..420824a 100644 --- a/project.godot +++ b/project.godot @@ -22,13 +22,13 @@ TRANSITION="*res://singleton/Transition.tscn" QUEST="*res://quest/Quest.tscn" OVERWORLD="*res://overworld/Overworld.gd" SCENE="*res://scene/Scene.gd" -CUTSCENE="*res://cutscene/Cutscene.gd" BATTLE="*res://battle/Battle.gd" PARTY="*res://party/Party.gd" COOKING="*res://cooking/Cooking.gd" SAVE="*res://save/Save.gd" -ControllerIcons="*res://addons/controller_icons/ControllerIcons.gd" +CUTSCENE="*res://cutscene/CutsceneSingleton.gd" UI="*res://ui/UISingleton.gd" +ControllerIcons="*res://addons/controller_icons/ControllerIcons.gd" [debug] diff --git a/ui/mainmenu/MainMenu.gd b/ui/mainmenu/MainMenu.gd index a5571ba..4043323 100644 --- a/ui/mainmenu/MainMenu.gd +++ b/ui/mainmenu/MainMenu.gd @@ -14,7 +14,9 @@ func onNewGamePressed() -> void: #OVERWORLD.mapChange(newGameScene, "PlayerSpawnPoint") SCENE.setScene(SceneSingleton.SceneType.BATTLE) BATTLE.startBattle({ - BattleScene.BattlePosition.LEFT_TOP_BACK: PartySingleton.PARTY_JOHN, + 'fighters': { + BattleScene.BattlePosition.RIGHT_TOP_FRONT: PartySingleton.PARTY_JOHN, + } }) func onSettingsPressed() -> void: