Tuesday, June 21, 2011

Let there be sound

The TsAGE engine for Ringworld now has sound playing! I'd be hard to pressed to express just how happy I was when I ran ScummVM and finally had correct sound playing back. I was like, Oh My God! it's finally working. After all the time spent re-implementing all the sound code from the original, and then spending nearly as much time slowly tracing through the execution of the original versus ScummVM to try and figuring out the cause of differences, it was a relief to finally have it working.

As such, the Ringworld game is that much closer to being complete. There are still a few areas left to look into, and polish up, such as:
* Sound fading isn't yet working correctly
* I need to hook the sound manager into the savegame format, and ensure playing sounds are persisted
* There are certain suspect areas in the sound manager's main _sfRethinkVoiceTypes method to review; at least one variable is being assigned to at one point and not currently being used, so I need to double check if that's really the case.
* The sound manager could use an overall clean-up.

It won't be too much longer until it's ready for public testing. Soon Larry Niven fans will be able to explore the Ringworld, and search for a way to defeat the bloodthirsty Kzins.

So what's coming next? Well, I've promised myself some time to work on Rex Nebular again, which I've somewhat neglected in my zest to have Ringworld completed. Strangerke is also enthusiastic about working on the other games that used the TsAGE engine, so I'll probably be spending some time on the game Blue Ice to determine what changes have been made to the engine, and provide a basis for being able to re-implement the game scene logic similar to what was done for Ringworld. Finally, I may offer to help out somewhat on the other games the team has received original source for. Gotta keep busy after all. :)

Monday, June 13, 2011

TsAGE sound support progressing

Work on the TsAGE sound has been progressing. I had originally hoped that the raw format used by the game would be a standard Adlib raw format that I could feed into one of the existing Adlib Sound FX classes. I tried to pass the data to the player class in the Cruise engine, which I had previously worked on, but unfortunately, whilst it didn't crash, it didn't play anything. And I'm not familiar enough with sound formats to have been able to diagnose why.

As such, I've spent some time powering through implementing all the relevant sound code directly from the demo executable. With the symbols identified, I at least had a heads up for the original engine names for a lot of the methods. Plus, we were able to garner some additional information from a demo version of the game Protostar. Whilst it's not an adventure game, the sound code has a lot in common with Ringworld; and not only did it have method names, it also had a lot of field information for the classes and structures. As with the Ringworld demo, it didn't have it for all the classes, but I was at least able to name fields in the sound classes and the sound manager.

From this basis I've now implemented what I think are all the relevant methods of the demo for both the Adlib sound driver and the sound manager classes - I'm currently using the OPL functionality with OPLWriteReg in place of direct port access. The resulting code I've completed doesn't actually play anything back yet, though. Making a log of the underlying writes to the Adlib port versus my ScummVM code, the results are different, so there's obviously some incorrectly implemented code.

My current major suspect is a method called _sfRethinkVoiceTypes - it's a enormously big method with over 500 lines, responsible for updating the voice channels based on queued sounds. It's one big mess, with a large pre-processing, post-processing, and main processing areas. I'll have to slowly trace through the execution both in ScummVM and the demo in the DOSBox Debugger to identify the problem. Hopefully once I've identified the differences, I'll finally hear some sound output.

Fingers crossed. :)

Sunday, April 24, 2011

Most wonderful Ringworld demo

Hopefully everyone had a happy Easter weekend; or for those of other religions, were able to enjoy a long weekend wherever you are. :)

It's been a little over a week since the TsAGE engine hit the trunk, and a big thanks go out to everyone who's helped out with commits - fixing compilation problems, and cleaning up the code. Special thanks again go to Strangerke, who has been busy working his way through the Ringworld game to fix bugs and make the game completable. I too have spent most of my time fixing some of the outstanding bugs, as well as newly identified bugs in the core engine.

On another topic, we've had a stroke of exceptional luck. I had been starting to get bogged down in all the various classes related to sound handling, and I wasn't looking forward to trying to figure out what it all did. But then Strangerke discovered that one of the two available Ringworld demos actually had embedded symbol information for most of the variables and methods of the demo!

Since the full game engine isn't anticipated to be much different from that used in the demo, it likewise means we've suddenly got a huge jump forward in understanding the remaining sound-related parts of the engine. Fuzzie was able to extract the information into a text file listing, and I wrote a quick and dirty script in IDA's IDC language to load the symbol information into a new IDB file for the demo executable.

