Skip to content

Remember threads between quest playthroughs - #2693

Merged
manuq merged 7 commits into
mainfrom
wjt/store-collected-threads
Oct 20, 2026
Merged

manuq merged 7 commits into
mainfrom
wjt/store-collected-threads

Conversation

@wjt

@wjt wjt commented Aug 11, 2026 •

Copy link
Copy Markdown
Member

Quests in Threadbare can be replayed. Previously you would be able to
collect each thread again, and take them to the loom a second time. Then
they would be forgotten forever.

We would also like to make it possible to have optional threads in a
quest, so that there is value in replaying a quest. Perhaps there's a
thread you can only get through careful exploration, or via an optional
puzzle, or with an ability unlocked later in the game.

Finally, we would like to make threads a sort of currency, with which
you can buy powerups of some kind. It follows that you shouldn't be able
to collect the same thread in the same scene multiple times because then
you could just grind an easy quest to buy all the powerups.

Change the game state storage to record the scene and node from which a
thread was collected. At the end of a quest, copy the new threads to a
new global inventory. When starting a quest, pre-populate the quest
inventory with the threads already collected in a previous run. In
CollectibleItem, and in the HUD, detect when a thread is from a previous
run through the quest and dither it.

In the two places where threads are awarded in dialogue, add a
CollectibleItem to the scene and use that as the source of the item.
Perhaps in future it would be better to have a method on CollectibleItem
to do this outside of an interaction. Or maybe these should be playable
scenes and this should not be supported?

@wjt

wjt commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

How to test:

  1. New game.
  2. Skip tutorial.
  3. Go to Dev Archipelago
  4. Talk to the first elder. i've patched him to show the level design quests
  5. Chose the "Optional Threads" quest
  6. On your first playthrough, collect only the green thread on the right. Don't try to avoid the guards.
  7. Go back to Fray's End. Deposit the threads at the Loom. Watch the animation.
  8. Quit to title then continue (works around a bug in this branch)
  9. Go to Dev Archipelago again, and play the quest again. You should see that the green thread has a dither effect on it.
  10. This time, avoid the guards and collect the red thread. Then deliberately allow the guards to catch you.
  11. When you respawn, the red thread should still be gone.
  12. Go back past the guards and collect the (dithered) green thread.
  13. Take the 1 new thread you have collected to the loom.
  14. Repeat step 8
  15. Repeat step 9. You should see that the red thread is missing, and the green thread is stippled.

@github-actions

Copy link
Copy Markdown

Play this branch at https://play.threadbare.game/branches/endlessm/wjt/store-collected-threads/.

(This launches the game from the start, not directly at the change(s) in this pull request.)

@wjt

wjt commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

This is a work in progress. I am more interested in review of the gameplay than of the code. The incompatible requirements I am trying to square are:

  1. We want quests to be replayable
  2. We want to be able to have optional threads in quests
  3. You shouldn't be able to collect the same thread more than once (because you'll be able to spend your threads on powerups and otherwise you could just grind an easy quest and unlock the whole tech tree)...
  4. ...but collectible threads are how we link scenes together.

In this branch, the behaviour of a previously-collected thread depends on whether the thread has a "next scene" configured:

  • If it does, then it is shown in-world, but stippled, and collecting it again does not readd it to the inventory
  • If it does not, then it is deleted immediately

The intuition is that optional threads should not link to another scene, while mandatory threads always do. (However I can already imagine cases where we might want to teleport the player after an optional thread...)

@felixwalberg

Copy link
Copy Markdown
Contributor

This is cool! I like your distinction of dithering the previously collected threads to indicate it won't be contributing to threads used in the skill tree!

I know that this is more of a collection of what threads you are bringing back to Fray's End than a "progress bar", but when there are optional threads, it might be nice if there is a way to indicate that. If you are not able to collect optional threads more than once, there is only one attempt where this could be completely full.
Screenshot 2026-08-12 at 4 02 33 PM
If you play it again and only collect the green thread, you then go back to Fray's End and have to deposit threads even though none are visible in the collection in the top right.

I was wondering... would it be worth experimenting with a different visual for threads that are optional and previously collected? Something that shows up but is not interactive like the green thread. But then I was questioning (and maybe I am missing a key point) why we need to make that distinction? If the green thread doesn't contribute to the skill tree and doesn't show in the progress bar, is there any problem with doing the same with the optional red thread?

@manuq

manuq commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

All works as expected:

image

I played without reading your requirements first. I would have expected the green spool to dither and also have collisions removed (like the powerups). But then I realized that there wouldn't be an exit, because collecting the green spool does the level progression (what you call mandatory threads that link scenes together). Also I would have expected the red thread to be dithered and without collider, instead of gone (to indicate that I grabbed it at one point in gameplay).

