Patch:Game stats

From KeenWiki
(Redirected from Patch:Item bytes)
Jump to navigation Jump to search

Game stats are, in a nutshell, all the information an executable has on the game currently being played. This is roughly equivalent to all the information stored in an executable's memory. Where this intersects with patching is that you can patch an executable so it alters or reads different game stats at various times.

There are three basic formats to consider, Vorticons, Dreams and Galaxy. The last two are quite similar, but not identical.


What game stats are

Game stats are simply locations in memory that hold a certain value. Specifically these are locations in the game's 'data segment' that is used for storing many things such as most of the game text. In the various Keen games the data segment starts at the following locations:

Keen 1: $13050
Keen 2: $17780
Keen 3: $19820
Keen 4: $2EE70
Keen 5: $30340
Keen 6: $30D30
Keen D: $23A70


Game stats use two bytes of the data segment each and can be located anywhere in the data segment. It is possible for stats to overlap and overwrite each other or other things (such as text strings) in the data segment.

Each variable thus consists of two important parts; firstly is the actual location of the variable in memory, that stores the value and the pointer that identifies that specific variable by location. These two elements appear in almost all stat related patches.


Bytes, words, dwords and values

All data can be broken down into bytes. These have a value between 0-255 ($00-$FF). Two bytes make a 'word' which can have values between 0-65'535 ($0000W-$FFFFW) and four bytes make a 'double word' or dword, which can have values between 0-4'294'967'295. In Keen the game works in words, dwords must be treated as two different variables a 'high' word and a 'low' word. (The high word holds the biggest half of the value, the low word the smallest half.)

Values can be 'signed' or 'unsigned'. Unsigned values are always positive; the biggest number is the biggest value. As noted above a byte can have a value between 0 and 255.

Singed values can be negative. In that case only half the values are positive and half negative. In this case a byte's value starts at 0 and increases up to 128. But 129 becomes -127, 130 is -126 and so on until 255 is -1.

The two types of possible value are important to keep track of since treating a large negative number like a large positive number seldom works out well.


Overflow and underflow

Since there are no limits that tell the game when to stop increasing or decreasing a stat, eventually a stat can reach the largest\smallest possible value it can and the game will keep going. When this happens a 'flip' can occur. Keen games are often set up to avoid this.

As an example Keen's ammo counter decreases by 1 each time he shoots. When it reaches zero the game makes sure he cannot shoot anymore. If it did not do this Keen's next shot would give him -1 shots, which the game actually treats in that case as 65'535 shots. While the game prevents this, the reverse case Keen can acquire so much ammunition that he ends up with no ammo at all is possible.


Changing stats

Setting a stat

A six byte string is required to set a stat. This involves overwriting the previous value with a new one. This is often done when something starts or stops, such as starting a new game. The first two bytes indicate setting, the next two are the variable's pointer and the last two the value it is set to.

Patch example

#Set variable $C28B to 4
%patch $1234 $C7 $06 {$C28BW}  [$0004W]


Increasing\decreasing a stat by 1

Two special commands will increase or decrease a variable by exactly one. These are both four bytes in length. The first two bytes indicate whether to increase or decrease the variable while the last two are the variable involved. (Since the increase\decrease is regular no value is needed.)

This is often done when modifying a variable's value in a regular, repeated manner, such as a counter ticking down to zero. (Note that stats will not 'stop' at any value, they can always be decreased or increased.) Keen's ammo counter is an example of this, decreasing by 1 every time he shoots.

Patch example

#Decrease variable $C28B by 1
%patch $1234 $FF $06 {$C28BW}

#Increase variable $C28B by 1
%patch $1234 $FF $0E {$C28BW}


Increasing\decreasing a stat by larger amounts

A five or six byte string will increase a variable by a specific amount. There are two versions of this command; the first is five bytes long and adds a 1-byte value to the variable, the second is six bytes long and adds a two-byte value. The difference lies in the first byte; $83 is 1 byte and $81 is two bytes. These two versions can be seen in the example, both doing the exact same thing.

