Resource centre for ZX Spectrum games
      using Manic Miner and Jet Set Willy game engines

 

Archive of the

Manic Miner & Jet Set Willy Yahoo! Group

messages

 

 

 

Message: 5816

Author: andrewbroad

Date: 24/04/2006

Subject: Harmless guardians: Pokes for JSW

 

--------------------------------------
Method A: The quick and dirty solution
--------------------------------------

The nastiest way to have harmless guardians in Jet Set Willy is...

POKE 37050,58 (Hex 90BA: 3A)

...which modifies the following code...

#90B8: LD A,#FF
#90BA: LD (#85D1),A ; set 'airborne' status to 'dead' (#FF)

...as follows:

#90BA: LD A,(#85D1) ; get 'airborne' status

Guardians still collide (and are only drawn down to the point of
collision), Fire-cells don't kill you, and if you fall too far, you
just disappear and have to reset the game.

-------------------------------------------
Method B: Modify the sprite-drawing routine
-------------------------------------------

The following two POKEs, which must be used together, ...

POKE 37982,0 (Hex 945E: 00)
POKE 37994,0 (Hex 946A: 00)

...modify the sprite-drawing subroutine at #9456 to ignore
collisions. This subroutine has the following preconditions...

* C == 1 if collision is to be enabled, 0 if disabled;
* DE == address of sprite to draw;
* HL == address to draw it to.

...and the following postconditions...

* Zero-flag == set (Z) if no collision occurred - the whole sprite
was drawn;
* Zero-flag == reset (NZ) if a collision occurred - the sprite was
drawn only down to the point of collision.

#9456: LD B,#10 ;;;; 16 pixel-rows to draw
#9458: BIT 0,C ;;;;; (loop starts at #9458) test Bit 0 of C-register
#945A: LD A,(DE) ;;; get pixel-row from sprite's left cell-column
#945B: JR Z,#9461 ;; skip collision-detection if Bit 0 of C is 0
#945D: AND (HL) ;;;; if any pixels collide
#945E: RET NZ ;;;;;; then return with Zero-flag reset (collision!)
#945F: LD A,(DE) ;;; get pixel-row from sprite's left cell-column
#9460: OR (HL) ;;;;; merge sprite's pixels with what's already there
#9461: LD (HL),A ;;; draw pixel-row (left cell-column)
#9462: INC L ;;;;;;; move right by one cell-column
#9463: INC DE ;;;;;; point to next pixel-row in sprite's right column
#9464: BIT 0,C ;;;;; ditto re. sprite's right cell-column...
#9466: LD A,(DE)
#9467: JR Z,#946D
#9469: AND (HL) ;;;; if any pixels collide
#946A: RET NZ ;;;;;; then return with Zero-flag reset (collision!)
#946B: LD A,(DE)
#946C: OR (HL)
#946D: LD (HL),A
#946E: DEC L ;;;;;;; move left by one cell-column
#946F: INC H ;;;;;;; move down by one cell-row
#9470: INC DE ;;;;;; point to next pixel-row in sprite's left column
another>
#9486: DJNZ #9458 ;; repeat until whole sprite drawn
#9488: XOR A ;;;;;;; A:= 0 and set Zero-flag (Z)
#9489: RET ;;;;;;;;; return with Zero-flag set (no collision)

The above two POKEs replace the RET NZ instructions with NOPs, so if
a collision does occur, it is ignored and the whole sprite is drawn.
This means that if Willy walks into a guardian, their pixels are
merged together.

Note that this subroutine is called not only for guardians, but also
for Maria (but not the toilet), Willy's extra lives, the objects on
the Game Over screen, and the colour-code routine. So the above two
POKEs allow Willy to walk through Maria as well as guardians.

-------------------------------------------------------
Method C: Modify calls to the sprite-drawing subroutine
-------------------------------------------------------

For guardians and Maria, the above subroutine is called with C == 1
to enable collision-detection.

So, to disable collision-detection for guardians, we can call it
with C == 0 by using the following POKE...

POKE 37392,0 (Hex 9210: 00)

...which modifies the following code...

#920F: LD C,1 ;;;;;;;; enable collision-detection
#9211: LD A,(IX+1) ;;; A:= animation-mask
#9214: AND (IX+0) ;;;; bitwise-AND it with the current frame-number
#9217: OR (IX+2) ;;;;; bitwise-OR that with the start-sprite
#921A: AND %11100000 ; extract frame-number to be drawn
#921C: LD E,A ;;;;;;;; this forms the low byte of the sprite-address
#921D: LD D,(IX+5) ;;; D:= sprite-page (high byte of sprite-address)
#9220: LD H,#82 ;;;;;; lookup-table at #8200: position -> address
#9222: LD L,(IX+3) ;;; L:= guardian's row (in pixels*2)
#9225: LD A,(IX+2) ;;; A:= start-sprite | cell-column
#9228: AND %00011111 ; extract cell-column
#922A: OR (HL) ;;;;;;; table lookup: (row, column) -> low byte
#922B: INC HL ;;;;;;;; point to next byte in table
#922C: LD H,(HL) ;;;;; table lookup: (row, column) -> high byte
#922D: LD L,A ;;;;;;;; {HL == address to draw sprite}
#922E: CALL #9456 ;;;; call sprite-drawing subroutine

...as follows:

#920F: LD C,0 ;;;;;;;; disable collision-detection

This differs from Method B in that:

(a) it's only one POKE;

(b) it doesn't disable collision-detection for Maria (that can be
done by POKE 38242,0 (Hex 9562: 00));

(c) each guardian-sprite overwrites everything in its 16x16-pixel
square, rather than merging its pixels with what's there already.
This means that each guardian is like a moving portal; thus
stationary guardians can be combined with teleporters to simulate
portals (which are permanently open, regardless of any items in the
room).

--
Dr. Andrew Broad
http://geocities.com/andrewbroad/
http://geocities.com/andrewbroad/spectrum/
http://geocities.com/andrewbroad/spectrum/willy/

 

 

arrowleft
arrowright