This is a work in progress. I am more interested in review of the gameplay than of the code. The incompatible requirements I am trying to square are:

  1. We want quests to be replayable
  2. We want to be able to have optional threads in quests
  3. You shouldn't be able to collect the same thread more than once (because you'll be able to spend your threads on powerups and otherwise you could just grind an easy quest and unlock the whole tech tree)...
  4. ...but collectible threads are how we link scenes together.

In this branch, the behaviour of a previously-collected thread depends on whether the thread has a "next scene" configured:

  • If it does, then it is shown in-world, but stippled, and collecting it again does not readd it to the inventory
  • If it does not, then it is deleted immediately

The intuition is that optional threads should not link to another scene, while mandatory threads always do. (However I can already imagine cases where we might want to teleport the player after an optional thread...)

The level explains very well the problem. I think that to avoid any issues we shoulds make all threads the same, optional. And use a separate toggleable object with a teleporter inside to link scenes together. A closed/opened door, for example. That is, remove requirement 4. We'll have to update all the quests, though.

Alternatively, the dithered spools should link to the next scene but not count as collected. That is, don't go to the inventory.

@manuq

manuq commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

One reference of optional collectible: the 10-flower coins in Mario Wonder. These are big purple flower-shaped collectibles. There are 3 per level. Once you collect them, they dissapear. The next time you play the same level, they appear stippled. If you re-collect them stippled, they dissapear again.

@JoniCeceri

Copy link
Copy Markdown

Noting here the convo from the meeting: removing requirement 4 by having the teleporter interactable threads be "legacy" and new threads going forward just be collectables (with existing levels reworked to accommodate changes)

Also noting, have collected threads on replaying level be replaced with bonus buttons to "mark" their collection and also give a slight bonus to players who backtrack to them.

@wjt

wjt commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

We discussed this in the build review. In summary:

  • Either stipple previously-collected collectibles when you re-play the quest, or replace them with collectibles of lower value. TBC.
  • The consensus was that yes, we should split the "collectible" and the "teleport to next scene" functionality (and I think we should split the "play dialogue" functionality at the same time!). One idea to avoid having to redesign every quest in the game is that we could implement a new object; leave the existing one but mark it as deprecated, and then quests would continue to work.

Actually I think we could do the refactoring mechanically:

  1. Add a collected signal to collectible_item.gd
  2. Write a script to go through every scene in the game that instances collectible_item.tscn (I already did this!). For each one:
    • If the thread has dialogue as well as a next_scene, add a Cinematic node. Configure it with the same dialogue and next_scene. Connect the collectible's collected signal to the start signal on the Cinematic.
    • Otherwise, add a SceneLink node. Configure it with the same link. Connect the collectible's collected signal to its switch method.

There are some edge cases to deal with here though:

  • Collectibles update the challenge_start_scene (used by the lives functionality which we have effectively disabled...), nothing else does.
  • We need to take control of the player character while the cinematic is playing and/or the scene switch is occurring.

@wjt
wjt force-pushed the wjt/store-collected-threads branch 2 times, most recently from 14ed33f to 0982254 Compare August 21, 2026 19:08
@wjt wjt changed the title WIP: Store which threads have been collected [2/2] WIP: Remember threads between quest playthroughs Aug 21, 2026
@wjt
wjt changed the base branch from main to wjt/store-inventoryitems-as-separate-resource-files August 21, 2026 19:08
@wjt
wjt force-pushed the wjt/store-collected-threads branch from 0982254 to 337c2e3 Compare August 21, 2026 19:09
@wjt wjt changed the title [2/2] WIP: Remember threads between quest playthroughs WIP: Remember threads between quest playthroughs Aug 21, 2026
@wjt

wjt commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

What I decided to do as a first step is to make the behaviour consistent as follows:

  • If you have collected a thread in the current (or abandoned + resumed) run of the quest, it is full-colour in the HUD, and does not re-appear in the world after you die & respawn.
  • Otherwise: if you have collected a thread in a previous run of the thread, when you replay the thread the "progress" HUD shows it, dithered. When you encounter it again in the world, it is displayed, dithered. Collecting it does not re-add it to the quest inventory, but it does trigger effects such as dialogue or switching scene. (Once it has been re-collected, it will not appear again in the same run of the quest.)

@wjt

wjt commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

There are still some bugs in this patch but I ran out of time before my week of vacation so I've pushed what I have and tried to summarise what's left.

