Categories
Week 8

Week 8: Keymapper Support for Neverhood and Prince Engines

After the intense and complex work on the Sherlock engine last week, this week felt like a welcome break. I focused on implementing keymapper support for two much simpler engines: Neverhood and Prince. Both were relatively lightweight in terms of required effort and complexity.


Neverhood Engine

The Neverhood engine was straightforward to work with. It has only a few core actions and menus, so mapping keys was a smooth process. I created keymaps for the available actions and then located the appropriate points in the code to enable and disable specific keymappers as needed.

Despite the simplicity, it was still important to ensure that everything was well integrated and that there were no unintended conflicts. Once the mappings were set up and tested, everything worked as expected.


Prince Engine

The Prince engine was even easier to handle. It involves only a few key actions, and unlike other engines, it didn’t require any additional keymapper switching logic. One keymap was enough to cover the entire gameplay.

Because of its simplicity, I didn’t need to worry about enabling or disabling different keymaps during runtime, which made the process very efficient.


Wrap-Up

This week, I:

  • Added keymapper support for the Neverhood engine

  • Added keymapper support to the Prince engine

Categories
Week 7

Week 7: Sherlock Engine Keymapper

This week was a major milestone: I passed my midterm evaluations! 🎉 Right after that, I dove straight into one of the most complex engines so far—the Sherlock engine. I also got my Buried and Access keymapper PRs merged earlier in the week.

Sherlock Engine

The Sherlock engine supports two games from The Lost Files of Sherlock Holmes series:

  • The Case of the Serrated Scalpel
  • The Case of the Rose Tattoo

This engine was by far the most complex I’ve worked on, with around 2000 insertions and 600 deletions. Both games have separate input handling code, yet they share some common code. This made changes particularly delicate—I had to make sure that updating one game’s behavior wouldn’t break the other.

The Case of the Serrated Scalpel

This game turned out to be the trickiest, mainly because it’s localized in 5 different languages. Each language has its own translated UI, including verbs like “Look” or “Talk”.

Why does this matter?
The game uses the first letter of a verb/option to trigger it via keyboard shortcuts. For example, “L” for “Look” (or its translated equivalent). Thankfully, the engine code already had these localized key bindings stored. I leveraged that to bind the correct keys to actions dynamically, based on the game’s language.

Another subtle challenge was visual feedback: when a verb is selected, the corresponding UI button appears pressed. If the player selects a different verb or deselects the current one, the button should visually “pop back out.” Implementing this required extra logic to track which verb is active and update the UI accordingly.

Also, the sheer number of possible actions took significant time to map properly.

The Case of the Rose Tattoo

Compared to Scalpel, this one had a slightly easier path since it’s not localized. Hence no need to worry about language-specific keybindings.

However, it still had more total actions, which made the task just as time-consuming. The logic was a bit cleaner here, so once the actions were identified, the process went fairly smoothly.


Wrap-Up

This week, I:

  • Passed my midterm evaluations 🎉
  • Got my Buried and Access keymapper PRs merged🎉
  • Implemented keymapper support for the Sherlock engine
Categories
Week 6

Week 6: EFH Keymapper and PR Cleanups

This week, I focused on implementing keymapper support for the Escape from Hell (EFH) engine and addressing feedback on my previous PRs. I also had three of my earlier PRs merged: Tetraedge, Sword25, and Teenagent.


EFH Engine

EFH was by far the most involved keymapper implementation I’ve done so far. Unlike other engines, EFH is controlled entirely via the keyboard—there’s no mouse support at all. This meant that without a proper keymapper, the game was essentially unplayable on devices without physical keyboards.

I started by listing out all the keys used in various gameplay scenarios and organizing them into 11 distinct keymaps. To make switching between these keymaps easier, I wrote a helper function that takes an enum and switches the keymapper context accordingly.

What made this implementation even trickier was that a previous contributor had partially implemented keymapper support—mainly for movement and a few other actions. While their work gave me a helpful starting point, I noticed a few issues:

  • Some important keys were missing or not fully mapped.

  • The partial mapping led to conflicts with unmapped actions.

To resolve this, I reviewed their commits to recover any missed inputs and reworked the implementation to cover all keyboard actions comprehensively. Once everything was mapped properly, the conflicts disappeared, and the engine behaved as expected. It took a while, but the process was smooth overall.


Fixes to Previous PRs

Alongside EFH, I also fixed some minor typos in the action descriptions across a few older PRs.

More importantly, I revisited the workaround I had written for the Access engine last week. That engine uses internal numeric codes for verbs rather than relying on keycodes, so I had initially matched keymapper actions to verb codes by relying on the order of actions—calculating the verb code by subtracting a base value.

A mentor correctly pointed out that this was dangerous. If someone ever changed the action order in the future, it would silently break. To fix this, I replaced the order-based logic with a proper mapping table that explicitly associates each action with its corresponding verb code. The function now loops through this table and passes the appropriate internal code only when a match is found—much safer and more maintainable.

Another improvement based on mentor feedback: I removed all engine-specific key bindings for the GMM (Global Main Menu). Since it’s already mapped in the global keymap, duplicating it in engine keymaps is unnecessary and could lead to confusion.

 


Wrap-Up

This week, I:

  • Implemented keymapper support for the EFH engine
  • Updated my previous keymapper PRs
  • Got my Tetraedge, Sword25, and Teenagent keymapper PRs merged 🎉
Categories
Week 5

Week 5: Buried and Access

This week, I focused on bringing keymapper support to two more engines: Buried and Access. Both engines came with their own set of challenges


Buried

The Buried engine had an unusual approach to input: it handled most keypresses on key release rather than on key press.

In terms of actual key replacement, there wasn’t much heavy lifting to do. However, the real challenge—like in some of the previous engines—was figuring out when to activate or deactivate keymaps. Buried has different contexts where certain keymaps should be enabled or ignored, and tracing that logic took the majority of my time this week.

Once I understood those transitions, hooking up the rest of the keymapper functionality was fairly smooth.


Access

Access was easier to work with in comparison, but it did come with one major twist: it used function keys (like F1, F2, etc.) to change the current active verb in the game.

The function responsible for switching verbs didn’t rely on keycodes—it used internal numeric codes corresponding to different verbs. I couldn’t just update that function to use actions instead, because it was used in other parts of the engine where those codes were passed directly.

To solve this, I came up with a workaround: I mapped keymapper actions to these verb codes by ensuring the actions were written in a specific order, and then calculated the correct internal code by subtracting a default base. It’s not the cleanest solution, but it worked without requiring intrusive changes to the engine’s logic.


Wrap-Up

This week, I:

  • Implemented keymapper support for Buried and Access

Next week, I’ll continue expanding support to more engines—each one bringing its own surprises.