Skip to content

Commit 0948ae6

Browse files
committed
Add retelling to Fray's End
1 parent 17fa331 commit 0948ae6

23 files changed

Lines changed: 468 additions & 4 deletions

project.godot

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,8 @@ locale/translations_pot_files=PackedStringArray("res://scenes/menus/title/compon
308308
textures/canvas_textures/default_texture_filter=0
309309
renderer/rendering_method="gl_compatibility"
310310
renderer/rendering_method.mobile="gl_compatibility"
311+
312+
[threadbare]
313+
314+
debugging/skip_sokobans=true
315+
debugging/skip_splash=true
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-FileCopyrightText: The Threadbare Authors
2+
# SPDX-License-Identifier: MPL-2.0
3+
~ start
4+
Here's some help!
5+
Bye!
6+
do GameState.clear_upgrade()
7+
=> END
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[remap]
2+
3+
importer="dialogue_manager"
4+
importer_version=15
5+
type="Resource"
6+
uid="uid://c667fv6ngpc7s"
7+
path="res://.godot/imported/default_helper.dialogue-2d2de185b0afee791b6bd97e2398a0de.tres"
8+
9+
[deps]
10+
11+
source_file="res://scenes/game_elements/characters/npcs/components/default_helper.dialogue"
12+
dest_files=["res://.godot/imported/default_helper.dialogue-2d2de185b0afee791b6bd97e2398a0de.tres"]
13+
14+
[params]
15+
16+
defaults=true
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-FileCopyrightText: The Threadbare Authors
2+
# SPDX-License-Identifier: MPL-2.0
3+
extends Node
4+
5+
@export var target_upgrade: InventoryItem.ItemType = InventoryItem.ItemType.MEMORY
6+
@onready var character: CharacterRandomizer = get_parent()
7+
8+
9+
func _ready() -> void:
10+
GameState.upgrade_changed.connect(_on_upgrade_changed)
11+
_on_upgrade_changed()
12+
13+
14+
func _on_upgrade_changed() -> void:
15+
var is_enabled := (
16+
target_upgrade == GameState.upgrade_type and bool(GameState.upgrade_character_seed)
17+
)
18+
character.visible = is_enabled
19+
character.process_mode = Node.PROCESS_MODE_INHERIT if is_enabled else Node.PROCESS_MODE_DISABLED
20+
if is_enabled:
21+
character.character_seed = GameState.upgrade_character_seed
22+
character.apply_character_randomizations()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://diskln3jup064

scenes/game_elements/props/eternal_loom/components/eternal_loom.gd

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
class_name EternalLoom
44
extends Node2D
55

6+
signal retelling_started
7+
signal retelling_finished
8+
signal give_retelling_upgrade(type: InventoryItem.ItemType)
9+
610
const ETERNAL_LOOM_INTERACTION: DialogueResource = preload("uid://yafw7bf362gh")
711

812
## Scenes that are the first of three Sokoban puzzles. A random one will be used
@@ -24,7 +28,7 @@ var _have_threads := is_item_offering_possible()
2428

2529
func _ready() -> void:
2630
talk_behavior.dialogue = ETERNAL_LOOM_INTERACTION
27-
talk_behavior.title = "have_threads" if _have_threads else "no_threads"
31+
talk_behavior.before_dialogue = _before_dialogue
2832
interact_area.interaction_ended.connect(self._on_interaction_ended)
2933

3034
if GameState.incorporating_threads:
@@ -46,6 +50,16 @@ func _ready() -> void:
4650
GameState.mark_quest_completed()
4751

4852

53+
func _before_dialogue() -> void:
54+
if _have_threads:
55+
if GameState.current_quest and GameState.current_quest.retelling:
56+
talk_behavior.title = "start_retelling"
57+
else:
58+
talk_behavior.title = "have_threads"
59+
else:
60+
talk_behavior.title = "no_threads"
61+
62+
4963
func _find_elder(quest: Quest) -> Elder:
5064
for elder in elders:
5165
if quest.resource_path.begins_with(elder.quest_directory):
@@ -56,6 +70,16 @@ func _find_elder(quest: Quest) -> Elder:
5670

5771
func _on_interaction_ended() -> void:
5872
if _have_threads:
73+
if GameState.current_quest and GameState.current_quest.retelling:
74+
# Hide interact label during retelling
75+
interact_area.disabled = true
76+
DialogueManager.show_dialogue_balloon(GameState.current_quest.retelling, "", [self])
77+
retelling_started.emit()
78+
await DialogueManager.dialogue_ended
79+
await on_offering_succeeded()
80+
interact_area.disabled = false
81+
retelling_finished.emit()
82+
5983
if not ProjectSettings.get_setting(ThreadbareProjectSettings.SKIP_SOKOBANS):
6084
# Hide interact label during scene transition
6185
interact_area.disabled = true
@@ -65,6 +89,60 @@ func _on_interaction_ended() -> void:
6589
GameState.mark_quest_completed()
6690

6791

92+
func _has_magical_thread_of_type(type: InventoryItem.ItemType) -> bool:
93+
for item in GameState.items_collected():
94+
if item.type == type:
95+
return true
96+
return false
97+
98+
99+
func has_memory() -> bool:
100+
return _has_magical_thread_of_type(InventoryItem.ItemType.MEMORY)
101+
102+
103+
func has_imagination() -> bool:
104+
return _has_magical_thread_of_type(InventoryItem.ItemType.IMAGINATION)
105+
106+
107+
func has_spirit() -> bool:
108+
return _has_magical_thread_of_type(InventoryItem.ItemType.SPIRIT)
109+
110+
111+
func memory_text() -> String:
112+
var has_it := _has_magical_thread_of_type(InventoryItem.ItemType.MEMORY)
113+
return "(Memory available!)" if has_it else ""
114+
115+
116+
func imagination_text() -> String:
117+
var has_it := _has_magical_thread_of_type(InventoryItem.ItemType.IMAGINATION)
118+
return "(Imagination available!)" if has_it else ""
119+
120+
121+
func spirit_text() -> String:
122+
var has_it := _has_magical_thread_of_type(InventoryItem.ItemType.SPIRIT)
123+
return "(Spirit available!)" if has_it else ""
124+
125+
126+
func _give_upgrade(type: InventoryItem.ItemType) -> void:
127+
var has_it := _has_magical_thread_of_type(type)
128+
if not has_it:
129+
push_warning("Trying to give an upgrade for missing item type", type)
130+
return
131+
give_retelling_upgrade.emit(type)
132+
133+
134+
func give_memory_upgrade() -> void:
135+
_give_upgrade(InventoryItem.ItemType.MEMORY)
136+
137+
138+
func give_imagination_upgrade() -> void:
139+
_give_upgrade(InventoryItem.ItemType.IMAGINATION)
140+
141+
142+
func give_spirit_upgrade() -> void:
143+
_give_upgrade(InventoryItem.ItemType.SPIRIT)
144+
145+
68146
func on_offering_succeeded() -> void:
69147
loom_offering_animation_player.play(&"loom_offering")
70148
await loom_offering_animation_player.animation_finished

scenes/game_elements/props/eternal_loom/components/eternal_loom_interaction.dialogue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ It seems you are lacking the threads of Memory, Imagination, and Spirit... try c
1414
The Memory, Imagination, and Spirit threads are ready to be incorporated into the loom!
1515
do on_offering_succeeded()
1616
=> END
17+
18+
~ start_retelling
19+
Tell us a story about your last adventure!
20+
=> END

scenes/globals/game_state/game_state.gd

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ signal completed_quests_changed
2929
## Emitted when lore or StoryQuest player abilities change.
3030
signal abilities_changed
3131

32+
signal upgrade_changed
33+
3234
const GAME_STATE_PATH := "user://game_state.cfg"
3335
const INVENTORY_SECTION := "inventory"
3436
const INVENTORY_ITEMS_KEY := "items_collected"
@@ -38,6 +40,8 @@ const QUEST_CHALLENGE_START_KEY := "challenge_start_scene"
3840
const QUEST_PLAYER_ABILITIES_KEY := "quest_player_abilities"
3941
const GLOBAL_SECTION := "global"
4042
const GLOBAL_INCORPORATING_THREADS_KEY := "incorporating_threads"
43+
const GLOBAL_UPGRADE_TYPE_KEY := "upgrade_type"
44+
const GLOBAL_UPGRADE_CHARACTER_SEED_KEY := "upgrade_character_seed"
4145
const COMPLETED_QUESTS_KEY := "completed_quests"
4246
const CURRENTSCENE_KEY := "current_scene"
4347
const SPAWNPOINT_KEY := "current_spawn_point"
@@ -87,6 +91,9 @@ var current_lives: int = MAX_LIVES
8791
## Current state of artificial lights.
8892
var lights_on: bool
8993

94+
var upgrade_type: InventoryItem.ItemType = InventoryItem.ItemType.NONE
95+
var upgrade_character_seed: int = 0
96+
9097
## Set when the loom transports the player to a trio of Sokoban puzzles, so that
9198
## when the player returns to Fray's End the loom can trigger a brief cutscene.
9299
var incorporating_threads: bool = false
@@ -148,6 +155,28 @@ func _ready() -> void:
148155
prints("[LIVES DEBUG] GameState initialized with", current_lives, "lives")
149156

150157

158+
func set_upgrade(new_upgrade_type: InventoryItem.ItemType, new_upgrade_character_seed: int) -> void:
159+
upgrade_type = new_upgrade_type
160+
upgrade_character_seed = new_upgrade_character_seed
161+
upgrade_changed.emit()
162+
163+
_state.set_value(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY, upgrade_type)
164+
_state.set_value(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY, upgrade_character_seed)
165+
_save()
166+
167+
168+
func clear_upgrade() -> void:
169+
upgrade_type = InventoryItem.ItemType.NONE
170+
upgrade_character_seed = 0
171+
upgrade_changed.emit()
172+
173+
if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY):
174+
_state.erase_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY)
175+
if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY):
176+
_state.erase_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY)
177+
_save()
178+
179+
151180
## Set the [member incorporating_threads] flag.
152181
func set_incorporating_threads(new_incorporating_threads: bool) -> void:
153182
incorporating_threads = new_incorporating_threads
@@ -484,6 +513,12 @@ func restore() -> Dictionary:
484513

