GSoC Summary

Project description

The goal for the project was to finish the work on qdEngine and make all games based on it playable and completable. Milestones for the project were:

  1. Multiple MinigameManagers could be instantiated. Mini-games for dogncat are running.
  2. Games with advanced mini-games are supported.
  3. All games on qdEngine are supported.

Because I continued working on the engine since my first contribution at the start of March, I was able to finish the task in the first week on the GSoC period.

Thus, for the GSoC period itself, my task was to finish the work on existing engines.

What was done

The original goal for qdEngine was met and I was able to reach all milestones – all games are completable to the end. The news item with the engine announcement can be found here.

The second engine after qdEngine was SLUDGE. The engine was already very close to be done, so only I added a few minor enhancements:

  • Support for extended saves
  • Support for Return-to-Launcher and custom quit dialog
  • Fixed some crashes during autosaves

Following this, I worked on adding language support for the Teenagent game. At that time it only supported English strings, and my task was add support for Polish, Czech and Russian (fan-translated) strings. The challenge was that all language-related data was stored inside the executables, so I had to first extract them, and then modify create_teenagent tool, so that it generated the .dat file that contained the data for all languages in it. This task took quite some time, but in the end, I was able to extract all strings, pack them into dat file and make changes to the engine to support everything.

Shortly after this, I also added support for Polish voice-overs, the only version with voice acting.

After Teenagent, I worked on WAGE engine to support games made with World Builder game creation system. This included both fixing the bugs and also redumping the games, so that they are in right format (Macbinary). The latter took some time and iterations, however with the help of my mentor, we were able to produce the master collection and announce engine for the public testing.

After this I worked on playtesting and improving the MacVenture engine. I was able to fix a couple of blocking bugs, implement number of missing features and playtest games to the end.

Finishing the work on engine also includes taking screenshots, writing wiki pages and preparing news items. So in addition to writing code, I also helped with screenshots and wrote three news items for WAGE, SLUDGE and qdEngine.

Code merged

There were a number of pull requests created over whole period of GSoC. Below are some of the important ones:

qdEngine

Adding support for advanced minigames

Adding 32bpp support

Adding punycode support

SLUDGE

Add support for extended saves

WAGE

Various bug fixes

Adding fallback detection

More fixes

Teenagent

Adding language (textual) support for Polish, Czech and Russian

Adding Polish voice-overs

MacVenture

Bug fixes and improvements

What’s left to do

Finishing last bits of MacVenture:

  • Display Title and StartupScreen images on startup.
  • Extend MacDialog to support text input and use it everywhere in the engine instead of existing dialog class. This will make pop-up dialogs look more similar to original.
  • Sync Click-To-Continue button’s behavior with original. In other words, enable click-to-continue button when text inside console window needs to scrolled to be fully read to the end.
Conclusion

I really enjoyed my time spend with ScummVM this summer. It was my first time contributing to open source project and doing it with ScummVM was a great experience. I am pleased that I had a chance to work on a real world application used by players all around the world.

Working on this project helped me to improve my skills in navigating enormous codebases, reading and understanding other people’s code and correctly formulating and asking questions when get stuck.

Lastly, I want to thank project organizers at ScummVM team for selecting me and giving me a chance to participate in this program. Of course, I also want to say huge thanks to my mentor – Eugene Sandulenko, aka, sev, who guided and helped through this entire period. He was always there for help when I got stack and provided deep explanations when I did not know certain things. I also would like to thank other developers who reviewed my code, provided suggestions and pointed to mistakes. Finally, I am grateful to GSoC organizers for providing this incredible opportunity.

GSoC: Final Blog

Goals of the Project

The aim of the project was to integrate a File Integrity Service into ScummVM, along with a supporting application for managing the database. The main goals were:

  1. Populating the database with the detection entries used by ScummVM for game detection, followed by existing game file collections containing full MD5 checksums.
  2. Developing a utility for scanning game directories and generating data to further populate the database.
  3. Allowing users to verify their game files through this integrity service, and contribute new game variants.
  4. Building an application for managing the server and the database with role based access.

What I Did

  • A large portion of the work involved rewriting the codebase, as the existing logic for filtering and matching the filesets was not correct.
  • For ensuring correctness of code while matching old game collections, a lot of manual checking was required for over 100 different engines.
  • For the scan utility, I extended support for legacy Mac file formats (AppleDouble, MacBinary, etc.), ensuring proper matching with filesets present in the database.
  • For user integrity service, I worked on reporting information like Missing files, Unknown Files, Mismatched Files and Ok files. Further, I built a moderation queue system for user submitted files and also solidified the checks on user submitted data to allow submission of only valid data.
  • For the application, I added support for manually merging filesets, updating filesets within the application, improved search filtering and logging. Further, I added a configuration page for customising some user display settings and integrated Github OAuth with role-based access control (Admins, Moderators, and Read-only users).

Current State and What’s Left

The application is in a complete working state. All the workflows are functioning properly. The remaining step is to populate the database with all existing data so the integrity service can start operating officially.

Code that got merged

List of PRs that got merged – 

Server Side:

Github OAuth

Extending Web app features

User File Integrity Check, Web App updates and Project Restructuring

Scan Utility and Scanned fileset matching