@wjt
wjt force-pushed the wjt/store-collected-threads branch from 337c2e3 to e7e5f5d Compare August 21, 2026 19:16
@manuq

manuq commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

There are still some bugs in this patch but I ran out of time before my week of vacation so I've pushed what I have and tried to summarise what's left.

Thanks! I can take it from here.

wjt added 3 commits September 20, 2026 17:10
Previously we defined InventoryItem resources inline in every scene that
uses them; and we hardcoded the world texture, HUD texture, and colour
for each in the script.

Turn these into properties of the resource. Create 3 on-disk resources
for the memory, imagination, and spirit threads. Add migration code to
collectible_item.gd which updates the property so that loading & saving
a scene using this script does the migration. Leave the migration code
in-place so that as out-of-tree quests are merged we can easily update
them.

Change the inventory storage to refer to those, rather than saving just
the item type name and reconstructing resources on load.

I think this will make it easier to add collectibles which are not
threads in future, and also to remember which threads have been
collected when loading or replaying a quest, though I haven't attempted
to do that here.
Quests in Threadbare can be replayed. Previously you would be able to
collect each thread again, and take them to the loom a second time. Then
they would be forgotten forever.

We would also like to make it possible to have optional threads in a
quest, so that there is value in replaying a quest. Perhaps there's a
thread you can only get through careful exploration, or via an optional
puzzle, or with an ability unlocked later in the game.

Finally, we would like to make threads a sort of currency, with which
you can buy powerups of some kind. It follows that you shouldn't be able
to collect the same thread in the same scene multiple times because then
you could just grind an easy quest to buy all the powerups.

Change the game state storage to record the scene and node from which a
thread was collected. At the end of a quest, copy the new threads to a
new global inventory. When starting a quest, pre-populate the quest
inventory with the threads already collected in a previous run. In
CollectibleItem, and in the HUD, detect when a thread is from a previous
run through the quest and dither it.

In the two places where threads are awarded in dialogue, add a
CollectibleItem to the scene and use that as the source of the item.
Perhaps in future it would be better to have a method on CollectibleItem
to do this outside of an interaction. Or maybe these should be playable
scenes and this should not be supported?
@wjt
wjt force-pushed the wjt/store-collected-threads branch from e7e5f5d to 5d6d2e6 Compare September 20, 2026 16:14
@wjt wjt changed the title WIP: Remember threads between quest playthroughs Remember threads between quest playthroughs Sep 20, 2026
@wjt
wjt marked this pull request as ready for review September 20, 2026 16:16
@wjt
wjt requested review from a team as code owners September 20, 2026 16:16
@wjt

wjt commented Sep 20, 2026

Copy link
Copy Markdown
Member Author

Rebased, fixed the TODOs. But it will need testing...

Base automatically changed from wjt/store-inventoryitems-as-separate-resource-files to main October 20, 2026 13:30
@manuq
manuq requested review from a team as code owners October 20, 2026 13:30
@manuq
manuq force-pushed the wjt/store-collected-threads branch from 2026374 to 626c3cf Compare October 20, 2026 14:40
@manuq

manuq commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Totally unrelated to this: the new StoryQuest "El hilo que no tejí" use "partial" threads in a custom HUD. The player has to grab 3 Memory threads to count for one. Still, each collected part is in the Inventory as a single thread. This is something to solve in that StoryQuest, although it doesn't break it.

image

What broke was a function in the outro to leave a single item of each type, done this way because otherwise it would show 3 Memory items in the 3 slots:

# Al volver al pueblo, el HUD base muestra los primeros 3 ítems del inventario. Con los 9
# fragmentos serían 3 del mismo color; se deja uno de cada hilo (verde, amarillo y rojo).
func _dejar_un_hilo_de_cada_color() -> void:
	if not GameState.quest:
		return
	var hilos: Array[InventoryItem] = []
	for tipo: InventoryItem.ItemType in [
		InventoryItem.ItemType.MEMORY,
		InventoryItem.ItemType.IMAGINATION,
		InventoryItem.ItemType.SPIRIT,
	]:
		hilos.append(InventoryItem.with_type(tipo))
	var inventario := GameState.quest.inventory
	inventario.items = hilos
	inventario.emit_changed()

The quest should use generic facts directly. For now I will unbreak it.

@manuq

manuq commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

The optional threads example was very useful! I've been playing a lot with this branch today. I think is ready to be merged, and we'll continue fixing this as they appear, and handle the TODO notes.

@manuq
manuq merged commit 15eb6cd into main Oct 20, 2026
6 checks passed
@manuq
manuq deleted the wjt/store-collected-threads branch October 20, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants