Talk:Monster Bash

From ModdingWiki
Jump to navigation Jump to search

Patching Actor and Sprite Structures in the Executable

Animation and actor behaviours in Monster Bash are governed by 10-byte action structures, similar to those found in Commander keen Galaxy, but much simpler.

typedef struct action {
	void _seg ***left_sprite, _seg ***right_sprite; 
	uint16_t time;
	int (*think)(actor *);
	struct action *next;
} action_t;

Actions exist in the data segment, and all pointers are 16 bits. In the data segment, Monster bash stores sprite information in linked list of variable-sized nodes. Each node has the sprite name, a null-terminated list of segment pointers that store the value of the segment where the raw EGA graphics data is for that sprite, an ASCII string with the name of the graphic, and two 16-bit signed integers of unknown function (possibly the sprite "hotspot" x and y coordinates). There is a second array of near pointers in the data segment, with one entry for each sprite that points to the segment pointer in the linked list. If the sprite is cached, then this value is set, otherwise it is null. Finally, the 16-bit left_sprite and right_sprite pointers point to their respective entry in this second array. Thus, the value in the action structure is a near pointer to a near pointer to a segment pointer!

The other fields are much simpler to understand.

  • time is the length of animation in x'ths of a second.
  • think is the actor behaviour function that is in use for this animation frame
  • next is the action structure that the sprite uses when the action timer expires

There is a second array of 6-byte structs that hold animation information for each "group" of frames.

typedef struct {
	void _seg ***first_sprite; // same as the action_t field, references first sprite in spritegroup
	char *groupname;
	int num_frames;
} spritegroup_t;

For whatever reason, the .exe has the names of the spritegroups stored in the data segment.

Diving into the .exe to figure out which action belongs to which sprite

As an example, I am using the Registered version 2.1 of the first episode. Say we want to find the actions for the green hand. I am using IDA Free v 5.0 to disassemble the .exe (which has been unpacked by UNP.EXE v 4.11. At dseg:3FBC, we find the array of spritegroups. We scroll down until we find the spritegroup that corresponds to the hand.

dseg:4250                 spritegroup <offset off_244C2, offset aHand_l, 6> ; "hand_l"
dseg:4256                 spritegroup <offset off_244B6, offset aHand_r, 6> ; "hand_r"

Actually, there are two spritegroups for the hand, one for each direction. We see that that left hand sprites start at off_244C2 in the .exe image. Therefore, we want to look for action structures that have off_244C2 in their left_sprite field. One such struct exists at dseg:2DAE. Because all of the hand actions are located next to each other, and all of the right handed values must be between off_244B6 and off_244C0, we can identify which actions belong to the hand.

We know that the first four hand frames are for the walking loop, which would be actions with off_244C2 through off_244C8. The remaining actions likely have to do with the jump sequence, and we can make guesses as to what each action is for based upon the frame field content.

dseg:2DAE ac_hand_walk_0  action <offset off_244C2, offset off_244B6, 50, offset think, \
dseg:2DAE                                         ; DATA XREF: dseg:ac_hand_walk_3�o
dseg:2DAE                         offset ac_hand_walk_1>
dseg:2DB8 ac_hand_walk_1  action <offset off_244C4, offset off_244B8, 50, offset think, \
dseg:2DB8                                         ; DATA XREF: dseg:ac_hand_walk_0�o
dseg:2DB8                         offset ac_hand_walk_2>
dseg:2DC2 ac_hand_walk_2  action <offset off_244C6, offset off_244BA, 50, offset think, \
dseg:2DC2                                         ; DATA XREF: dseg:ac_hand_walk_1�o
dseg:2DC2                         offset ac_hand_walk_3>
dseg:2DCC ac_hand_walk_3  action <offset off_244C8, offset off_244BC, 50, offset think, \
dseg:2DCC                                         ; DATA XREF: dseg:ac_hand_walk_2�o
dseg:2DCC                         offset ac_hand_walk_0>
dseg:2DD6 ac_hand_curl_0  action <offset off_244CC, offset off_244C0, 350, offset think_21, \
dseg:2DD6                                         ; DATA XREF: sub_3931+E2�o
dseg:2DD6                         offset ac_hand_curl_1>
dseg:2DE0 ac_hand_curl_1  action <offset off_244CC, offset off_244C0, 0, offset think_83, \
dseg:2DE0                                         ; DATA XREF: dseg:ac_hand_curl_0�o
dseg:2DE0                         offset ac_hand_fly_0>
dseg:2DEA ac_hand_fly_0   action <offset off_244CA, offset off_244BE, 50, offset think_31, \
dseg:2DEA                                         ; DATA XREF: dseg:ac_hand_curl_1�o
dseg:2DEA                                         ; dseg:ac_hand_fly_0�o
dseg:2DEA                         offset ac_hand_fly_0>
dseg:2DF4 ac_hand_fly_1   action <offset off_244CA, offset off_244BE, 50, offset think_32, \
dseg:2DF4                                         ; DATA XREF: sub_3931+E7�o
dseg:2DF4                                         ; dseg:ac_hand_fly_1�o
dseg:2DF4                         offset ac_hand_fly_1>
dseg:2DFE ac_hand_fly_2   action <offset off_244C2, offset off_244B6, 300, offset think_31, \
dseg:2DFE                                         ; DATA XREF: dseg:ac_hand_fly_2�o
dseg:2DFE                         offset ac_hand_fly_2>
dseg:2E08 ac_hand_land_0  action <offset off_244CC, offset off_244C0, 50, offset think_32, \
dseg:2E08                                         ; DATA XREF: dseg:ac_hand_land_0�o
dseg:2E08                         offset ac_hand_land_0>

Finally, it is of use to look at the think functions. These thinks may be used by multiple actors, but some may be specific to one actor.

How would this be used for modding?

First of all, a modding program would have to output a patch file to update the spritegroup array. MBPATCH can use the %patchfile command to patch a binary file generated by the modding program at the appropriate offset (e.g., dseg:2DAE in Monster Bash 1). As for the modder himself, he would be interested in modifying the action structures. Sprites, animation timing and loops, and behaviours can all be changed.