Ruff formatter and linter

Macfiles support, Initial Seeding and matching with old game collections

Punycode

Readme Update

ScummVM:

Freeze issue for Integrity Dialog

 

Challenges and Learnings

The most challenging part was handling the variations across engines and game variants, and ensuring correctness in the filtering and matching process while populating the database. This often required manual validation of filesets. Working on this project taught me about the level of care needed to maintain the code and the importance of sharing the thoughts with the team. It was a highly rewarding experience working with ScummVM, and I am very grateful to my mentors Sev and Rvanlaar for their guidance and support throughout the project.

GSoC Final Work Product

Project Goals

The main goal of this project was to add text-to-speech, or TTS, to a variety of ScummVM engines. TTS enhances the accessibility of games supported by these engines and helps language learners. Furthermore, adding TTS to more engines standardizes the implementation of this feature, meaning the inclusion of TTS will be more consistent across engines. Adding TTS to an engine entails adding responsive voicing of text elements such as dialogue, menus, user input, objects, and credits, as well as adapting TTS to user actions and the functionalities of the games themselves.

What was Done

The original goal of the project was to add TTS to 12 engines, but I had enough time to add TTS to an additional 3 engines. Therefore, I added full TTS support to a total of 15 engines over the summer. In addition, I added TTS to 2 engines prior to the official start of GSoC, and I helped fix a few bugs for one engine.

Current State

All of my pull requests have been merged, meaning 17 engines now have full TTS implementations. Games that use these engines should have comprehensive and usable TTS.

What’s Left

All of my project’s goals, as well as a few stretch goals, have been completed. Nonetheless, some engines that support a wide variety of games, such as SCUMM, may need additional testing by end users. Any required changes found from this testing should only be tweaks to behavior: the core of the TTS implementations themselves should be complete. In addition, there are still a few engines left that need TTS support.

Code

Most PRs are for adding TTS to certain engines, but some are fixes for previously merged code. The following is a list of each PR I opened:

  1. TTS for Drascula: https://github.com/scummvm/scummvm/pull/6526
  2. TTS for TeenAgent: https://github.com/scummvm/scummvm/pull/6566
  3. TTS for WAGE: https://github.com/scummvm/scummvm/pull/6669
  4. Fix for Russian TTS for TeenAgent: https://github.com/scummvm/scummvm/pull/6722
  5. TTS for Cine: https://github.com/scummvm/scummvm/pull/6700
  6. TTS for CruisE: https://github.com/scummvm/scummvm/pull/6710
  7. TTS for Draci: https://github.com/scummvm/scummvm/pull/6742
  8. Fixes for TTS for CruisE: https://github.com/scummvm/scummvm/pull/6752
  9. TTS for MADE: https://github.com/scummvm/scummvm/pull/6779
  10. TTS for ADL: https://github.com/scummvm/scummvm/pull/6785
  11. TTS for Parallaction: https://github.com/scummvm/scummvm/pull/6795
  12. TTS for Prince: https://github.com/scummvm/scummvm/pull/6807
  13. TTS for EFH: https://github.com/scummvm/scummvm/pull/6820
  14. Bug fixes for EFH: https://github.com/scummvm/scummvm/pull/6821
  15. TTS for MM: https://github.com/scummvm/scummvm/pull/6835
  16. Czech and Polish TTS for TeenAgent: https://github.com/scummvm/scummvm/pull/6867
  17. TTS for SCUMM: https://github.com/scummvm/scummvm/pull/6856
  18. TTS for AGI: https://github.com/scummvm/scummvm/pull/6862
  19. TTS for Gob: https://github.com/scummvm/scummvm/pull/6880
  20. TTS for Got: https://github.com/scummvm/scummvm/pull/6888
  21. Fix for TTS for Got: https://github.com/scummvm/scummvm/pull/6900
  22. TTS for Hugo: https://github.com/scummvm/scummvm/pull/6897
Challenges and What was Learned

Ensuring TTS compatibility across numerous games, languages, and versions that a single engine may support was sometimes challenging to comprehensively address. Furthermore, some engines handle their text almost entirely with game scripts, which makes it more difficult to narrow down where text is being displayed and how to feed it to TTS. To address these problems, I had to test thoroughly, think about limitations and features that differ between games or platforms, and employ strategies such as recreating click boxes to properly voice text as the user interacts with the game. Thus, most challenges with adding TTS revolved around compatibility and logical voicing of text elements.

I learned a great amount this summer about working with a team, understanding and modifying code written by other developers, and writing code that fits into an existing codebase. I am now more comfortable with navigating and working on larger projects.

Conclusion

I enjoyed working on my Google Summer of Code project, and I found it to be a very entertaining and rewarding experience. I am happy that I was able to contribute something to ScummVM, and I hope that it will be helpful to users.

I would like to thank my mentor, criezy, for kindly guiding me throughout the summer, and sev, for guiding me as well. I would also like to thank all members of the ScummVM team that I interacted with for their patience and assistance, and the entire ScummVM team for their work on this application.

Expanding Director Engine compatibility in ScummVM

For the last 12 weeks I’ve been working on the Director Engine to increase support for it in ScummVM. Originally created by Macromedia, the Director Engine is under development for the last 9 years in ScummVM now. My goal was to inch ever closer to fully supporting games made using Director 4 and Director 5.


