From KeenWiki
Jump to: navigation, search

The Dopefish is a large green enemy found in the Well of Wishes in Keen 4. It swims towards Keen and can eat him whole; being the only enemy in the Keen galaxy series that gives Keen a novel death. It is linked to the Schoolfish.

Sprite Type

The Dopefish uses sprite type 21 which is used only by the Dopefish and doesn't affect anything else. When eating Keen it changes his type to 1 so that Keen will not trigger a death event after being eaten (Which just looks odd.)

Patch: Keen 4
#Dopefish sprite types
%patch $120C4 $15
%patch $123FD $01
#What eaten Keen becomes

Sprite Actions

The Dopefish's actions are relatively simple, Dopefish are spawned swimming; this is a 2 action loop that they remain in until they collide with something edible. Chomping is a single frame sequence that lasts as long as needed for the Dopefish to move onto and consume something.

After chomping the Dopefish enters the burping sequence, a four action sequence that ends with the Dopefish returning to swimming again. When burping the Dopefish produces a bubble which floats offscreen.

The Dopefish also produces two unique sprites. The first is an eaten Keen; this is a two action sequence produced when the player is eaten. It ends by losing the level. The second is an eaten ' produced when anything else edible is eaten. This second sprite is tied in with the Schoolfish however, linking the Dopefish and Schoolfish together unless several things are changed.

The eaten Keen action in theory goes to the 'invisible dead' Keen but it doesn't animate. Instead the Dopefish 're-eats' dead Keen converting him into the invisible dead action. The invisible dead action animates to itself, ending the level when it does so.

$35C0W #Dopefish swimming 1
$35DEW #Dopefish swimming 2
$35FCW #Dopefish chomping [Mouth wide open]
$361AW #Dopefish burping 1
$3638W #Dopefish burping 2 (Face screen)
$3656W #Dopefish burping 3
$3674W #Dopefish burping 4
$3692W #Eaten fish
$36B0W #Eaten Keen
$36CEW #Eaten Keen - invisible

Patch: Keen 4
#When spawned
%patch $12112 $35C0W
#Swim loop
%patch $3244C $35DEW %patch $3246A $35C0W
#When bumping into food
%patch $12447 $35FCW
#While chomping - wait
%patch $32488 $0000W
#After food has been chomped
%patch $12286 $361AW
#Burping sequence
%patch $324A6 $3638W %patch $324C4 $3656W %patch $324E2 $3674W %patch $32500 $35C0W
#What other eaten stuff becomes
%patch $123E1 $3692W
%patch $12411 $36B0W
#What eaten Schoolfish does
%patch $3251E $0000W
#What eaten Keen does
%patch $3253C $36CEW
#Dead Keen is re-eaten by Dopefish
%patch $12112 $36CEW
#What to do when re-eaten
%patch $3255A $36CEW

Sprite Behavior

The Dopefish has no less than four behaviors of its own plus one for its bubbles. The first behavior, head towards the player, is used when it swims. This gets it close to Keen. On colliding with something edible the Dopefish goes to chomping which uses its second behavior. This picks an edible sprite and destroys it. If that sprite is Keen, he dies.

After doing this the Dopefish uses its third behavior to produce a big bubble and noise; its 'burp'. After that it uses a special return-to-swimming behavior so that it can seamlessly start swimming again.

The consumed sprites have no behavior except for dead Keen who has a special behavior that kills him without his death sprite appearing. The big bubble uses its own special behavior that lets it float offscreen then vanish. (Preventing a game crash due to excess sprites.)

$11A20700RL #Keen dead invisible
$11A20711RL #Head toward Keen both h and v
$11A2077ARL #Eat something and destroy it
$11A2086ERL #Dopefish return to swimming
$11A20912RL #Produce a big bubble
$11A20974RL #Bubbles

