Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
@tool
class_name ThreadbareProjectSettings
extends EditorPlugin

## Debug aspect ratio while playing the game.
const DEBUG_ASPECT_RATIO = "debugging/debug_aspect_ratio"
const DEBUG_ASPECT_RATIO = "threadbare/debugging/debug_aspect_ratio"
const SKIP_SOKOBANS = "threadbare/debugging/skip_sokobans"
const SKIP_SPLASH = "threadbare/debugging/skip_splash"

static var setttings_configuration = {
DEBUG_ASPECT_RATIO:
{
value = false,
type = TYPE_BOOL,
hint_string = "Display a letterbox overlay in the game, to debug aspect ratio issues.",
},
SKIP_SOKOBANS:
{
value = false,
type = TYPE_BOOL,
hint_string = "Skip the sokobans from the core game loop, and complete the quest directly.",
},
SKIP_SPLASH:
{
value = false,
type = TYPE_BOOL,
hint_string =
"Skip the splash screen and title menu, and resume the game state. Like when clicking Continue.",
},
}

Expand All @@ -20,9 +36,9 @@ func _enter_tree() -> void:


static func setup_threadbare_settings() -> void:
for key: String in setttings_configuration:
var setting_config: Dictionary = setttings_configuration[key]
var setting_name: String = "threadbare/%s" % key
for setting_name: String in setttings_configuration:
var setting_config: Dictionary = setttings_configuration[setting_name]
assert(setting_name.begins_with("threadbare"))