Goals for the Project:

I had outlined the following three major goals in my original proposal:
1. Completing support for all the workshop movies and implement all the stubbed functions.
2. Writing Director Files in ScummVM by implementing saveMovie lingo command.
3: Add support for titles SafeCracker and The Journeyman Project in the Director Engine.

Goal number 2 was the primary goal of the project, which I worked on first.

Goal number 3 was changed partially. Instead of working on the titles SafeCracker or Journeyman Project, I tried to work on Trektech.

Goal number 1 was changed. Instead of working on Stubbed functions and workshop movies, I worked on the ImGui visual debugger in the Director engine.

The goals for this project were regularly discussed with my mentor @sev.


What I did:

Before and during the initial few days of the coding period, I worked on the QTVR Xtra for the Director Engine. I implemented rendering in higher quality and warp (mode 0) for panoramas. I also implemented the swing transition while panning panoramas.

To add support for games like tkkg-1, I implemented the lingo command saveMovie which saves the current movie in its current state, effectively working as a save file.

I tried implementing support for movies as cast members which was an essential feature required for the title Trektech. However, I only went as far as loading them and processing lingo scripting for simple movies. I couldn’t get it to work for Trektech. Since, it proved too much for my level of experience, as per my mentor @sev’s advice, I left the work incomplete and pivoted to the next task.

I fixed the following bugs in Director.
1. Fix Duplication of cast members in case of multiple casts.
2. Avoid usage of  unreliable value LingoDec::Scripts::CastId.
3. Disabling event processing while b_alert is called.
4. Fix deprecation warnings in Director engine compilation.

I also made some upgrades to the ImGui visual debugger in the Director engine. Majorly including:
1. Rendering previews for some of the cast members.
2. Improving/refactoring the Script/Callstack window into the Execution Context window.
3. Improving the Score window to show continuation data.
4. Implement Loading/Saving ImGui state.
5. Reworking Functions window to use reliable references.
and a number of other small things.


The Current Status:

The saveMovie lingo command was successfully implemented. This was also tested and verified using the title tkkg-1.

Support for Trektech and movie cast members is incomplete. Simple test movies with basic lingo scripting work well. However, it is unreliable as seen by the crash in Trektech, as soon as it tries to load a movie cast member. I will continue working on this.

The ImGui debugger has seen a fair number of upgrades. However, it does need more work to be called complete. I still have a draft PR continuing the work.


Implemented code:

Here is a link to all the pull request that were merged during the period (18 in total).

Here is the link to the draft PR for ImGui improvements.


Challenges faced/Lessons Learned:

Director engine, as mentioned, is under development since the last 9 years. A lot of the development is already complete. Hence, it was difficult for me to grasp its large code base, given my limited experience with large projects. On top of that, My insistence on figuring out solutions independently proved harmful, sometimes resulting in slow progress.

The Director engine is a fun engine to work with. I learned a lot of concepts related to Software Development and Object Oriented Programming. I also learned how to use version control systems properly.  I also learned how to communicate programming ideas when there are multiple people working on the project.


I enjoyed working on ScummVM. So much so that I’ll continue contributing occasionally. I am thankful for the organizers of GSoC and my mentors @sev, @rvanlaar, @OMGPizzaGuy and @somaen, for guiding me through. I hope my contribution benefits developers as well as users of ScummVM.

GSoC Final Report

My project focused on extending ScummVM’s Keymapper system to a larger number of game engines. The Keymapper allows players to remap controls to their liking, but many engines in ScummVM still relied on fixed input handling. By integrating the Keymapper into more engines, the project set out to improve accessibility, provide a consistent user experience, and give players greater flexibility in how they play.


What I did:
I added Keymapper support to 24 engines, fixed a few bugs encountered during the implementations, and helped standardize keymapper action descriptions. This standardization reduces the number of unique strings in the codebase, easing the workload for translators.


The current state:
Keymapper support is now available in 24 additional engines, allowing players to remap controls in a wide range of games that previously relied on fixed input. Several of my pull requests have already been merged into the main ScummVM codebase, and the remaining ones are under review. Overall, the project goals have been successfully achieved, and the improvements are now part of ScummVM’s ongoing development.


What’s left to do:
All goals outlined in my proposal have been completed, I added Keymapper support to the 23(The first one was not part of proposal) engines I had committed to. Beyond the scope of the proposal, there are still around 40 engines in ScummVM without Keymapper support, which could be future work for anyone interested in continuing this effort.


List of PRs:

  1. Toltecs keymapper: Pull Request
  2. Sludge keymapper: Pull Request
  3. Supernova keymapper: Pull Request
  4. Voyeur keymapper: Pull Request
  5. Titanic keymapper: Pull Request
  6. Normalize keymapper action descriptions: Pull Request
  7. Sword25 keymapper: Pull Request
  8. TeenAgent keymapper: Pull Request
  9. NGI keymapper: Pull Request
  10. Buried keymapper: Pull Request
  11. Access keymapper: Pull Request
  12. EFH keymapper: Pull Request
  13. Sherlock keymapper: Pull Request
  14. Neverhood keymapper: Pull Request
  15. Prince keymapper: Pull Request
  16. Lab keymapper: Pull Request
  17. Petka keymapper: Pull Request
  18. Queen keymapper: Pull Request
  19. Fix capitalization in Queen keymapper action descriptions: Pull Request
  20. Pink keymapper: Pull Request
  21. Drascula keymapper: Pull Request
  22. Chamber keymapper: Pull Request
  23. Make EFH keymapper table use POD and avoid global constructors: Pull Request
  24. Hypno keymapper: Pull Request
  25. DM keymapper: Pull Request
  26. Private keymapper: Pull Request

