Add townies system with occasional helpers#2129
Conversation
|
Play this branch at https://play.threadbare.game/branches/endlessm/townies-system/. (This launches the game from the start, not directly at the change(s) in this pull request.) |
0948ae6 to
1c98b25
Compare
|
This is implementation for an idea that @wjt and I had this morning: a townie helps you with the most difficult part of the Stealth level, by fixing a bridge that opens a shortcut. Here is one Video: recording.webm |
|
Update: I added 6 townies to quests now: In musician quest:
In void quest:
Useful game states to try: |
0b22abd to
075be85
Compare
0a22e2e to
10d41d1
Compare
|
I rebased this and adapted it to the flawless new game state! Here are the new game states "snapshots" I took for testing this: I´'m now polishing this to put it for review. |
4877509 to
cb1f206
Compare
Persist the type of help, matching one of the magical threads, and a character seed for the visual features of the character. Add methods to obtain and consume the help.
The NONE type is needed in the enum to better identify no state, when consuming the help. The colors will be used in the HUD as background to indicate the type of help.
By setting an unique name to this node. This will be used to show the head in the HUD.
If not, when randomizing multiple characters at the same time, they all end up moving in sync. This is the case of the retelling townies in Fray's End.
This dialogue will be displayed when interacting with the eternal loom, before the threads offering.
Listen to the global state for doing so. If there is helper state, instantiate the face of the character according to its seed, and set the background color to the type of help.
The RetellingManager coordinates the retelling with the EternalLoom, to avoid cluttering that node. It does so by listening to signals and calling a method.
Node that will be used to make characters become helpers in levels, for consuming the help obtained during the retelling at the eternal loom. There is no actual implementation, this help could be spent in imaginative ways and is left to the level creators. A default dialogue is provided as example.
Change the interaction of the eternal loom when the player is ready to offer the threads. Now if the quest has retelling dialogue, display it. A retelling may result in the player obtaining help, that can be used later in the game. After the retelling, or if no retelling happened, trigger the incorporating threads cutscene and let the corresponding elder congratulate the player. Remove the sokoban puzzles, which are going to be repurposed. More cleanup on this later.
The dialogue lines should be considered placeholders.
Add the following helpers: - 1_music_puzzle: Memory helper that triggers a dialogue saying "Lore lore lore" as placeholder. - 2_ink_combat: Spirit helper that fills the hard to reach inkwell. - 3_stealth_level: Imagination helper that fixes the bridge.
Add the following helpers: - 1_void_quest: Memory helper that displays a placeholder dialogue. - 1_void_quest: Spirit helper that slows down the enemy. - 2_grappling_hook: Imagination helper that makes needles appear in the optional loop.
|
This is now finally ready for review! Things left out of this change:
Also there is a small bug in the walking animations, when the character that gets closer to the player leaves the loom. |
wjt
left a comment
There was a problem hiding this comment.
Nice!
I think we will want to revisit the logic that hides the thread HUD when you're not on a quest. What happens as of this branch is that you tell the townie a story, they offer their help (and appear in the HUD), but then the threads go to the Loom and then the HUD is hidden.
| MEMORY, | ||
| IMAGINATION, | ||
| SPIRIT, | ||
| NONE, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
|
||
|
|
||
| func _on_helper_state_changed() -> void: | ||
| var has_helper := bool(GameState.global.helper.character_seed) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Let me try without the NONE before merging.
There was a problem hiding this comment.
@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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Yes, is only because of that. Do you think this could be done with a separate scene for the head?
There was a problem hiding this comment.
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.
| - Learned a forgotten song {{ memory_text() }} => retell_memory | ||
| - Slipped past the guards {{ imagination_text() }} => retell_imagination | ||
| - Fought off some InkDrinkers {{ spirit_text() }} => retell_spirit |
There was a problem hiding this comment.
We can iterate on this but I wonder if we should make the options conditional on the thread being available. Something like this:
- Learned a forgotten song [if has_memory()] => retell_memory
- Slipped past the guards [if has_imagination()] => retell_imagination
- Fought off some InkDrinkers [if has_spirit()] => retell_spirit
- Can't really remember => END
There was a problem hiding this comment.
This comes from the spec by @JoniCeceri, but now I see that's not part of the text I copy/pasted in the issue. The retelling of each option should be available anyways. If the player has the corresponding thread, they receive a reward.
Currently, the 2 quests to which I added retelling will have all 3 threads, so is impossible to test at this point.
There was a problem hiding this comment.
I guess I disagree with the spec then 😀 but indeed – impossible to test without making threads optional.
| var result := void_spreading_enemy.get_node_and_resource( | ||
| "NavigationFollowWalkBehavior:speeds:walk_speed" |
…/fix_bridge.gd Co-authored-by: Will Thompson <wjt@endlessaccess.org>
And add a helper_changed signal to listen only to that change.
This adds a help system to the game. Quests creators can now define a dialogue tree for retelling the adventures recently lived before offering the magical threads collected to the Eternal Loom. People from the town gathers around to listen the retelling. If the player has collected a thread that matches one of the options, that option will be highlighted. And if that option is picked, one of the villagers will stand up, and "equipped" (indicated in the HUD) for helping later in the game. The thread collected indicates the type or category of the help, which can be interpreted by level creators in any way.
Level creators can add helper characters to the level. They will appear only if the player got help, and if their helper type matches the one obtained during the retelling. When the player interacts with this helper character, a dialogue is displayed to offer the help. If the player accepts, it is expected that the level creator does something, and then consume the help (disappearing from the HUD). For example: An imagination helper at the stealth level can fix the bridge, which is a shortcut to skip the most difficult part of the level, full of guards.
Details below.
Void quest: Add helpers
Add the following helpers:
Musician quest: Add helpers
Add the following helpers:
Musician and Void quests: Add retelling dialogue
The dialogue lines should be considered placeholders.
Sokobans: Remove project setting to skip the sokobans
Sokobans cleanup: Remove incorporating threads state
Frays End, Eternal Loom: Add retelling and remove sokobans
Change the interaction of the eternal loom when the player is ready to offer the
threads. Now if the quest has retelling dialogue, display it. A retelling may
result in the player obtaining help, that can be used later in the game.
After the retelling, or if no retelling happened, trigger the incorporating
threads cutscene and let the corresponding elder congratulate the player.
Remove the sokoban puzzles, which are going to be repurposed. More cleanup on
this later.
Add HelperCharacter
Node that will be used to make characters become helpers in levels, for
consuming the help obtained during the retelling at the eternal loom. There is
no actual implementation, this help could be spent in imaginative ways and is
left to the level creators. A default dialogue is provided as example.
Add RetellingManager and RetellingTownie
The RetellingManager coordinates the retelling with the EternalLoom, to avoid
cluttering that node. It does so by listening to signals and calling a method.
StoryQuestProgress: Add helper character face to HUD
Listen to the global state for doing so. If there is helper state, instantiate
the face of the character according to its seed, and set the background color to
the type of help.
Quest: Add optional retelling dialogue to the resource
This dialogue will be displayed when interacting with the eternal loom, before
the threads offering.
CharacterRandomizer: Vary the animation when randomizing
If not, when randomizing multiple characters at the same time, they all end up
moving in sync. This is the case of the retelling townies in Fray's End.
CharacterRandomizer: Allow accessing the head sprite.
By setting an unique name to this node. This will be used to show the head in
the HUD.
InventoryItem: Add color constants
The colors will be used in the HUD as background to indicate the type of help.
Add global state for helper characters
Persist the type of help, matching one of the magical threads, and a character
seed for the visual features of the character.
Add methods to obtain and consume the help. And a signal to monitor changes.
Resolve #2119