The PW128 Mid-Game Completion Patch

===================================



The JSW128 version of Party Willy (PW128) uses a special patch whereby both Rooms 33 and 97 behave like "The Bathroom", and both Rooms 35 and 99 behave like "Master Bedroom".



On collecting the 128 items from Part 1, the Part 1 Maria disappears and you can run into the toilet. On falling into the toilet, you are teleported to the start-room of Part 2, with a minute of flashing colours like when you gain an extra life in Manic Miner!



Once you have collected all 256 items, the Part 2 Maria disappears and you can complete the game in the usual way.



In the regular JSW (and JSW128) engine, the code to handle the end-game sequence is arranged as follows:



38196-38275: Master Bedroom routine

38276-38297: Routine to detect the toilet when Willy is running

38298-38343: Routine to draw the toilet



The corresponding code in PW128 is arranged as follows:



38196-38280: Master Bedroom (Part 2) routine (finishes 5 bytes later)

38281-38285: Extended test for "got all items?" (38286-38292 unused)

38293-38343: Routine to draw the Part 2 toilet (starts 5 bytes earlier)



38912-38984: Master Bedroom (Part 1) routine

38985-39036: Routine to detect both toilets when Willy is running

39037-39067: Routine to draw the Part 1 toilet

39068-39075: Subroutine to select sprites for remaining lives



(38912-39423 are spare in JSW128, since the title-screen is stored elsewhere.)



----------------------

Master Bedroom routine

----------------------



In the regular JSW engine, the main routine to handle Master Bedroom is as follows:



38196: LD A,(33824) ; get current room-number

38199: CP 35        ; are you in Master Bedroom?

38201: JR NZ,+95    ; if not then jump to toilet-drawing routine (38298)

38203: LD A,(34271) ; get current game-status

38206: OR A         ; is Status 0? (Status 0: not all items collected yet)

38207: JR NZ,+53    ; if not then jump to bed-detection routine (38262)

38209: LD A,(34251) ; get ticker (which is incremented every time-frame)

38212: AND 2        ; AND 00000010 - Maria's foot moves every two time-frames

38214: RRCA         ;     0000000X

38215: RRCA         ;     X0000000

38216: RRCA         ;     0X000000

38217: RRCA         ;     00X00000 - A is now either 0 or 32

38218: OR 128       ; OR 10000000 - A is either 128 (Sprite 4) or 160 (Sprite 5)

38220: LD E,A

38221: LD A,(34255) ; get Willy's vertical position (YYYYyyy0)

38224: CP 208       ; at row 13?

38226: JR Z,+8      ; if so then jump to 38236 - Willy is at ground-level