if not ProjectSettings.has_setting(setting_name):
ProjectSettings.set_setting(setting_name, setting_config.value)
Expand Down
5 changes: 5 additions & 0 deletions project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,8 @@ locale/translations_pot_files=PackedStringArray("res://scenes/menus/title/compon
textures/canvas_textures/default_texture_filter=0
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"

[threadbare]

debugging/skip_sokobans=true
debugging/skip_splash=true
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
@tool
extends Node2D
class_name CharacterRandomizer
extends CharacterBody2D
## @experimental
##
## Provide a single button to randomize various aspects of a character.
Expand Down Expand Up @@ -41,6 +42,8 @@ var random_texture_nodes: Array[RandomTextureSpriteBehavior] = []

var _undoredo: Object # EditorUndoRedoManager

var _random_number_generator := RandomNumberGenerator.new()

var _previous_look_at_side: Enums.LookAtSide = Enums.LookAtSide.UNSPECIFIED


Expand All @@ -49,18 +52,18 @@ var _previous_look_at_side: Enums.LookAtSide = Enums.LookAtSide.UNSPECIFIED
## Do it in a consistent way by first seeding the default random number generator
## with the [member character_seed].
func apply_character_randomizations() -> void:
seed(character_seed)
_random_number_generator.seed = character_seed

if skin_recolor_nodes:
var new_skin_medium_color: Color
skin_recolor_nodes[-1].set_random_skin_color()
skin_recolor_nodes[-1].set_random_skin_color(_random_number_generator)
new_skin_medium_color = skin_recolor_nodes[-1].medium_color
for n in skin_recolor_nodes:
n.automatic_shades = true
n.medium_color = new_skin_medium_color

for n in random_texture_nodes:
n.randomize_texture()
n.randomize_texture(_random_number_generator)


## Set a random seed and randomize the character.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
~ start
Here's some help!
Bye!
do GameState.clear_upgrade()
=> END
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[remap]

importer="dialogue_manager"
importer_version=15
type="Resource"
uid="uid://c667fv6ngpc7s"
path="res://.godot/imported/default_helper.dialogue-2d2de185b0afee791b6bd97e2398a0de.tres"

[deps]

source_file="res://scenes/game_elements/characters/npcs/components/default_helper.dialogue"
dest_files=["res://.godot/imported/default_helper.dialogue-2d2de185b0afee791b6bd97e2398a0de.tres"]

[params]

defaults=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
extends Node

@export var target_upgrade: InventoryItem.ItemType = InventoryItem.ItemType.MEMORY
@onready var character: CharacterRandomizer = get_parent()


func _ready() -> void:
GameState.upgrade_changed.connect(_on_upgrade_changed)
_on_upgrade_changed()


func _on_upgrade_changed() -> void:
var is_enabled := (
target_upgrade == GameState.upgrade_type and bool(GameState.upgrade_character_seed)
)
character.visible = is_enabled
character.process_mode = Node.PROCESS_MODE_INHERIT if is_enabled else Node.PROCESS_MODE_DISABLED
if is_enabled:
character.character_seed = GameState.upgrade_character_seed
character.apply_character_randomizations()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://diskln3jup064
6 changes: 4 additions & 2 deletions scenes/game_elements/components/cel_shading_recolor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,11 @@ func colorize() -> void:


## Pick a random color from [constant SKIN_COLORS] and automatically set all shades from it.
func set_random_skin_color() -> void:
func set_random_skin_color(rng: RandomNumberGenerator = null) -> void:
automatic_shades = true
medium_color = SKIN_COLORS.values().pick_random()
var random_int: int = rng.randi() if rng else randi()
var index := random_int % SKIN_COLORS.size()
medium_color = SKIN_COLORS.values()[index]


func _get_configuration_warnings() -> PackedStringArray:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
class_name EternalLoom
extends Node2D

signal retelling_started
signal retelling_finished
signal give_retelling_upgrade(type: InventoryItem.ItemType)

const ETERNAL_LOOM_INTERACTION: DialogueResource = preload("uid://yafw7bf362gh")

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

func _ready() -> void:
talk_behavior.dialogue = ETERNAL_LOOM_INTERACTION
talk_behavior.title = "have_threads" if _have_threads else "no_threads"
talk_behavior.before_dialogue = _before_dialogue
interact_area.interaction_ended.connect(self._on_interaction_ended)

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


func _before_dialogue() -> void:
if _have_threads:
if GameState.current_quest and GameState.current_quest.retelling:
talk_behavior.title = "start_retelling"
else:
talk_behavior.title = "have_threads"
else:
talk_behavior.title = "no_threads"


func _find_elder(quest: Quest) -> Elder:
for elder in elders:
if quest.resource_path.begins_with(elder.quest_directory):
Expand All @@ -56,11 +70,77 @@ func _find_elder(quest: Quest) -> Elder:

func _on_interaction_ended() -> void:
if _have_threads:
# Hide interact label during scene transition
interact_area.disabled = true
if GameState.current_quest and GameState.current_quest.retelling:
# Hide interact label during retelling
interact_area.disabled = true
DialogueManager.show_dialogue_balloon(GameState.current_quest.retelling, "", [self])
retelling_started.emit()
await DialogueManager.dialogue_ended
await on_offering_succeeded()
interact_area.disabled = false
retelling_finished.emit()

if not ProjectSettings.get_setting(ThreadbareProjectSettings.SKIP_SOKOBANS):
# Hide interact label during scene transition
interact_area.disabled = true
GameState.set_incorporating_threads(true)
SceneSwitcher.change_to_file_with_transition(SOKOBANS.pick_random())
else:
GameState.mark_quest_completed()


func _has_magical_thread_of_type(type: InventoryItem.ItemType) -> bool:
for item in GameState.items_collected():
if item.type == type:
return true
return false


func has_memory() -> bool:
return _has_magical_thread_of_type(InventoryItem.ItemType.MEMORY)


func has_imagination() -> bool:
return _has_magical_thread_of_type(InventoryItem.ItemType.IMAGINATION)


func has_spirit() -> bool:
return _has_magical_thread_of_type(InventoryItem.ItemType.SPIRIT)


func memory_text() -> String:
var has_it := _has_magical_thread_of_type(InventoryItem.ItemType.MEMORY)
return "(Memory available!)" if has_it else ""


func imagination_text() -> String:
var has_it := _has_magical_thread_of_type(InventoryItem.ItemType.IMAGINATION)
return "(Imagination available!)" if has_it else ""


func spirit_text() -> String:
var has_it := _has_magical_thread_of_type(InventoryItem.ItemType.SPIRIT)
return "(Spirit available!)" if has_it else ""


func _give_upgrade(type: InventoryItem.ItemType) -> void:
var has_it := _has_magical_thread_of_type(type)
if not has_it:
push_warning("Trying to give an upgrade for missing item type", type)
return
give_retelling_upgrade.emit(type)


func give_memory_upgrade() -> void:
_give_upgrade(InventoryItem.ItemType.MEMORY)


func give_imagination_upgrade() -> void:
_give_upgrade(InventoryItem.ItemType.IMAGINATION)


GameState.set_incorporating_threads(true)
SceneSwitcher.change_to_file_with_transition(SOKOBANS.pick_random())
func give_spirit_upgrade() -> void:
_give_upgrade(InventoryItem.ItemType.SPIRIT)


func on_offering_succeeded() -> void:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ It seems you are lacking the threads of Memory, Imagination, and Spirit... try c
The Memory, Imagination, and Spirit threads are ready to be incorporated into the loom!
do on_offering_succeeded()
=> END

~ start_retelling
Tell us a story about your last adventure!
=> END
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ func _offset_child_sprites(offset: Vector2) -> void:


## Pick a random texture from [member textures] and set it to the sprite.
func randomize_texture() -> void:
var new_texture: Texture2D = textures.pick_random()
func randomize_texture(rng: RandomNumberGenerator = null) -> void:
var random_int: int = rng.randi() if rng else randi()
var index := random_int % textures.size()
var new_texture := textures[index]

var offset := _get_offset_from_texture_filename(new_texture)
_offset_child_sprites(offset)
SpriteFramesHelper.replace_texture(null, new_texture, sprite.sprite_frames)
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ extends CanvasLayer


func _ready() -> void:
if not ProjectSettings.get_setting("threadbare/debugging/debug_aspect_ratio"):
if not ProjectSettings.get_setting(ThreadbareProjectSettings.DEBUG_ASPECT_RATIO):
queue_free()
35 changes: 35 additions & 0 deletions scenes/globals/game_state/game_state.gd
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ signal completed_quests_changed
## Emitted when lore or StoryQuest player abilities change.
signal abilities_changed

signal upgrade_changed

const GAME_STATE_PATH := "user://game_state.cfg"
const INVENTORY_SECTION := "inventory"
const INVENTORY_ITEMS_KEY := "items_collected"
Expand All @@ -38,6 +40,8 @@ const QUEST_CHALLENGE_START_KEY := "challenge_start_scene"
const QUEST_PLAYER_ABILITIES_KEY := "quest_player_abilities"
const GLOBAL_SECTION := "global"
const GLOBAL_INCORPORATING_THREADS_KEY := "incorporating_threads"
const GLOBAL_UPGRADE_TYPE_KEY := "upgrade_type"
const GLOBAL_UPGRADE_CHARACTER_SEED_KEY := "upgrade_character_seed"
const COMPLETED_QUESTS_KEY := "completed_quests"
const CURRENTSCENE_KEY := "current_scene"
const SPAWNPOINT_KEY := "current_spawn_point"
Expand Down Expand Up @@ -87,6 +91,9 @@ var current_lives: int = MAX_LIVES
## Current state of artificial lights.
var lights_on: bool

var upgrade_type: InventoryItem.ItemType = InventoryItem.ItemType.NONE
var upgrade_character_seed: int = 0

## Set when the loom transports the player to a trio of Sokoban puzzles, so that
## when the player returns to Fray's End the loom can trigger a brief cutscene.
var incorporating_threads: bool = false
Expand Down Expand Up @@ -148,6 +155,28 @@ func _ready() -> void:
prints("[LIVES DEBUG] GameState initialized with", current_lives, "lives")


func set_upgrade(new_upgrade_type: InventoryItem.ItemType, new_upgrade_character_seed: int) -> void:
upgrade_type = new_upgrade_type
upgrade_character_seed = new_upgrade_character_seed
upgrade_changed.emit()

_state.set_value(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY, upgrade_type)
_state.set_value(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY, upgrade_character_seed)
_save()


func clear_upgrade() -> void:
upgrade_type = InventoryItem.ItemType.NONE
upgrade_character_seed = 0
upgrade_changed.emit()

if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY):
_state.erase_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY)
if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY):
_state.erase_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY)
_save()