Patch: Keen 4
#Swim, swim
%patch $32440 $11A20711RL
#Float toward Keen
%patch $3245E $11A20711RL
#Float toward Keen
%patch $3247C $11A2077ARL
#Eat something and destroy it
%patch $3249A $00000000L
%patch $324B8 $11A20912RL
#Produce a big bubble
%patch $324D6 $00000000L
%patch $324F4 $11A2086ERL
#Dopefish return to swimming
#Eaten Schoolfish
%patch $32512 $00000000L
#Eaten Keen
%patch $32530 $00000000L
%patch $3254E $11A20700RL
#Keen dead invisible
#Big bubble
%patch $3256C $11A20974RL
%patch $3258A $11A20974RL
%patch $325A8 $11A20974RL
%patch $325C6 $11A20974RL

Seeking Keen

The Dopefish seeks Keen both vertically and horizontally (it swims towards him.) It will also turn to face anything it eats, including Keen.

Patch: Keen seeking
#Seek Keen horizontally
%patch $1214D $0001W %patch $12154 $FFFFW
#Seek Keen vertically
%patch $12177 $0001W %patch $1218B $FFFFW
#When eating something, face it
%patch $1243D $FFFFW
%patch $12444 $0001W

Dopefish still chases Keen horizontally, but moves vertically *away* from him

This patch makes the Dopefish try to be above or below Keen. It works by reversing the vertical seeking so that the Dopefish tries to flee Keen vertically.

Patch: The Dopefish still chases Keen l/r, but moves u/d *away* from him
#Seek Keen vertically - reversed
%patch $12177 $FFFFW %patch $1218B $0001W

Dopefish rise up offscreen when eating

This unusual patch (which may have unintended side effects) causes the Dopefish to rise up and up when trying to eat, eventually leaving the level top. It will still kill Keen however.

Patch: Dopefish rise up offscreen when eating
#Dopefish rise up offscreen when eating
%patch $121AA $80 %patch $12411 $36CEW


The Dopefish's swimming speed is determined entirely by its behavior and not its animation motion. Eaten sprites also do not move in any way.

Patch: Dopefish swimming speed
#Dopefish swimming speeds
%patch $12157 $000AW
%patch $12173 $000AW
%patch $12187 $000AW

Patch: Animation motion
%patch $3243C $0000W $0000W %patch $3245A $0000W $0000W
%patch $32478 $0000W $0000W
%patch $32496 $0000W $0000W %patch $324B4 $0000W $0000W %patch $324D2 $0000W $0000W %patch $324F0 $0000W $0000W
#Eaten Schoolfish
%patch $3250E $0000W $0000W
#Eaten Keen
%patch $3250E $0000W $0000W %patch $3254A $0000W $0000W

Sprite Collision

The Dopefish's collision is responsible for it responding to both Schoolfish and Keen (and also not responding to Keen when he has God mode enabled.) As such it is only used when the Dopefish is swimming. The eaten Schoolfish\Keen have no collision.

Collision values

The Dopefish only has a collision when swimming. This avoids mass chompings. Making the Dopefish chomping use a collision means it will consume fish much faster.

$11A209B0RL #Dopefish: Eat Schoolfish, swim, kill Keen

Patch: Keen 4
%patch $32444 $11A209B0RL
%patch $32462 $11A209B0RL
%patch $32480 $00000000L
#No collision
%patch $3249E $00000000L
#No collision
%patch $324BC $00000000L
#No collision
%patch $324DA $00000000L
#No collision
%patch $324F8 $00000000L
#No collision
#Eaten Schoolfish
%patch $32516 $00000000L
#No collision
#Eaten Keen
%patch $32534 $00000000L
#No collision
%patch $32552 $00000000L
#No collision

Collision code

This is the complete collision code for the Dopefish. It is quite complex. On the first line the Dopefish checks for the Schoolfish to eat it. If found it converts the fish to an eaten fish and goes to burping on line 2. If the fish is not found then it checks for Keen on line 3. If he is found it then checks if God Mode cheat is enabled, if it is then nothing happens. (Keen is safe.) If not then Keen will be eaten.

Still on the third line Keen's sprite type is set to 1 to avoid him 'dying' after being eaten; which would look odd. On line 4 the Dopefish's clipping is set to 0 (to avoid problems with solid tiles when burping.) and sound $0017 is played. On the fifth line Keen's action is changed to being eaten invisible; this will quickly lead to the level being lost.

