Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
Expand Up @@ -49,6 +49,9 @@ var _random_number_generator := RandomNumberGenerator.new()

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

## The character head node. This can be used to show the head only in the HUD.
@onready var head: AnimatedSprite2D = %AnimatedSprite2DHead


## Randomize the skin color and textures of the character.
## [br][br]
Expand Down Expand Up @@ -79,6 +82,7 @@ func randomize_character() -> void:
else:
character_seed = new_character_seed
apply_character_randomizations()
_randomize_all_sprites_progress()


func _ready() -> void:
Expand Down
1 change: 1 addition & 0 deletions scenes/game_elements/characters/npcs/townie.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ sprite = NodePath("..")
metadata/_custom_type_script = "uid://dy68p7gf07pi3"

[node name="AnimatedSprite2DHead" type="AnimatedSprite2D" parent="AnimatedSprite2DLegs/AnimatedSprite2DBody" unique_id=421503015]
unique_name_in_owner = true
material = ExtResource("1_nj51j")
sprite_frames = ExtResource("22_8wbfo")
animation = &"idle"
Expand Down
2 changes: 2 additions & 0 deletions scenes/globals/game_state/global_state.gd
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ signal completed_quests_changed
## used instead. [GameState.player] always points to the correct instance.
@export var player: PlayerState = PlayerState.new()

@export var helper: HelperCharacterState = HelperCharacterState.new()


func _validate_property(property: Dictionary) -> void:
match property.name:
Expand Down
30 changes: 30 additions & 0 deletions scenes/globals/game_state/helper_character_state.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
@tool
class_name HelperCharacterState
extends Resource

## The type of help, matching the magical threads type.
## This is left to game designers interpretation but usually:
## [br][br]
## - Memory is about expanding the lore of the game.[br]
## - Imagination is about making things appear in the level.[br]
## - Spirit is about reducing the difficulty of an action-based puzzle.[br]
@export var helper_type: InventoryItem.ItemType = InventoryItem.ItemType.NONE

## The seed to display a character with same visual features when offering help.
@export var character_seed: int = 0


## Consume the help.
func clear() -> void:
helper_type = InventoryItem.ItemType.NONE
character_seed = 0
emit_changed()


## Obtain the help.
func obtain(new_helper_type: InventoryItem.ItemType, new_character_seed: int) -> void:
helper_type = new_helper_type
character_seed = new_character_seed
emit_changed()
1 change: 1 addition & 0 deletions scenes/globals/game_state/helper_character_state.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://yu6cw51sylfu
7 changes: 7 additions & 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,13 @@ enum ItemType {
MEMORY,
IMAGINATION,
SPIRIT,
NONE,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you put NONE at the end because you didn't want to have to update every instance in the game. OK! Perhaps we can later reorder this and update all resources.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other option is to have GameState.global.helper be null when there is no helper. Then you would not need to introduce the NONE member here, which is a potential source of bugs if someone sets NONE on a CollectibleItem.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I couldn't find another way in the prior game state. But now with resources, it looks like I should be able to get rid of the NONE enum and use null on the whole helper state. Thanks! Let me try it.

}

const COLORS_PER_TYPE: Dictionary[ItemType, Color] = {
ItemType.MEMORY: Color(0.459, 0.867, 0.0, 1.0),
ItemType.IMAGINATION: Color(0.969, 0.792, 0.0, 1.0),
ItemType.SPIRIT: Color(0.929, 0.0, 0.0, 1.0)
}