## Set the [member incorporating_threads] flag.
func set_incorporating_threads(new_incorporating_threads: bool) -> void:
incorporating_threads = new_incorporating_threads
Expand Down Expand Up @@ -484,6 +513,12 @@ func restore() -> Dictionary:

var scene_path: String = _state.get_value(GLOBAL_SECTION, CURRENTSCENE_KEY, "")
current_spawn_point = _state.get_value(GLOBAL_SECTION, SPAWNPOINT_KEY, ^"")
if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY):
upgrade_type = _state.get_value(GLOBAL_SECTION, GLOBAL_UPGRADE_TYPE_KEY)
if _state.has_section_key(GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY):
upgrade_character_seed = _state.get_value(
GLOBAL_SECTION, GLOBAL_UPGRADE_CHARACTER_SEED_KEY, 0
)
incorporating_threads = _state.get_value(
GLOBAL_SECTION, GLOBAL_INCORPORATING_THREADS_KEY, false
)
Expand Down
1 change: 1 addition & 0 deletions scenes/globals/game_state/inventory/inventory_item.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum ItemType {
MEMORY,
IMAGINATION,
SPIRIT,
NONE,
}

const HUD_TEXTURES: Dictionary[ItemType, Texture2D] = {
Expand Down
3 changes: 3 additions & 0 deletions scenes/menus/splash/components/splash.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ extends Control


func _ready() -> void:
if ProjectSettings.get_setting(ThreadbareProjectSettings.SKIP_SPLASH):
SceneSwitcher.change_to_file(next_scene)
return
logo_stitcher.finished.connect(scene_switch_timer.start)
scene_switch_timer.timeout.connect(switch_to_intro)

Expand Down
Loading
Loading