38228: LD E,204     ; Sprite 6 (Maria's finger cocked)

38230: CP 204       ; at row 12?

38232: JR NC,+2     ; if >= then jump to 38236 - Willy is on lower ramp-block

38234: LD E,224     ; Sprite 7 (Maria pointing her finger)

38236: LD D,156     ; Maria's sprite-page

38238: LD HL,26734  ; position in pixel-buffer to draw Maria (AT 11,14)

38241: LD C,1       ; Maria will kill you if she pixel-collides

38243: CALL 37974   ; generic guardian-drawing & collision-detection subroutine

38246: JP NZ,37047  ; if collided then flag you as fallen too far so you'll die

38249: LD HL,17733  ; Maria's upper colour-attributes (bright cyan ink)

38252: LD (23918),HL; write them to attribute-buffer (AT 11,14/15)

38255: LD HL,1799   ; Maria's lower colour-attributes (white ink)

38258: LD (23950),HL; write them to attribute-buffer (AT 12,14/15)

38261: RET



The bed-detection routine, which is jumped-to from the above, is as follows:



38262: LD A,(34259) ; get Willy's horizontal position (YYYXXXXX)

38265: AND 1F       ; AND 00011111 - extract the column only

38267: CP 6         ; at column 6?

38269: RET NC       ; if Willy is to the right of column 6 then return

38270: LD A,2

38272: LD (34271),A ; set Status 2 (running-right mode)

38275: RET





In PW128, the Part 2 Master Bedroom is Room 35 ("Jet Set Willy ;->"). The routine to handle it starts by checking whether you are in the Part 1 Master Bedroom, which is Room 99 ("Attributes of Maria (Sharapova)"):



38196: LD A,(33824) ; get current room-number

38199: CP 99        ; are you in Part 1 Master Bedroom?

38201: JP Z,38912   ; if so then jump to Part 1 Master Bedroom routine



It continues with a copy of the regular Master Bedroom routine (38199-38275) in 38204-38280 - i.e. everything is shunted up 5 bytes. The instruction to jump to the toilet-drawing routine (JR NZ,+95) is replaced with JR NZ,+85, because it is ten bytes nearer due to code-relocation.



The routine to handle the Part 1 (mid-game) Master Bedroom is a copy of 38203-38275 in 38912-38984. The colour-attributes of Maria are different in the two parts, as is her sprite-page.



------------------------

Toilet-detection routine

------------------------



In the regular JSW engine, the subroutine to detect when Willy hits the toilet - which is called when Willy is running right (Status 2) - is as follows:



38276: LD A,(33824) ; get current room-number

38279: CP 33        ; are you in The Bathroom?

38281: RET Z        ; if not then return

38282: LD A,(34259) ; get Willy's horizontal position (YYYXXXXX)

38285: CP 188       ; is Willy in column 28, at row 5 or 13?

38287: RET NZ       ; if not then return

38288: XOR A

38289: LD (34251),A ; set ticker to 0

38292: LD A,3

38294: LD (34271),A ; set Status 3 (Willy in toilet)

38297: RET





In PW128, this subroutine is relocated to 38985-39036, and extended to handle both toilets. First of all, the call to the subroutine has to be fixed to accommodate the relocation:



35302: CALL Z,38985



The new toilet-detection routine starts by ascertaining which Bathroom you are in:



38985: LD A,(33824) ; get current room-number

38988: CP 97        ; are you in the Part 1 Bathroom?

38990: JR Z,+19     ; if so then jump to 39011



A copy of 38279-38297 follows in 38992-39010 to handle the Part 2 toilet (in Room 33) in the usual way.



The code to handle the Part 1 toilet (in Room 97) is different. Instead of setting Status 3, it sets Status 0 and teleports you to the start-room of Part 2. So it uses a copy of 38282-38291 in 39011-39020 - which leaves A as 0 - and continues as follows:



39021: LD (34271),A ; set Status 0

39024: LD A,20

39026: LD (33824),A ; set room to 20 (Part 2 start-room)

39029: LD A,255

39031: LD (35253),A



The byte at 35253 is a fossil from Manic Miner, used to control the length of time for which the PAPER-colour cycles by the extra-life routine, which still exists in JSW! POKE 35253,255 (which only works at runtime, BTW) sets it in this mode for well over a JSW-minute!



Finally...



39034: JP 35090



...actually teleports you to Room 20, forcing the room to be drawn at that point. I know it's not a proper return from the subroutine, but what the user don't see, the programmer gets away with! ;-)



----------------------

Toilet-drawing routine

----------------------



In the regular JSW engine, the routine to draw the toilet - which is only jumped-to when you're NOT in Master Bedroom - is as follows:



38298: LD A,(33824) ; get current room-number

38301: CP 33        ; are you in The Bathroom?

38303: RET NZ       ; if not then return

38304: LD A,(34251) ; get ticker

38307: AND 1        ; AND 00000001 - is this an even or odd time-frame?

38309: RRCA         ;     X0000000

38310: RRCA         ;     0X000000

38311: RRCA         ;     00X00000 - A is now either 0 or 32