const HUD_TEXTURES: Dictionary[ItemType, Texture2D] = {
Expand Down
4 changes: 4 additions & 0 deletions scenes/menus/storybook/components/quest.gd
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ const FILENAME := "quest.tres"
## Which abilities to award if the quest is skipped
@export var skip_abilities: Array[Enums.PlayerAbilities] = []

## Optional dialogue to retell the adventures that occurred in the quest,
## when returning the magical threads to the loom.
@export var retelling: DialogueResource

@export_group("Animation")

## An optional sprite frame library to show in the storybook page for this quest.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ sprite = NodePath("..")
metadata/_custom_type_script = "uid://dy68p7gf07pi3"

[node name="AnimatedSprite2DHead" type="AnimatedSprite2D" parent="AnimatedSprite2DLegs/AnimatedSprite2DBody" unique_id=421503015]
unique_name_in_owner = true
material = ExtResource("2_1mlvj")
position = Vector2(-4, -16)
sprite_frames = ExtResource("15_ndexk")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
extends PanelContainer

const ITEM_SLOT: PackedScene = preload("uid://1mjm4atk2j6e")
const TOWNIE = preload("uid://dgrrudegturnw")

@onready var items_container: HBoxContainer = %ItemsContainer
@onready var helper_container: CenterContainer = %HelperContainer
@onready var helper_marker: Marker2D = %HelperMarker
@onready var helper_color: ColorRect = %HelperColor


func _ready() -> void:
GameState.global.helper.changed.connect(_on_helper_state_changed)
_on_helper_state_changed()

var n := 0
if GameState.quest:
n = GameState.quest.quest.threads_to_collect
Expand All @@ -31,6 +38,22 @@ func _ready() -> void:
GameState.global.item_consumed.connect(self._on_item_consumed)


func _on_helper_state_changed() -> void:
var has_helper := bool(GameState.global.helper.character_seed)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here you're not using the NONE state but the magic 0 value for the seed to indicate "no helper". I think having helper be null would be clearer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh… but it's so that you can connect to the changed signal. OK; but that could also be done by monitoring GameState.global.changed and emitting that when the helper property is assigned to.

Maybe it's clear enough as you have it, don't feel the need to rewrite it all.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me try without the NONE before merging.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wjt I made it work identifying null as the lack of helper, and is much better. I added a new signal GameState.global.helper_changed for monitoring the change, similar to the existing completed_quests_changed. Otherwise listening to GameState.global.changed would trigger for other things.

Sorry that it took me some time. I had to run the whole game again, because my state snapshots for quick testing didn't work anymore.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something I took away from a Bippinbits talk (perhaps that you shared?) was the value of a custom "run" button that lets you choose the state of the game to run. That might be useful!

BTW you can also change the GameState of the running game in the inspector quite easily now.

helper_container.visible = has_helper
if has_helper:
var helper_character: CharacterRandomizer = TOWNIE.instantiate()
add_child(helper_character)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems weird at first glance to instantiate a scene, fish out its head, and delete it again. I guess this is because the seed is used for the townie as a whole.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, is only because of that. Do you think this could be done with a separate scene for the head?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having thought about it a bit, I think this is fine – it ensures that the HUD head is the same as the corresponding townie.

You could imagine splitting the townie scene up into a resource for the components + corresponding colours which is input for the scene... but I don't think it's worth it.

helper_character.character_seed = GameState.global.helper.character_seed
helper_character.apply_character_randomizations()
var head := helper_character.head
head.global_position = helper_marker.global_position
head.reparent(helper_container)
head.process_mode = Node.PROCESS_MODE_DISABLED
remove_child(helper_character)
helper_color.color = InventoryItem.COLORS_PER_TYPE[GameState.global.helper.helper_type]


func _on_item_collected(item: InventoryItem) -> void:
for child in items_container.get_children():
var item_slot := child as ItemSlot
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,25 @@ offset_bottom = 96.0
theme_override_styles/panel = SubResource("StyleBoxTexture_hqnrr")
script = ExtResource("2_hvmtc")

[node name="ItemsContainer" type="HBoxContainer" parent="." unique_id=202523362]
[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=2124538819]
layout_mode = 2

[node name="HelperContainer" type="CenterContainer" parent="HBoxContainer" unique_id=1334612586]
unique_name_in_owner = true
custom_minimum_size = Vector2(80, 0)
layout_mode = 2

[node name="HelperMarker" type="Marker2D" parent="HBoxContainer/HelperContainer" unique_id=1030669604]
unique_name_in_owner = true
position = Vector2(40, 18)

[node name="HelperColor" type="ColorRect" parent="HBoxContainer/HelperContainer" unique_id=1044648131]
unique_name_in_owner = true
custom_minimum_size = Vector2(60, 30)
layout_mode = 2
color = Color(1, 0, 1, 1)

[node name="ItemsContainer" type="HBoxContainer" parent="HBoxContainer" unique_id=202523362]
unique_name_in_owner = true
custom_minimum_size = Vector2(32, 32)
layout_mode = 2