Any challenges or important things you learned during the project:
Each engine in ScummVM handles input differently, so I had to study and adapt to new codebases before adding Keymapper support. In doing so, I often uncovered and fixed unrelated bugs. Working on a new engine every 3–4 days also greatly improved my ability to read, understand, and modify existing code, and gave me confidence in working with large, mature projects.


Conclusion:
This project successfully achieved its goals by bringing Keymapper support to 24 engines in ScummVM, making input more flexible and accessible for players. Along the way, I learned how to work effectively with large codebases and contribute to a mature open-source project. I’d like to thank my mentors and the ScummVM team for their guidance and support, and GSoC for giving me the opportunity to work on a project that will benefit both developers and players.

Prepare to Descend Deep Into the Mine to Uncover Its Dark Secrets

The ScummVM team is happy to announce full support for the first-person survival adventure Penumbra: Overture!

Step into the boots of Philip, who is drawn to Greenland in search of answers after receiving a letter from his long-lost father. Once there, you find yourself trapped inside an abandoned mine… with no way out but deeper in.

The game is fully 3D and presented in a first-person perspective, featuring elements of stealth and physics-based puzzle-solving.

If you own a copy of the game and want to help test this release, download a daily build and be sure to read our testing guidelines.

Don’t forget your torch. You’re going to need it.

Another upgrade to the ImGui Debugger

For the last week of GSoC, I was working on some more improvements to the ImGui Debugger in the Director engine. Making the ImGui debugger as close to the original Director engine as possible will be very helpful in adding support for games in the future.

The first thing to do was to revamp the Functions window. It used to show all the handlers from all the scripts in the window in a single table. Since, that was not only messy and not properly navigable, @sev asked me to revamp it so that there are two views:

 

 

 

 

 

One: that shows all the handlers just like how it was shown previously and two: one that shows each script, and each script (‘Lscr’ context) and under each script we have all the handlers in that script. This allows us to navigate between scripts very easily. This also means, in the second view, the filtering works better, i.e. we can filter out all the handlers with a certain name (e.g. mouseUp) or those associated with a particular cast member (say no. 123) easily.

After that, we noticed that some of the scripts didn’t show the cast member number in the Execution Context window properly (e.g. -1 for the topicmaker:mnew in the screenshot):

Now, the cast id (even though present in the ‘Lscr’ data stream, is not reliable) is fetched from the associated cast member. Since cast IDs and script IDs are linked together, we can map the script ID to its corresponding cast ID. But, it was possible that some of the cast members are not loaded, because of lack of support or some error (e.g. Picture cast member). Hence, at first I thought, forcing the loading of their cast member info might solve this problem. However, I was wrong. But I thought it might still be a good and harmless addition, hence I made a PR.

It turns out that some of the ‘Lscr’ contexts are factory scripts, i.e. they have a parent script (which is associated with a cast member) and the handlers in the current script context are called in reference to the parent’s cast member. As you can see from the following screenshot of LCARS___.dir loaded into the origin Director engine, the handler `topicmaker:mnew` is part of a movie script (cast ID: 1285):

Even while dumping the scripts, ProjectorRays/ScummVM dumps the handlers in the current script as part of the parent script and completely ignores the current script (the one without a cast member associated):

This is the list of all the parent scripts and their child script:

“`
Who is: 236, whose parent: 89
Who is: 239, whose parent: 93
Who is: 232, whose parent: 234
Who is: 188, whose parent: 599
Who is: 597, whose parent: 623
Who is: 216, whose parent: 624
Who is: 21, whose parent: 646
Who is: 230, whose parent: 657
Who is: 26, whose parent: 721
Who is: 131, whose parent: 722
Who is: 24, whose parent: 723
Who is: 179, whose parent: 725
Who is: 131, whose parent: 727
Who is: 163, whose parent: 728
Who is: 199, whose parent: 729
Who is: 131, whose parent: 730
“`
Hence, the solution was to not show the associated castID but rather the script ID, which is unique to each script. Hence, it required storing the parent number and the script number in the ScriptContext class, and show that in the Execution Context window. This solved the problem. @sev then asked me to change all the references to a handler in a similar way, including the way we name the dumped scripts. This honestly took way too much time to figure out.

Also, the scripts are now shown in a separate window when we click on a handler in the Functions window rather than showing them in the Execution Context window. Hence, we can see as many scripts as we want at the same time.

Also, the handlers in the call stack are now selectable. You can click on them to jump to the exact byte code in the script shown below in the Execution Context window. To make the scrolling work, I had to include a separate boolean in the ImGuiState struct.