485514
var scene_path: String = _state.get_value(GLOBAL_SECTION, CURRENTSCENE_KEY, "")
486515
current_spawn_point = _state.get_value(GLOBAL_SECTION, SPAWNPOINT_KEY, ^"")
516+
if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY):
517+
upgrade_type = _state.get_value(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY)
518+
if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY):
519+
upgrade_character_seed = _state.get_value(
520+
GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY, 0
521+
)
487522
incorporating_threads = _state.get_value(
488523
GLOBAL_SECTION, GLOBAL_INCORPORATING_THREADS_KEY, false
489524
)

scenes/globals/game_state/inventory/inventory_item.gd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ enum ItemType {
88
MEMORY,
99
IMAGINATION,
1010
SPIRIT,
11+
NONE,
1112
}
1213

1314
const HUD_TEXTURES: Dictionary[ItemType, Texture2D] = {

scenes/menus/storybook/components/quest.gd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ const FILENAME := "quest.tres"
4545
## Whether this is a lore quest (part of the main storyline).
4646
@export var is_lore_quest: bool = false
4747

48+
## Optional dialogue to retell the adventures that occurred in the quest,
49+
## when returning the magical threads to the loom.
50+
@export var retelling: DialogueResource
51+
4852
@export_group("Animation")
4953

5054
## An optional sprite frame library to show in the storybook page for this quest.

0 commit comments

Comments
 (0)