Skip to content
Open
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
13 changes: 9 additions & 4 deletions scenes/game_elements/characters/npcs/elder/components/elder.gd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ const STORYBOOK_SCENE := preload("uid://bhm7fdjvppt8b")
abandon_point = new_value
update_configuration_warnings()

## Optional dialogue passed to `TalkBehavior`. Used when
## instantiating an elder in a scene that doesn't use the standard
## eternal loom dialogue flow.
@export var dialogue: Resource

Comment on lines +30 to +34

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 3 elders in Fray's End actually already have different dialogues: they are each an instance of a different scene, so we can just set the TalkBehavior node's dialogue directly in each one.

Though if there are many elders in the archipelago I can see why you want to avoid continuing that trend. I think it's fine to do this. I wish Godot had a built-in way to export specific properties of child nodes from the root of the owning scene!

## The quest chosen by the player from the storybook
var chosen_quest: Quest

Expand All @@ -46,9 +51,12 @@ func _ready() -> void:
if Engine.is_editor_hint():
return

if self not in eternal_loom.elders:
if eternal_loom and self not in eternal_loom.elders:
eternal_loom.elders.append(self)

if dialogue:
talk_behavior.dialogue = dialogue

interact_area.interaction_ended.connect(_on_interaction_ended)
animated_sprite_2d.connect("frame_changed", _on_frame_changed)

Expand All @@ -73,9 +81,6 @@ func _get_configuration_warnings() -> PackedStringArray:
if not quest_directory:
warnings.append("Quest Directory property should be set")

if not eternal_loom:
warnings.append("Eternal Loom property must be set")