After that, there were a bunch of minor issues, like the scrolling in the Execution Context window when we jump to the definition, sanity checks for fetching `ScriptContext` through the handler Director::DT::getScriptContext, marking the script dirty when a button in the control panel is placed, and some other stuff too minor to notice here.

Also, in the Score, the original director shows whether or not a sprite changes in subsequent frames. Like follows:

I was working on adding a similar functionality in the Score window, but I’m only halfway there.

I’ll be adding the rest of the functionality in the next two days.

Hence, overall a slightly less than average week. I was busy over the weekend for the academic project for final year (my faculty advisor is not happy with our progress). Initially I planned on making this post my final submission, but later decided against it. I’ll be making a separate post underlining all the progress that I made over the last  12 weeks as my final submission.

Week 12

 

Last week was mainly spent by fixing left-over bugs from previously worked engines: WAGE, MacVenture and SLUDGE.

At the beginning of the week, me and Sev finished work on redumping and preparing ultimate archive of WAGE-based games. Finally, after multiple checks the we were able to prepare the collection and release it on the site, together with the engine announcement. However, a couple of issues was reported by the devs, so I returned back to the engine to fix them. In particular, I had to fix issues with closing the game, where confirmations pop-ups were not really working, i.e. the games were not closing. Also, for some games, closing them in midst of playing sounds resulted in crash, because the thread for audio was referencing the deleted engine object. Lastly, there were crashes due to null pointer accesses in scripts, which are could be either due to buggy scripts or due to engine issues. There is a possibility for the last one, since the game that was crashing (Mormonoids from the Deep) also throws exception in the Java codebase, which was ported to ScummVM.

Another engine to which I returned was SLUDGE. There was a PR by ccawley2011 to add the game (demo) called Otto Experiment. However, the problem was that it was crashing at the startup. The problem as it turned out was that the code was not looking for the file inside the game directory, only in the save game dir. Also, in general, the support for reading .ini files was missing. This was mainly used for language setting, some graphical preferences and so on. This feature appeared to be rare in general, however it was used in Otto Experiment and Cubert Badbone, so it must have been dealt with.

Last but not least, I did some work on on MacVenture. There was a few a differences with the Mac versions that needed be done: main game window names (which were not upper-cased) and console window.

Week 12: Keymapper Support for Hypno and Dungeon Master

This week I worked on the Hypno and Dungeon Master engines. I also got my Chamber keymapper PR merged 🎉.


Hypno Engine

Working on the Hypno engine felt a bit nostalgic—it was actually the first engine I touched in ScummVM when I fixed a small bug as an intake task for GSoC.

The engine supports three different games, each with its own input handling. Because of this, I had to create separate keymaps for each game, rather than a single shared one.

Apart from that, the implementation was fairly straightforward. The main tasks were:

  • Disabling the keymapper in certain sections where the game uses full keyboard input

  • Enabling/disabling keymaps for some of the menus

Nothing particularly tricky, but it was nice to revisit the engine where my GSoC journey began.


Dungeon Master Engine

Dungeon Master was another unannounced engine that I added keymapper support to. Fortunately, it didn’t have any blocking bugs or missing features, so I was able to test it thoroughly without issues.

The engine came with a decent number of keys to map, but overall the process was smooth and didn’t pose any significant difficulties.


Wrap-Up

This week, I:

  • Added keymapper support for Hypno and Dungeon Master

  • Got my Chamber PR merged 🎉

Week 12

Welcome to this week’s blog. This week, I added features related to updating metadata as well as file data directly from the application UI, along with some smaller fixes and improvements.

For any fileset, you can now update metadata fields directly from the UI. For user filesets in particular, there is an additional step of adding metadata first particularly gameid and engineid as they require creating entries in separate tables. To make filling metadata easier, I also added a dropdown feature that displays all existing values for a field from the database. This way, moderators can either type in a new value or directly choose an existing one. In addition to metadata, I added functionality to update individual files as well. This can be useful for tasks such as manually marking a file as detection file or updating other fields.

For better reliability, confirmation dialogs have been added for most buttons, such as deleting/updating files and adding/updating metadata. Further a separate button has been added for deleting the entire fileset. Another improvement is the ability to delete all filesets in bulk that appear in a filtered search result in the fileset search page.

To enhance logging for scanned files, a new field called data_path has been introduced. This field stores the relative path of the game directory, which is particularly useful when multiple files are scanned at once. This information can later be included in scan.dat related logs.

Lastly, I added an endpoint for sending a fileset ID as a mail notification. This is suppose to be triggered from the mail server whenever a user submits any fileset-related information, using a predefined mail structure in the ScummVM application. (This feature has not yet been integrated with the mail server.)

Week 12: Got and Hugo

Introduction

This week, I opened PRs for adding text-to-speech to Got and Hugo. They were relatively simple engines, and neither had any major challenges.


Got

I started this week by finishing TTS for Got. As previously mentioned, Got was quite simple for TTS: most of its text was easy to locate in the code, and text was rarely primarily handled by the game scripts. Thus, most of the game’s text could be voiced rather easily. For cleaner voicing, I included checks for when the score, jewels, or keys change, allowing their values to only be voiced when they change; delays as the credits are voiced to prevent them from moving too quickly for TTS to keep up; and voicing of dialogue as soon as it is started, so that it syncs well with the text while it appears one character at a time.

