272
edits
m (colour -> color) |
Dreammaster (talk | contribs) (Added Practical Examples section to Reverse Engineering HOWTO) |
||
Line 140: | Line 140: | ||
Particularly for cases like that, identifying and naming the graphic/screen methods may be helpful, since you could work the disassembly from both the front end reading the animation, and from the low level drawing of the graphics of the animation. | Particularly for cases like that, identifying and naming the graphic/screen methods may be helpful, since you could work the disassembly from both the front end reading the animation, and from the low level drawing of the graphics of the animation. | ||
=== Practical Examples === | |||
Following are a few other examples of specific strategies I used to make initial progress in figuring out adventure games I've worked on in the past. They may help give you inspiration for your own work: | |||
==== The font system ==== | |||
I frequently like to tackle the font system for a game early on, since it's usually fairly straight-forward to figure out, and it's a nice milestone for your own re-implementation of the game to be able to display visual text. | |||
* I started by taking a screenshot of the game that showed some text, and used Paint to determine the screen co-ordinates of one of the pixels in a character that was displayed on-screen. | |||
* I then calculated what the memory location of that pixel was in the screen. Presuming the fairly standard 320x200 8-bit graphics, the segment would be A000h, and the offset would be y * 320 + x. | |||
* Using the DosBox Debugger to run the game up to a point just before the text was displayed, I set a memory breakpoint for the pixel, and then allowed the game to start to display the text. | |||
* The point where the pixel set was identified as the routine for drawing a character. It's fairly standard for it to take in an x and y position, and the specified character to display. I gave it an appropriate name like 'font_write_char'. | |||
* By examining how the character is used to lookup the pixel data to copy the screen, I was able to identify where the font was stored, and what structure it had. | |||
* By looking at other places that referenced the same memory I was able to identify other font related methods, such as for loading the font, or determining the width of a given character. And then some of the callers of these methods could then be identified. For example, one caller called the method in a loop for every character of a string, so I was able to call it 'font_string_width'. Further, since that method was now known to take in printable strings, I was able to see what called it and identify string handling in other parts of the game. | |||
* Similarly, I was able to identify a method that called font_write_char in a loop, and could name it 'font_write_string'. As with the identified font_string_width, I could then look at callers to font_write_string to identify how other parts of the system pass strings. | |||
* Because the display of information is so important for adventure games, the font_write_string method becomes an excellent starting point for all sorts of further investigations. For example, suppose in your adventure game if you try to combine two arbitrary items together and it prints "That doesn't work". You can set a breakpoint in DosBox debugger in the font_write_string method at it's end, and when it's hit by trying to combine the items, trace backwards to find out which method called it. | |||
* Based on a similar test, I was able to identify methods that worked with the inventory, and the lists in memory of all the available items as well as the list of items in the player's inventory. I then set up an appropriate structure for items. I didn't know all the fields they held initially, but some fields, such as a pointer to the textual name, were easy to figure out, and I could always come back to the structure later and add proper definition for other fields when I figured them out. I then went on to identify other methods that also access the inventory list and identified the methods that handle adding and removing items from the inventory. I was also able to see the method that gets the details of the inventory for displaying the inventory on-screen. This was extremely useful, since it used a standard "sprite draw" method to draw both the inventory area background as well as the glyphs for each item in the player's inventory. And with the sprite drawing method identified, there would be the potential for looking at all it's callers and identifying methods that handle drawing in-game screens and dialogs. | |||
In fact, even other inventory methods like adding and removing proved to be important too, as I was able to check their callers, and identify them as methods that were part of a script engine. These methods were indexed by a table of all possible script command handler methods, so I was able to see which method was using that list to identify the main script execution method. By setting breakpoints in the method and doing various actions in-game, I was able to start figuring out what the various script methods did, and based on that, identifying and naming the methods that they called. A pretty good result from a process that started with a single pixel on the screen. | |||
==== The Hotspot list ==== | |||
In adventure games, hotspots are areas of the screen that has an interactable item. Moving the mouse over the area causes a description of the hotspot. Using a breakpoint in the write string method, I was able to see what the caller was. Then examining the caller to find out how the description came to be passed, I was able to figure out the structure of how the list of hotspots were stored in memory. This allowed me to create a Hotspot structure, and set up the array of hotspots in memory. From there I was able to go in two direcitons. Firstly, by identifying other methods that access the same hotspot list, then finding out which one set up the values, I was able to locate the hotspot laoding code, which was part of the overall scene loading code. With scene loading identified, I could look at the other files being accessed, and the structures being loaded, and get further ideas of what information each scene contains. | |||
The other direction I was able to go in was hotspot interaction. By setting breakpoints in other methods that accessed the hotspot list and then trying to interact with a hotspot, I was able to identify the general method that handles actually doing item interactions. In this case, it turned out to use other fields of the Hotspot record, and then load a script and call it to be executed. Since I'd already identified the script execution method, it made it easier to realize that script data was being loaded, since it was immediately passed on to be executed. | |||
==== Scene sprites ==== | |||
Scenes would be kind of boring if they didn't have any animation or action within them. As such adventure games tend to have a main scene drawing method to draw in the background and then add in any sprites for extra items within the scene. I was able to take an item that's obviously animating, and then set a memory breakpoint on a pixel within it just before the new scene was loaded, and see what changes it. The first change was clearing the screen. Next was rendering of the scene background, which in itself was a useful diversion to figure how the scene specified the background to load, and what format backgrounds are stored in. Then the next change came from rendering the sprite onto the scene. In this, I confirmed that the scene items were using the already identified sprite drawing method. So by tracing out of the sprite drawing method (by setting a breakpoint on it's 'retf' opcode and then running DosBox debugger until it it's hit, you can then single step out of the method), I was able to identify the code looping to draw items within the scene, and the overall method that draws the contents of the scene for each frame. | |||
I was also able to start figuring out how the structures for the scene sprites were being stored in memory, with fields such as the position for where to draw the sprite, which set of sprites to use, and what frame number. The frame number particularly is useful.. sprites in games generically collect multiple "frames" in a single sprite, representing all the possible ways the given sprite can be drawn. By seeing what method was called to get a specific frame to pass to the sprite drawing code, I was able to locate the methods that handle managing sprites, and flesh out both it as well as other nearby methods in the disassembly that handled loading a sprite from files. | |||
==== What Followed ==== | |||
In fact, at this point, the only thing I was missing was loading in an appropriate palette to be able to implement the basics of loading a game scene, drawing meaningful sprites within the scene, and having hotspots work. Presuming any other adventure game you look into has similar kinds of structures, this could lead to you having a concrete start at reimplementing the game, and enough methods figured out in the disassembly, and pick any area of the game you want to work on.. at this point you'd have the basics of scene loading, graphics rendering and sprite display, scene interaction, and the basics of actually doing items. Maybe you could.. | |||
* figure out which sprite controls the player, and put memory breakpoints on the sprites position and/or frame. From that, you could identify methods that control moving the character, and from there investigate the pathfinding logic the game uses, leading to you being able to have your re-implemention's character walking around the screen | |||
* Flesh out more of the script system. Maybe concentrate on some of the first actions done in the game, so your reimplementation can likewise do them. | |||
* Look into the music/sound system. From strings in the data segment, or the filenames of specially loaded music drivers, you may be able to figure out where the sound code is loaded, and start looking into what commands the sound and/or music drivers have, and what sound formats are used. | |||
There's lot of areas you can proceed to delve in. Hopefully the suggestions above will help get you over the initial barrier of not being sure how to start, and assist you getting started in your efforts. | |||
== Final Words == | == Final Words == |
edits