On line 7 the Dopefish's chomping direction is set, depending on where Keen is it will chomp left or right. (This doesn't happen for the Schoolfish which means a Schoolfish can be eaten despite being by the Dopefish's tail.) On line 8 the Dopefish's action changes to the burping sequence start and on the final line the clipping is again set to 0. (This is duplicate code it appears.)

Patch: Keen 4
#Dopefish collision code
%patch $123D0 $55 $8B $EC $56 $57 $8B $76 $06 $8B $7E $08 $83 $3D $16 $75 $0F $B8 $3692W $50 $57 $9A $09DC120ARL $83 $C4 $04 $EB $34 $83 $3D $02 $75 $64 $83 $3E $C629W $00 $75 $5D $C7 $05 $0001W $C7 $45 $06 $0000W $B8 $0017W $50 $9A $187409F1RL $83 $C4 $02 $B8 $36B0W $50 $57 $9A $09DC120ARL $83 $C4 $04 $EB $04 $5F $5E $5D $CB $8B $44 $0A $89 $44 $40 $8B $44 $0C $89 $44 $42 $89 $7C $44 $8B $45 $2A $3B $44 $2A $73 $07 $C7 $44 $0E $FFFFW $EB $05 $C7 $44 $0E $0001W $B8 $35FCW $50 $56 $9A $09DC120ARL $83 $C4 $04 $C7 $44 $06 $0000W $5F $5E $5D $CB

Don't eat Keen

This patch stops the Dopefish from devouring Keen, in essence making it harmless.

Patch: Dopefish never eats Keen, even without god mode
#Dopefish never eats Keen, even without god mode
%patch $123F9 $EB

Eat Keen even with god mode

This patch lets the Dopefish eat Keen even if he has god mode.

Patch: Dopefish always eats Keen, even with god mode
#Dopefish always eats Keen, even with god mode
%patch $123F9 $90 $90


The Dopefish's animations are quite simple. Notice there are two actions with no animation screen. The first is chomping; where the Dopefish will take as long as it needs to properly chase down an edible sprite. The second action is the last burping action where the Dopefish must re-orient itself to return to swimming. Notice also that the Dopefish's cache contains two frames used not by it itself but by is bubbles.

The eaten Schoolfish uses the same animation as the swimming Schoolfish, it is this that links the two sprites together. Likewise eaten Keen uses the same animation as dead scuba Keen providing another link. (The invisible action is what loses the level however.)

Patch: Keen 5
%patch $306F8 $0194W
#Dopefish Cache start
%patch $30742 $01A4W
#Dopefish cache end
#Dopefish swimming
%patch $32430 $01A2W $0194W %patch $3243A $0014W
#Animation speed
%patch $3244E $01A3W $0195W %patch $32458 $0014W
#Animation speed
#Dopefish chomping
%patch $3246C $01A4W $0196W %patch $32476 $0000W
#Move until touching food
#Dopefish burping
%patch $3248A $01A2W $0194W %patch $32494 $003CW
#Animation speed
%patch $324A8 $0197W $0197W
#Face screen
%patch $324B2 $003CW
#Pause before burp
%patch $324C6 $0198W $0198W %patch $324D0 $003CW
#Pause after burp
%patch $324E4 $01A2W $0194W
#Stop facing screen
%patch $324EE $0000W
#Animation speed
#Dead Schoolfish
%patch $32502 $01A5W $01A7W %patch $3250C $0000W
#Eaten Keen
%patch $32520 $0139W $0139W %patch $3252A $0000W
#Animation speed
%patch $3253E $FFFFW $FFFFW
#Invisible, wait a bit before level restart
%patch $32548 $00B4W
#Animation speed


The Dopefish makes two distinct sounds; one when eating Keen and another when burping. Both can be blocked.