Patch example

#Increase variable $C28B by 5
%patch $1234 $83 $06 {$C28BW}  [$05]

#Increase variable $C28B by 5
%patch $1234 $81 $06 {$C28BW}  [$0005W]


If the value added is greater than $80 (1 byte) or $8000W (two bytes) then the value will 'flip' and become negative. (For example $FF\$FFFFW is -1.) This allows for decreasing a variable as well as increasing it.


Flipping stat bits

It is possible to 'flip' various bits of a stat; in essence add or subtract a value from it in a reversible manner. For example the demonstration command given here adds or removes 1 from a stat. if the stat is odd the '1 bit' is "on".) then 1 will be subtracted. If it is even (The '1 bit' is "off") then 1 will be added.

This is useful since it can act as a 'switch' for a stat, flipping it between two different values and even positive\negative whenever it is run.

Patch example

#Flip variable $C28B by 1
%patch $1234 $83 $36 {$C28BW}  [$01]

#Flip variable $C28B by 256
%patch $1234 $81 $36 {$C28BW}  [$0100]


Current stat

Only one 2-byte value can be manipulated at a time in 16-bit games. This is the 'current stat' and it has no address.


Setting the current stat

A three byte command will change the current top stat to a specific two-byte value. This will have no effect unless combined with other commands. A special case is setting to zero which is a two byte command. (Though the three byte command will also work.)

Patch example

#Set current stat to 8
%patch $1234 $B8 [$0008W]

#Set current stat to 0
%patch $1234 $33 $C0


Changing the current stat's value

Often the current stat will be copied from another stat. (See below.) and is relative to that value. In this case there are two three-byte commands that will increase or decrease the current stat by a given amount.

Patch example

#Increase current stat by 8
%patch $1234 $05 [$0008W]

#Decrease current stat by 8
%patch $1234 $2D [$0008W]


Reading\writing to current stat

It is also possible to copy a game stat to the top stat or to write the top stat to a game stat. This is needed to store stats or make use of game stats without altering them. While reading has little effect unless paired with other commands writing will permanently change the value of a game stat.

By combining these commands it is possible to copy the value from one game stat to another or even multiple stats.

Patch example

#Copy value $C28B to current stat
%patch $1234 $A1 {$C28BW}

#Copy current stat value to $C28B
%patch $1234 $A3 {$C28BW}

#Copy variable $C28B to current stat then copy it to $CDBCW, $CDBEW and $D8F0W
%patch $1234 $A1 {$C28BW}  $A3 {$CDBCW}  $A3 {$CDBEW}  $A3 {$D8F0W}


Sprite stats

Sprite stats or sprite variables are stats unique to each individual sprite in a level. In Galaxy and Dreams each sprite has 70 bytes (35 words) of stats, most of which are used for important things such as its current speed or animation. Sprite stats cannot be called 'globally'; instead the sprite(s) involved are selected by the game when calling a piece of code. An example of this is the sprite collision; this takes two colliding sprites so any variables referenced will belong to those.

There is a one byte command that shows sprites are being referred to, $8B.


Selecting sprites

As noted above specific sprites must be chosen when a piece of code is run. This is usually done at the start of a piece of code. The maximum number of sprites a piece of code may refer to at once is 3, two interacting sprites and the 'universal' player sprite. A 3 byte command sets up a sprite as either $44 type or $47 type. The first sprite is usually the one running the code while the second is the one it interacts with. (The player can be $45 type unless it is directly interacting with another sprite.)

Patch example

#Set 1st sprite as $44 type
%patch $1234 $8B $76 $06

#Set 1st sprite as $44, 2nd as $47
%patch $1234 $8B $76 $06 $8B $7E $08

#Set 2nd sprite as $44, 1st as $47
%patch $1234 $8B $7E $06 $8B $76 $08


Referring to sprite stats

