Patch:Patching Vorticon Sprites
This patch is a tutorial on patching Vorticons sprites. It will give a demonstration of making an entirely new sprite in Keen 1 and altering its properties and behaviors while utilizing all the different kinds of sprite patches. If there is something in this tutorial that you do not understand, skip it, since the easier patches will come last, not first. However it is beneficial to be able to go through the entire tutorial in the right order.
A related page for Keen Galaxy (And Dreams) is Patch:Patching Galaxy Sprites
The first step is to take a clean copy of Keen 1 and place a sprite of value 11 in level 1. By default this is only good for switches as it does nothing at all. Testing the level works fine, there is no indication the sprite is there.
New sprites
The first step then is to make this sprite do something. This is done by using the 'new sprite' patch at Patch:Sprites (Keen 1) As stated on the page, this requires a bit of a rewrite of the sprite code.
Here the jump to spawn code and spawn code are both stored in the same place, the unused screenshot code located at $0AF2 - $0C50. This means we don't have to calculate our $E8 jump, it will always be $0006W in this situation. The $E9 jump goes to $16EF (It's at $0AFA, 16EF - $0AFA - 2 = $0BF2) Here we're using a copy of the Patch:Chain's sprite spawning code, so our sprite will act just like the Chain, except we have changed the starting animation, it will appear in the level like a BWB rocket sprite.
This is the bare minimum needed to make a new sprite, using other sprite's behaviors and such for the minimum amount of code usage. The free space here can take about 5 of these new sprites. The variables highlighted in the spawning code are, in order, the sprite type, sprite behavior, sprite collision and starting sprite animation. The $E8 jumps in the code are similarly calculated as our $E9 one.
This patch, and all that are built on it is incompatible with all other $0AF2 using patches. Note that 'as-is' this patch will not work as it references custom behaviors and collision that are added below. (To make this patch work by itself replace both $0B3AW and $0BFEW with $3360W
Keen 1
#Re-write the core switch statement.
%patch $161D $4B $83 $FB [$0A] $76 $0A $81 $FB $FE $00 $0F $84 $A0 $00 $E9 $C1
$00 $D1 $E4 $2E $D1 $E3 $2E $FF $A7 {$168AW}
#Combine the ice-launchers
%patch $16B1 $D1 $EB $83 $EB $05 $53
#Locations of jumps to sprite initiation code
%patch $168A {$1656W} #Yorp
{$1661W} #Garg
{$166CW} #Vort
{$1676W} #Butler
{$1680W} #Tank
{$16B1W} #Ice Launcher 1
{$16B1W} #Ice Launcher 2
{$16B1W} #Ice Launcher 3
{$16B1W} #Ice Launcher 4
{$16C1W} #Falling Block
{$0AF2W} #New sprite
#Initiation code
%patch $0AF2 $57 $56 $E8 $0006W $83 $C4 $04 $E9 $0BF2W
#New sprite spawn code
%patch $0AFD $55 $8B $EC $56 $E8 $1E31W $8B $F0 $C7 $04 [$0008W] $8B $46 $04
$99 $B1 $0C $E8 $D63EW $89 $44 $04 $89 $54 $06 $8B $46 $06 $99
$B1 $0C $E8 {$D62FW} $89 $44 $08 $89 $54 $0A $C7 $44 $34 {$0BFEW}
$C7 $44 $32 {$0B3AW} $C7 $44 $28 [$0030W] $5E $5D $C3
Adding custom behaviors
Now we are in a position to add custom behaviors. Like the initiation and spawn code we will place the new behaviors in the free space at $0AF2. The first behavior will be placed right after the spawn code, which is at $0B3A. The second custom behavior is located after this at $0BA5.
The behaviors being used here are modifications of the Yorp walking without jumping code and the Yorp searching code. To see what the various highlighted variables do then following those links is informative.
In this example patch the code is completely unchanged except for the $E8 calls. These have to be altered as they are relative jumps, and placing them somewhere different means they will point somewhere different unless altered. (Note that the $E8 $000x code found in both behaviors is not a jump and so must not be changed.)
The original walking code was at $194F and is moved to $0B3A, a change of - $0E15. Three jumps need to be altered by this amount in the walking code. The first, on line 1, is $A771W in the original code and becomes $A771 + $0E15 = $B586 in the new code. (Notice we add this amount to the jump, to cancel out the subtraction from the code location. Opposites balance.) The other two jumps are similar. In the searching code the original location was $19D3, the new $0BA5,a difference of $0E2E. This makes the first jump (Near the end of the code.) is changed - $1203 + $0E2E = $2031.
New sprite behavior
#Sprite walks and randomly searches
%patch $0B3A $55 $8B $EC $56 $83 $3E $42 $82 $00 $75 $15 $E8 $B586W $3B $06
$14 $5B $73 $0C $C7 $06 $52
$82 {$0BA5W} $C7 $06 $4A $82 [$0000W] $83 $3E $40 $82 [$00] {$7E} $08
$C7 $06 $48 $82 [$0034W] $EB $06 $C7 $06 $48 $82 [$0036W] $A1 $35
$51 $B1 [$04] $D3 $E8 $25 [$0001W] $8B $16 $48 $82 $03 $D0 $89 $16
$48 $82 $E8 $128FW $E8 $12CFW $8B $F0 $A9 [$0004W] {$74} $06 $C7
$06 $40 $82 [$FFC4W] $F7 $C6 [$0001W] {$74} $06 $C7 $06 $40 $82 [$003CW]
$5E $5D $C3
#Sprite searching code
%patch $0BA5 $55 $8B $EC $C7 $06 $40 $82 [$0000W] $A1 $35 $51 $B1 [$05] $D3 $E8
$25 [$0003W] $05 [$0030W] $A3 $48 $82 $A1 $4A $82 $03 $06 $14 $5B
$A3 $4A $82 $3D [$00C8W] $7C $29 $A1 $26 $82 $8B $16 $24 $82 $3B
$06 $E0 $6E $7F $10 $7C $06 $3B $16 $DE $6E $73 $08 $C7 $06 $40
$82 [$003CW] $EB $06 $C7 $06 $40 $82 [$FFC4W] $C7 $06 $52 $82 {$0B3AW}
$E8 $2031W $E8 $2071W $5D $C3
Adding custom collision
All that remains now is to give the Sprite a custom collision. This could be done easily enough; using $1E94 for the collision in the spawning code would make it indestructible. (It would be sharing the Butler Robot's collision.) However for more variety a custom collision can be created. The one used here is a modification of the Yorp collision; following that link will show what all the highlighted values are.
The method is similar to that for behavior; the old code was located at 1A68, the new at 0BFE, a difference of 0E6A. There is only one jump to alter, originally $A451W it becomes $B2BBW. Again while this makes a sprite very similar to the Yorp, the modder can alter various values to change its appearance and behavior.
Sprite collision
#Sprite collision
%patch $0BFE $55 $8B $EC $56 $57 $8B $76 $04 $8B $7E $06 $83 $3D [$0A] {$74} $05
$83 $3D [$0B] {$75} $27 $C7 $44 $2A [$0000W] $C7 $44 $2C [$0002W] $C7
$44 $28 [$003AW] $C7 $44 $32 [$489DW] $C7 $44 $34 [$3360W] $C7 $44
$22 [$FFB0W] $B8 [$0022W] $50 $E8 {$B2BBW} $44 $44 $5F $5E $5D $C3
Final patch
This is the complete example patch assembled from all its components on this page. It produces a Yorplike deadly enemy.
Keen 1
#Re-write the core switch statement.
%patch $161D $4B $83 $FB [$0A] $76 $0A $81 $FB $FE $00 $0F $84 $A0 $00 $E9 $C1
$00 $D1 $E4 $2E $D1 $E3 $2E $FF $A7 {$168AW}
#Combine the ice-launchers
%patch $16B1 $D1 $EB $83 $EB $05 $53
#Locations of jumps to sprite initiation code
%patch $168A {$1656W} #Yorp
{$1661W} #Garg
{$166CW} #Vort
{$1676W} #Butler
{$1680W} #Tank
{$16B1W} #Ice Launcher 1
{$16B1W} #Ice Launcher 2
{$16B1W} #Ice Launcher 3
{$16B1W} #Ice Launcher 4
{$16C1W} #Falling Block
{$0AF2W} #New sprite
#Initiation code
%patch $0AF2 $57 $56 $E8 $0006W $83 $C4 $04 $E9 $0BF2W
#New sprite spawn code
%patch $0AFD $55 $8B $EC $56 $E8 $1E31W $8B $F0 $C7 $04 [$0003W] $8B $46 $04
$99 $B1 $0C $E8 $D63EW $89 $44 $04 $89 $54 $06 $8B $46 $06 $99
$B1 $0C $E8 $D62FW $89 $44 $08 $89 $54 $0A $C7 $44 $34 {$0BFEW}
$C7 $44 $32 {$0B3AW} $C7 $44 $28 [$0030W] $5E $5D $C3
#Sprite walks and randomly searches
%patch $0B3A $55 $8B $EC $56 $83 $3E $42 $82 $00 $75 $15 $E8 $B586W $3B $06
$14 $5B $73 $0C $C7 $06 $52
$82 {$0BA5W} $C7 $06 $4A $82 [$0000W] $83 $3E $40 $82 [$00] {$7E} $08
$C7 $06 $48 $82 [$0034W] $EB $06 $C7 $06 $48 $82 [$0036W] $A1 $35
$51 $B1 [$04] $D3 $E8 $25 [$0001W] $8B $16 $48 $82 $03 $D0 $89 $16
$48 $82 $E8 $128FW $E8 $12CFW $8B $F0 $A9 [$0004W] {$74} $06 $C7
$06 $40 $82 [$FFC4W] $F7 $C6 [$0001W] {$74} $06 $C7 $06 $40 $82 [$003CW]
$5E $5D $C3
#Sprite searching code
%patch $0BA5 $55 $8B $EC $C7 $06 $40 $82 [$0000W] $A1 $35 $51 $B1 [$05] $D3 $E8
$25 [$0003W] $05 [$0030W] $A3 $48 $82 $A1 $4A $82 $03 $06 $14 $5B
$A3 $4A $82 $3D [$00C8W] $7C $29 $A1 $26 $82 $8B $16 $24 $82 $3B
$06 $E0 $6E $7F $10 $7C $06 $3B $16 $DE $6E $73 $08 $C7 $06 $40
$82 [$003CW] $EB $06 $C7 $06 $40 $82 [$FFC4W] $C7 $06 $52 $82 {$0B3AW}
$E8 $2031W $E8 $2071W $5D $C3
#Sprite collision
%patch $0BFE $55 $8B $EC $56 $57 $8B $76 $04 $8B $7E $06 $83 $3D [$0A] {$74} $05
$83 $3D [$0B] {$75} $27 $C7 $44 $2A [$0000W] $C7 $44 $2C [$0002W] $C7
$44 $28 [$003AW] $C7 $44 $32 [$489DW] $C7 $44 $34 [$3360W] $C7 $44
$22 [$FFB0W] $B8 [$0022W] $50 $E8 {$B2BBW} $44 $44 $5F $5E $5D $C3
Alternative patch
This is an alternative patch, that produces a Butler Robot like sprite that uses only one frame of animation (The Icecubes'), moving back and forth. Instead of modified Yorp behavior it uses modified Bot movement. This illustrates how simple it can be to alter the behavior of a new sprite.
Keen 1
#Re-write the core switch statement.
%patch $161D $4B $83 $FB [$0A] $76 $0A $81 $FB $FE $00 $0F $84 $A0 $00 $E9 $C1
$00 $D1 $E4 $2E $D1 $E3 $2E $FF $A7 {$168AW}
#Combine the ice-launchers
%patch $16B1 $D1 $EB $83 $EB $05 $53
#Locations of jumps to sprite initiation code
%patch $168A {$1656W} #Yorp
{$1661W} #Garg
{$166CW} #Vort
{$1676W} #Butler
{$1680W} #Tank
{$16B1W} #Ice Launcher 1
{$16B1W} #Ice Launcher 2
{$16B1W} #Ice Launcher 3
{$16B1W} #Ice Launcher 4
{$16C1W} #Falling Block
{$0AF2W} #New sprite
#Initiation code
%patch $0AF2 $57 $56 $E8 $0006W $83 $C4 $04 $E9 $0BF2W
#New sprite spawn code
%patch $0AFD $55 $8B $EC $56 $E8 $1E31W $8B $F0 $C7 $04 [$0003W] $8B $46 $04
$99 $B1 $0C $E8 $D63EW $89 $44 $04 $89 $54 $06 $8B $46 $06 $99
$B1 $0C $E8 $D62FW $89 $44 $08 $89 $54 $0A $C7 $44 $34 {$0BFEW}
$C7 $44 $32 {$0B3AW} $C7 $44 $28 [$0070W] $5E $5D $C3
#New sprite walks back and forth
%patch $0B3A $55 $8B $EC $56 $83 $3E $40 $82 $00 $7E $08 $C7 $06 $48 $82 [$0070W]
$EB $06 $C7 $06 $48 $82 [$0070W] $A1 $35 $51 $B1 [$05] $D3 $E8
$25 [$0000W] $8B $16 $48 $82 $03 $D0 $89 $16 $48 $82 {$E8 $20C0W}
{$E8 $2100W} $8B $F0 $A9 $02 $00 $75 $1A $A1 $3C $82 $F7 $D8 $D1
$E0 $A3 $3C $82 $C7 $06 $3E $82 [$0000W] $A1 $40 $82 $F7 $D8 $A3
$4C $82 $EB $1A $F7 $C6 $04 $00 $74 $08 $C7 $06 $4C $82 [$FFA6W]
$EB $0C $F7 $C6 $01 $00 $74 $14 $C7 $06 $4C $82 [$005AW] $C7 $06
$52 $82 {$0BB9W} $33 $C0 $A3 $40 $82 $A3 $4A $82 $5E $5D $C3
#New sprite turns
%patch $0BB9 $55 $8B $EC $A1 $4A $82 $03 $06 $14 $5B $A3 $4A $82 $3D [$0032W]
$7E $0C $C7 $06 $52 $82 {$0B3AW} $A1 $4C $82 $A3 $40 $82 $A1 $35
$51 $B1 [$05] $D3 $E8 $25 [$0000W] $05 [$0070W] $A3 $48 $82 {$E8 $2040W}
{$E8 $2080W} $5D $C3
Keen 2 patch
This is an alternative patch, that works for Keen 2. In fact several new sprites can be added using this patch, added before the spawn list at $3B83. Here the new sprite has the unused 'YAWN' sprite image and randomly fires orange and blue shots rightwards.
Keen 2
#Regularized Keen 2 spawning code
%patch $3B35 $81 $FB $00FFW $74 $69 $4B $83 $FB [$07] $76 $03 $E9 $0084W $D1
$E3 $2E $FF $A7 {$3B83W}
%patch $3B4B $57 $56 $E8 $009AW $EB $4D $57 $56 $E8 $00F5W $EB $46
$57 $56 $E8 $0150W $EB $3F $57 $56 $E8 $01ABW $EB $38
$57 $56 $E8 $01E1W $EB $31 $57 $56 $E8 $0221W $EB $2A
$57 $56 $E8 $0262W $EB $23 $57 $56 $E8 $CF71W $EB $1C
%patch $3B83 $3B4BW $3B52W $3B59W $3B60W $3B67W $3B6EW $3B75W $3B7CW
#New sprite spawn, immortal, blocks
%patch $0AF2 $55 $8B $EC $56 $E8 $4C7EW $8B $F0 $C7 $04 [$0007W] $8B $46 $04
$99 $B1 $0C $E8 $CD79W $89 $44 $04 $89 $54 $06 $8B $46 $06 $99
$B1 $0C $E8 $CD6AW $89 $44 $08 $89 $54 $0A $C7 $44 $32 {$0B34W}
$C7 $44 $34 {$4677W} $C7 $44 $28 [$0010W] $C7 $44 $20 [$0049W] $5E
$5D $C3
#New behavior, randomly shoot red and blue shots
%patch $0B34 $55 $8B $EC $56 $E8 $ACABW $8B $16 $5AF0W $D1 $E2 $3B $C2 $73
$38 $E8 $AC9EW $8B $16 $2FC2W $D1 $E2 $3B $C2 $73 $2E $B8 $0026W
$50 $E8 $AAB2W $44 $44 $BE $015EW $56 $A1 $96CAW $8B
$16 $96C8W $81 $C2 $FF00W $15 $FFFFW $50 $52 $FF $36 $96C6W
$FF $36 $96C4W $E8 $6AC3W $83 $C4 $0A $5E $5D $C3 $83 $3E $6028W
$00 $7C $CB $B8 $000CW $50 $E8 $AA7DW $44 $44 $FF $36 $96CAW
$FF $36 $96C8W $FF $36 $96C6W $FF $36 $96C4W $E8 $6876W $83
$C4 $08 $5E $5D $C3
#Change shot collisions to respect new sprite (platform) type
%patch $7677 {$75C5W}
%patch $75BD $83 $3D [$07] $74 $27 $E9 $01B4W
%patch $75C5 $55 $8B $EC $56 $57 $8B $76 $04 $8B $7E $06 $83 $3D $06 $74 $14
$83 $3D $0D $74 $0F $83 $3D $04 $74 $0A $83 $3D [$07] $74 $05 $E9
$0192W $90 $90