38312: LD E,A       ; select Sprite 0 or Sprite 1

38313: LD A,(34271) ; get status

38316: CP 3         ; Status 3 (Willy in toilet)?

38318: JR NZ,+2     ; if not then jump to 38322

38320: SET 6,E      ; E is now either 64 (Sprite 2) or 96 (Sprite 3)

38322: LD D,166     ; toilet sprite-page

38324: LD IX,33488  ; index into lookup-table (vertical position of toilet)

38328: LD BC,4124   ; B: 16 pixel-rows to draw; C: column 28

38331: CALL 38504   ; toilet-drawing subroutine

38334: LD HL,1799   ; toilet's colour-attributes (white ink)

38337: LD (23996),HL; write them to attribute-buffer (AT 13,28/29)

38340: LD (24028),HL; write them to attribute-buffer (AT 14,28/29)

38343: RET





In PW128, the routine starts 5 bytes lower in memory because it is 5 bytes longer. It starts by checking whether you are in the Part 1 Bathroom, which is Room 97 ("Where I Ends and II Begins."):



38293: LD A,(33824) ; get current room-number

38296: CP 97        ; are you in Part 1 Bathroom?

38298: JP Z,39037   ; if so then jump to Part 1 toilet-drawing routine



The code from 38301-38343 is the usual code in the usual place.



The routine to handle the Part 1 (mid-game) toilet is a simplified copy of the regular toilet-drawing routine. It need not concern itself with Status 3 (Willy in the toilet), so it simply copies 38304-38312 into 39037-39045 (to select Sprite 0 or 1 only), and copies 38322-38343 into 39046-39067 (to actually draw the toilet). The position and colour-attributes of the toilet are different in the two parts, as is its sprite-page.



----------------

"Got all items?"

----------------



JSW maintains a count of the items collected in 34270, which is always 256 minus the number of items remaining (except when they're all collected, when it goes `up' to 0). Whenever an item is collected, the following code is executed:



37918: LD A,(34270) ; get item-count

37921: INC A

37922: LD (34270),A ; add 1 to item-count

37925: JR NZ,+5     ; if not got all items then jump to 37932

37927: LD A,1

37929: LD (34271),A ; set Status 1 (got all items - Maria will disappear)





But in PW128, we need to set Status 1 when we've got 128 items (so that we can teleport to Part 2), and again when we've got all 256 items. To achieve this, the LD (34270),A instruction is replaced with a call to a subroutine:



37922: CALL 38281



The subroutine (which fits into the cavity left by all the relocation above) applies an AND-mask of 01111111 to the item-count in order that 128 and 256 both appear to the calling routine as 0:



38281: LD (34270),A

38284: AND 127      ; AND 01111111

38286: RET



---------------

Remaining lives

---------------



When JSWED v2.0.3 upgrades a 48K JSW game to JSW128, it checks for my patch for specifying the player's sprite-page in Room-Offset 237 (as documented in _Jet Set Willy: The Lord of the Rings_). If it recognises my patch, it leaves it in instead of applying the JSW128 patch to specify the player's sprite-page.



However, because JSW128 relocates the code which draws the remaining lives, this breaks my patch for drawing the remaining lives - they appear as Willy facing left (because my patch entails swapping the two halves of Sprite-Page 157 so that Willy is treated consistently with horizontal guardians).



Recall from TECHNICA.TXT of JSW:LOTR that I wrote a subroutine to select the sprites for the remaining lives. In PW128, this is located at 39068-39075:



39068: XOR 128      ; select other half of sprite-page

39070: LD E,A

39071: LD A,(33005) ; get Offset 237 for current room

39074: LD D,A       ; use it as the sprite-page for remaining lives

39075: RET



Recall that the call to this subroutine replaces instructions LD E,A and LD D,157 (at 35232-35234 in JSW48). In JSW128 these are located at 60175-60177, so that's where the subroutine-call goes:



60175: CALL 39068