return warnings


Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://clndtrncpdxl5"
path="res://.godot/imported/hook-string-2.png-faad3f4d6b999aada803f4f988249e6f.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://scenes/game_elements/characters/player/components/hook-string-2.png"
dest_files=["res://.godot/imported/hook-string-2.png-faad3f4d6b999aada803f4f988249e6f.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
~ start
Basics Elder: [[Hi|Hello|Greetings]], StoryWeaver. Welcome to Dev Archipelago!
Basics Elder: This is a place of creativity, play, and experimentation!
Basics Elder: While I can't explain all of what happens here, I invite you to learn about the basics of our unraveling world!
do balloon.hide()
do show_storybook()
if chosen_quest == null:
% Basics Elder: Feel free to explore these islands, however these quests might be a helpful way to start!
% Basics Elder: Explore and have fun! I hope to see you again if you need to relearn the basics.
% Basics Elder: The people of Threadbare are counting on you. Your understanding of our world is necessary for its survival!
else:
% Basics Elder: Excellent choice, your training will surely help with your world-saving efforts.
% Basics Elder: Ah, those! Capable of such inginuity. To do what? I can't quite remember...

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.

Suggested change
% Basics Elder: Ah, those! Capable of such inginuity. To do what? I can't quite remember...
% Basics Elder: Ah, those! Capable of such ingenuity. To do what? I can't quite remember...

% Basics Elder: I'm confident you will know how to use this on your journey.
=> 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://cjo0b4vsho0yh"
path="res://.godot/imported/dev_archipelago_basics_elder.dialogue-064da2d2d7bb8dd2fdcf22e13ab7b45a.tres"

[deps]

source_file="res://scenes/world_map/components/dev_archipelago_basics_elder.dialogue"
dest_files=["res://.godot/imported/dev_archipelago_basics_elder.dialogue-064da2d2d7bb8dd2fdcf22e13ab7b45a.tres"]

[params]

defaults=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
~ start
Grapple Elder: Welcome to my grapple island, StoryWeaver.
Grapple Elder: Did you know that you can hook on to more than just pins? And how do you reckon that sheep got a different string?
Grapple Elder: Perhaps these quests may offer you some inspiration on how your grapple can be used!
do balloon.hide()
do show_storybook()
if chosen_quest == null:
% Grapple Elder: Oh well, be sure to return when you are ready to learn about all that is hookable.
% Grapple Elder: There are many other islands here with fun to be had! Take your time exploring.
else:
% Grapple Elder: Nice one! I'd be trying this too, if I could only get my string back from those woolly rascals...
% Grapple Elder: Good luck with your experimenting!
=> 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://cmk5th3xqyb5j"
path="res://.godot/imported/dev_archipelago_grapple_elder.dialogue-1b1d445c80bd85e838823a1a197b5c7f.tres"

[deps]

source_file="res://scenes/world_map/components/dev_archipelago_grapple_elder.dialogue"
dest_files=["res://.godot/imported/dev_archipelago_grapple_elder.dialogue-1b1d445c80bd85e838823a1a197b5c7f.tres"]

[params]

defaults=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
~ start
# TODO: Name is up for debate

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.

Personally I love it. I laughed out loud when I got the joke.

RepElder: [[Hi|Hello|Greetings]], StoryWeaver. I see you have decided to explore!
RepElder: Oh, the sheep? They've been at this for hours, I'm tired just watching them.
RepElder: I wonder how they learned how to play like that... anyhow, repelling is a skill everyone should try at least once.
do balloon.hide()
do show_storybook()
if chosen_quest == null:
% RepElder: The archipelago is full of opportunities to play and be inventive. I trust you will use it wisely.
% RepElder: You don't find me repellent, do you? If you change your mind, my quests are always available for you to practice.
% RepElder: Explore and have fun! I hope to see you again if you find yourself forgetting how powerful repel can be.
else:
% RepElder: Nice one, that will certainly be fun to play with.
% RepElder: Good luck teaching the sheep how to do that!
=> 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://b8afvr4fcfx0t"
path="res://.godot/imported/dev_archipelago_repel_elder.dialogue-ca8c45b782680ae480d67180c8581baa.tres"

[deps]

source_file="res://scenes/world_map/components/dev_archipelago_repel_elder.dialogue"
dest_files=["res://.godot/imported/dev_archipelago_repel_elder.dialogue-ca8c45b782680ae480d67180c8581baa.tres"]

[params]

defaults=true
45 changes: 45 additions & 0 deletions scenes/world_map/components/sheep_tug_of_war.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
extends Node2D

const MIN_DELAY: float = 0.5
const MAX_DELAY: float = 3

var hook_control_1: Node2D
var hook_control_2: Node2D

@onready var player_hook: PlayerHook = $TuggingSheep/Sheep/PlayerHook
@onready var player_hook_2: PlayerHook = $TuggingSheep/Sheep2/PlayerHook2
@onready var hookable_box: AnimatableBody2D = $HookableBox


## Called when the node enters the scene tree for the first time.
func _ready() -> void:
player_hook.remove_from_group("hook_listener")
player_hook_2.remove_from_group("hook_listener")
hook_control_1 = player_hook.find_child("HookControl")
hook_control_2 = player_hook_2.find_child("HookControl")
hook_control_1.state = 0
hook_control_2.state = 0
Comment on lines +18 to +23

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.

Interesting. That component really wasn't designed for non-interactive use! I think this is fine as a workaround but rather than the boilerplate "called when..." comments, I think it would be worth documenting here why these lines are needed (as below for the state).



## Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
# TODO: Better way to avoid getting input from player aim/controls?
if hook_control_1.state == 1:
hook_control_1.state = 0
if hook_control_2.state == 1:
hook_control_2.state = 0
Comment on lines +29 to +32

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.

Could you not use HookControl.State.AIMING rather than 1 here?



func _on_timer_timeout() -> void:
var sheep_options := [player_hook, player_hook_2]
sheep_options.shuffle()
var first_sheep: PlayerHook = sheep_options.pop_front()
var second_sheep: PlayerHook = sheep_options.pop_front()

first_sheep.hooked(hookable_box.find_child("HookableArea"), true)

await get_tree().create_timer(max(randf() * MAX_DELAY, MIN_DELAY)).timeout

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.

Suggested change
await get_tree().create_timer(max(randf() * MAX_DELAY, MIN_DELAY)).timeout
await get_tree().create_timer(randf_range(MIN_DELAY, MAX_DELAY)).timeout


second_sheep.hooked(hookable_box.find_child("HookableArea"), true)
1 change: 1 addition & 0 deletions scenes/world_map/components/sheep_tug_of_war.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://chf6ixk63ntro
12 changes: 12 additions & 0 deletions scenes/world_map/components/sheep_volleyball.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
extends Node2D
@onready var repel_timer: Timer = %RepelTimer
@onready var repel_timer_2: Timer = $Sheep2/PlayerRepel2/RepelTimer2
Comment on lines +4 to +5

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 would suggest either consistently using % unique names, or using @exports. But...



## Called when the node enters the scene tree for the first time.
func _ready() -> void:
if repel_timer_2.is_node_ready():

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.

...this is guaranteed by the scene structure. A node becomes ready after all its children are ready. But...

await get_tree().create_timer(.5).timeout
repel_timer.start()
Comment on lines +11 to +12

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.

Since the other two timers are nodes in the scene, I would personally structure this with a third timer, with autostart set to True, timeout set to 0.5, oneshot set to true, and connect its timeout to start on RepelTimer. I think that makes the whole setup more consistent: it's all done in the scene tree.

1 change: 1 addition & 0 deletions scenes/world_map/components/sheep_volleyball.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://c0nbaisj38qn4
203 changes: 203 additions & 0 deletions scenes/world_map/dev_archipelago.tscn

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 love how this scene is taking shape.

Some minor nitpicking about foam:

Image

Red circle: as documented on https://github.com/endlessm/threadbare/wiki/TileMapLayers-and-TileSets#foam the fake perspective means that the top edge of a patch of grass raised "one level" above the water should not have foam.

Blue circle: if you look closely you can see the foam through the cliff, which is because there is no cliff underneath that patch of grass:

Image

Large diffs are not rendered by default.