As noted above sprites ca be assigned a type when a block of code starts. After this a sprite stat is referred to by its location and type. This example patch increases the type $44 sprite's $3E stat by 1 then checks the type $47 sprite's $3E stat. Here the two sprites are differentiated by their type.

All other patches here will use type $44 for simplicity.

Patch example

#Increase 1st sprite's stat then check 2nd sprite's stat
%patch $1234 $FF $44 $3E $8B $47 $3E $3D [$0006W] {$75} $0C


Set a sprite stat

Setting a sprite stat is very similar to setting a game stat; the string of commands is only one byte shorter. Here a sprite's $10 stat, its vertical direction is set to -1 or 'up'.

Patch example

#Set sprite's direction to up
%patch $1234 $C7 $44 {$10} [$FFFFW]


Increase a sprite stat

Again the commands for doing this are similar to their game stat counterparts. All that need be referred to is the sprite's type and stat.

Patch example

#Increase a sprite stat by 1
%patch $1234 $FF $44 $3E


The stack

The 'stack' is a collection of values 'stacked' one on top of the other in memory. The game uses these values and the location of a given value in the stack is important. The stack is not the same as the game stats and is located in a different area of memory.

Only the 'topmost' value in the stack can be manipulated; if 'lower' values are needed then the 'higher' values must be removed from the stack. If those variables will be needed later they will have to be stored as game stats and loaded back onto the stack as needed. This makes manipulating the stack complex.

It is important to note that the stat being worked with is not on the stack. It is the 'current stat' and a copy of it can be added to the stack but it itself is not associated with the stack.


Pushing on\off the stack

The stack can be made 'taller' by copying the current stat and adding it to the stack. This is a single byte command, $50. It is usually combined with the 'set current variable' to in effect set the topmost stack variable. Repeating the push command will simply push the current stat onto the stack multiple times. (Thus $B8 [$0008W] $50 $B8 [$0008W] $50 can be shortened to $B8 [$0008W] $50 $50.)

Patch example

#Push the value 8 onto the stack
%patch $1234 $B8 [$0008W] $50

#Push the value 0 onto the stack
%patch $1234 $33 $C0 $50

#Push the value 8 onto the stack twice
%patch $1234 $B8 [$0008W] $50 $50


Much more rarely a game stat can be copied to the stack by first changing the current stat.

Patch example

#Push the value at $C28B onto the stack
%patch $1234 $A1 {$C28BW} $50


The stack is extremely limited in size and as such as soon as a value is used it is wise to pull it off the stack. This in effect deletes the value making the stack 'shorter.' There are multiple ways to do this. The command $44 removes one byte (Half a stat!) from the stack. (Meaning it must always appear as $44 $44 in Keen.) The command $83 $C4 $xx removes x bytes from the stack up to 128 bytes. There is also the never used command $81 $C4 $xxxxW which can remove up to 32'000 bytes from the stack, but this is impractical.

Patch example

#Remove 2 stats from the stack 1
%patch $1234 $44 $44 $44 $44

#Remove 2 stats from the stack 2
%patch $1234 $83 $C4 [$04]


In total the most commonly seen arrangement in Keen is for several variables to be set, pushed onto the stack and code run followed by the variables being deleted from the stack. In the example given here the code starting at $9A takes seven variables. The first two are $0001W and the last $1424W. (The other four are loaded in $57 $56 $50 $1E which is outside our scope.)

Patch example

#Typical code arrangement
%patch $1234 $B8 [$0001W] $50 $50 $57 $56 $50 $1E $B8 [$1424W]  $50 $9A $1D290F28RL  $83 $C4 $0E


Vorticons

Vorticons values are quite simple. These are the values for versions 1.31 of all three games:


Keen 1:

