I've been working on this project the past couple of months. It's my first platformer, inspired by Yume Nikki, Dreaming Sarah and a bunch of other stuff. It has been a learning experience, but outside one or two hiccups I've really enjoyed working with Godot.<br><br>My long-term goal is to have a world where any npc can be hurt/killed or befriended. The player can mutate, and the mutations let them reach new areas (e.g. wings enable flying). <br><br>My short-term goal is to finish the Alpha within the next month. It has 5 maps, the "nexus" crossroads map, 2 big maps with events and such, and 2 smaller maps. I feel like that will be a good point to stop and decide if I want to make it bigger. <br><br>I spent most of the first two months figuring out how to organize things and making objects like elevators, ladders, teleports, npcs, the dialogue system. But I think now I'm to the point where most of the development is content. I would like to release the source code at some point if I can tidy it up enough to be useful/readable.<br><br>Right now this is a solo project, and I have no experience with pixel art so programmer art ahoy!<br>

I&#039;ve spent some time refactoring and simplifying the event system, which controls dialogue and scripted events.I had issues with control flow until I discovered custom signals and coroutines. I tried to come up with a system that is easy to add content to and keep organized, but can be expanded as new needs arise.I&#039;m storing all the game&#039;s text in a json dictionary. Each event key contains a dictionary that has some combination of the following:[code]{ &quot;repeat&quot;: [A dialogue array that displays each line, the repeats the last line until a new event is loaded],&quot;txt&quot; : [A dialogue array that is displayed once (used as part of complex events)],&quot;function&quot;: &quot;function&quot; to call,&quot;next&quot;: &quot;eventkey&quot; that will be loaded as the next event, but not fired until the player triggers it. Only needed to queue up dialogue arrays with breaks in between. }[/code]Each npc inherits the following. [code]signal player_inputsignal event_finished... vars, connections etc...func _input(event): if event.is_action_pressed(&quot;button_action&quot;): if player_in_area == name: if active_event: emit_signal(&quot;player_input&quot;) print(name, &quot; emitted player_input_signal&quot;) elif event_loaded: initiate_event(event_loaded) func initiate_event(event): active_event = true repeat = false if &quot;next&quot; in global.txt[name][event]: event_loaded = global.txt[name][event][&quot;next&quot;] print(&quot;next eventkey &quot;, event_loaded, &quot; loaded&quot;) if &quot;function&quot; in global.txt[name][event]: var run_event = funcref(self,global.txt[name][event][&quot;function&quot;]) print(&quot;calling function&quot;) run_event.call_func() else: if &quot;txt&quot; in global.txt[name][event]: if global.txt[name][event][&quot;txt&quot;].size() &gt; 0: dialogue_list = global.txt[name][event][&quot;txt&quot;] print(&quot;txt loaded&quot;) elif &quot;repeat&quot; in global.txt[name][event]: repeat = true dialogue_list = global.txt[name][event][&quot;repeat&quot;] print(&quot;repeating txt loaded&quot;) player.freeze=true chat(dialogue_list, repeat)func chat(dialogue_list, repeat=false): get_textbox() while dialogue_list.size()&gt;0: textbox.message(dialogue_list[0]) print(dialogue_list[0]) yield(self,&quot;player_input&quot;) if dialogue_list.size()==1 and repeat: break else: dialogue_list.remove(0) print(&quot;line removed&quot;) get_node(&quot;textbox&quot;).free() event_ended()func event_ended(): print(&quot;event ended&quot;) active_event = false player.freeze = false emit_signal(&quot;event_finished&quot;)[/code]Here&#039;s an example of what a complex event would look like:[code]func power(): if active: print(&quot;trying to shut lord down after powered&quot;) shutdown() else: get_textbox() textbox.message(global.txt.lord.desc) textbox.choice(global.txt.lord.power_menu) yield(get_node(&quot;textbox&quot;), &quot;choice_selected&quot;) if textbox.player_choice == 0: if &quot;tvland power&quot; in global.triggered_events: print(&quot;lord is turned on&quot;) active = true initiate_event(&quot;turned-on-safe&quot;) yield(self, &quot;event_finished&quot;) initiate_event(&quot;on-friendly&quot;) else: textbox.popup(&quot;You click the button repeatedly. Nothing happens.&quot;) else: textbox.close_overlay() event_ended()[/code]

9 days later

I&#039;ve almost finalized the dialogue system. One character uses a different text box for some lines (but not all) and I&#039;m trying to figure out the best way to handle that. I figured out the Label properties in the editor changed when I instanced the textbox in-game, so I define them in ready() now. I&#039;m not sure if that&#039;s something on my end but defining them in the script solved the problem.The choice menu is a dynamic menu that creates buttons based on items in a list, then returns the index of the item chosen.[code]func choice(button_list): for item in button_list: var new_button = Button.new() new_button.set_text(item) get_node(&quot;vbox/menu&quot;).add_child(new_button) new_button.connect(&quot;pressed&quot;, self, &quot;choice_menu_button_pressed&quot;, [button_list.find(item)])func choice_menu_button_pressed(choice): player_choice = choice emit_signal(&quot;choice_selected&quot;,choice) self.close_menu()[/code]

a month later

Wow.... Can&#039;t believe I lost this tread. Looks awesome!

21 days later

Hey, your project looks really good! Keep it up!Thanks for sharing your code as well, it is very helpful!