Nevertheless, one consideration for Got was the best means of cleaning text. In most cases, newlines break up sentences in dialogue, which results in choppy voicing if they aren’t replaced. However, some dialogue, such as signs, use newlines instead of punctuation to break up distinct sentences. If these newlines are replaced, TTS awkwardly pronounces everything as one quick sentence. My solution to this issue was to keep the newlines only if there are two or more in a row, as this is usually the case for sentences separated exclusively by newlines. Singular newlines tend to break up whole sentences, and thus should be replaced.

Ultimately, Got was one of the simpler engines that I’ve worked on. It required some care for properly cleaning up text and guarding against awkward voicing, but it otherwise offered few unique challenges.


Hugo

After Got, I worked on adding TTS to Hugo. Like Got, Hugo was a fairly simple engine for TTS. Its games are straightforward and similar to each other, which made it easier to implement functional TTS for all scenarios. Furthermore, it has few unique procedures of displaying text, so voicing most or all of its text only required adding TTS calls to a few methods. Nevertheless, Hugo required some consideration for its dialog boxes. Unlike most other engines that I’ve worked with, Hugo displays a considerable amount of its text in ScummVM dialog boxes, which have their own TTS. This means that opening or working with some dialog boxes, like the top menu, stops all TTS. Stopping TTS in this manner, however, can interrupt voicing of the sound setting, which is shown in Hugo’s score line. Voicing it as soon as it changes doesn’t work properly, as in many cases, the top menu is immediately opened again, thus interrupting the voicing. Therefore, my solution was to keep trying to voice the new sound setting for as long as the cursor is in a position to open the top menu. In this way, once the top menu finally fully closes and doesn’t open again, the sound setting will be voiced.

Other aspects of Hugo were rather simple. It mostly entailed implementing more TTS for the aforementioned dialog boxes, as their built-in TTS only voices text as it’s hovered over and only one line at a time, and it seemed to me that these boxes needed to be voiced as one clean paragraph or sentence and as soon as they appear; voicing scoring changes; and correctly queuing voicing when dialog boxes, user input, and scores are voiced, to prevent them from interrupting each other as dialog boxes appear.

In conclusion, Hugo was fairly simple. Because its games involved few different means of displaying text and simple controls, it didn’t offer that many unique challenges.


Conclusion

This week, I finished adding TTS to Got and Hugo. Both of these engines were simple to work with, and they didn’t have any major caveats or challenges.

Announcing support for World Builder-based games

After many years of development, games made with World Builder are ready for testing. The World Builder creation system was released for the original Macintosh and was extremely popular among developers. As such, we're announcing that over 160 games built on the engine are ready for public testing in ScummVM. Notable games made with World Builder include:

  • Ray's Maze. The game follows Frank Farley, a part-time adventurer, who finds himself in a Maze full of dangerous monsters and deadly traps. The objective of the game is to solve puzzles and escape the maze.
  • Radical Castle. You are given the role of a squire, who must bring back the stolen "Oracle" to the King to escape a fatal punishment.
  • Enchanced Scepters. The first game created using World Builder, and one of the few commercial games made with it. The player must find fire, earth, air, and water scepters and bring them back to the castle.

Most games made with WAGE are either freeware or shareware, and for your convenience we've collected all titles with these types into one big downloadable archive. So grab it from our game downloads page, get yourself a daily development build, and start your journey. As always, if you happen to have any issues, please submit the bug reports to our issue tracker. Lastly, contact us if you have some other unrecognised games or a new demo.

ImGui: Refine the debugger to a usable state

This week again, I continued working on the ImGui visual debugger in Director, mostly working on small bugs and broken features caused by the work in the previous weeks.

The Execution Context window shows the lingo scripts being executed. To make it show multiple handlers from the same script at once, I had made changes that broke the navigation. Stepping in, stepping over and stepping out in the control panel didn’t work properly, jumping multiple instructions at once. The problem was that startOffsets of the script weren’t getting stored, since I needed to render multiple handlers, each with a separate ImGuiScript object. These startOffsets store the offsets of each line of script. While stepping in/over/out, the lingo program counter is compared with these to find out which line is getting executed at the moment.  I had to make sure that the ImGuiScript object associated with handler currently being executed persisted and was passed by reference to the renderScript() function so that it will store the startOffsets properly. Also I had to make sure that the _script->_dbg._isScriptDirty flag is set after all the scripts are rendered. Previously it was set to false after rendering the first script.

In the lingo scripts in the Execution Context window, if there is a call to a function, you can press the function to go to its definition. However, the search for the handler was flawed. The value we were passing to the function that fetches the ImGuiScript as the castId of target script, was wrong. It took me some time (and some messing around with ProjectorRays) to figure out that this is the Id (or index) of the script (in cast of a localcall, this is the index of the script in the script context (consisting of scripts in the same file/’Lscr’ resource), whereas in an extcall it was the index of the script in the global context (consisting of all scripts)).

This is obviously wrong, hence I had to find out the actual castId of the script which contains the handler, since castId and scriptId are coupled, I can find the castId using the scriptId and pass that, which worked as expected.

