Introduction
Another week of GSoC has passed, and I’m fairly satisfied with my progress. This week, I mostly focused on adding TTS to CruisE, and I’ve opened a PR for it. However, I also spent some time working on Draci, and on updating older PRs.
CruisE
I began this week with adding TTS to CruisE. Fortunately, CruisE wasn’t too difficult to work with, as it has very few cases of text in the form of an image. In addition, most of Cruise for a Corpse’s text is displayed from renderText
, which made it much easier to identify where text is displayed in the code. The difficulty with Cruise for a Corpse, however, came from making it user-friendly. For example, text can’t simply be voiced from renderText
, as there are cases when the text appears on screen a significant amount of time after renderText
is called, or cases where the text isn’t visible, such as when the user tries to open the inventory in the copy protection screen. In a similar manner, text can’t be voiced from createMenu
, because there are times when it shouldn’t be voiced (mainly when the inventory is empty). It also can’t be voiced from createTextObject
, which handles much of the game’s text, because freezeCell
is sometimes called on objects created with this method, which means that the text appears on screen later. Voicing text for CruisE, therefore, required addressing these exceptions accordingly, such as by storing the text from createTextObject
and voicing it when the cell is unfrozen; queuing the text of the first menu item hovered over after a menu is opened instead of interrupting the current speech, so the title of the menu is always voiced; and checking for button input in Op_GetMouseButton
to stop TTS when skipping through dialog or a cutscene. I believe that these changes make the TTS for CruisE more responsive and more accurate to the gameplay.
Ultimately, actually finding where text was displayed in CruisE wasn’t that difficult. The more time-consuming part was finding and accounting for the many exceptions, skips, and places in the code that freeze, show, or hide text, in order to create a user-friendly experience. It was entertaining to look through the code and ponder the best implementation, as its code was more spread out than that of Cine or WAGE.
Miscellaneous
After CruisE, I worked on various components related to my project. For one, I revisited my WAGE PR, which required a fair number of changes, including resolving some difficulties across games that I missed (in some cases, different WAGE games handle the same circumstances surprisingly differently, such as Eidisi only calling renderSubmenu
when hovering over a new item, while Ray’s Maze and Another Fine Mess call it every frame, requiring a check for the last submenu item that was hovered over in these games). I also worked on fixing TTS for TeenAgent’s Russian translation, which uses a custom encoding that has to be replicated for proper voicing – fortunately, it seemed that this encoding followed a simple pattern of adding a number to the original character to obtain a Cyrillic character in UTF-8, though since I don’t speak Russian, I’m uncertain if this works in all cases.
Beyond that, I started work on TTS for Draci. So far, Draci seems even simpler than CruisE, with fewer exceptions and oddities. Good progress has been made on Draci, but there is always a chance that something unexpected will emerge.
Conclusion
CruisE was a somewhat more complex engine to add TTS to than WAGE or Cine, and it was entertaining to hunt down its different exceptions and learn how it handles its inputs and menus. A PR has been opened for it, and while I imagine that there’ll be more work for it in the future, the hardest part for it is done. Next week, I’ll be continuing work on Draci, and I look forward to completing TTS support for it.