This isn't quite as good as getting the full original source for the game, but it's still a major find. The biggest limitation of the symbol information is that such symbol tables don't include information for fields within structures. So, for example, the 'ASound' class has 282h bytes of information, but the instance of the class only has the symbol for the first byte, not all of the bytes. Therefore, I'll still need to spend a reasonable amount of time figuring out the contents of the various methods. But at least with the method names known, I can more easily figure out what each method actually does.

In the space of under two days, I've already implemented support for the two Ringworld demos. Luckily, the demos use a single script sequence rather than direct code, which made it very easy to add support for. All that still needs to be implemented for the demo are a few custom dialogs, and ensuring none of the full game functionality, like Saving and Restoring, is enabled for it.

Implementing support for the demo also identified a key difference between the two versions of the demo - the second demo was similar to the CD version, in that they changed the format of how the data for priority regions and walkable areas was stored. Having a disassembly of the demo with symbols made it easier to identify the relevant areas of code, and figure out the differences.

In addition to polishing up support for the demo, I'll likely making a branch to work on the sound classes separately. We currently have some hard-coded logic in the existing engine to properly signal actions that any played sound has immediately ended, so I don't want to interface with that whilst working on a proper implementation of the sound system.

So things are definitely rapidly moving forward. :)

Wednesday, April 13, 2011

TsAGE has now hit the trunk

Hi all,

I'd been meaning to write a new blog post for a while, but progress was progressing so quickly, that I never quite got around to it. Now, though, work has progressed far enough that the tSage engine has now been merged into trunk. Huzzah! :)

Many thanks go to Strangerke, who joined me in implementing all the various game scenes of the Ringworld game. Together, we've implemented all the game logic.

The following is the state of the game:
* All the game scenes for the floppy version of the game are implemented, although some still need some bug-fixing, so the game isn't completable.
* Sound isn't supported yet, and still needs to be reverse engineered in the original game.

So we have the following goals for the near future:
* We'll be working on fixing the remaining scene bugs, and ensuring the game runs smoothly from start to finish.
* Implementing the sound code.
* I also want to implement support for the original game's cheating/debug functionality.
* Add support for the CD version of the game, which has some minor differences.
* And add support for the demo version, if possible.

All in all, it's a celebration for another engine being added to the ScummVM universe. :)

Sunday, December 19, 2010

tSage engine proceeding quickly

Hi all,

I've really been making some great strides forward with my implementation of the tSage engine. I offer the two screenshots below. One is from the first game scene when run in DOSBox, the other under ScummVM:







Hard to tell them apart, isn't it? :). The one on the left is from DOSBox, and the one on the right is ScummVM. All the initial hotspots in the first game room are now set up, are being drawn on the screen, and have correct look descriptions. The only exception is a minor graphic glitch with the doorway - the current drawing code doesn't yet support clipping objects based on priority calculations, so the top of the doorway isn't correctly clipped off.

One of the next major steps from here is to delve further into the movement classes and code. Whilst the player is now drawn on-screen, I don't yet have any code responsible for moving the player, such as when you manually walk somewhere, or when the computer moves the player to a set location, such as when you use the door beam.

From what little I've looked into the movement code so far, the game maintains a set of classes responsible for moving objects within the scene. For the player specifically, there's a lot of code that seems to make use of special 'walk regions', which indicate where on the screen the user can walk. The movement code is tied into this, and uses them to determine both where the player can move to, and for pathfinding to move the player to the given destination.

Given the pace I've been having recently in other areas of the engine, I don't anticipate that it will take too long. Hopefully, soon I'll be able to move the player about on the screen. Then I can start delving into implementing all the logic involved in the first cut-scene, where the Kzin comes to the door and speaks with the player. It's so much more fun working on an engine when you can almost day-by-day make visible progress in it's implementation.

PS: I've been making such rapid progress with tSage, I've been somewhat neglecting work on the MADS engine. I hope any fans of Rex Nebular will be patient with me.. I will get back to work on it eventually. :)

Sunday, November 21, 2010

Update on the game engines

Hi all,

It's been a while since my last blog posting, so I figure it was time to wax poetic on what I'm currently up to.

I've spent some considerable time working on the Broken Sword 2.5 engine with Sev. As has happened previously, what I originally intended as something else to work on alongside Rex Nebular, quickly overshadowed it, and I ended up spending most of my recent holiday just working on it. It's now available in the public SVN, and is running fairly well, so I'm going to leave any remaining work to any other interested parties, and have returned to work on my other engines.

-----

Rex Nebular is coming along nicely. As I've mentioned in the past, I've been creating a custom script engine, based on the Tinsel script interpreter, to handle interpretation of game scripts. I've then created a custom script program that iterates over specified functions in the Rex Nebular disassembly, and converts them to a script text file. I then have a simple script compiler I've developed that compiles the scripts, and creates a new 'mads.dat' file.