Patch: Keen 4
#Dopefish sounds
%patch $12386 $2A
#Dopefish burp
%patch $12405 $17
#Dopefish eat Keen
#Don't play Dopefish sounds
%patch $12385 $EB $0A
#Don't play Dopefish burp
%patch $12404 $EB $0A
#Don't play Dopefish eat Keen

Sprite positioning

There are a lot of positioning patches relating to the Dopefish due to its large size. The first is its spawn position. This is three tiles higher than its location. The second is the big bubble produced when the Dopefish burps. This is spawned two tiles down and 3.5 tiles right from the top left corner of the Dopefish sprite.

The third patch relates to the Dopefish moving around something it is eating since its facing the screen sprite is a different size to that of its swimming sprites. It will always move 1 tile up towards what it eats. If it is facing left it moves 2 pixels left, if right two pixels right. Finally the Dopefish always turns to face whatever it is going to eat.

Patch: Keen 4
#Spawn height (3 tiles up)
%patch $120E5 $FD00W
#Burp bubble spawn location
%patch $12356 $0200W
%patch $12349 $0380W
#When eating
%patch $121AC $0100W
#Move up 1 tile...
%patch $121CC $0020W
#How far right to go when eating right
%patch $121BE $0020W
#How far left to go when eating left
#When eating something, face it
%patch $1243D $FFFFW
%patch $12444 $0001W

Clipping and foreground

There are remarkably many clipping variables associated with the Dopefish. The first is its default clipping; this is 2, which keeps it out of any tile that is sloped or blocking. (Most swimming sprites use this.) The Dopefish's big bubble, produced when it burps, has no clipping so it can float offscreen. Anything eaten by the Dopefish also gets its clipping removed. Finally the Dopefish itself has no clipping when it is chomping something. This lets it get into odd spots to eat things.