$5DAAW: God mode
$6EC2W: Extra keen at
$AA94W: Joystick  	$AA96W: Vacuum      	$AA98W: Whiskey  	$AA9AW: Pogo       
$AA9CW: Battery   	$AA9EW: Yellow card 	$AAA0W: Red card 	$AAA2W: Green card 
$AAA4W: Blue card 	$AAA6W: Level 1     	$AAA8W: Level 2  	$AAAAW: Level 3
$AAACW: Level 4   	$AAAEW: Level 5     	$AAB0W: Level 6  	$AAB2W: Level 7
$AAB4W: Level 8   	$AAB6W: Level 9     	$AAB8W: Level 10 	$AABAW: Level 11
$AABCW: Level 12  	$AABEW: Level 13    	$AAC0W: Level 14 	$AAC2W: Level 15
$AAC4W: Level 16  	$AAC6W: Lives       	$AAC8W: Ammo     	$AACAW: Points
$AACCW: Points * 65536

Keen 2:

$5D86W: God mode
$6E9EW: Extra keen at
$9AAAW: Joystick  	$9AACW: Vacuum      	$9AAEW: Whiskey  	$9AB0W: Pogo       
$9AB2W: Battery   	$9AB4W: Yellow card 	$9AB6W: Red card 	$9AB8W: Green card 
$9ABAW: Blue card 	$9ABCW: Level 1     	$9ABEW: Level 2  	$9AC0W: Level 3
$9AC2W: Level 4   	$9AC4W: Level 5     	$9AC6W: Level 6  	$9AC8W: Level 7
$9ACAW: Level 8   	$9ACCW: Level 9     	$9ACEW: Level 10 	$9AD0W: Level 11
$9AD2W: Level 12  	$9AD4W: Level 13    	$9AD6W: Level 14 	$9AD8W: Level 15
$9ADAW: Level 16  	$9ADCW: Lives       	$9ADEW: Ammo     	$9AE0W: Points
$9AE2W: Points * 65536

Keen 3:

$5FD6W: God mode
$70EEW: Extra keen at
$990CW: Number of sparks destroyed
$9946W: Ankh time
$9D1AW: Pogo      	$9D1EW: Yellow card 	$9D20W: Red card 	$9D22W: Green card 
$9D24W: Blue card 	$9D26W: Level 1     	$9D28W: Level 2  	$9D2AW: Level 3
$9D2CW: Level 4   	$9D2EW: Level 5     	$9D30W: Level 6  	$9D32W: Level 7
$9D34W: Level 8   	$9D36W: Level 9     	$9D38W: Level 10 	$9D3AW: Level 11
$9D3CW: Level 12  	$9D3EW: Level 13    	$9D40W: Level 14 	$9D42W: Level 15
$9D44W: Level 16  	$9D46W: Lives       	$9D48W: Ammo     	$9D4AW: Points
$9D4CW: Points * 65536


Saved game format