As of right now, I've only converted the scripts associated with the first game room. The scripts associated with scene entry and 'scene tick/step' are working properly, so Rex is now waking up and standing entirely based on script execution, rather than the hard coded behaviour I previously had. I consider this a big step, since it validates the entire process of converting original executable instructions to script code, and final execution works properly.

The next step is to implement some remaining missing pieces of the action dispatch code so that Rex can actually do actions, rather than just walking about. Right now, I'm aiming for right-click Look actions to work properly. Then it should only be minor further changes to have other actions work as well. Soon Rex will be able to do all the various things in the first room. And I'm looking forward to the day when Rex will finally be able to take his first steps into a bigger world and finally leave the cockpit.. :)

----

Another game engine I'm currently working on is the tSage engine, which is used by the Ringworld game. Previously, the fact that it was so Object Oriented annoyed me, because it made it harder to understand the game flow since some classes, such as the event manager, had four descendant classes, making it difficult to understand what each class in the hierarchy did. Now, though, I'm actually starting to see some benefit from it.

The classes related to handling the game state are very clean. For example, there is a generic 'Scene' class, from which each game scene dervices a specific implementation class. So, there is a 'Scene30' class for the first scene in the game, and it has fields for the various hotspots and objects within the scene. Speaking of hotspots, there too is a hierarchy, with a base 'SavedObject' (used for object persistence), which subclasses to a 'SceneHotspot' (used for basic hotspots), which subclasses to a SceneObject (which is an object in the scene that is drawn into it, rather than being part of the background). From there, a SceneObject is sub-classed to the NPC class - this is where the encapsulation really helps, since all logic related to drawing NPC's is already handled by the SceneObject class, so didn't need to be disassembled multiple times for different kinds of things in the scene. The NPC class only has to implement the additional logic for moving character around the scene.

In fact, the NPC class also further sub-classes to the 'Player' class, which has extra logic to handle allowing the player to interact within the game. A lot of the logic for handling the player is thus already handled by the NPC class, so the Player class only has to add on the extra logic for allowing direct player control.

Because of this OO model, all the game logic is implemented by deriving new custom classes from these base classes, and then adding them into a particular scene. So, for example, the first scene in the game has the player having to ring a doorbell by 'using' a motion sensing beam. This beam is implemented as a 'SceneObject' derived custom class, which overrides the 'action' method to either provide a description on-screen for the 'Look' action, and start the 'kzin answering the door' sequence in response to a 'Use'.

I'm still undecided about whether I'll re-implement the game by manually converting all the game logic to C++ code, or try to create a process, as with Rex Nebular, to convert the game executable routines into equivalent scripts that could be interpreted. The OO nature of the game engine would make it trickier to convert to scripts. I'm planning to at least, eventually, converting the logic for the first scene to full C++, and see how it looks.

Tuesday, July 27, 2010

Rex can now walk about on-screen

Here I was bracing myself for the imagined complexities of movement logic, and it turned out to be a whole lot simpler than I imagined. Probably blame it on the other two engines I've had experience with path-finding for: Lure, and Tinsel, both of which have their share of complicated logic. For Rex Nebular, though, the implementation was a lot more elegant than I'd expected.

What the MADS engine does for walkable areas is to have two parts. The first is a priority/depth surface, which had already been previously implemented. This is a surface which both specifies the walkable areas, and is also used to determine which parts of an object, at a given 'depth', should be drawn on-screen. In the first room, for example, the area comprising the chair has some varying levels so that the player gets drawn behind it.

The other part to the movement functionality is a series of 'scene nodes'. These are a series of points distributed across the scene to represent appropriate intermediate points in movement. If a straight line between the start and end point isn't possible, because of a marked obstruction, then the engine calculates the distance between each node in the scene, including both the start and end points as two extra nodes. It then calculates which series of nodes will take the shortest amount of time to traverse, and uses that as the basis for movement - the actual walking then moves the player from node to node until the destination is reached.

This works well for the game since, unlike in Tinsel or Lure, there aren't ever any moving actors that could interrupt the walking path. The only NPC character movement that ever happens is in cut-scenes, where the player is either not moving, or is being controlled by the computer (such as when Rex is taken to the cells).

Now that I've got Rex moving around on the screen, the next immediate step is to get the hotspot and selection code working. Somewhat ironically, this is turning out to be more complicated than the walking code itself. I'm currently working my way through disassembling the various routines and implementing comparable code. Hopefully, I'll soon have enough implemented that I can properly implement some actual actions in the first room.