massaquerade

$ a murder mystery game built in 72 hours for Winter MelonJam 2025

overview

Massaquerade is the third game built with a partner, for the Winter MelonJam 2025. The theme was "Mask." The player attends a masquerade ball as the murderer: talk to guests, collect clues, and identify the traitor. Each new piece of information can open up branches in conversations you've already had. Once you've decided who the target is, press M to strike.

The game ranked 36th overall out of 200 submissions, with 17th place in the Art category and 39th in Gameplay.

tech stack

  • Godot 4, GDScript: game engine and scripting
  • JSON dialogue trees: per-character, per-mask branching dialogue with declarative flag conditions and mutations
  • Flag system: conversationState (local per-dialogue) and Data.player.actionFlags (global persistent)

links

play

Massaquerade
▶ Play

showcase

Massaquerade masquerade ball scene Massaquerade character dialogue Massaquerade character dialogue Massaquerade character dialogue Massaquerade character dialogue Massaquerade jam results

how it works

Dialogue is driven entirely by JSON files. One file per character per mask. Each dialogue node defines the display text, response options, conditions required to show the option, flags to set when the option is chosen, and the next node to advance to. Conditions are evaluated against two scopes: conversationState, a dictionary local to the active conversation that accumulates flags set during the current exchange, and Data.player.actionFlags, the global persistent flag store that persists across all conversations.

The result is that choosing a response in one conversation can set a global flag that unlocks a new branch in an entirely different character's dialogue tree. The clue chain the player follows to identify the target.

challenges

Building a scalable dialogue system was the core technical challenge. A naive approach, writing dialogue state directly into scripts, would have made branching and authoring impossible to manage. The JSON tree format let dialogue content be written outside the code entirely.

The two-scope flag system (local conversation vs. global) required careful design: local flags track what has been said in the current exchange (useful for preventing repeat questions), while global flags track what the player has learned across all interactions (useful for unlocking new branches after the fact). Getting the evaluation order right (check conditions, display options, then apply mutations) meant no flag changes could leak backward into the conditions that gated the current step.

The honest limitation of this jam was throughput. The main bottleneck was not systems but content: writing enough unique, coherent dialogue for multiple characters across multiple mask variants consumed most of the 72 hours. The game systems were solid; the game was smaller than planned because writing is slow.

takeaways

By far the biggest thing learned through this jam was how to build a dialogue system. We did a JSON-based system where you could define flags to set, flags to check, the next node to go to, and many other options. Not only was building this scalable system a challenge, but it was also quite difficult to try and write all the dialogue itself.

One of the main differences between this game and the previous ones is that it felt like the main limitation was how fast we could write dialogue instead of adding cooler systems and interactions. The game systems were solid; the game was smaller than planned because writing is slow. Regardless, it was a great time working on it and the result is something to be proud of.

The biggest learning was how much time narrative content takes relative to code. Systems that feel small to implement become enormous when multiplied by the number of characters, masks, and dialogue branches needed to make the mystery feel real. Some key takeaways:

  • JSON-driven dialogue trees, separating content from logic for scriptable narrative systems
  • Two-scope flag evaluation for local conversation state vs. global persistent state
  • Designing for content throughput, how much dialogue can actually be written in 72 hours
  • Branching narrative design, clue chains that reward exploration without requiring a walkthrough