When a game is saved in Keen Vorticons, all that happens is a small segment of game memory is saved as a file. This is always 92 bytes of data starting at the joystick. (In Keen 3 the ship parts values aren't used, but are saved to the file anyway. These values are not listed above, but are simple enough to work out. Likewise Keen 2's city values aren't listed here.)

Thus the joystick value is saved to the first two bytes of the file, level 1's done status is saved at byte 18, and all saved game files are 92 bytes long. The format for saved games is as below. Notice that the level Keen is in is not saved, so he can only save on the map.

FILE STRUCTURE:
0   18   Stuff       Stuff got? 9 2-byte entries, $0001 for yes. In order the
                     parts are Battery, Vacuum, Joystick, Pogo, Whiskey and
                     R,G,B,Y keycards (Keycards usually not saved with game.)
18  32   Levels      Levels 1-16 completed? 16 2-byte entries, $0001 for yes.
                     With the 32 levels patch this becomes 32 1-byte entries.
50  2    Numlives    Number of lives Keen has
52  2    Numshots    Number of shots Keen has
54  4    Score       Keen's score
58  1    Blank
59  4    Loc x       x-Location on map level, in pixels. (= tiles * 16)
63  4    Loc y       y-Location
67  2    Screen x    x-Location of left of visible screen in pixels, usually
                     Keen's loc - 9 tiles.
69  2    Blank
71  2    Screen y    y-location of top of visible screen in pixels, usually
                     Keen's loc - 3 tiles, but variable.
73  18   Cities      In Keen 2, cities saved. 9 2-byte entries, the last seems
                     not to be a valid city, but is kept in memory.

Dreams

Dreams stats are some of the least known among the Keen games.

$70ECW: ???			$70EEW: Map X position		$70F0W: Map Y position
$70F2W: Lev 1 done		$70F4W: Lev 2 done		$70F6W: Lev 3 done
$70F8W: Lev 4 done		$70FAW: Lev 5 done		$70FCW: Lev 6 done
$70FEW: Lev 7 done		$7100W: Lev 8 done		$710AW: Lev 9 done
$7104W: Lev 10 done		$7106W: Lev 11 done		$7108W: Lev 12 done
$7102W: Lev 13 done		$710CW: Lev 14 done		$710EW: Lev 15 done
$7110W: Lev 16 done		$7112W: Lev 17 done		$7114W: Lev 18 done
$7116W: Lev 19 done		$7118W: EKA score (Low)		$711AW: EKA score (High)
$711CW: Flower Power		$711EW: Boobus Bombs		$7120W: Temp B. Bombs
$7122W: Keys			$7124W: Current level		$7126W: Lives
$7128W: Difficulty		$712AW: ???


Galaxy

In some respects Galaxy values are simpler, since there are less values we can easily edit. However they are usually more complex to edit also.

Note that the level state in Keen 4 will play the Oracle Council Message if set to 3. In all galaxy episodes a value of 2 will immediately win the level, 1 will bring up the 'didn't make it past' box and zero will do nothing. A value of 4 or higher will restart the level (Without loss of life.)

The 'next level' variable stores what level Keen will enter next when the 'change level' code is run.


Keen 4:

$7A14W: ???		$7A16W: Debug variable	$7A18W: Joypad variable	$7A1AW: Player X Pos
$7A1CW: Player Y Pos	$7A1EW: Lev 0 done	$7A20W: Lev 1 done	$7A22W: Lev 2 done
$7A24W: Lev 3 done	$7A26W: Lev 4 done	$7A28W: Lev 5 done	$7A2AW: Lev 6 done
$7A2CW: Lev 7 done	$7A2EW: Lev 8 done	$7A30W: Lev 9 done	$7A32W: Lev 10 done
$7A34W: Lev 11 done	$7A36W: Lev 12 done	$7A38W: Lev 13 done	$7A3AW: Lev 14 done
$7A3CW: Lev 15 done	$7A3EW: Lev 16 done	$7A40W: Lev 17 done	$7A42W: Lev 18 done
$7A44W: Lev 19 done	$7A46W: Lev 20 done	$7A48W: Lev 21 done	$7A4AW: Lev 22 done
$7A4CW: Lev 23 done	$7A4EW: Lev 24 done
$7A50W: Score (Low)	$7A52W: Score (High)	$7A54W: EKA score (Low)	$7A56W: EKA score (High)
$7A58W: Ammo		$7A5AW: Drops		$7A5CW: Wetsuit		$7A5EW: Members saved
$7A60W: Red gems	$7A62W: Blue gems	$7A64W: Yellow gems	$7A66W: Green gems
$7A68W: Next lvl	$7A6AW: Lives		$7A6CW: Difficulty	$7A6EW: ???
$7A70W: Level state	$7A72W: Demo mode var
$7ADCW: TED5 variable
$A7EDW: Current lvl
$C629W: God cheat	$C62BW: Jump cheat	$C62DW: Slow motion
$CAB5W: Mooning variable

Keen 5:

$6F14W: Debug variable	$6F16W: Joypad variable	$6F18W: ???		$6F1AW: Player X Pos	
$6F1CW: Player Y Pos	$6F1EW: Lev 1 done	$6F20W: Lev 2 done	$6F22W: Lev 3 done
$6F24W: Lev 4 done	$6F26W: Lev 5 done	$6F28W: Lev 6 done	$6F2AW: Lev 7 done
$6F2CW: Lev 8 done	$6F2EW: Lev 9 done	$6F30W: Lev 10 done	$6F32W: Lev 11 done
$6F34W: Lev 12 done	$6F36W: Lev 13 done	$6F38W: Lev 14 done	$6F3AW: Lev 15 done
$6F3CW: Lev 16 done	$6F3EW: Lev 17 done	$6F40W: Lev 18 done	$6F42W: Lev 19 done
$6F44W: Lev 20 done	$6F46W: Lev 21 done	$6F48W: Lev 22 done	$6F4AW: Lev 23 done
$6F4CW: Lev 24 done	$6F4EW: Score (Low)	$6F50W: Score (High)	$6F52W: EKA score (Low)
$6F54W: EKA score (High)$6F56W: Ammo		$6F58W: Vitalin		$6F5AW: V card
$6F5CW: Unused		$6F5EW: Q.E.D. variable	$6F60W: Red gems	$6F62W: Blue gems
$6F64W: Yellow gems	$6F66W: Green gems	$6F68W: Next lvl	$6F6AW: Lives
$6F6CW: Difficulty    	$6F6EW: OnPlatform	$6F70W: Level state	$6F72W: Demo mode var
$9E55W: Current lvl
$BC91W: God cheat	$BC93W: Jump cheat	$BC95W: Slow motion

Keen 6:

$754CW: ???		$754EW: Debug variable	$7550W: Joypad variable	$7552W: Player X Pos	
$7554W: Player Y Pos	$7556W: Lev 0 done	$7558W: Lev 1 done	$755AW: Lev 2 done
$755CW: Lev 3 done	$755EW: Lev 4 done	$7560W: Lev 5 done	$7562W: Lev 6 done
$7564W: Lev 7 done	$7566W: Lev 8 done	$7568W: Lev 9 done	$756AW: Lev 10 done
$756CW: Lev 11 done	$756EW: Lev 12 done	$7570W: Lev 13 done	$7572W: Lev 14 done
$7574W: Lev 15 done	$7576W: Lev 16 done	$7578W: Lev 17 done	$757AW: Lev 18 done
$757CW: Lev 19 done	$757EW: Lev 20 done	$7580W: Lev 21 done	$7582W: Lev 22 done
$7584W: Lev 23 done	$7586W: Lev 24 done
$7588W: Score (Low)	$758AW: Score (High)	$758CW: EKA score (Low)	$758EW: EKA score (High)
$7590W: Ammo		$7592W: Vivas		$7594W: Sandwich	$7596W: Rope+hook
$7598W: Rocket card	$759AW: ???		$759CW: Red gems	$759EW: Blue gems
$75A0W: Yellow gems	$75A2W: Green gems	$75A4W: Current lvl	$75A6W: Lives
$75A8W: Difficulty	$75AAW: ???		$75ACW: Level state	$75AEW: Demo mode var
$75C0W: Next lvl?
$C7B7W: God cheat	$C7B9W: Jump cheat	$C7BBW: Slow motion


Saved game format

Much more than a few values are written to file when Keen saves a game in Galaxy. As Keen can save within a level, the entire level and its current state, including the locations and states of all enemies and tiles, are saved. This means that every saved game is a different size, as well as containing some compression. (RLEW) The start of all games contain the basic game variables and are thus the same.

The first 16 bytes stores the game's name. This is followed by 112 bytes storing basic game variables such as which levels are completed, score, ammo, etc. After this begins the level data, three sets of RLEW compressed plane data. (Background, foreground and infoplane.) These each consist of a word describing the length of the compressed data followed by the data itself. Finally there is a 3'420 byte array, consisting of 114 30-byte entries, giving the values of all the sprites in the level at the time the game was saved.