The foreground is much simpler. Dopefish have a value of 2 which makes them appear in front of most sprites and fore tiles (So you don't see anything odd when it eats things.) but behind the 'extra fore' tiles that hide things like items in the level. The Dopefish's bubble uses a value of 3, appearing in front of everything.

Patch: Clipping
#Dopefish clipping
%patch $120D3 $0002W
%patch $1236C $0000W
#Dopefish's big bubble
%patch $12402 $0000W
#Stuff eaten by Dopefish (Keen or Schoolfish)
%patch $12456 $0000W
#Dopefish chomping (No clipping while doing this)

Patch: Foreground
#Dopefish foreground
%patch $120CE $0002W
%patch $12362 $0003W
#Dopefish big bubble

Sprite-tile interaction

The Dopefish has its own unique tile collision when swimming. This allows it to avoid all solid and sloped tiles while still tracking Keen. In all other actions it uses a generic 'ignore solid tiles' collision that is used by many sprites. This includes dead Schoolfish\Keen

Patch: Keen 4
%patch $32448 $11A20A3CRL %patch $32466 $11A20A3CRL
%patch $32484 $09DC176ERL
%patch $324A2 $09DC176ERL %patch $324C0 $09DC176ERL %patch $324DE $09DC176ERL %patch $324FC $09DC176ERL
#Dopefish bubble
%patch $32574 $09DC176ERL %patch $32592 $09DC176ERL %patch $325B0 $09DC176ERL %patch $325CE $09DC176ERL
#Eaten Schoolfish
%patch $3251A $09DC176ERL
#Eaten Keen
%patch $32538 $09DC176ERL %patch $32556 $09DC176ERL

Action type

The Dopefish swims using type 3 actions, allowing it to move smoothly and react quickly. Chomping and the last burping action are type 2 actions since they must move smoothly but wait an indeterminate amount of time for something to happen. All other actions are type 0.

Eaten Keen\Schoolfish use type 2 actions as they must wait an indeterminate amount of time before vanishing. Eaten Keen is the same, though when he turns invisible he uses type 0 so he can wait until his animation timer runs out before losing the level.

Patch: Keen 4
%patch $32434 $0003W %patch $32452 $0003W
%patch $32470 $0002W
%patch $3248E $0000W %patch $324AC $0000W %patch $324CA $0000W %patch $324E8 $0002W
#Eaten Schoolfish
%patch $32606 $0002W
#Eaten Keen
%patch $32524 $0002W %patch $32542 $0000W

Deprotect and stick to ground

Neither the Dopefish nor anything associated with it needs either of these two variables; so they are 0 in all actions. This includes dead Keen\Schoolfish

Patch: Keen 4
%patch $32436 $0000W $0000W %patch $32454 $0000W $0000W
%patch $32472 $0000W $0000W
%patch $32490 $0000W $0000W %patch $324AE $0000W $0000W %patch $324CC $0000W $0000W %patch $324EA $0000W $0000W
#Chomped Schoolfish
%patch $32508 $0000W $0000W
#Chomped Keen
%patch $32526 $0000W $0000W %patch $32544 $0000W $0000W
#Dopefish bubble
%patch $32562 $0000W $0000W %patch $32580 $0000W $0000W %patch $3259E $0000W $0000W %patch $325BC $0000W $0000W

Probability and randomness

The Dopefish's initial direction is random with a 50:50 chance of facing left or right. This has little effect on the Dopefish as it immediately faces Keen and chases him.

Patch: Keen 4
#Spawn left or right frequency
%patch $120F0 $80

Sprite spawn code

In the initiation code notice the two difficulty checks (Allowing three difficulty appearances.) and the Dopefish cache being set ($C7 $06 $CB63W $0001W.)

In the spawning code the last blue highlighted value is the sprite action the sprite uses as it proceeds to act in-level. $C7 $06 $xxxxW sets the clipping, $C7 $06 $xxxxW sets the sprite activity, $C7 $07 $xxxxW sets the sprite type, $C7 $20 $xxxxW sets the foreground value. Finally $D3 $E0 $05 $xxxx is how far down (Or more usually up) the sprite is spawned from where it is placed. This is necessary for sprites that walk on the ground as they can only be placed in the level at multiples of 16 pixels high while their actual height can be anything.

The Dopefish, being so large is placed both horizontally and vertically in the level. It always spawns moving down. There is however randomness in what horizontal direction the Treasure Eater spawns with. A 50:50 probability check is made which causes the Treasure Eater to spawn either facing left ($FFFFW) or right ($0001W; $C7 $47 $0E $xxxxW is the horizontal direction.) The check code is $9A $1D02002ARL $3D $0080W.

A special thing to note is $C7 $02 $0001W which sets the Dopefish's sprite activity to 1 which means it stops 'working' when offscreen.

Patch: Keen 4
#Location of initiation code
%patch $EEA1 $0269W
#Easy Dopefish (At $EB59)
%patch $EF31 $025FW
#Medium Dopefish (At $EB4F)
%patch $EF33 $0255W
#Hard Dopefish (At $EB45
#Dopefish Initiation code
%patch $EB45 $83 $3E $7A6CW $03 $7D $03 $E9 $02AEW $83 $3E $7A6CW $02 $7D $03 $E9 $02A4W $FF $76 $FC $57 $9A $11A20690RL $83 $C4 $04 $C7 $06 $CB63W $0001W $E9 $028FW
#Dopefish spawn code
%patch $120B0 $55 $8B $EC $33 $C0 $50 $9A $06BD1E11RL $83 $C4 $02 $8B $1E $D8 $A7 $C7 $07 $0015W $C7 $47 $02 $0001W $C7 $47 $20 $0002W
#Sprite type = 15, activity = 1, fore = 2
$C7 $47 $06 $0002W $8B $46 $06 $B1 $08 $D3 $E0 $89 $47 $0A $8B
#Clipping = 2
$46 $08 $D3 $E0 $05 $FD00W $89 $47 $0C $9A $1D02002ARL $3D $0080W $7D $0B $8B $1E $D8 $A7 $C7 $47 $0E $0001W $EB $09 $8B $1E $D8 $A7 $C7 $47 $0E $FFFFW $8B $1E $D8 $A7 $C7 $47 $10 $0001W $B8 $35C0W $50 $53 $9A $09DC118CRL $83 $C4 $04 $5D $CB