During this, I also realized that for some reason, some of the scripts weren’t showing up in the debugger at all, apparently for no reason at all. Upon some investigation, I found out that the way the scripts were fetched was, that the LingoDec decoder reads these scripts and the corresponding data. One of which was the castId of the script, which it turns out isn’t reliable. It may be wrong, it may have duplicates, can’t be trusted. Hence, instead, from the HashMap that maps the castID of a cast member to its script id, I fetch the castID and use that to fetch the script, which worked like a charm. This PR should explain the issue in detail. This also solved an issue where, when asked to dump the scripts, the names of the files dumped and the scripts didn’t match at all.

I had to also solve scrolling issue in the Scripts window. After jumping to a handler, if the script contained only one handler, the scrolling worked fine, but in case of multiple handlers, it used to jump to the last handler. Had to introduce a _scrollTo flag which was set only when rendering the current script.

I also got rendering of text and shape previews this week. In order to render them, I was at first checking which channel had the text/shape to be rendered, and pass that channel and a ManagedSurface to Window::inkBlitFrom(), and showing the surface in the preview. However, obviously, this meant that if a shape/text is not on the stage at the moment, it won’t show a preview. Hence, I had to prepare a dummy channel with the correct sprite and relevant properties (e.g. thickness, foreground color, background color, pattern, etc.) and then blit it to a temporary surface for preview. This honestly took some time to figure out.

Other than this, there were some minuscule things, too unnecessary to mention here.

Hence, overall a pretty normal week again. Next week is the final week for coding after which there is the final submission. I hope to have done enough to count the project as a success.

This week also brought good news in the form of a job offer. In most engineering colleges in India, recruiters visit the college to hire final year students as graduate trainees. I was lucky enough to be selected at one such offer. Now that I have this security, I can continue to contribute to ScummVM even after GSoC. Not as regularly but over weekends and holidays. Working on ImGui has been fun but I wanted to directly work on making a game work in ScummVM’s Director, similar to how @rvanlaar was working in SafeCracker. Couldn’t unfortunately succeed at that during GSoC but I’m planning on doing so afterwards. Looking forward to that!

Week 11: Keymapper Support for Drascula and Chamber

This week I worked on two more engines: Drascula and Chamber. I also got my PRs for the Pink, EFH, Drascula, and Lab engines merged 🎉.


Drascula Engine

The Drascula engine wasn’t particularly difficult, but it came with a decent number of keys and keymaps. The process was straightforward overall, though it was somewhat time-consuming due to the sheer amount of keys that needed replacing.

One interesting aspect of this engine was that I came across my first in-game easter egg while testing the key actions—definitely a fun surprise during the work.

I also had to handle enabling and disabling keymaps in a few spots. Nothing too complicated, but still took time.


Chamber Engine

Chamber became my second unannounced engine (after Sludge engine) where I added keymapper support. Normally, I’ve been focusing only on announced and tested engines, to avoid running into unrelated bugs that might interfere with the keymapper work.

In this case, I only realized the engine was unannounced after I had already started working on it. Since I didn’t encounter any gameplay-breaking issues, I decided to go ahead and finish the keymapper implementation.

The work itself was on the simpler side. Chamber only had a handful of keys, and just a single keymap that needed to be toggled on and off. Figuring this out was quick and straightforward.


Wrap-Up

This week, I:

  • Added keymapper support for Drascula and Chamber

  • Got my Pink, EFH, Drascula, and Lab PRs merged 🎉

Week 11

In the previous I continued to work printing the task. I’ve added the initial options to printing such as layout (portrait, landscape), margins as well as the selecting the printer itself. In the process of adding these, I’ve customed myself a bit to Win32 printing API, since this is the only backend with which I was testing the actual printout.

First of all, I continued the work from the last week by introducing PrintingDialog, which will be opened when printout happens. To it, I’ve added layout and printer selection. In Win32 Print Spooler API, printer list is a string array, so for now, in the PrintingManager class, this virtual method is also Common::StringArray. Implement it was quite easy, since the documentation is there and not much code was needed. By adding printer selection, users can select the real physical printer or virtual one to get PDF-output. Since I have the actual printer, I started testing the code and see what was the output:

Tiny ScummVM logo printed as a test
CLUT8 test remained from the original PR

As you can see, while the logo and were printed, they were too small and not centered. This made me to spend some time actually looking how different platforms handle image printing. After comparing printer dialogs in different browsers, operating systems, I concluded I definitely needed to add scaling (or, rather, fitting to paper) and margins. To not waste more paper, I’ve been testing with PDF output since then, and was able to get the printing centered and fit to paper.

After that I started to think about preview image functionality, which is common these days in printer dialogs. Luckily, there is already an ImageAlbumDialog present, which had more enhanced image output as well as image preview. That meant I only needed to migrate all dialog code there. I’ve managed to make printing work when the right command is send, however, implementing GUI nice looking correctly (so that both preview appears on the left and printer settings on the right) appeared to be a little harder, and is not yet finished. This week I plan to fix this, and as was commented and suggested earlier start adding printing support to actual engines and see if the current API functionality is enough or needs to be adapted. Before that I plan to quickly fix a few things (mostly visual differences) in MacVenture engine, so that it looks and plays like in the original Macintosh.

 

