capitalex revised this gist 11 months ago. Go to revision
1 file changed, 0 insertions, 0 deletions
00_SimpleState.gd renamed to 04_SimpleState.gd
File renamed without changes
capitalex revised this gist 11 months ago. Go to revision
1 file changed, 67 insertions
00_SimpleState.gd(file created)
| @@ -0,0 +1,67 @@ | |||
| 1 | + | extends Node | |
| 2 | + | class_name _SimpleState | |
| 3 | + | ||
| 4 | + | signal state_changed(name, state) | |
| 5 | + | ||
| 6 | + | var state := { } | |
| 7 | + | ||
| 8 | + | ||
| 9 | + | func register(state_name: String, inital_state: Dictionary = {}) -> void: | |
| 10 | + | state[state_name] = inital_state | |
| 11 | + | ||
| 12 | + | ||
| 13 | + | func replace(state_name: String, new_state: Dictionary) -> void: | |
| 14 | + | state[state_name] = new_state.duplicate(true) | |
| 15 | + | emit_signal("state_changed", state_name, state) | |
| 16 | + | ||
| 17 | + | ||
| 18 | + | func update(state_name: String, new_state: Dictionary) -> void: | |
| 19 | + | state[state_name] = _SimpleState.merge(get_state(state_name), new_state) | |
| 20 | + | emit_signal("state_changed", state_name, state) | |
| 21 | + | ||
| 22 | + | ||
| 23 | + | func update_deep(state_name: String, new_state: Dictionary) -> void: | |
| 24 | + | state[state_name] = _SimpleState.merge_deep(get_state(state_name), new_state) | |
| 25 | + | emit_signal("state_changed", state_name, state) | |
| 26 | + | ||
| 27 | + | ||
| 28 | + | func update_mut(state_name: String, new_state: Dictionary) -> void: | |
| 29 | + | _SimpleState.copy_to(state[state_name], new_state) | |
| 30 | + | emit_signal("state_changed") | |
| 31 | + | ||
| 32 | + | ||
| 33 | + | func _on_update_state(data: Dictionary) -> void: | |
| 34 | + | update(data.state_name, data.state) | |
| 35 | + | ||
| 36 | + | ||
| 37 | + | func get_state(state_name: String) -> Dictionary: | |
| 38 | + | return state[state_name].duplicate() | |
| 39 | + | ||
| 40 | + | ||
| 41 | + | static func copy_to(a: Dictionary, b: Dictionary) -> void: | |
| 42 | + | for key in b: | |
| 43 | + | a[key] = b[key] | |
| 44 | + | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + | static func copy_to_deep(a: Dictionary, b: Dictionary) -> void: | |
| 48 | + | for k in b: | |
| 49 | + | if process_recursively(a, b, k): | |
| 50 | + | copy_to_deep(a[k], b[k]) | |
| 51 | + | else: | |
| 52 | + | a[k] = b[k] | |
| 53 | + | ||
| 54 | + | ||
| 55 | + | static func process_recursively(a, b, k) -> bool: | |
| 56 | + | return a.has(k) and a[k] is Dictionary and b[k] is Dictionary | |
| 57 | + | ||
| 58 | + | static func merge(a: Dictionary, b: Dictionary) -> Dictionary: | |
| 59 | + | var c := a.duplicate(true) | |
| 60 | + | copy_to(c, b) | |
| 61 | + | return c | |
| 62 | + | ||
| 63 | + | ||
| 64 | + | static func merge_deep(a: Dictionary, b: Dictionary) -> Dictionary: | |
| 65 | + | var c := a.duplicate(true) | |
| 66 | + | copy_to_deep(c, b) | |
| 67 | + | return c | |
capitalex revised this gist 11 months ago. Go to revision
6 files changed, 0 insertions, 0 deletions
Main.gd renamed to 00_Main.gd
File renamed without changes
EventPlayerContainer.gd renamed to 01_EventPlayerContainer.gd
File renamed without changes
EventPlayer.gd renamed to 02_EventPlayer.gd
File renamed without changes
CharacterHandler.gd renamed to 03_CharacterHandler.gd
File renamed without changes
OptionPresenter.gd renamed to 03_OptionPresenter.gd
File renamed without changes
Playback.gd renamed to 03_Playback.gd
File renamed without changes
capitalex revised this gist 11 months ago. Go to revision
1 file changed, 0 insertions, 0 deletions
EventPlayerContainer renamed to EventPlayerContainer.gd
File renamed without changes
capitalex revised this gist 11 months ago. Go to revision
No changes
capitalex revised this gist 11 months ago. Go to revision
6 files changed, 572 insertions
CharacterHandler.gd(file created)
| @@ -0,0 +1,104 @@ | |||
| 1 | + | extends Node | |
| 2 | + | ||
| 3 | + | @export var character_layer_path : NodePath | |
| 4 | + | @export var msg_listener_name = "character_handler" | |
| 5 | + | ||
| 6 | + | @onready var character_layer: CanvasLayer = get_node(character_layer_path) | |
| 7 | + | ||
| 8 | + | var _characters = {} | |
| 9 | + | var _last_character := "" | |
| 10 | + | ||
| 11 | + | func enter(who: String, modifiers: Dictionary = {}) -> void: | |
| 12 | + | if modifiers.has("facing") : match modifiers.facing: | |
| 13 | + | "left" : modifiers.facing = Character.FACING_LEFT | |
| 14 | + | "right" : modifiers.facing = Character.FACING_RIGHT | |
| 15 | + | else: | |
| 16 | + | modifiers.facing = Character.FACING_RIGHT | |
| 17 | + | ||
| 18 | + | if modifiers.has("standing") : match modifiers.standing: | |
| 19 | + | "left" : modifiers.standing = Character.STANDING_LEFT | |
| 20 | + | "center": modifiers.standing = Character.STANDING_CENTER | |
| 21 | + | "right" : modifiers.standing = Character.STANDING_RIGHT | |
| 22 | + | else: | |
| 23 | + | modifiers.standing = Character.STANDING_LEFT | |
| 24 | + | ||
| 25 | + | if not modifiers.has("current_emote"): modifiers.current_emote = "default" | |
| 26 | + | ||
| 27 | + | if not who in _characters: | |
| 28 | + | _characters[who] = Characters.items[who].instantiate() | |
| 29 | + | character_layer.add_child(_characters[who]) | |
| 30 | + | ||
| 31 | + | ||
| 32 | + | for modifier in modifiers: | |
| 33 | + | _characters[who][modifier] = modifiers[modifier] | |
| 34 | + | ||
| 35 | + | _last_character = who | |
| 36 | + | ||
| 37 | + | SimpleState.update_deep("sequence", | |
| 38 | + | { characters = { who: modifiers } } | |
| 39 | + | ) | |
| 40 | + | ||
| 41 | + | ||
| 42 | + | func face(face: String, character: String = _last_character) -> void: | |
| 43 | + | assert(face in ["left", "right"] | |
| 44 | + | , "Invalid position %s. Must be 'left' or 'right" % face) | |
| 45 | + | SimpleState.update_deep("sequence", | |
| 46 | + | { characters = { character: { facing = face } } } | |
| 47 | + | ) | |
| 48 | + | if character != _last_character: _last_character = character | |
| 49 | + | ||
| 50 | + | var facing: int = Character.STANDING_LEFT | |
| 51 | + | match face: | |
| 52 | + | "left" : facing = Character.FACING_LEFT | |
| 53 | + | "right" : facing = Character.FACING_RIGHT | |
| 54 | + | ||
| 55 | + | update(character, "facing", facing) | |
| 56 | + | ||
| 57 | + | ||
| 58 | + | func stand(stand: String, character: String = _last_character) -> void: | |
| 59 | + | assert(stand in ["left", "center", "right"] | |
| 60 | + | , "Invalid position %s. Must be 'left' or 'center' or 'right" % stand) | |
| 61 | + | ||
| 62 | + | SimpleState.update_deep("sequence", | |
| 63 | + | { characters = { character: { standing = stand } } } | |
| 64 | + | ) | |
| 65 | + | if character != _last_character: _last_character = character | |
| 66 | + | ||
| 67 | + | var standing: int = Character.STANDING_LEFT | |
| 68 | + | match stand: | |
| 69 | + | "left" : standing = Character.STANDING_LEFT | |
| 70 | + | "center": standing = Character.STANDING_CENTER | |
| 71 | + | "right" : standing = Character.STANDING_RIGHT | |
| 72 | + | ||
| 73 | + | update(character, "standing", standing) | |
| 74 | + | ||
| 75 | + | ||
| 76 | + | func emote(emote: String, character: String = _last_character) -> void: | |
| 77 | + | SimpleState.update_deep("sequence", | |
| 78 | + | { characters = { character: { current_emote = emote } } } | |
| 79 | + | ) | |
| 80 | + | if character != _last_character: _last_character = character | |
| 81 | + | ||
| 82 | + | update(character, "current_emote", emote) | |
| 83 | + | ||
| 84 | + | ||
| 85 | + | func update(who: String, what: String, with) -> void: | |
| 86 | + | _characters[who][what] = with | |
| 87 | + | _last_character = who | |
| 88 | + | ||
| 89 | + | func leave(who: String) -> void: | |
| 90 | + | var characters: Dictionary = SimpleState.state.sequence.characters.duplicate() | |
| 91 | + | characters.erase(who) # warning-ignore:return_value_discarded | |
| 92 | + | SimpleState.update("sequence", | |
| 93 | + | { characters = characters } | |
| 94 | + | ) | |
| 95 | + | ||
| 96 | + | if who in _characters: | |
| 97 | + | character_layer.remove_child(_characters[who]) | |
| 98 | + | _characters[who].queue_free() | |
| 99 | + | _characters.erase(who) | |
| 100 | + | ||
| 101 | + | ||
| 102 | + | func everyone_leave() -> void: | |
| 103 | + | for who in _characters: | |
| 104 | + | character_layer.remove_child(_characters[who]) | |
EventPlayer.gd(file created)
| @@ -0,0 +1,198 @@ | |||
| 1 | + | extends Control | |
| 2 | + | class_name EventPlayer | |
| 3 | + | ||
| 4 | + | # Signal | |
| 5 | + | signal fade_in_started() | |
| 6 | + | signal fade_out_started() | |
| 7 | + | signal scene_ended() | |
| 8 | + | ||
| 9 | + | # Proxied Signals | |
| 10 | + | signal minigame_started(minigame : String, initial_state : Dictionary) | |
| 11 | + | signal sequence_changed(sequence : String) | |
| 12 | + | ||
| 13 | + | # Signals to Yield on | |
| 14 | + | signal fade_finished() # warning-ignore:unused_signal | |
| 15 | + | signal minigame_finished() # warning-ignore:unused_signal | |
| 16 | + | signal change_scene_finished() # warning-ignore:unused_signal | |
| 17 | + | ||
| 18 | + | enum NextFade { FADE_OUT, FADE_IN } | |
| 19 | + | var fade_active = false | |
| 20 | + | var next_fade : NextFade = NextFade.FADE_OUT | |
| 21 | + | ||
| 22 | + | @onready var playback : Playback = $Playback | |
| 23 | + | @onready var dialogue_presenter = $DialoguePresenter | |
| 24 | + | @onready var background_presenter = $BackgroundPresenter | |
| 25 | + | @onready var character_handler = $CharacterHandler | |
| 26 | + | @onready var blackout_panel = $BlackoutPanel | |
| 27 | + | @onready var dialogue_box = $DialogueBox | |
| 28 | + | @onready var prize_screen = $PrizeScreen | |
| 29 | + | @onready var choice_panel = get_tree().current_scene.get_node("%MainLayout/%ChoicePanel") | |
| 30 | + | ||
| 31 | + | func _ready() -> void: | |
| 32 | + | playback.line_changed.connect(_on_line_changed) | |
| 33 | + | playback.dialogue_shown.connect(_on_dialogue_shown) | |
| 34 | + | playback.options_shown.connect(_on_options_shown) | |
| 35 | + | playback.dialogue_cleared.connect(_on_dialogue_cleared) | |
| 36 | + | playback.scene_finished.connect(_on_scene_finished) | |
| 37 | + | choice_panel.option_picked.connect(_on_option_picked) | |
| 38 | + | ||
| 39 | + | playback.extra_game_states = [ self | |
| 40 | + | , dialogue_presenter | |
| 41 | + | , background_presenter | |
| 42 | + | , character_handler | |
| 43 | + | , dialogue_box | |
| 44 | + | , prize_screen | |
| 45 | + | ] | |
| 46 | + | ||
| 47 | + | ||
| 48 | + | # Callbacks | |
| 49 | + | func _on_line_changed(line_id: String) -> void: | |
| 50 | + | SimpleState.update("sequence", | |
| 51 | + | { current_line_id = line_id }) | |
| 52 | + | ||
| 53 | + | ||
| 54 | + | func _on_dialogue_shown(dialogue_line : DialogueLine) -> void: | |
| 55 | + | if get_parent()._changing_scenes: | |
| 56 | + | await self.change_scene_finished | |
| 57 | + | ||
| 58 | + | await dialogue_presenter.show_dialogue(dialogue_line) | |
| 59 | + | playback.dialogue_finished.emit() | |
| 60 | + | ||
| 61 | + | func _on_options_shown(options: Array[String]) -> void: | |
| 62 | + | if get_parent()._changing_scenes: | |
| 63 | + | await self.change_scene_finished | |
| 64 | + | ||
| 65 | + | choice_panel.show_options(options) | |
| 66 | + | ||
| 67 | + | ||
| 68 | + | func _on_dialogue_cleared() -> void: | |
| 69 | + | dialogue_presenter.clear_dialogue() | |
| 70 | + | ||
| 71 | + | ||
| 72 | + | func _on_scene_finished() -> void: | |
| 73 | + | emit_signal("scene_ended") | |
| 74 | + | ||
| 75 | + | ||
| 76 | + | func _on_options_cleared() -> void: | |
| 77 | + | choice_panel.clear_options() | |
| 78 | + | ||
| 79 | + | ||
| 80 | + | func _on_option_picked(__, line_id) -> void: | |
| 81 | + | playback.emit_signal("options_picked", line_id) | |
| 82 | + | ||
| 83 | + | ||
| 84 | + | # Public Methods | |
| 85 | + | func run(sequence: String, entry: String) -> void: | |
| 86 | + | playback.run(Events.items[sequence], entry) | |
| 87 | + | ||
| 88 | + | ||
| 89 | + | func restore(sequence: String, entry: String) -> void: | |
| 90 | + | var dialogue_pos = SimpleState.state.sequence.dialogue_pos | |
| 91 | + | var background = SimpleState.state.sequence.background | |
| 92 | + | var blackout_visible = SimpleState.state.sequence.blackout_visible | |
| 93 | + | var characters = SimpleState.state.sequence.characters | |
| 94 | + | ||
| 95 | + | next_fade = SimpleState.state.sequence.next_fade | |
| 96 | + | ||
| 97 | + | dialogue_box.call(dialogue_pos) | |
| 98 | + | background_presenter.background(background) | |
| 99 | + | ||
| 100 | + | for character in characters: | |
| 101 | + | character_handler.enter(character, characters[character]) | |
| 102 | + | ||
| 103 | + | choice_panel.clear_options() | |
| 104 | + | blackout(blackout_visible) | |
| 105 | + | playback.run(Events.items[sequence], entry, true) | |
| 106 | + | ||
| 107 | + | ||
| 108 | + | func goto(sequence: String) -> void: | |
| 109 | + | sequence_changed.emit(sequence) | |
| 110 | + | await change_scene_finished | |
| 111 | + | ||
| 112 | + | ||
| 113 | + | func visit_random_minigame() -> void: | |
| 114 | + | var seen = MemoryState.get_seen_minigames() | |
| 115 | + | var unseen = ArrayUtil.difference(CarnivalGames.items.keys(), seen) | |
| 116 | + | var key = ArrayUtil.either(unseen) | |
| 117 | + | var sequence_name = to_squence_name(key) | |
| 118 | + | ||
| 119 | + | sequence_changed.emit("minigames/%s/init" % sequence_name) | |
| 120 | + | ||
| 121 | + | ||
| 122 | + | func to_squence_name(key) -> String: | |
| 123 | + | return key \ | |
| 124 | + | .capitalize() \ | |
| 125 | + | .replace(" ", "-") \ | |
| 126 | + | .to_lower() | |
| 127 | + | ||
| 128 | + | ||
| 129 | + | func exit() -> void: | |
| 130 | + | await fade_out() | |
| 131 | + | ||
| 132 | + | ||
| 133 | + | func blackout(visibility: bool) -> void: | |
| 134 | + | SimpleState.update("sequence", { blackout_visible = visibility }) | |
| 135 | + | blackout_panel.visible = visibility | |
| 136 | + | ||
| 137 | + | ||
| 138 | + | func swap_background(layers: Array) -> void: | |
| 139 | + | await fade_out() | |
| 140 | + | await get_tree().process_frame | |
| 141 | + | background_presenter.background(layers) | |
| 142 | + | await fade_in() | |
| 143 | + | ||
| 144 | + | ||
| 145 | + | func unimplemented() -> void: | |
| 146 | + | assert(false, "Unimplemented Scene") | |
| 147 | + | ||
| 148 | + | ||
| 149 | + | func play_minigame(minigame: String, initial_state: Dictionary = {}) -> void: | |
| 150 | + | minigame_started.emit(minigame, initial_state) | |
| 151 | + | var result = await self.minigame_finished | |
| 152 | + | SimpleState.update_deep("temp", { values = result }) | |
| 153 | + | ||
| 154 | + | ||
| 155 | + | ||
| 156 | + | func fade() -> void: | |
| 157 | + | if fade_active: return | |
| 158 | + | ||
| 159 | + | fade_active = true | |
| 160 | + | ||
| 161 | + | match next_fade: | |
| 162 | + | NextFade.FADE_OUT: | |
| 163 | + | next_fade = NextFade.FADE_IN | |
| 164 | + | await fade_out() | |
| 165 | + | ||
| 166 | + | NextFade.FADE_IN: | |
| 167 | + | next_fade = NextFade.FADE_OUT | |
| 168 | + | await fade_in() | |
| 169 | + | ||
| 170 | + | SimpleState.update("sequence", { next_fade = next_fade }) | |
| 171 | + | fade_active = false | |
| 172 | + | ||
| 173 | + | ||
| 174 | + | ||
| 175 | + | func fade_out() -> void: | |
| 176 | + | fade_out_started.emit() | |
| 177 | + | await self.fade_finished | |
| 178 | + | ||
| 179 | + | ||
| 180 | + | func fade_in() -> void: | |
| 181 | + | fade_in_started.emit() | |
| 182 | + | await self.fade_finished | |
| 183 | + | ||
| 184 | + | ||
| 185 | + | func set_input_disabled(value: bool) -> void: | |
| 186 | + | $Background.input_disabled = value | |
| 187 | + | $Background/SubViewport.gui_disable_input = value | |
| 188 | + | ||
| 189 | + | ||
| 190 | + | func goto_birth_scene() -> void: | |
| 191 | + | var scene = TempState["parasite"].birthing_scene | |
| 192 | + | ExploreState.emit_signal("event_triggered", scene) | |
| 193 | + | ||
| 194 | + | ||
| 195 | + | func interaction(background: String) -> void: | |
| 196 | + | set_input_disabled(false) | |
| 197 | + | await background_presenter.start_interaction(background) | |
| 198 | + | set_input_disabled(true) | |
EventPlayerContainer(file created)
| @@ -0,0 +1,169 @@ | |||
| 1 | + | extends Control | |
| 2 | + | class_name EventPlayerContainer | |
| 3 | + | ||
| 4 | + | signal scene_change_finished() | |
| 5 | + | signal sequence_changed(sequence) # warning-ignore:unused_signal | |
| 6 | + | signal options_shown(options) | |
| 7 | + | signal scene_change_started() | |
| 8 | + | signal minigame_started(minigame, initial_state) | |
| 9 | + | ||
| 10 | + | const EventPlayerScene = preload("res://scenes/ui/EventPlayer.tscn") | |
| 11 | + | ||
| 12 | + | var allow_fade_skip := false | |
| 13 | + | ||
| 14 | + | var _event_player_scene : EventPlayer = null | |
| 15 | + | var _changing_scenes := false | |
| 16 | + | ||
| 17 | + | func _ready() -> void: | |
| 18 | + | set_input_disabled(true) | |
| 19 | + | SimpleState.state_changed.connect(_on_state_changed) # warning-ignore:return_value_discarded | |
| 20 | + | ||
| 21 | + | ||
| 22 | + | func _on_state_changed(_name: String, _state: Dictionary) -> void: | |
| 23 | + | pass | |
| 24 | + | ||
| 25 | + | ||
| 26 | + | func _input(event) -> void: | |
| 27 | + | var mouse_down = event is InputEventMouseButton and event.is_pressed() and event.button_index == MOUSE_BUTTON_LEFT | |
| 28 | + | var ui_accept = event.is_action_pressed("ui_accept") and not event.is_echo() | |
| 29 | + | if (mouse_down or ui_accept) and allow_fade_skip: | |
| 30 | + | $FadePanel.skip() | |
| 31 | + | ||
| 32 | + | ||
| 33 | + | func connect_events(scene) -> void: | |
| 34 | + | # Handled Events | |
| 35 | + | scene.fade_in_started.connect(_on_fade_in_started) | |
| 36 | + | scene.fade_out_started.connect(_on_fade_out_started) | |
| 37 | + | scene.scene_ended.connect(_on_scene_ended) | |
| 38 | + | scene.sequence_changed.connect(_on_sequence_changed) | |
| 39 | + | ||
| 40 | + | # Bubbled Events | |
| 41 | + | scene.minigame_started.connect(_on_minigame_started) | |
| 42 | + | ||
| 43 | + | ||
| 44 | + | func add_to_tree(scene : EventPlayer) -> void: | |
| 45 | + | add_child(scene) | |
| 46 | + | move_child(scene, 0) | |
| 47 | + | ||
| 48 | + | ||
| 49 | + | func run_scene(scene : EventPlayer, sequence : String, entry : String) -> void: | |
| 50 | + | MemoryState.seen_passage(sequence) | |
| 51 | + | scene.run(sequence, entry) | |
| 52 | + | ||
| 53 | + | ||
| 54 | + | func restore_scene(scene : EventPlayer, sequence : String, entry : String) -> void: | |
| 55 | + | scene.restore(sequence, entry) | |
| 56 | + | ||
| 57 | + | ||
| 58 | + | func run(sequence: String, entry: String = "intro") -> void: | |
| 59 | + | _event_player_scene = EventPlayerScene.instantiate() | |
| 60 | + | SimpleState.update("sequence", { current_sequence = sequence, current_line_id = entry }) | |
| 61 | + | ||
| 62 | + | show() | |
| 63 | + | connect_events(_event_player_scene) | |
| 64 | + | add_to_tree(_event_player_scene) | |
| 65 | + | run_scene(_event_player_scene, sequence, entry) | |
| 66 | + | ||
| 67 | + | ||
| 68 | + | func restore_from_state() -> void: | |
| 69 | + | var sequence = SimpleState.state.sequence.current_sequence | |
| 70 | + | var entry = SimpleState.state.sequence.current_line_id | |
| 71 | + | _event_player_scene = EventPlayerScene.instantiate() | |
| 72 | + | ||
| 73 | + | show() | |
| 74 | + | connect_events(_event_player_scene) | |
| 75 | + | add_to_tree(_event_player_scene) | |
| 76 | + | restore_scene(_event_player_scene, sequence, entry) | |
| 77 | + | ||
| 78 | + | ||
| 79 | + | func minigame_finished(result) -> void: | |
| 80 | + | if is_instance_valid(_event_player_scene): | |
| 81 | + | _event_player_scene.emit_signal("minigame_finished", result) | |
| 82 | + | ||
| 83 | + | ||
| 84 | + | func _on_fade_out_started() -> void: | |
| 85 | + | allow_fade_skip = true | |
| 86 | + | if not $FadePanel.fade_shown: | |
| 87 | + | await $FadePanel.fade_out() | |
| 88 | + | ||
| 89 | + | if is_instance_valid(_event_player_scene): | |
| 90 | + | _event_player_scene.emit_signal("fade_finished") | |
| 91 | + | else: | |
| 92 | + | _on_fade_out_started() | |
| 93 | + | ||
| 94 | + | ||
| 95 | + | func _on_fade_in_started() -> void: | |
| 96 | + | if $FadePanel.fade_shown: | |
| 97 | + | await $FadePanel.fade_in() | |
| 98 | + | ||
| 99 | + | ||
| 100 | + | allow_fade_skip = false | |
| 101 | + | if is_instance_valid(_event_player_scene): | |
| 102 | + | _event_player_scene.emit_signal("fade_finished") | |
| 103 | + | ||
| 104 | + | ||
| 105 | + | func _on_scene_ended() -> void: | |
| 106 | + | if not _changing_scenes: | |
| 107 | + | stop() | |
| 108 | + | ||
| 109 | + | ||
| 110 | + | # Bubble Up Events | |
| 111 | + | func _on_minigame_started(minigame: String, initial_state: Dictionary) -> void: | |
| 112 | + | emit_signal("minigame_started", minigame, initial_state) | |
| 113 | + | ||
| 114 | + | ||
| 115 | + | func _on_sequence_changed(scene: String, line: String = "intro") -> void: | |
| 116 | + | emit_signal("scene_change_started") | |
| 117 | + | _changing_scenes = true | |
| 118 | + | ||
| 119 | + | if not $FadePanel.fade_shown: | |
| 120 | + | await $FadePanel.fade_out() | |
| 121 | + | ||
| 122 | + | if is_instance_valid(_event_player_scene): | |
| 123 | + | if _event_player_scene.get_parent(): | |
| 124 | + | _event_player_scene.get_parent().remove_child(_event_player_scene) | |
| 125 | + | _event_player_scene.queue_free() | |
| 126 | + | ||
| 127 | + | run(scene, line) | |
| 128 | + | ||
| 129 | + | if $FadePanel.fade_shown: | |
| 130 | + | await $FadePanel.fade_in() | |
| 131 | + | ||
| 132 | + | _changing_scenes = false | |
| 133 | + | _event_player_scene.emit_signal("change_scene_finished") | |
| 134 | + | emit_signal("scene_change_finished") | |
| 135 | + | ||
| 136 | + | ||
| 137 | + | func _options_shown(options: Array) -> void: | |
| 138 | + | emit_signal("options_shown", options) | |
| 139 | + | ||
| 140 | + | ||
| 141 | + | func stop() -> void: | |
| 142 | + | SimpleState.update("sequence", { current_sequence = "NONE" | |
| 143 | + | , current_line_id = "" | |
| 144 | + | , background = [] | |
| 145 | + | , dialogue_pos = "left" | |
| 146 | + | , blackout_visible = false | |
| 147 | + | , dialogue_visible = false | |
| 148 | + | , characters = {} | |
| 149 | + | }) | |
| 150 | + | await $FadePanel.fade_out() | |
| 151 | + | ||
| 152 | + | if is_instance_valid(_event_player_scene): | |
| 153 | + | if _event_player_scene and _event_player_scene.get_parent(): | |
| 154 | + | _event_player_scene.get_parent().remove_child(_event_player_scene) | |
| 155 | + | _event_player_scene.queue_free() | |
| 156 | + | ||
| 157 | + | await $FadePanel.fade_in() | |
| 158 | + | hide() | |
| 159 | + | ||
| 160 | + | func hard_stop() -> void: | |
| 161 | + | if is_instance_valid(_event_player_scene): | |
| 162 | + | if _event_player_scene and _event_player_scene.get_parent(): | |
| 163 | + | _event_player_scene.get_parent().remove_child(_event_player_scene) | |
| 164 | + | _event_player_scene.queue_free() | |
| 165 | + | ||
| 166 | + | ||
| 167 | + | func set_input_disabled(value: bool) -> void: | |
| 168 | + | if is_instance_valid(_event_player_scene): | |
| 169 | + | _event_player_scene.set_input_disabled(value) | |
main.gd renamed to Main.gd
File renamed without changes
OptionPresenter.gd(file created)
| @@ -0,0 +1,55 @@ | |||
| 1 | + | extends Node | |
| 2 | + | class_name Choice | |
| 3 | + | const ButtonBase = preload("res://scenes/ui/misc/ButtonBase.tscn") | |
| 4 | + | ||
| 5 | + | signal options_shown() | |
| 6 | + | signal options_cleared() | |
| 7 | + | signal option_picked(index, line_id) | |
| 8 | + | ||
| 9 | + | @export var option_path : NodePath | |
| 10 | + | @export var msg_listener_name = "option_presenter" | |
| 11 | + | ||
| 12 | + | var active := false | |
| 13 | + | ||
| 14 | + | @onready var options: VBoxContainer = get_node(option_path) | |
| 15 | + | ||
| 16 | + | ||
| 17 | + | func show_options(option_list: Array) -> void: | |
| 18 | + | assert(len(option_list) % 2 == 0, "Options must be multiples of 2") | |
| 19 | + | ||
| 20 | + | var count = min(6, len(option_list)) | |
| 21 | + | var buttons = [] | |
| 22 | + | for i in range(0, count, 2): | |
| 23 | + | buttons.append(_add_option(option_list[i], option_list[i + 1])) | |
| 24 | + | ||
| 25 | + | (buttons[0] as Button).grab_focus() | |
| 26 | + | for i in range(1, len(buttons)): | |
| 27 | + | var top: Button = buttons[i - 1] | |
| 28 | + | var bottom: Button = buttons[i] | |
| 29 | + | bottom.focus_neighbor_top = top.get_path() | |
| 30 | + | top.focus_neighbor_bottom = bottom.get_path() | |
| 31 | + | ||
| 32 | + | active = true | |
| 33 | + | emit_signal("options_shown") | |
| 34 | + | ||
| 35 | + | ||
| 36 | + | func clear_options() -> void: | |
| 37 | + | for child in options.get_children(): | |
| 38 | + | options.remove_child(child) | |
| 39 | + | child.queue_free() | |
| 40 | + | ||
| 41 | + | active = false | |
| 42 | + | emit_signal("options_cleared") | |
| 43 | + | ||
| 44 | + | ||
| 45 | + | func _add_option(text: String, line_id: String) -> Button: | |
| 46 | + | var button = ButtonBase.instantiate() | |
| 47 | + | button.focus_mode = Control.FOCUS_ALL | |
| 48 | + | button.text = text | |
| 49 | + | button.connect("pressed", Callable(self, "_on_button_pressed").bind(options.get_child_count(), line_id)) | |
| 50 | + | options.add_child(button) | |
| 51 | + | return button | |
| 52 | + | ||
| 53 | + | func _on_button_pressed(index: int, line: String) -> void: | |
| 54 | + | clear_options() | |
| 55 | + | emit_signal("option_picked", index, line) | |
Playback.gd(file created)
| @@ -0,0 +1,46 @@ | |||
| 1 | + | extends Node | |
| 2 | + | class_name Playback | |
| 3 | + | ||
| 4 | + | signal line_changed(line : String) | |
| 5 | + | signal dialogue_shown(dialogue : DialogueLine) | |
| 6 | + | signal options_shown(options : Array[String]) | |
| 7 | + | signal dialogue_cleared | |
| 8 | + | signal scene_finished | |
| 9 | + | ||
| 10 | + | signal options_picked(line_id : String) | |
| 11 | + | signal dialogue_finished # warning-ignore:unused_signal | |
| 12 | + | ||
| 13 | + | var dialogue_line : DialogueLine | |
| 14 | + | var extra_game_states : Array | |
| 15 | + | ||
| 16 | + | func run(script : DialogueResource, entry: String = "intro", _restore : bool = false) -> void: | |
| 17 | + | dialogue_line = await DialogueManager.get_next_dialogue_line(script, entry, extra_game_states) | |
| 18 | + | ||
| 19 | + | line_changed.emit(entry) | |
| 20 | + | while dialogue_line: | |
| 21 | + | var next_id = dialogue_line.next_id | |
| 22 | + | ||
| 23 | + | if not dialogue_line.text.is_empty(): | |
| 24 | + | dialogue_shown.emit(dialogue_line) | |
| 25 | + | await self.dialogue_finished | |
| 26 | + | ||
| 27 | + | if len(dialogue_line.responses) > 0: | |
| 28 | + | var options : Array[String] = [] | |
| 29 | + | ||
| 30 | + | for response in dialogue_line.responses: | |
| 31 | + | options.append(response.text) | |
| 32 | + | options.append(response.next_id) | |
| 33 | + | ||
| 34 | + | options_shown.emit(options) | |
| 35 | + | next_id = await self.options_picked | |
| 36 | + | ||
| 37 | + | else: | |
| 38 | + | var default : Array[String] = [">> Next", ""] | |
| 39 | + | options_shown.emit(default) | |
| 40 | + | await self.options_picked | |
| 41 | + | ||
| 42 | + | dialogue_cleared.emit() | |
| 43 | + | line_changed.emit(next_id) | |
| 44 | + | dialogue_line = await DialogueManager.get_next_dialogue_line(script, next_id, extra_game_states) | |
| 45 | + | ||
| 46 | + | scene_finished.emit() | |
capitalex revised this gist 11 months ago. Go to revision
1 file changed, 179 insertions
main.gd(file created)
| @@ -0,0 +1,179 @@ | |||
| 1 | + | # warning-ignore-all:return_value_discarded | |
| 2 | + | extends HBoxContainer | |
| 3 | + | class_name ChitinousCanrival | |
| 4 | + | ||
| 5 | + | const event_player_scene = preload("res://scenes/ui/EventPlayer.tscn") | |
| 6 | + | ||
| 7 | + | @onready var MinigameHandler := %MinigameHandler as MinigameHandler | |
| 8 | + | @onready var TravelButtons := %TravelButtons as TravelButtons | |
| 9 | + | @onready var EventPlayerContainer := %EventPlayerContainer as EventPlayerContainer | |
| 10 | + | @onready var InventoryMenu := %InventoryMenu as InventoryMenu | |
| 11 | + | @onready var SettingsMenu := %SettingsMenu as SettingsMenu | |
| 12 | + | @onready var SaveMenu := %SaveMenu as SaveMenu | |
| 13 | + | @onready var ChoicePanel := %ChoicePanel as Choice | |
| 14 | + | @onready var StatusPanel := %StatusPanel as StatusPanel | |
| 15 | + | @onready var Blackout := %BlackoutPanel as BlackoutPanel | |
| 16 | + | ||
| 17 | + | var _current_sequence: String = "" | |
| 18 | + | ||
| 19 | + | func _ready() -> void: | |
| 20 | + | randomize() | |
| 21 | + | ||
| 22 | + | MusicState.change_bg(MusicState.BACKGROUND_THEME) | |
| 23 | + | ||
| 24 | + | ExploreState.set_start_time() | |
| 25 | + | ExploreState._set_location(SimpleState.state.explore.location) | |
| 26 | + | TravelButtons.set_button_disabled(SimpleState.state.explore.location) | |
| 27 | + | ||
| 28 | + | SaveState.save_loaded.connect(_on_save_loaded) | |
| 29 | + | EventPlayerContainer.minigame_started.connect(_on_minigame_started) | |
| 30 | + | MinigameHandler.minigame_finished.connect(_on_minigame_finished) | |
| 31 | + | ||
| 32 | + | StatusPanel.inventory_button_toggled.connect(_on_inventory_button_toggled) | |
| 33 | + | StatusPanel.settings_button_toggled.connect(_on_settings_button_toggled) | |
| 34 | + | StatusPanel.save_button_toggled.connect(_on_save_button_toggled) | |
| 35 | + | ||
| 36 | + | InventoryMenu.visibility_changed.connect(_on_menu_visibility_changed) | |
| 37 | + | ||
| 38 | + | SaveMenu.visibility_changed.connect(_on_menu_visibility_changed) | |
| 39 | + | SaveMenu.closed.connect(StatusPanel.saving_closed) | |
| 40 | + | ||
| 41 | + | SettingsMenu.visibility_changed.connect(_on_menu_visibility_changed) | |
| 42 | + | SettingsMenu.closed.connect(StatusPanel.settings_closed) | |
| 43 | + | ||
| 44 | + | TravelButtons.waited.connect(_on_wait_button_pressed) | |
| 45 | + | ||
| 46 | + | ChoicePanel.options_shown.connect(_on_options_shown) | |
| 47 | + | ChoicePanel.options_cleared.connect(_on_options_cleared) | |
| 48 | + | ||
| 49 | + | ExploreState.trap_triggered.connect(_on_trap_triggered) | |
| 50 | + | ExploreState.event_triggered.connect(_on_event_triggered) | |
| 51 | + | ExploreState.event_trigger_forced.connect(_on_event_trigger_forced) | |
| 52 | + | ExploreState.revisited.connect(_on_revisited) | |
| 53 | + | ExploreState.wandered.connect(_on_wandered) | |
| 54 | + | ExploreState.item_selected.connect(_on_item_selected) | |
| 55 | + | ExploreState.masturbated.connect(_on_masturbated) | |
| 56 | + | ||
| 57 | + | if not MemoryState.has_seen("00-intro/00-premise"): | |
| 58 | + | InventoryState.add_trap("intro") | |
| 59 | + | EventPlayerContainer.run("00-intro/00-premise") | |
| 60 | + | ||
| 61 | + | if not SimpleState.state.sequence.current_sequence != "None": | |
| 62 | + | EventPlayerContainer.restore_from_state() | |
| 63 | + | ||
| 64 | + | await Blackout.fade_in() | |
| 65 | + | ||
| 66 | + | ||
| 67 | + | func _on_revisited(event: String) -> void: | |
| 68 | + | EventPlayerContainer.run(event) | |
| 69 | + | ||
| 70 | + | ||
| 71 | + | func _on_wandered(where: String) -> void: | |
| 72 | + | EventPlayerContainer.run("01-location/%s/wander" % where) | |
| 73 | + | ||
| 74 | + | ||
| 75 | + | func _on_item_selected(what: String) -> void: | |
| 76 | + | StatusPanel.inventory_closed() | |
| 77 | + | EventPlayerContainer.run("items/%s" % what) | |
| 78 | + | ||
| 79 | + | func _on_save_loaded(title) -> void: | |
| 80 | + | if not title: | |
| 81 | + | await Blackout.fade_out() | |
| 82 | + | ||
| 83 | + | EventPlayerContainer.hard_stop() | |
| 84 | + | ChoicePanel.clear_options() | |
| 85 | + | ||
| 86 | + | if SimpleState.state.sequence.current_sequence != "NONE": | |
| 87 | + | EventPlayerContainer.restore_from_state() | |
| 88 | + | else: | |
| 89 | + | EventPlayerContainer.hide() | |
| 90 | + | ||
| 91 | + | await Blackout.fade_in() | |
| 92 | + | ||
| 93 | + | ||
| 94 | + | func _on_minigame_started(minigame: String, initial_state: Dictionary) -> void: | |
| 95 | + | MinigameHandler.play_minigame(minigame, initial_state) | |
| 96 | + | ||
| 97 | + | ||
| 98 | + | func _on_minigame_finished(result) -> void: | |
| 99 | + | EventPlayerContainer.minigame_finished(result) | |
| 100 | + | ||
| 101 | + | ||
| 102 | + | func _on_inventory_button_toggled(pressed: bool) -> void: | |
| 103 | + | ||
| 104 | + | InventoryMenu.visible = pressed | |
| 105 | + | ||
| 106 | + | if pressed: | |
| 107 | + | SettingsMenu.visible = false | |
| 108 | + | StatusPanel.settings_closed() | |
| 109 | + | ||
| 110 | + | SaveMenu.visible = false | |
| 111 | + | StatusPanel.saving_closed() | |
| 112 | + | ||
| 113 | + | ||
| 114 | + | func _on_settings_button_toggled(pressed: bool) -> void: | |
| 115 | + | SettingsMenu.visible = pressed | |
| 116 | + | ||
| 117 | + | if pressed: | |
| 118 | + | InventoryMenu.visible = false | |
| 119 | + | StatusPanel.inventory_closed() | |
| 120 | + | ||
| 121 | + | SaveMenu.visible = false | |
| 122 | + | StatusPanel.saving_closed() | |
| 123 | + | ||
| 124 | + | ||
| 125 | + | func _on_save_button_toggled(pressed: bool) -> void: | |
| 126 | + | SaveMenu.visible = pressed | |
| 127 | + | ||
| 128 | + | if pressed: | |
| 129 | + | InventoryMenu.visible = false | |
| 130 | + | StatusPanel.inventory_closed() | |
| 131 | + | ||
| 132 | + | SettingsMenu.visible = false | |
| 133 | + | StatusPanel.settings_closed() | |
| 134 | + | ||
| 135 | + | ||
| 136 | + | func _on_menu_visibility_changed() -> void: | |
| 137 | + | EventPlayerContainer.set_input_disabled(any_menu_open()) | |
| 138 | + | ChoicePanel.visible = !any_menu_open() and ChoicePanel.active | |
| 139 | + | ||
| 140 | + | ||
| 141 | + | func _on_wait_button_pressed() -> void: | |
| 142 | + | await Blackout.fade_out() | |
| 143 | + | ExploreState.wait() | |
| 144 | + | await Blackout.fade_in() | |
| 145 | + | ||
| 146 | + | ||
| 147 | + | func _on_options_shown() -> void: | |
| 148 | + | ChoicePanel.visible = !any_menu_open() and ChoicePanel.active | |
| 149 | + | ||
| 150 | + | ||
| 151 | + | func _on_options_cleared() -> void: | |
| 152 | + | ChoicePanel.hide() | |
| 153 | + | await get_tree().process_frame | |
| 154 | + | ||
| 155 | + | ||
| 156 | + | func _on_trap_triggered(_trap_name: String, event: String) -> void: | |
| 157 | + | EventPlayerContainer.run(event) | |
| 158 | + | ||
| 159 | + | ||
| 160 | + | func _on_event_triggered(event, entry: String = "intro") -> void: | |
| 161 | + | EventPlayerContainer.run(event, entry) | |
| 162 | + | ||
| 163 | + | ||
| 164 | + | func _on_event_trigger_forced(event, entry: String) -> void: | |
| 165 | + | if event == "NONE": | |
| 166 | + | EventPlayerContainer._on_scene_ended() | |
| 167 | + | ChoicePanel.clear_options() | |
| 168 | + | else: | |
| 169 | + | EventPlayerContainer._on_sequence_changed(event, entry) | |
| 170 | + | ||
| 171 | + | ||
| 172 | + | func _on_masturbated() -> void: | |
| 173 | + | EventPlayerContainer.run("masturbations/init") | |
| 174 | + | ||
| 175 | + | ||
| 176 | + | func any_menu_open() -> bool: | |
| 177 | + | return InventoryMenu.visible \ | |
| 178 | + | or SettingsMenu.visible \ | |
| 179 | + | or SaveMenu.visible | |