Week 11

Welcome to this week’s blog. This week, I worked on testing the workflow for scan data as well as the user file integrity service.

For the scan data, we tested with the WAGE game archives, which provided a good opportunity to test both the scan utility and the scan matching for the Mac files. Some fixes were indeed needed for the matching process. Initially, I was using both size (data fork size) and size-rd (resource fork’s data section size) simultaneously while filtering filesets. However, this was incorrect, since detection filesets only contain one of these at a time. Additionally, I fixed how matched entries were being processed. Previously, entries matched with detection were placed for manual merge to add specific files while avoiding unnecessary ones like license or readme files from commercial games. However, it made more sense to merge them automatically and later remove such files if necessary—especially since, for the archives like WAGE, the issue of extra files from commercial games would not occur.

I also carried out testing for the user integrity service, focusing on different response cases:

  1. All files are okay when a full fileset matches.

  2. Extra files are present.

  3. Some files are missing.

Another missing piece was reporting files due to checksum mismatches, which previously was being classified under extra files. This is now fixed. I also reviewed the manual merge process for user filesets. Unlike set filesets, the source fileset (user fileset here) should not be deleted after a manual merge, since it could be a possible new variant which would need additional metadata information. To support this, I implemented a feature to update fileset metadata—though it still requires some refinement. An additional thing that I need to add is to create an endpoint in the web server that can be triggered by the mail server. This endpoint will provide the mail information, particularly the user fileset ID, for which the user has provided some additional information via the pre-drafted email that is promted when user uses the ‘check integrity’ feature in the ScummVM application.

A few other fixes this week included:

  • Deleting multiple files from a fileset through dashboard: Previously, the query was being generated incorrectly. Instead of ‘DELETE FROM file WHERE id IN (‘1’, ‘2’, ‘3’)’ it was generating ‘DELETE FROM file WHERE id IN (‘1, 2, 3′)’ which, of course, did not work. This issue is now fixed.

  • Search filter issue: A bug occurred when a single quote (‘) was used as a value in search filters, breaking the query due to missing escaping for the quote. This has also been fixed.

Week 11: Gob

Introduction

This week, I opened a PR for adding text-to-speech to Gob, my first stretch goal. It was an engine that posed a few more challenges than usual, but that was entertaining to work on. I also started early work on adding TTS to Got as my next stretch goal.


Gob

Gob was a rather interesting engine for adding TTS to, primarily because of how it handles text and buttons. Unlike many of the engines that I’ve worked on, hotspots and text are inherently separated in Gob. This meant that there was no easy way to retrieve the text of a button or menu as the user hovers over it, which makes it more difficult to voice. Furthermore, without knowing which text is part of a clickable hotspot and which text is not, text that shouldn’t be voiced the instant it appears will be voiced. My solution to this issue was to maintain an array, _hotspotText, which holds printed text and their positions. Then, as hotspots are added, their collision boxes are checked against those of the text array. If they intersect, the hotspot text’s collision rect is expanded to that of the hotspot. Through this method, hotspot text can be voiced as the user hovers over it, while most other non-hotspot text is voiced by a separate method to make sure that all text on screen is voiced. Nonetheless, refining this strategy took some time, as I encountered issues with properly removing elements from _hotspotText when text is removed from the screen, which I resolved by deleting unassigned hotspot text in certain methods and removing pieces of assigned hotspot text when their corresponding hotspots are removed; the cursor being instantly placed over a hotspot in some cases, interrupting the speaking of non-hotspot text, which was resolved by queuing hotspot text when a non-hotspot piece of text is voiced; and having to move hotspot text in o1_copySprite, as the text itself is sometimes moved there, and not moving the hotspot text with it results in a disjointed collision.

Another problem with Gob was timing of dialogue. From what I could tell, there are no unique indicators for when dialogue starts, progresses, or ends in Gob, which causes issues during dialogue interactions, as they may move too fast and interrupt voicing. In addition, dialogue appears to be displayed as TOT text, but so are object names, which means that TOT text can’t be set to always interrupt or always queue without causing awkward voicing. My solution was to only queue text if the user isn’t hovering over a hotspot, as in most cases, this means that it’s text that should be queued. After resolving this issue, most of Gob’s other problems – including needing to improve voicing of Ween’s notepad, which awkwardly tries to voice one character or section at a time as the user types, by only voicing it when it first opens – were rather straightforward.

Ultimately, Gob was an interesting engine because of how it handles hotspots and dialogue. It required different solutions from previous engines, and I’m quite happy with the result, though there may be more problems to resolve in the future.


Got

After Gob, I started work on adding TTS to Got. So far, Got seems very simple for TTS. Most timing and menus do not seem to be handled by game scripts, which makes it easier to locate where to voice text and to implement clean voicing. At the moment, nothing difficult has emerged, but this may change as I add more TTS to the engine.


Conclusion

This week, I added TTS to Gob, and started work on adding TTS to Got. Gob had several considerable intricacies, while Got appears to be rather simple so far. Next week, I’ll be continuing work on Got, and perhaps starting work on adding TTS to another engine if time permits. However, my semester starts next week, which will limit the time I have to work on my project.