Advertisement
wallyweek

JSW disassembly

Aug 16th, 2017 (edited)
323
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; Jet Set Willy JSW48 Game Engine Source
  2. ; ======================================
  3. ; JSW Copyright (C) 1984 Matthew Smith & Software Projects
  4.  
  5. ; Commentary Copyright (C) 1985, 2004 J.G.Harston
  6. ;  See http://mdfs.net/Software/JSW/
  7. ; The source is assembleable with ZMac
  8. ;  See http://mdfs.net/Software/Z80/ZMac
  9.  
  10. ; This was originally a commented disassembly, but it became easier to type
  11. ; up as a source file and create the disassembly from it.
  12.  
  13. ; I have typed this up from my disassembly commentary from an 19-year-old
  14. ; exercise book ;) The guardian movement and Willy movement code is not
  15. ; commented as I treated it as "magic" code that did it's job! I'd welcome
  16. ; anyone else's commentary to be inserted, with appropriate credits.
  17.  
  18. ; These flags control assembly of the JGH extensions. Set to 1 to turn
  19. ; them on.
  20. FIXPAUSE1   EQU 0       ; Pause bugfix version 1
  21. FIXPAUSE2   EQU 0       ; Pause bugfix version 2
  22. FIXPAUSE3   EQU 1       ; Pause bugfix version 3
  23. FIXBLOCKS   EQU 1       ; Block graphics bugfix
  24. GAMEEXIT    EQU 1       ; Allow exit from game
  25. MOREROOMS   EQU 1       ; 7-bit rooms
  26. UDTELEPORT  EQU 0       ; Up/Down teleport routine
  27. WALLLEFT    EQU 0       ; Check for wall when moving left
  28. WALLRIGHT   EQU 0       ; Ignore wall when moving right
  29. ROOMSPRITE  EQU 1       ; Room data specifies Willy's sprite?
  30.                     ; Geoff/Broad/Elliot extension
  31.  
  32. ORG &8000               ; Program starts at &8000
  33.  
  34.  
  35. ; Some terminology
  36. ; ================
  37. ; Room
  38. ;   256 bytes of data that define a room and what guardians appear in it.
  39. ; Guardian Instance
  40. ;   2 bytes of data in a room specifying a guardian class and initial
  41. ;   position. Each room can have up to eight guardian instances.
  42. ; Guardian Class
  43. ;   8 bytes of data specifying how a guardian moves, its colours, minimum
  44. ;   and maximum positions and sprite. A JSW game can have up to 127 guardian
  45. ;   classes, numbered 0-126.
  46. ; Sprite
  47. ;   32 byte 16x16pixel 1bpp image. Can be numbered in various ways:
  48. ;   Sprite page/subpage:
  49. ;     sprite address=Page*256+subpage*32
  50. ;   Sprite bank/sprite:
  51. ;     sprite address=&8000+Bank*8192+sprite*32
  52. ;   Sprite Number:
  53. ;     sprite address=&9B00+sprite*32
  54. ; Guardian
  55. ;   The guardian classes for a specific room specified by that room's guardian
  56. ;   instances.
  57. ; With acknowledgements to Andrew Broad, JSWMM posting, 03-Apr-2004.
  58.  
  59.  
  60. ; Guardian Classes
  61. ; ================
  62. ; A guardian class is defined by eight bytes in the guardian table at &A000
  63. ; 0 - b7=Direction, b3-b0=Type
  64. ;  Types are: 0=null, 1=horizontal, 2=vertical, 3=rope,
  65. ;             4=arrow, 5=horizontal, 6=vertical, 7=rope
  66. ; 1 - b7-b4=Animation, b3=BRIGHT, b2-b0=INK
  67. ; 2 - Initial X (from room data)
  68. ; 3 - Initial Y
  69. ; 4 - Speed
  70. ; 5 - Sprite page
  71. ; 6 - Movement Minimum
  72. ; 7 - Movement Maximum
  73.  
  74.  
  75. ; Screen buffers
  76. ; ==============
  77. ; To prevent flicker and give fast screen update, JSW writes to two screen
  78. ; buffers, copying from buffer 1 to buffer 2 before copying buffer 2 to the
  79. ; screen to be displayed.
  80. ; The current room is drawn to buffer 1. On each game tick buffer 1 is
  81. ; copied to buffer 2. The sprites are draw to buffer 2, then buffer 2 is
  82. ; copied to the screen.
  83. SCREEN      EQU &4000       ; Screen
  84. SCREEN2     EQU &6000       ; Screen buffer 2
  85. SCREEN1     EQU &7000       ; Screen buffer 1
  86. ATTR        EQU &5800       ; Attributes
  87. ATTR2       EQU &5C00       ; Attribute buffer 2
  88. ATTR1       EQU &5E00       ; Attribute buffer 1
  89.  
  90.  
  91. ; Program data areas
  92. ; ==================
  93. ATTRS       EQU &9800       ; Startup and status attributes
  94. GUARDIANS   EQU &A000       ; Guardian table
  95. OBJECTS     EQU &A3FF       ; Object table
  96. SPRITES     EQU &AB00       ; Main sprites
  97. ROOMS       EQU &C000       ; Base of room data
  98.  
  99.  
  100. ; Current room buffer
  101. ; ===================
  102. ; On entry to a room its definition is copied here.
  103. ROOM        DEFS    256
  104. NAME        EQU ROOM+&80
  105. BACKGROUND  EQU ROOM+&A0
  106. FLOOR       EQU ROOM+&A9
  107. WALL        EQU ROOM+&B2
  108. NASTY       EQU ROOM+&BB
  109. SLOPE       EQU ROOM+&C4
  110. CONVEYOR    EQU ROOM+&CD
  111. CONV_DIR    EQU ROOM+&D6
  112. CONV_PSN    EQU ROOM+&D7
  113. CONV_NUM    EQU ROOM+&D9
  114. SLOPE_DIR   EQU ROOM+&DA
  115. SLOPE_PSN   EQU ROOM+&DB
  116. SLOPE_NUM   EQU ROOM+&DD
  117. BORDER      EQU ROOM+&DE
  118. OBJECT      EQU ROOM+&E1
  119. LEFT        EQU ROOM+&E9
  120. RIGHT       EQU ROOM+&EA
  121. UP      EQU ROOM+&EB
  122. DOWN        EQU ROOM+&EC
  123. WILLYSP     EQU ROOM+&ED
  124. INSTANCES   EQU ROOM+&F0
  125.  
  126. ; Current room's guardian instance buffer
  127. ; =======================================
  128. ; The eight-byte data for each guardian specified in the current room at
  129. ; &80F0-&80FF is copied here. If you only save the program code from &8200
  130. ; onwards, this terminator will be omitted. Any room with exactly eight
  131. ; guardians then continues using nonexistant guardian data past &8140.
  132. ; This can happen if a room's eighth guardian is a rope, as a rope uses
  133. ; sixteen bytes of guardian data and so will overwrite the terminator.
  134. GUARDIAN    DEFS    64      ; Space for 8 guardian instances
  135.         DEFB    &FF     ; This terminates the guardians
  136.         DEFS    &BF     ; Spare
  137.  
  138.  
  139. ; Pixel-line lookup table
  140. ; =======================
  141. ; The word at (PIXEL+line*2) is the address of the first character cell on
  142. ; pixel line 'line' in the second screen buffer. This makes converting pixel
  143. ; cell coordinates to screen address a lot faster and easier.
  144. PIXEL:      DEFW    &6000,&6100,&6200,&6300,&6400,&6500,&6600,&6700 ; line 0
  145.         DEFW    &6020,&6120,&6220,&6320,&6420,&6520,&6620,&6720 ; line 1
  146.         DEFW    &6040,&6140,&6240,&6340,&6440,&6540,&6640,&6740 ; line 2
  147.         DEFW    &6060,&6160,&6260,&6360,&6460,&6560,&6660,&6760 ; line 3
  148.         DEFW    &6080,&6180,&6280,&6380,&6480,&6580,&6680,&6780 ; line 4
  149.         DEFW    &60A0,&61A0,&62A0,&63A0,&64A0,&65A0,&66A0,&67A0 ; line 5
  150.         DEFW    &60C0,&61C0,&62C0,&63C0,&64C0,&65C0,&66C0,&67C0 ; line 6
  151.         DEFW    &60E0,&61E0,&62E0,&63E0,&64E0,&65E0,&66E0,&67E0 ; line 7
  152.         DEFW    &6800,&6900,&6A00,&6B00,&6C00,&6D00,&6E00,&6F00 ; line 8
  153.         DEFW    &6820,&6920,&6A20,&6B20,&6C20,&6D20,&6E20,&6F20 ; line 9
  154.         DEFW    &6840,&6940,&6A40,&6B40,&6C40,&6D40,&6E40,&6F40 ; line 10
  155.         DEFW    &6860,&6960,&6A60,&6B60,&6C60,&6D60,&6E60,&6F60 ; line 11
  156.         DEFW    &6880,&6980,&6A80,&6B80,&6C80,&6D80,&6E80,&6F80 ; line 12
  157. PIXTOILET:  DEFW    &68A0,&69A0,&6AA0,&6BA0,&6CA0,&6DA0,&6EA0,&6FA0 ; line 13
  158.         DEFW    &68C0,&69C0,&6AC0,&6BC0,&6CC0,&6DC0,&6EC0,&6FC0 ; line 14
  159.         DEFW    &68E0,&69E0,&6AE0,&6BE0,&6CE0,&6DE0,&6EE0,&6FE0 ; line 15
  160.  
  161.  
  162. ; Rope structure table
  163. ; ====================
  164. ROPE:       DEFB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0     ; Rope X offsets
  165.         DEFB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  166.         DEFB    1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2
  167.         DEFB    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
  168.         DEFB    2,2,1,2,2,1,1,2,1,1,2,2,3,2,3,2
  169.         DEFB    3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0
  170.         DEFB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  171.         DEFB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  172.         DEFB    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6     ; Rope Y offsets
  173.         DEFB    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
  174.         DEFB    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
  175.         DEFB    4,6,6,4,6,4,6,4,6,4,4,4,6,4,4,4
  176.         DEFB    4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
  177.         DEFB    4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0
  178.         DEFB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  179.         DEFB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  180.  
  181.  
  182.  
  183. ; Program starts here
  184. ; ===================
  185. START:      DI          ; Disable interupts
  186. IF GAMEEXIT
  187.         LD  SP,&5C00    ; Stack is at &5B00-&5BFF
  188.         JP  GAMESTART   ; Jump to GAMESTART to start
  189.  
  190. ; Check a key to start the game, or exit to Basic
  191. ; ===============================================
  192. ; This is called from the intro screen. If SS-Space is pressed, Basic is
  193. ; re-entered with RAMTOP at &7FFF. Otherwise, Enter/Fire/0 are checked.
  194. L840D:      LD  A,&7F       ; Keyrow 'b'-'spc'
  195.         IN  A,(&FE)     ; Read from keyboard
  196.         AND 3       ; SS-SPC pressed?
  197.         JP  NZ,L96C9    ; No, check Enter
  198.         LD  DE,&7FFF    ; Top of memory
  199.         JP  &0005       ; Jump to NEW_ETC
  200. ;
  201.         DEFB    0,0,0,0,0   ; Spare
  202.         DEFB    0,0,0,0,0   ; Spare
  203. ELSE
  204.         LD  HL,&5BFF        ; Stack is at &5B00-&5BFF
  205.         LD  (HL),GAMESTART / 256    ; Push GAMESTART onto stack
  206.         DEC HL          ; Original pushes PASSCHECK
  207.         LD  (HL),GAMESTART % 256
  208.         LD  SP,&5BFE        ; Set up stack pointer
  209.  
  210. ; The following would scan through memory, but does nothing to it. It could
  211. ; be the remnents of some code decryption. Putting a RET at L840C releases
  212. ; this space for more code. The GameExit patch uses this space.
  213.  
  214. L840C:      SUB A       ; Zero A register
  215.         LD  L,A     ; Set L to zero
  216.         XOR &0A     ; A now equals &0A
  217.         LD  B,A
  218.         INC B       ; B now equals &0B
  219.         LD  H,B     ; H now equals &0B
  220.         RRC H       ; Divide H by 2. HL now equals &0500
  221. L8415:      LD  C,(HL)      ; Get byte from memory
  222.         LD  A,L
  223.         XOR C
  224.         XOR H       ; A=byte EOR (addr low) EOR (addr high)
  225.         LD  (HL),C      ; If this was LD (HL),A then it
  226.         INC HL      ; would store back to memory
  227.         BIT 7,H
  228.         JR  NZ,L8415    ; Loop until loops past &FF
  229.         RET         ; Jump to stacked GAMESTART to start
  230. ENDIF
  231.  
  232. HERE:       DEFB    &00     ; Current room number
  233.  
  234. ; Conveyor stuff
  235. ; --------------
  236. L8421:      DEFB    0,1,0,1,1,3,1,3,2,0,2,0,0,1,2,3
  237.  
  238. ; Bitmaps for triangle characters
  239. ; -------------------------------
  240. L8431:      DEFB    &C0,&F0,&FC,&FF,&FF,&FF,&FF,&FF
  241.         DEFB    &00,&00,&00,&00,&C0,&F0,&FC,&FF
  242.         DEFB    &FF,&FF,&FF,&FF,&FC,&F0,&C0,&00
  243.         DEFB    &FC,&F0,&C0,&00,&00,&00,&00,&00
  244.  
  245.  
  246. ; Program Strings
  247. ; ===============
  248. L8451:      DEFB    "AIR"
  249. MESSAGE:    DEFB    "+++++ Press ENTER to Start +++++"
  250.         DEFB    "  JET SET WILLY by Matthew Smith  "
  251.         DEFB    &7F," 1984 SOFTWARE PROJECTS Ltd "
  252.         DEFB    ". . . . .Guide Willy to collect "
  253.         DEFB    "all the items around the house "
  254.         DEFB    "before Midnight so Maria will let "
  255.         DEFB    "you get to your bed. . . . . . ."
  256.         DEFB    "+++++ Press ENTER to Start +++++"
  257. ITEMS:      DEFB    "Items collected 000 Time 00:00 m"
  258. GAME:       DEFB    "Game"
  259. OVER:       DEFB    "Over"
  260. COLLECTED:  DEFB    "000"
  261. NOWTIME:    DEFB    " 7:00a"    ; Current time
  262. STARTTIME:  DEFB    " 7:00a"    ; Start time
  263.  
  264.  
  265. ; Password code entry prompts
  266. ; ===========================
  267. ; This space is spare if the password code is bypassed
  268. PROMPT1:    DEFB    "Enter Code at grid location     "
  269. PROMPT2:    DEFB    "Sorry, try code at location     "
  270.  
  271.  
  272. ; Game state variables
  273. ; ====================
  274. TICKER:     DEFB    0       ; Game ticker, 1/256th of a JSW minute
  275. LIVES:      DEFB    0       ; Number of lives left
  276. FLASH:      DEFB    0       ; Screen flash counter
  277. KEMPSTON:   DEFB    0       ; Kempston joystick present
  278.  
  279.  
  280. ; Current Willy state
  281. ; ===================
  282. YPOSN:      DEFB    0       ; Willy's Y position
  283. L85D0:      DEFB    0
  284. FALLING:    DEFB    0       ; died/movement/falling state - -1/0/1/2
  285. FRAME:      DEFB    0       ; Willy's animation frame - 0/1/2/3
  286. POSITION:   DEFW    0       ; Willy's position on screen
  287. JUMPING:    DEFB    0       ; jumping
  288. ONROPE:     DEFB    0       ; rope flag - 0=not on a rope
  289.  
  290.  
  291. ; Preserved Willy state
  292. ; =====================
  293. ; On entry to a room, Willy's state is saved here and restored if he dies.
  294. L85D7:      DEFB    0,0,0,0,0,0,0   ; Seven bytes of Willy state
  295.  
  296.  
  297. ; Other variables
  298. ; ===============
  299. REMAIN:     DEFB    0       ; Number of objects to collect.
  300. STATUS:     DEFB    0       ; Game/finished/flee/vomit flag
  301. COUNTDOWN:  DEFB    0       ; Pause countdown timer
  302. MTICK:      DEFB    0       ; Music ticker
  303. MFLAGS:     DEFB    0       ; Sound on/off flags
  304.                     ; b0: 0='h'-'ent' pressed
  305.                     ; b1: 0=play music, 1=no music
  306. TELEPORT:   DEFB    0       ; Number of teleport keys matched
  307.                     ; 10=Teleport ON
  308. TEMP:       DEFB    0       ; Temporary location
  309.  
  310.  
  311. ; Password entry codes
  312. ; ====================
  313. ; Each keypress is encoded in two bytes, only b0-b4 relevant.
  314. ; First byte is the keystate to expect reading 'Q'-'T'.
  315. ; The second byte is the keystate to expect reading 'Y'-'P'.
  316. L85E5:      DEFB    &1F,&1F     ; ----------
  317. L85E7:      DEFB    &1D,&1F     ; -W--------
  318.         DEFB    &17,&1F     ; ---R------
  319.         DEFB    &1F,&1B     ; -------I--
  320.         DEFB    &0F,&1F     ; ----T-----
  321.         DEFB    &1B,&1F     ; --E-------
  322.         DEFB    &0F,&1F     ; ----T-----
  323.         DEFB    &1F,&0F     ; -----Y----
  324.         DEFB    &1F,&1E     ; ---------P
  325.         DEFB    &1B,&1F     ; --E-------
  326.         DEFB    &17,&1F     ; ---R------
  327.  
  328.  
  329. ; Game Music Data
  330. ; ===============
  331. ; Moonlight Sonata is played at the intro screen
  332. MOONLIGHT:  DEFB    &51,&3C,&33,&51,&3C,&33,&51,&3C,&33,&51,&3C,&33
  333.         DEFB    &51,&3C,&33,&51,&3C,&33,&51,&3C,&33,&51,&3C,&33
  334.         DEFB    &4C,&3C,&33,&4C,&3C,&33,&4C,&39,&2D,&4C,&39,&2D
  335.         DEFB    &51,&40,&2D,&51,&3C,&33,&51,&3C,&36,&5B,&40,&36
  336.         DEFB    &66,&51,&3C,&51,&3C,&33,&51,&3C,&33,&28,&3C,&28
  337.         DEFB    &28,&36,&2D,&51,&36,&2D,&51,&36,&2D,&28,&36,&28
  338.         DEFB    &28,&3C,&33,&51,&3C,&33,&26,&3C,&2D,&4C,&3C,&2D
  339.         DEFB    &28,&40,&33,&51,&40,&33,&2D,&40,&36,&20,&40,&36
  340.         DEFB    &3D,&79,&3D,&FF     ; Terminated with &FF
  341.  
  342. ; If I Were A Rich Man is played through the game
  343. RICHMAN:    DEFB    &56,&60,&56,&60,&66,&66,&80,&80,&80,&80,&66,&60
  344.         DEFB    &56,&60,&56,&60,&66,&60,&56,&4C,&48,&4C,&48,&4C
  345.         DEFB    &56,&56,&56,&56,&56,&56,&56,&56,&40,&40,&40,&40
  346.         DEFB    &44,&44,&4C,&4C,&56,&60,&66,&60,&56,&56,&66,&66
  347.         DEFB    &51,&56,&60,&56,&51,&51,&60,&60,&40,&40,&40,&40
  348.         DEFB    &40,&40,&40,&40     ; 64 bytes long, just loops
  349.  
  350.  
  351. ; Copy Protection Password Entry Code
  352. ; ===================================
  353. ; This code space becomes free for other use if the password system is
  354. ; bypassed.
  355. PASSCHECK:  LD  HL,&4000    ; Clear screen
  356.         LD  DE,&4001
  357.         LD  BC,&1AFF
  358.         LD  (HL),&00
  359.         LDIR
  360.         LD  IX,PROMPT1  ; Point to message 1
  361.         CALL    PASSASK     ; Ask for a password
  362.         JP  Z,GAMESTART ; Password ok, enter game
  363.         LD  IX,PROMPT2  ; Point to message 2
  364.         CALL    PASSASK     ; Ask for a password
  365.         JP  Z,GAMESTART ; Password ok, enter game
  366.         JP  &0000       ; Reset
  367.  
  368. ; Ask for a password, displaying the message pointed to by IX
  369. ; -----------------------------------------------------------
  370. PASSASK:    LD  DE,&4800    ; Point to line 8
  371.         LD  C,&20       ; 32 characters
  372.         CALL    PRMESSAGE   ; Print the message
  373.         LD  HL,&4842    ; Column 2, line 10
  374.         LD  DE,&9B00    ; Point to '1' block
  375.         LD  C,&00       ; Ignore collisions
  376.         CALL    DRAWSPRITE  ; Draw the sprite to screen
  377.         LD  HL,&4845    ; Column 5, line 10
  378.         CALL    DRAWSPRITE  ; Draw '2' block
  379.         LD  HL,&4848    ; Column 8, line 10
  380.         CALL    DRAWSPRITE  ; Draw '3' block
  381.         LD  HL,&484B    ; Column 11, line 10
  382.         CALL    DRAWSPRITE  ; Draw '4' block
  383.         LD  HL,&9B80    ; Point to password screen attributes
  384.         LD  DE,&5900    ; Point to screen middle third
  385.         LD  BC,&0080    ; Four lines of attributes
  386.         LDIR            ; Copy attributes to screen
  387.         LD  A,(&5C78)   ; Get FRAMES to seed randomiser
  388.         ADD A,&25
  389.         LD  (&5C78),A   ; Store updated FRAMES for next call
  390.         CP  &B3     ; There are 180 codes. If FRAMES>&B3
  391.         JR  C,L8701     ; reduce by 180.
  392.         SUB &B4
  393. L8701:      LD  L,A     ; Index into passcodes in &9Exx
  394.         LD  H,&9E
  395.         LD  A,(HL)      ; Get passcode
  396.         ADD A,L     ; Add offset to passcode
  397.         LD  (TEMP),A    ; Store in temp location
  398.         LD  C,L     ; Calculate code location
  399.         LD  E,&2F       ; Start at digit '0'-1
  400. L870C:      INC E       ; Increment digit
  401.         LD  A,C
  402.         CP  &12
  403.         JR  C,L8717     ; Jump to ask for passcode
  404.         SUB &12
  405.         LD  C,A
  406.         JR  L870C       ; Loop to manipulate passcode
  407.  
  408. L8717:      LD  A,E     ; Get digit
  409.         LD  DE,&481E    ; Column 30, line 10
  410.         CALL    PRCHAR      ; Print digit
  411.         LD  A,C     ; Get letter offset
  412.         ADD A,&41       ; Add to 'A'
  413.         LD  DE,&481D    ; Coulmn 29, line 10
  414.         CALL    PRCHAR      ; Print letter
  415. L8727:      LD  IX,&5950    ; Point to attributes for 1st block
  416. L872B:      CALL    PASSKEY     ; Get keypress and colour in a block
  417.         INC IX
  418.         INC IX
  419.         INC IX      ; Bump IX up to point to next block
  420.         DEFB    &DD
  421.         LD  A,L     ; LD A,IXL
  422.         CP  &5C     ; Got to nonexistant 5th block?
  423.         JR  NZ,L872B    ; No, loop to get another keypress
  424.         JR  L8727       ; Loop back to 1st block
  425.  
  426. ; Get a passcode keypress
  427. ; -----------------------
  428. PASSKEY:    LD  BC,&F7FE    ; Keyboard row '1'-'5'
  429.         IN  A,(C)       ; Read from keyboard
  430.         AND &0F     ; Keep '1'-'4' only
  431.         CP  &0F     ; No keys pressed?
  432.         JR  NZ,PASSKEY  ; Loop until *no* key pressed
  433. L8747:      LD  B,&BF       ; Keyboard row 'H'-'ent'
  434.         IN  A,(C)       ; Read from keyboard
  435.         BIT 0,A     ; Is 'Enter' pressed?
  436.         JR  NZ,L8785    ; No, jump to look for digit keys
  437.         LD  A,(&5959)   ; Get attribute of 4th block
  438.         AND &7F     ; Lose flash bit
  439.         CP  &07     ; Is it still white ink?
  440.         JR  Z,L8785     ; Jump to keep looking for digit keys
  441.         SUB &08
  442.         AND &18     ; Keep two bits
  443.         RRCA
  444.         RRCA
  445.         RRCA
  446.         LD  C,A
  447.         LD  A,(&5953)   ; Get attribute of 2nd block
  448.         SUB &08
  449.         AND &18     ; Keep two bits
  450.         RLCA
  451.         OR  C
  452.         LD  C,A
  453.         LD  A,(&5956)   ; Get attribute of 3rd block
  454.         SUB &08
  455.         AND &18     ; Keep two bits
  456.         RRCA
  457.         OR  C
  458.         LD  C,A
  459.         LD  A,(&5950)   ; Get attribute of 1st block
  460.         SUB &08
  461.         AND &18     ; Keep two bits
  462.         RLCA
  463.         RLCA
  464.         RLCA
  465.         POP HL      ; Lose return address
  466.         OR  C       ; Clear carry flag
  467.         LD  HL,TEMP     ; Point to temp store
  468.         CP  (HL)        ; Compare with entered passcode
  469.         RET         ; Return Z=Code Matches
  470.  
  471. L8785:      SET 7,(IX+&00)  ; Make current block flashing
  472.         SET 7,(IX+&01)
  473.         SET 7,(IX+&20)
  474.         SET 7,(IX+&21)
  475.         LD  BC,&F7FE    ; Keyboard row '1' to '5'
  476.         IN  A,(C)       ; Read keyboard
  477.         AND &0F     ; Keep '1'-'4'
  478.         LD  E,&08       ; Prepare for blue paper
  479.         CP  &0E     ; '1' pressed?
  480.         JR  Z,L87B5     ; Yes, jump to set
  481.         LD  E,&10       ; Prepare for red paper
  482.         CP  &0D     ; '2' pressed?
  483.         JR  Z,L87B5     ; Yes, jump to set
  484.         LD  E,&18       ; Prepare for magenta paper
  485.         CP  &0B     ; '3' pressed?
  486.         JR  Z,L87B5     ; Yes, jump to set
  487.         LD  E,&20       ; Prepare for green paper
  488.         CP  &07     ; '4' pressed?
  489.         JP  NZ,L8747    ; No, loop back to wait again
  490. L87B5:      LD  (IX+&00),E  ; Set attribute of the current block
  491.         LD  (IX+&01),E
  492.         LD  (IX+&20),E
  493.         LD  (IX+&21),E
  494.         LD  BC,&0018    ; Loop &1800 times
  495. L87C4:      DJNZ    L87C4       ; Slight pause
  496.         DEC C
  497.         JR  NZ,L87C4
  498.         RET
  499.  
  500.  
  501. ; JSW48 Game Engine
  502. ; =================
  503. ; The actual game engine starts at GAMESTART. The code is entered here
  504. ; from the password protection code, or direct from startup if the
  505. ; password scheme is bypassed.
  506.  
  507. ; Introduction screen
  508. ; -------------------
  509. GAMESTART:  XOR A       ; Clear a load of variables
  510.         LD  (KEMPSTON),A    ; Kempston joystick not present
  511.         LD  (MTICK),A   ; Music ticker
  512.         LD  (FLASH),A   ; No screen flash
  513.         LD  (FALLING),A ; Willy's not falling
  514.         LD  (TICKER),A  ; Game ticker counter
  515.         LD  (COUNTDOWN),A   ; Autopause countdown timer
  516.         LD  (STATUS),A  ; Normal gameplay
  517.         LD  A,&07
  518.         LD  (LIVES),A   ; Set lives to 8 minus 1
  519.         LD  A,&D0
  520.         LD  (YPOSN),A   ; Willy's pixel-line coordinate
  521.         LD  A,&21
  522.         LD  (HERE),A    ; Set HERE to 33 - The Bathroom
  523.         LD  HL,&5DB4    ; Put Willy at column 20, line 13
  524.         LD  (POSITION),HL   ; Set Willy's location
  525.         LD  HL,COLLECTED    ; Point to item count
  526.         LD  (HL),&30    ; Initialise to "000"
  527.         INC HL
  528.         LD  (HL),&30
  529.         INC HL
  530.         LD  (HL),&30
  531. IF MOREROOMS
  532.         LD  H,&A6       ; Point to relocated collection flags
  533. ELSE
  534.         LD  H,&A4       ; Point to object collection flags
  535. ENDIF
  536.         LD  A,(OBJECTS) ; Get object count
  537.         LD  L,A
  538.         LD  (REMAIN),A  ; Set 'objects remaining'
  539. L8809:      SET 6,(HL)      ; Clear 'object collected flag'
  540.         INC L
  541.         JR  NZ,L8809    ; Loop for all objects
  542.         LD  HL,MFLAGS
  543.         SET 0,(HL)      ; 'mute' keys not being pressed
  544. L8813:      LD  HL,&4000    ; Point to screen
  545.         LD  DE,&4001
  546.         LD  BC,&17FF
  547.         LD  (HL),&00
  548.         LDIR            ; Clear screen
  549.         LD  HL,ATTRS    ; Point to intro screen attributes
  550.         LD  BC,&0300
  551.         LDIR            ; Copy attributes to screen
  552.         LD  HL,&5A60    ; Point to attributes for line 16
  553.         LD  DE,&5A61
  554.         LD  BC,&001F
  555.         LD  (HL),&46    ; Bright yellow on black
  556.         LDIR            ; Set attributes for line 16
  557.         LD  IX,MESSAGE  ; Point to "Press SPACE..."
  558.         LD  DE,&5060    ; Point to line 16
  559.         LD  C,&20       ; 32 characters to print
  560.         CALL    PRMESSAGE   ; Print the string
  561.         LD  DE,&5800    ; Draw the triangle based on the
  562. L8844:      LD  A,(DE)      ; attributes on the screen
  563.         OR  A
  564.         JR  Z,L888E     ; Black/Black - block
  565.         CP  &D3
  566.         JR  Z,L888E     ; Red/Magenta - block
  567.         CP  &09
  568.         JR  Z,L888E     ; Blue/Blue - block
  569.         CP  &2D
  570.         JR  Z,L888E     ; Cyan/Cyan - block
  571.         CP  &24
  572.         JR  Z,L888E     ; Green/Green - block
  573.         LD  C,&00
  574.         CP  &08
  575.         JR  Z,L8871
  576.         CP  &29
  577.         JR  Z,L8871
  578.         CP  &2C
  579.         JR  Z,L886E
  580.         CP  &05
  581.         JR  Z,L8871
  582.         LD  C,&10
  583.         JR  L8871
  584.  
  585. L886E:      LD  A,&25
  586.         LD  (DE),A
  587. L8871:      LD  A,E
  588.         AND &01
  589.         RLCA
  590.         RLCA
  591.         RLCA
  592.         OR  C
  593.         LD  C,A
  594.         LD  B,&00
  595.         LD  HL,L8431    ; Index into triangle bitmaps
  596.         ADD HL,BC
  597.         PUSH    DE
  598.         BIT 0,D
  599.         LD  D,&40
  600.         JR  Z,L8888
  601.         LD  D,&48
  602. L8888:      LD  B,&08
  603.         CALL    PRMATRIX
  604.         POP DE
  605. L888E:      INC DE      ; Move to next attribute
  606.         LD  A,D     ; Check address high byte
  607.         CP  &5A     ; Got to &5A00 yet?
  608.         JP  NZ,L8844    ; Loop back for whole triangle
  609.  
  610.         LD  BC,&001F    ; Check for kempston joystick
  611.         DI          ; But INTs are already disabled
  612.         XOR A
  613. L889A:      IN  E,(C)       ; Read IN 31
  614.         OR  E
  615.         DJNZ    L889A       ; Loop to read 256 times
  616.         AND &20     ; Check out of range value
  617.         JR  NZ,L88A8    ; If set, no joystick present
  618.         LD  A,&01
  619.         LD  (KEMPSTON),A    ; Set joystick flag
  620. L88A8:      LD  HL,MOONLIGHT    ; Point to intro screen music
  621.         CALL    L96A2       ; Play until keypress
  622.         JP  NZ,L88FC    ; If ENTER/FIRE/0 pressed, start game
  623.         XOR A       ; Set scroll offset to zero
  624.         LD  (TEMP),A    ; Save in temp store
  625. L88B5:      CALL    L8AEB       ; Change screen attributes
  626.         LD  HL,&5A60    ; Ensure line 19 is white ink on
  627.         LD  DE,&5A61    ; blue paper
  628.         LD  BC,&001F
  629.         LD  (HL),&4F
  630.         LDIR
  631.         LD  A,(TEMP)    ; Get scroll offset
  632.         LD  IX,MESSAGE  ; Point to scrolling message
  633.         LD  E,A     ; Pass scroll offset into DE
  634.         LD  D,&00
  635.         ADD IX,DE       ; Add scroll offset into message
  636.         LD  DE,&5060    ; Point to line 19
  637.         LD  C,&20       ; 32 characters
  638.         CALL    PRMESSAGE   ; Print the string
  639.         LD  A,(TEMP)    ; Get scroll offset
  640.         AND &1F     ; Reduce to 0-31
  641.         ADD A,&32       ; Add 50 -> 50-81
  642.         CALL    L96DE       ; Play a note
  643. IF GAMEEXIT
  644.         CALL    L840D       ; Check ENTER/FIRE/SS-SPACE
  645.         DEFB    0,0,0,0,0,0
  646. ELSE
  647.         LD  BC,&AFFE    ; Keyboard row 'h'-'ent'
  648.         IN  A,(C)       ; Read keyboard
  649.         AND &01     ; Keep 'enter'
  650.         CP  &01     ; Is it pressed?
  651. ENDIF
  652.         JR  NZ,L88FC    ; ENTER pressed, enter current room
  653.         LD  A,(TEMP)    ; Get scroll offset
  654.         INC A       ; Increment offset
  655.         CP  &E0     ; End of message yet?
  656.         LD  (TEMP),A    ; Store offset back to temp location
  657.         JR  NZ,L88B5    ; Loop to keep scrolling
  658.         JP  L8813       ; Jump back to play intro music
  659.  
  660.  
  661. ; Play the game
  662. ; =============
  663. ; Before starting the game, the screen is cleared and the clock is set to
  664. ; 7:00am.
  665. L88FC:      LD  HL,STARTTIME    ; Point to start time
  666.         LD  DE,NOWTIME  ; Point to current time
  667.         LD  BC,&0006    ; Six characters
  668.         LDIR            ; Set clock to 7:00am
  669.         LD  HL,ATTRS+512    ; Point to bottom third attributes
  670.         LD  DE,&5A00
  671.         LD  BC,&0100
  672.         LDIR            ; Set attrs of bottom of screen
  673.  
  674.  
  675. ; Play a room
  676. ; ===========
  677. ; Entry here plays the room that is in HERE with Willy's position in
  678. ; POSITION. Any movement between rooms jumps straight back to here.
  679. PLAYROOM:   LD  A,(HERE)    ; Get current room
  680. IF MOREROOMS
  681.         XOR &C0     ; Convert to room data address
  682. ELSE
  683.         OR  &C0     ; Convert to room data address
  684. ENDIF
  685.         LD  H,A     ; Rooms start at &C000
  686.         LD  L,&00
  687.         LD  DE,ROOM     ; Point to room buffer
  688.         LD  BC,&0100    ; A room definition is 256 bytes
  689.         LDIR            ; Copy current room to room buffer
  690. L8922:      LD  IX,INSTANCES    ; Point to this room's guardian data
  691.         LD  DE,GUARDIAN ; Point to expanded guardian data
  692.         LD  A,&08       ; There are a maximum of 8 guardians
  693. L892B:      LD  L,(IX+&00)  ; Get guardian number
  694.         RES 7,L     ; Ensure 0-127
  695.         LD  H,&14       ; Guardian table address DIV &800
  696.         ADD HL,HL
  697.         ADD HL,HL
  698.         ADD HL,HL       ; HL=&A000+guardian*8
  699.         LD  BC,&0002    ; Copy first two bytes of data
  700.         LDIR
  701.         LD  C,(IX+&01)  ; Get guardian info byte
  702.         LD  (HL),C      ; Put into guardian data
  703.         LD  BC,&0006    ; Copy into guardian buffer
  704.         LDIR
  705.         INC IX      ; Move to next guardian entry
  706.         INC IX
  707.         DEC A
  708.         JR  NZ,L892B    ; Loop for eight entries
  709.  
  710.         LD  HL,YPOSN    ; Current Willy state
  711.         LD  DE,L85D7    ; Preserved Willy state
  712.         LD  BC,&0007
  713.         LDIR            ; Preserve current Willy state
  714.         CALL    DRAWROOM    ; Draw room to buffer 1
  715.         LD  HL,&5000
  716.         LD  DE,&5001
  717.         LD  BC,&07FF
  718.         LD  (HL),&00
  719.         LDIR            ; Clear bottom third of screen
  720.         LD  IX,NAME     ; Point to room name
  721.         LD  C,&20       ; 32 characters
  722.         LD  DE,&5000    ; Point to line 16
  723.         CALL    PRMESSAGE   ; Display room name
  724.         LD  IX,ITEMS    ; Point to "Items collected..."
  725.         LD  DE,&5060    ; Point to line 19
  726.         LD  C,&20       ; 32 characters
  727.         CALL    PRMESSAGE   ; Print string
  728.         LD  A,(BORDER)  ; Get border colour
  729.         LD  C,&FE
  730.         OUT (C),A       ; Set border colour
  731.         XOR A
  732.         LD  (ONROPE),A  ; Willy is not on a rope
  733.         JP  ACTION      ; Jump to action loop
  734.  
  735.  
  736. ; Print moving Willies along the bottom of the screen
  737. ; ===================================================
  738. ; One Willy is displayed for each remaining life. The Willies are animated
  739. ; according to the music ticker. If music is turned off the Willies will stand
  740. ; still.
  741. DRAWLIVES:  LD  A,(LIVES)   ; Get number of remaining lives
  742.         LD  HL,&50A0    ; Point to line 21
  743.         OR  A
  744.         RET Z       ; Exit with zero remaining lives
  745.         LD  B,A     ; Loop for remaining lives
  746. L8994:      LD  C,&00       ; Ignore collisions
  747.         PUSH    HL      ; Save registers
  748.         PUSH    BC
  749.         LD  A,(MTICK)   ; Get music ticker
  750.         RLCA
  751.         RLCA
  752.         RLCA            ; Multiply by eight
  753.         AND &60     ; Offset to sprite 0, 1, 2 or 3
  754.         LD  E,A     ; Low byte of sprite address
  755.         LD  D,&9D       ; Willies are in page &9D
  756.         CALL    DRAWSPRITE  ; Draw sprite
  757.         POP BC      ; Restore registers
  758.         POP HL
  759.         INC HL      ; Move to next positon on screen
  760.         INC HL
  761.         DJNZ    L8994       ; Loop for remaining lives
  762.         RET
  763.  
  764.  
  765. ; Action loop
  766. ; ===========
  767. ACTION:     CALL    DRAWLIVES   ; Display remaining lives Willies
  768.         LD  HL,&5E00    ; Point to attribute buffer 1
  769.         LD  DE,&5C00    ; Point to attribute buffer 2
  770.         LD  BC,&0200
  771.         LDIR            ; Copy from attrs buffer 1 to 2
  772.         LD  HL,&7000    ; Point to screen buffer 1
  773.         LD  DE,&6000    ; Point to screen buffer 2
  774.         LD  BC,&1000
  775.         LDIR            ; Copy from screen buffer 1 to 2
  776.         CALL    UPDATEGUARD ; Update guardians
  777.         LD  A,(STATUS)  ;
  778.         CP  &03     ; Is Willy throwing up?
  779.         CALL    NZ,MOVEMENT ; No, move Willy
  780.         LD  A,(YPOSN)   ; Get Willy's position
  781.         CP  &E1     ; Above the top of the screen?
  782.         CALL    NC,GO_UP    ; Go up
  783.         LD  A,(STATUS)  ; Is Willy throwing up?
  784.         CP  &03     ; If not, check what Willy is standing
  785.         CALL    NZ,UPDATEWILLY  ; on and draw him
  786.         LD  A,(STATUS)
  787.         CP  &02     ; Is Willy fleeing?
  788.         CALL    Z,CHKTOILET ; Yes, check if toilet reached yet
  789.         CALL    SPECIAL     ; Draw Maira and Toilet if needed
  790.         CALL    DRAWGUARD   ; Draw guardians to buffer 2
  791.         CALL    UPDATECONV  ; Update conveyors in buffer 2
  792.         CALL    CHKOBJECTS  ; Draw objects to buffer 2
  793. L89F5:      LD  HL,&6000    ; Point to screen 2
  794.         LD  DE,&4000    ; Point to displayed screen
  795.         LD  BC,&1000
  796.         LDIR            ; Copy screen buffer 2 to screen
  797.         LD  A,(STATUS)
  798.         AND &02     ; Keep flee/vomit bit
  799.         RRCA            ; Move to bit 0
  800.         LD  HL,FRAME    ; Willy's animation frame
  801.         OR  (HL)        ; Merge vomit bit into frame
  802.         LD  (HL),A      ; Only frames 2 and 3 if vomiting
  803.  
  804. ; The following code flashes the PAPER over the whole of the top two thirds
  805. ; of the screen from white down to black, if FLASH is nonzero. This appears
  806. ; to be a left-over from Manic Miner. [???]
  807.  
  808.         LD  A,(FLASH)   ; Get screen flash counter
  809.         OR  A       ; Is it zero?
  810.         JR  Z,L8A26     ; No screen flash, jump past
  811.         DEC A       ; Decrease flash counter
  812.         LD  (FLASH),A
  813.         RLCA            ; Move up into PAPER
  814.         RLCA
  815.         RLCA
  816.         AND &38     ; Set PAPER with black INK
  817.         LD  HL,&5C00
  818.         LD  DE,&5C01
  819.         LD  BC,&01FF
  820.         LD  (HL),A      ; Set first attribute in buffer 2
  821.         LDIR            ; Set all attributes
  822. L8A26:      LD  HL,&5C00    ; Point to attribute buffer 2
  823.         LD  DE,&5800    ; Point to displayed attributes
  824.         LD  BC,&0200
  825.         LDIR            ; Copy attrs from buffer 2 to screen
  826.         LD  IX,NOWTIME  ; Point to current time
  827.         LD  DE,&5079    ; Point to line 19, column 25
  828.         LD  C,&06       ; "xx:xx?m"=six characters
  829.         CALL    PRMESSAGE   ; Display clock
  830.         LD  IX,COLLECTED    ; Point to items collected string
  831.         LD  DE,&5070    ; Point to line 19, column 16
  832.         LD  C,&03       ; "xxx"=three characters
  833.         CALL    PRMESSAGE   ; Display collected items count
  834.  
  835. ; Update JSW clock
  836. ; ----------------
  837. ; JSW runs 256 ticks of the TICKER variable per JSW minute. One JSW minute
  838. ; equals about 15 real seconds, so the JSW clock runs about four times faster
  839. ; than reality.
  840.         LD  A,(TICKER)  ; Get TICKER
  841.         INC A       ; Increment TICKER
  842.         LD  (TICKER),A  ; Store updated TICKER
  843.         JR  NZ,L8AAB    ; TICKER<>0, so jump forward
  844.         LD  IX,NOWTIME  ; Point to displayed clock to update
  845.         INC (IX+&04)    ; Increment minutes units
  846.         LD  A,(IX+&04)  ; Get minutes units
  847.         CP  &3A     ; Overflowed past '9'?
  848.         JR  NZ,L8AAB    ; No, jump to continue
  849.         LD  (IX+&04),&30    ; Reset minutes units to '0'
  850.         INC (IX+&03)    ; Increment minutes tens digit
  851.         LD  A,(IX+&03)  ; Get minutes tens digit
  852.         CP  &36     ; Overflowed past '5'?
  853.         JR  NZ,L8AAB    ; No, jump to continue
  854.         LD  (IX+&03),&30    ; Reset minutes tens digit to '0'
  855.         LD  A,(IX+&00)  ; Get Hours tens digit
  856.         CP  &31     ; Is it '1'?
  857.         JR  NZ,L8A99    ; No, jump to update hours<10
  858.         INC (IX+&01)    ; Increment hours units digit
  859.         LD  A,(IX+&01)  ; Get hours unit digit
  860.         CP  &33     ; Overflowed past '2' (ie '12')?
  861.         JR  NZ,L8AAB    ; No, jump to continue
  862.         LD  A,(IX+&05)  ; Get 'am' or 'pm' character
  863.         CP  &70     ; Is is 'p' for 'pm'?
  864.         JP  Z,GAMESTART ; Yes -> midnight -> quit game
  865.         LD  (IX+&00),&20    ; ' ' - set to "1:00pm"
  866.         LD  (IX+&01),&31    ; '1'
  867.         LD  (IX+&05),&70    ; 'p'
  868.         JR  L8AAB       ; Jump to continue
  869. L8A99:      INC (IX+&01)    ; Update hours unit digit
  870.         LD  A,(IX+&01)  ; Get hours unit digit
  871.         CP  &3A     ; Overflowed past '9'?
  872.         JR  NZ,L8AAB    ; No, jump to continue
  873.         LD  (IX+&01),&30    ; Set hours to '10'
  874.         LD  (IX+&00),&31
  875.  
  876. L8AAB:      LD  BC,&FEFE    ; Keyboard row 'b'-'spc'
  877.         IN  A,(C)       ; Read from keyboard
  878.         LD  E,A     ; Save result in E
  879.         LD  B,&7F       ; Keyboard row 'sht'-'v'
  880.         IN  A,(C)       ; Read from keyboard
  881.         OR  E       ; Merge both rows
  882.         AND &01     ; Keep Shift+Space
  883.         JP  Z,GAMESTART ; If pressed, go back to intro
  884. L8ABB:      LD  A,(COUNTDOWN)
  885.         INC A
  886.         LD  (COUNTDOWN),A   ; Update autopause counter
  887.         JR  Z,L8AD1
  888.         LD  B,&FD
  889.         IN  A,(C)
  890.         AND &1F
  891.         CP  &1F
  892.         JR  Z,L8B17
  893.         LD  DE,&0000
  894. L8AD1:      LD  B,&02       ; Pause loop
  895.         IN  A,(C)
  896.         AND &1F
  897.         CP  &1F
  898.         JR  NZ,L8B07
  899.         INC E
  900.         JR  NZ,L8AD1
  901.         INC D
  902.         JR  NZ,L8AD1
  903.         LD  A,(TELEPORT)    ; Get teleport flag
  904.         CP  &0A     ; Is teleport on?
  905.         CALL    NZ,L8AEB    ; No, change background colours
  906.         JR  L8AD1       ; Loop to keep pausing
  907.  
  908. ; Change background colours while paused
  909. ; --------------------------------------
  910. ; While paused all the INKs on the screen change by have 3 added, and all the
  911. ; PAPERs have 1 added, and the border is set to the INK of the first character
  912. ; on screen.
  913. L8AEB:      LD  HL,&5800    ; Point to displayed attributes
  914.         LD  A,(HL)      ;
  915.         AND &07     ; Keep INK
  916.         OUT (&FE),A     ; Set border colour
  917. L8AF3:      LD  A,(HL)      ; Get attribute
  918.         ADD A,&03       ; Cycle INK by 3
  919.         AND &07
  920.         LD  D,A
  921.         LD  A,(HL)      ; Get attribute again
  922.         ADD A,&18       ; Cycle PAPER by 1
  923.         AND &B8
  924.         OR  D       ; Mask in updated INK
  925.         LD  (HL),A      ; Store back to attributes
  926.         INC HL      ; Move to next character cell
  927.         LD  A,H     ; Loop for all 24 lines. Fix PAUSE
  928.                     ; bug by changing this to CP &5A
  929. IF FIXPAUSE1
  930.         CP  &5A     ; Loop for top two thirds attributes
  931. ELSE
  932.         CP  &5B
  933. ENDIF
  934.         JR  NZ,L8AF3    ; Loop for all attributes
  935.         RET
  936.  
  937. L8B07:      LD  HL,ATTRS+512    ; Point to attrs for lower screen
  938.         LD  DE,&5A00    ; Point to lower screen
  939.         LD  BC,&0100    ; Copy 256 bytes to screen
  940.  
  941. ; This is where the PAUSE bug appears. C now holds &00 and will still hold
  942. ; &00 after the following LDIR. The IN (C) instruction at &8B24 assumes
  943. ; that C holds &FE. This results in an IN 0 which crashes the Interface 1.
  944. ; If the attribute-changing routine at &8AEB doesn't change the bottom of
  945. ; the screen, then this LDIR is not needed and can be changed to LD C,&FE
  946. ; instead.
  947.  
  948. IF FIXPAUSE1
  949.         LD  C,&FE       ; Restore keyboard i/o port
  950. ELSE
  951.         LDIR            ; Change to LD C,&FE to fix PAUSE bug
  952. ENDIF
  953.         LD  A,(BORDER)  ; Get border colour
  954.         OUT (&FE),A     ; Set border
  955. L8B17:      LD  A,(FALLING) ; Get flag
  956.  
  957. ; An alternate pause fix is to crunch the following code down to release
  958. ; a spare byte to replace the LD B,&BF with LD BC,&BFFE.
  959.  
  960. IF FIXPAUSE2
  961.         INC A       ; &FF->&00?
  962.         JP  Z,LOSTLIFE  ; Lost a life
  963.         LD  BC,&BFFE    ; 'h'-'enter'
  964.         LD  HL,MFLAGS
  965.         IN  A,(C)       ; Read keyboard row
  966. ENDIF
  967.  
  968. ; Another alternative is to read from port &FE directly instead of using
  969. ; the zeroed BC register.
  970.  
  971. IF FIXPAUSE3
  972.         CP  &FF     ; &FF?
  973.         JP  Z,LOSTLIFE  ; Lost a life
  974.         LD  A,&BF       ; 'h'-'enter'
  975.         LD  HL,MFLAGS
  976.         IN  A,(&FE)     ; Read keyboard row
  977. ENDIF
  978.  
  979. IF FIXPAUSE1+FIXPAUSE2+FIXPAUSE3=0
  980.         CP  &FF     ; &FF?
  981.         JP  Z,LOSTLIFE  ; Lost a life
  982.         LD  B,&BF       ; 'h'-'enter'
  983.         LD  HL,MFLAGS
  984.         IN  A,(BC)      ; Read keyboard row
  985. ENDIF
  986.  
  987.         AND &1F     ; Keep keys
  988.         CP  &1F     ; Are any keys pressed?
  989.         JR  Z,L8B36     ; No key pressed, jump ...
  990.         BIT 0,(HL)
  991.         JR  NZ,L8B38
  992.         LD  A,(HL)
  993.         XOR &03
  994.         LD  (HL),A
  995.         JR  L8B38
  996.  
  997. L8B36:      RES 0,(HL)
  998. L8B38:      BIT 1,(HL)      ; Is music enabled?
  999.         JR  NZ,L8B70    ; No, jump to check teleport
  1000.         XOR A
  1001.         LD  (COUNTDOWN),A
  1002.         LD  A,(MTICK)   ; Increment music ticker
  1003.         INC A
  1004.         LD  (MTICK),A
  1005.  
  1006. ; Play in-game music
  1007. ; -----------------
  1008.         AND &7E     ; Lose bit 7 & bit 0
  1009.         RRCA            ; Divide by 2 -> A=0..63
  1010.         LD  E,A     ; Pass to DE. A new note is played
  1011. L8B4B:      LD  D,&00       ; every two game ticks.
  1012.         LD  HL,RICHMAN  ; Point to in-game music
  1013.         ADD HL,DE       ; Point to current note
  1014.         LD  A,(LIVES)   ; Get number of remaining lives
  1015.         RLCA            ; Note gets lower with fewer lives
  1016.         RLCA            ; Lives*4
  1017.         SUB &1C     ; Lives*4-&1C
  1018.         NEG         ; &1C-lives*4 -> 0..28
  1019.         ADD A,(HL)      ; Add to current note
  1020.         LD  D,A     ; Save current note in D
  1021.         LD  A,(BORDER)  ; Get border colour
  1022.         LD  E,D     ; Initialise E with current note
  1023.         LD  BC,&0003
  1024. L8B63:      OUT (&FE),A     ; Set buzzer state
  1025.         DEC E
  1026.         JR  NZ,L8B6B    ; Loop for note delay
  1027.         LD  E,D     ; Reinitialise E with current note
  1028.         XOR &18     ; Toggle buzzer state
  1029. L8B6B:      DJNZ    L8B63       ; Loop 256 times with this note
  1030.         DEC C
  1031.         JR  NZ,L8B63    ; Loop 768 times with this note
  1032.  
  1033. ; Check for teleport jump
  1034. ; -----------------------
  1035. L8B70:      LD  BC,&EFFE    ; Keyrow '6'-'0'
  1036.         IN  A,(C)       ; Read keyboard
  1037.         BIT 1,A     ; Is '9' pressed?
  1038.         JP  NZ,L8B97    ; No, jump to check for password
  1039.         AND &10     ; Keep '6' keypress
  1040.         XOR &10     ; Flip bit
  1041.         RLCA            ; Move '6' up to bit 5
  1042.         LD  D,A     ; Save in D for later
  1043.         LD  A,(TELEPORT)    ; Get teleport state
  1044.         CP  &0A     ; Is teleport on?
  1045.         JP  NZ,L8B97    ; No, jump to check for password
  1046.         LD  BC,&F7FE    ; Keyrow '1'-'5'
  1047.         IN  A,(C)       ; Read keyboard
  1048.         CPL         ; Flip bits
  1049.         AND &1F     ; Keep '1'-'5'
  1050.         OR  D       ; Merge bit 5 in from earlier
  1051.         LD  (HERE),A    ; Store as current room
  1052.         JP  PLAYROOM    ; And jump to enter it
  1053.  
  1054. ; Check for teleport password entry
  1055. ; ---------------------------------
  1056. L8B97:      LD  A,(TELEPORT)    ; Get teleport state
  1057.         CP  &0A     ; Is teleport already on?
  1058.         JP  Z,ACTION    ; Yes, go back to action loop
  1059.         LD  A,(HERE)    ; Are we in room 28?
  1060.         CP  &1C     ; (The Main Landing)
  1061.         JP  NZ,ACTION   ; No, go back to action loop
  1062.         LD  A,(YPOSN)   ; Get Willy's pixel-line position
  1063.         CP  &D0     ; Are we on the floor?
  1064.         JP  NZ,ACTION   ; No, go back to action loop
  1065.         LD  A,(TELEPORT)    ; Get teleport state
  1066.         RLCA            ; Double it to index into keycodes
  1067.         LD  E,A
  1068.         LD  D,&00
  1069.         LD  IX,L85E7    ; Add to keycodes base
  1070.         ADD IX,DE       ; IX=>next keycode to expect
  1071.         LD  BC,&FBFE    ; Keyrow 'Q'-'T'
  1072.         IN  A,(C)       ; Read from keyboard
  1073.         AND &1F     ; Keep keys
  1074.         CP  (IX+&00)    ; Does it match expected keystate?
  1075.         JR  Z,L8BDA     ; Yes, jump to check other half-row
  1076.         CP  &1F     ; Are no keys pressed?
  1077.         JP  Z,ACTION    ; Yes, return to action loop
  1078.         CP  (IX-&02)    ; Does it match previous keystate?
  1079.         JP  Z,ACTION    ; Yes, return to action loop
  1080.         XOR A       ; Otherwise, reset teleport state
  1081.         LD  (TELEPORT),A
  1082.         JP  ACTION      ; Return to action loop
  1083.  
  1084. L8BDA:      LD  B,&DF       ; Keyrow 'Y'-'P'
  1085.         IN  A,(C)       ; Read keyboard
  1086.         AND &1F     ; Keep keys
  1087.         CP  (IX+&01)    ; Does it match expected keystate?
  1088.         JR  Z,L8BF7     ; Yes, jump to update teleport state
  1089.         CP  &1F     ; Are no keys pressed?
  1090.         JP  Z,ACTION    ; Yes, return to action loop
  1091.         CP  (IX-&01)    ; Does it match previous keystate?
  1092.         JP  Z,ACTION    ; Yes, return to action loop
  1093.         XOR A       ; Otherwise, resetl teleport state
  1094.         LD  (TELEPORT),A
  1095.         JP  ACTION      ; Return to action loop
  1096.  
  1097. L8BF7:      LD  A,(TELEPORT)    ; Get teleport state
  1098.         INC A       ; One more keypress has been matched
  1099.         LD  (TELEPORT),A    ; Update teleport state
  1100.         JP  ACTION      ; Return to action loop
  1101.  
  1102.  
  1103. ; Lost a life
  1104. ; ===========
  1105. ; When Willy dies the screen colours cycle from white on black to black
  1106. ; on black, with a squeeking sound. If there are no lives remaining, the
  1107. ; game ends. Otherwise, Willy's state is restored to when he entered the
  1108. ; room and the room is re-entered.
  1109. LOSTLIFE:   LD  A,&47       ; White INK on black PAPER
  1110. L8C03:      LD  HL,&5800    ; Point to start of attributes
  1111.         LD  DE,&5801
  1112.         LD  BC,&01FF    ; Top two thirds of screen
  1113.         LD  (HL),A      ; Set first attribute
  1114.         LDIR            ; Set all attributes
  1115.         LD  E,A     ; Save current attributes in E
  1116.         CPL         ; Flip all bits
  1117.         AND &07     ; Keep INK
  1118.         RLCA            ; Move up three bits
  1119.         RLCA
  1120.         RLCA            ; Buzzer pause is 8*(7-old INK)
  1121.         OR  &07     ; Set INK to white
  1122.         LD  D,A     ; Save in D
  1123.         LD  C,E     ; Copy old attributes to C
  1124.         RRC C       ; Move down three bits
  1125.         RRC C
  1126.         RRC C       ; Buzzer delay in C is old PAPER
  1127.         OR  &10     ; Superfluous instruction?
  1128.         XOR A       ; Clear A
  1129. L8C23:      OUT (&FE),A     ; Set border and buzzer
  1130.         XOR &18     ; Flip buzzer state
  1131.         LD  B,D     ;
  1132. L8C28:      DJNZ    L8C28       ; Pause according to INK value
  1133.         DEC C       ; Loop according to PAPER value
  1134.         JR  NZ,L8C23    ; Loop to make sound
  1135.         LD  A,E     ; Get saved attributes
  1136.         DEC A       ; Decrease attribute
  1137.         CP  &3F     ; Wrapped past black on black?
  1138.         JR  NZ,L8C03    ; Loop to cycles through colours
  1139.         LD  HL,LIVES
  1140.         LD  A,(HL)      ; Get remaining lives
  1141.         OR  A       ; No remaining lives?
  1142.         JP  Z,GAMEOVER  ; None left - Game Over
  1143.         DEC (HL)        ; Decrease remaining lives
  1144.         LD  HL,L85D7    ; Point to saved Willy state
  1145.         LD  DE,YPOSN    ; Point to current Willy state
  1146.         LD  BC,&0007    ; 7 bytes in total
  1147.         LDIR            ; Restore Willy state
  1148.         JP  PLAYROOM    ; Jump to reenter current room
  1149.  
  1150.  
  1151. ; Game Over
  1152. ; =========
  1153. ; Willy has died and has no lives remaining. Clear the top of the screen and
  1154. ; drop the foot onto Willy standing on the barrel.
  1155. GAMEOVER:   LD  HL,&4000    ; Point to screen
  1156.         LD  DE,&4001
  1157.         LD  BC,&0FFF
  1158.         LD  (HL),&00    ; Clear first byte
  1159.         LDIR            ; Clear top two thirds of screen
  1160.         XOR A       ; TEMP holds pixel-line*2
  1161.         LD  (TEMP),A    ; Start at pixel-line 0
  1162.         LD  DE,&9D40    ; Point to a Willy sprite
  1163.         LD  HL,&488F    ; Point to line 12, column 15
  1164.         LD  C,&00       ; Ignore collisions
  1165.         CALL    DRAWSPRITE  ; Draw Willy to screen
  1166.         LD  DE,&9C60    ; Point to barrel sprite
  1167.         LD  HL,&48CF    ; Point to line 14, column 15
  1168.         LD  C,&00       ; Ignore collisions
  1169.         CALL    DRAWSPRITE  ; Draw barrel to screen
  1170.  
  1171. ; Now loop to draw the foot descending above Willy. As the foot descends it
  1172. ; leaves two lines of pixels that generates the leg.
  1173.  
  1174. L8C71:      LD  A,(TEMP)    ; Get pixel-line*2
  1175.         LD  C,A     ; Look up screen address
  1176.         LD  B,PIXEL / 256   ; BC=>
  1177.         LD  A,(BC)      ; Get low byte of pixel-line address
  1178.         OR  &0F     ; Set to column 15
  1179.         LD  L,A     ; Store in L
  1180.         INC BC      ; Point to high byte of address
  1181.         LD  A,(BC)      ; Get high byte of pixel-line address
  1182.         SUB &20     ; Convert address from buffer 2 to
  1183.         LD  H,A     ;  screen address and store in H
  1184.                     ; HL now points to pixel-line in TEMP,
  1185.                     ;  column 15 on the displayed screen
  1186.         LD  DE,&9C40    ; Point to foot sprite
  1187.         LD  C,&00       ; Ignore collisions
  1188.         CALL    DRAWSPRITE  ; Draw foot to screen
  1189.         LD  A,(TEMP)    ; Get pixel-line to generate sound
  1190.         CPL         ; Delay gets shorter as foot decends
  1191.                     ; So, pitch gets higher
  1192.         LD  E,A     ; Set buzzer delay
  1193.         XOR A       ; Clear initial buzzer state
  1194.         LD  BC,&0040    ; Toggle buzzer 64 times
  1195. L8C91:      OUT  (&FE),A        ; Output to buzzer
  1196.         XOR &18     ; Toggle buzzer state
  1197.         LD  B,E     ; Get delay value
  1198. L8C96:      DJNZ    L8C96       ; Delay according to foot height
  1199.         DEC C
  1200.         JR  NZ,L8C91    ; Loop to toggle buzzer
  1201.         LD  HL,&5800    ; Point to attributes
  1202.         LD  DE,&5801
  1203.         LD  BC,&01FF    ; Top two thirds of screen
  1204.         LD  A,(TEMP)    ; Get pixel-line to generate colour
  1205.         AND &0C     ; Keep b2-b3
  1206.         RLCA            ; Move up to PAPER
  1207.         OR  &47     ; Ensure bright white INK
  1208.         LD  (HL),A      ; Set first attribute
  1209.         LDIR            ; Copy to top two thirds of screen
  1210.         AND &FA     ; Lose INK
  1211.         OR  &02     ; Set INK to red
  1212.         LD  (&59CF),A   ; Set attributes for barrel
  1213.         LD  (&59D0),A
  1214.         LD  (&59EF),A
  1215.         LD  (&59F0),A
  1216.         LD  A,(TEMP)    ; Get pixel-line
  1217.         ADD A,&04       ; Move down two lines
  1218.         LD  (TEMP),A    ; Store pixel-line
  1219.         CP  &C4     ; Has foot got past pixel-line 192?
  1220.         JR  NZ,L8C71    ; Loop until foot reaches barrel
  1221.  
  1222.         LD  IX,GAME     ; Point to "Game"
  1223.         LD  C,&04       ; 4 characters
  1224.         LD  DE,&40CA    ; Line 6, column 10
  1225.         CALL    PRMESSAGE   ; Print the message
  1226.         LD  IX,OVER     ; Point to "Over"
  1227.         LD  C,&04       ; 4 characters
  1228.         LD  DE,&40D2    ; Line 6, column 18
  1229.         CALL    PRMESSAGE   ; Print the message
  1230.                     ; Print "Game Over" and wobble the colours
  1231.         LD  BC,&0000    ; C=initial colour, B=initial loop counter
  1232.         LD  D,&06       ; Loop 6*256 times
  1233. L8CE8:      DJNZ    L8CE8       ; Pause for 256 loops
  1234.         LD  A,C     ; Get current colour
  1235.         AND &07     ; Keep INK
  1236.         OR  &40     ; Ensure BRIGHT
  1237.         LD  (&58CA),A   ; Set attribute of "G"
  1238.         INC A       ; Increment INK
  1239.         AND &07     ; Ensure black PAPER
  1240.         OR  &40     ; Ensure BRIGHT
  1241.         LD  (&58CB),A   ; Set attribute of "a"
  1242.         INC A       ; Increment INK
  1243.         AND &07     ; Ensure black PAPER
  1244.         OR  &40     ; Ensure BRIGHT
  1245.         LD  (&58CC),A   ; Set attribute of "m"
  1246.         INC A       ; Increment INK
  1247.         AND &07     ; Ensure black PAPER
  1248.         OR  &40     ; Ensure BRIGHT
  1249.         LD  (&58CD),A   ; Set attribute of "e"
  1250.         INC A       ; Increment INK
  1251.         AND &07     ; Ensure black PAPER
  1252.         OR  &40     ; Ensure BRIGHT
  1253.         LD  (&58D2),A   ; Set attribute of "O"
  1254.         INC A       ; Increment INK
  1255.         AND &07     ; Ensure black PAPER
  1256.         OR  &40     ; Ensure BRIGHT
  1257.         LD  (&58D3),A   ; Set attribute of "v"
  1258.         INC A       ; Increment INK
  1259.         AND &07     ; Ensure black PAPER
  1260.         OR  &40     ; Ensure BRIGHT
  1261.         LD  (&58D4),A   ; Set attribute of "e"
  1262.         INC A       ; Increment INK
  1263.         AND &07     ; Ensure black PAPER
  1264.         OR  &40     ; Ensure BRIGHT
  1265.         LD  (&58D5),A   ; Set attribute of "r"
  1266.         DEC C       ; Decrement colour
  1267.         JR  NZ,L8CE8    ; Loop 256 times
  1268.         DEC D       ; Decrement main loop counter
  1269.         JR  NZ,L8CE8    ; Loop 6*256 times
  1270.         JP  GAMESTART   ; Go back to intro screen
  1271.  
  1272.  
  1273. ; Draw the current room to Buffer 1
  1274. ; =================================
  1275. DRAWROOM:   CALL    BUILDROOM   ; Build up the attributes for the room
  1276.         LD  IX,&5E00    ; Point to top third attributes
  1277.         LD  A,&70       ; Point to top third of buffer 1
  1278.         LD  (L8D5C+1),A ; Poke into later code
  1279.         CALL    L8D4B       ; Draw the characters for the attributes
  1280.         LD  IX,&5F00    ; Point to middle third attributes
  1281.         LD  A,&78       ; Point to middle third of buffer 1
  1282.         LD  (L8D5C+1),A ; Poke into later code
  1283.  
  1284. IF FIXBLOCKS
  1285. L8D4B:      LD  E,&00       ; Start at screen address 0
  1286. L8D4D:      LD  A,(IX+0)    ; Get current attribute
  1287.         LD  HL,BACKGROUND-9 ; Start at the background attribute
  1288.         LD  BC,9        ; Nine bytes per block
  1289. L8D56:      ADD HL,BC       ; Step to next block
  1290.         CP  (HL)        ; Does attribute byte match?
  1291.         JR  NZ,L8D56    ; No match, check next block
  1292.         LD  B,&08       ; Eight pixel-lines
  1293. L8D5C:      LD  D,&00       ; This is poked to &70 or &78 earlier
  1294. L8D5E:      INC HL      ; Point to bitmap pixel line
  1295.         LD  A,(HL)      ; Get a character byte
  1296.         LD  (DE),A      ; Store into screen buffer
  1297.         INC D       ; Move to next pixel-line
  1298.         DJNZ    L8D5E       ; Loop for eight pixel-lines
  1299.         INC IX      ; Move to next attribute
  1300.         INC E       ; Move to next screen address
  1301.         JP  NZ,L8D4D    ; Loop for 256 attributes
  1302.         RET
  1303. ELSE
  1304.  
  1305. L8D4B:      LD  C,&00       ; Start at screen address 0
  1306. L8D4D:      LD  E,C     ; Set screen address low byte
  1307.         LD  A,(IX+&00)  ; Get current attribute
  1308.  
  1309. ; As pointed out by various people [ref], this is where the block graphics
  1310. ; bug occurs. Instead of checking the attribute bytes by stepping by 9 from
  1311. ; BACKGROUND, all bytes are checked, including the character matrix bitmaps.
  1312. ; Consequently, if an attribute matches a bitmap byte before the actual
  1313. ; attribute then the eight bytes from that point onwards will be used as the
  1314. ; character matrix, regardless of where they occur.
  1315.  
  1316.         LD  HL,BACKGROUND   ; Start at the background attribute
  1317.         LD  BC,&0036    ; Check a maximum of six 9-byte blocks
  1318.         CPIR            ; Look for a byte that matches
  1319.         LD  C,E     ; Get address low byte back
  1320.         LD  B,&08       ; Eight pixel-lines
  1321. L8D5C:      LD  D,&00       ; This is poked to &70 or &78 earlier
  1322. L8D5E:      LD  A,(HL)      ; Get a character byte
  1323.         LD  (DE),A      ; Store into screen buffer
  1324.         INC HL      ; Move to next byte
  1325.         INC D       ; Move to next pixel-line
  1326.         DJNZ    L8D5E       ; Loop for eight pixel-lines
  1327.         INC IX      ; Move to next attribute
  1328.         INC C       ; Move to next screen address
  1329.         JP  NZ,L8D4D    ; Loop for 256 attributes
  1330.         RET
  1331. ENDIF
  1332.  
  1333. ; Build room
  1334. ; ----------
  1335. BUILDROOM:  LD  HL,ROOM     ; Point to room buffer
  1336.         LD  IX,&5E00    ; Point to attribute buffer 1
  1337. L8D72:      LD  A,(HL)      ; Get a room byte
  1338.         RLCA
  1339.         RLCA            ; Rotate b6-b7 to b0-b1
  1340.         CALL    ROOMBLOCK   ; Insert attribute for this block
  1341.         LD  A,(HL)      ; Get the room byte again
  1342.         RRCA
  1343.         RRCA
  1344.         RRCA
  1345.         RRCA            ; Rotate b4-b5 to b0-b1
  1346.         CALL    ROOMBLOCK   ; Insert attribute for this block
  1347.         LD  A,(HL)      ; Get the room byte again
  1348.         RRCA
  1349.         RRCA            ; Rotate b2-b3 to b0-b1
  1350.         CALL    ROOMBLOCK   ; Insert attribute for this block
  1351.         LD  A,(HL)      ; Get the room byte a fourth time
  1352.         CALL    ROOMBLOCK   ; Insert attribute for this block
  1353.         INC HL      ; Point to next room byte
  1354.         LD  A,L     ; Get address low byte
  1355.         AND &80     ; Wrapped past &7F?
  1356.         JR  Z,L8D72     ; Loop for 128 bytes
  1357.  
  1358. ; Insert conveyor blocks into attribute buffer
  1359. ; --------------------------------------------
  1360.         LD  A,(CONV_NUM)    ; Get conveyor length
  1361.         OR  A       ; Is it zero?
  1362.         JR  Z,L8DA1     ; Jump forward with no conveyors
  1363.         LD  HL,(CONV_PSN)   ; Get conveyor start
  1364.         LD  B,A     ; Pass conveyor length to B
  1365.         LD  A,(CONVEYOR)    ; Get conveyor attribute
  1366. L8D9D:      LD  (HL),A      ; Store a conveyor attribute block
  1367.         INC HL      ; Move to next block
  1368.         DJNZ    L8D9D       ; Loop for length of conveyor
  1369. L8DA1:      LD  A,(SLOPE_NUM)   ; Get slope length
  1370.         OR  A       ; Is it zero?
  1371.         RET Z       ; Exit with no slopes
  1372.  
  1373. ; Insert slope blocks into attribute buffer
  1374. ; -----------------------------------------
  1375.         LD  HL,(SLOPE_PSN)  ; Get slope start
  1376.         LD  A,(SLOPE_DIR)   ; Get slope direction
  1377.         AND &01     ; Keep left/right bit
  1378.         RLCA            ; Move to b2
  1379.         ADD A,&DF       ; A=&DF or &E1 for left or right
  1380.         LD  E,A     ; Pass to E
  1381.         LD  D,&FF       ; DE is step between slope addresses
  1382.                     ; A slope leftwards steps by -33 (&FFDF)
  1383.                     ; A slope rightwards steps by -31 (&FFE1)
  1384.         LD  A,(SLOPE_NUM)   ; Get slope length again
  1385.         LD  B,A     ; Pass length to B for looping
  1386.         LD  A,(SLOPE)   ; Get slope attribute
  1387. L8DBB:      LD  (HL),A      ; Store a slope attribute block
  1388.         ADD HL,DE       ; Move up and one block left or right
  1389.         DJNZ    L8DBB       ; Loop for length of slope
  1390.         RET         ; All done
  1391.  
  1392. ; Insert a room block attribute
  1393. ; -----------------------------
  1394. ROOMBLOCK:  AND &03     ; Keep b0-b1
  1395.         LD  C,A     ; Hold in C for additional add
  1396.         RLCA
  1397.         RLCA
  1398.         RLCA            ; Multiply by 8
  1399.         ADD A,C     ; Add again to multiply by 9
  1400.         ADD A,BACKGROUND-ROOM   ; Add to base of room blocks
  1401.         LD  E,A     ; Pass to E to point to attribute
  1402.         LD  D,ROOM / 256    ;  within room buffer
  1403.         LD  A,(DE)      ; Get attribute for this block
  1404.         LD  (IX+&00),A  ; Store into attribute buffer
  1405.         INC IX      ; Point to next buffer location
  1406.         RET
  1407.  
  1408.  
  1409. ; Move Willy
  1410. ; ==========
  1411. ; Move Willy taking account of keypresses, joystick state, whether Willy is on
  1412. ; a conveyor or rope, whether he is jumping or falling, etc.
  1413. ; Will probably use somebody else's commentary for here...
  1414. MOVEMENT:   LD  A,(ONROPE)  ; Is Willy on a rope?
  1415.         DEC A
  1416.         BIT 7,A
  1417.         JP  Z,L8ED4     ; Jump to deal with Willy on a rope
  1418.         LD  A,(FALLING) ; moving/falling
  1419.         CP  &01
  1420.         JR  NZ,L8E36
  1421.         LD  A,(JUMPING) ; jumping
  1422.         AND &FE
  1423.         SUB &08
  1424.         LD  HL,YPOSN    ; Point to Willy's position
  1425.         ADD A,(HL)
  1426.         LD  (HL),A
  1427.         CP  &F0     ; Above top of screen?
  1428.         JP  NC,GO_UP    ; If so, go up
  1429.         CALL    L8E9C
  1430.         LD  A,(WALL)    ; Wall attribute
  1431.         CP  (HL)
  1432.         JP  Z,L8EBC
  1433.         INC HL
  1434.         CP  (HL)
  1435.         JP  Z,L8EBC
  1436.         LD  A,(JUMPING) ; jumping
  1437.         INC A
  1438.         LD  (JUMPING),A ; jumping
  1439.         SUB &08
  1440.         JP  P,L8E11
  1441.         NEG
  1442. L8E11:      INC A
  1443.         RLCA
  1444.         RLCA
  1445.         RLCA
  1446.         LD  D,A
  1447.         LD  C,&20
  1448.         LD  A,(BORDER)
  1449. L8E1B:      OUT (&FE),A
  1450.         XOR &18
  1451.         LD  B,D
  1452. L8E20:      DJNZ    L8E20
  1453.         DEC C
  1454.         JR  NZ,L8E1B
  1455.         LD  A,(JUMPING) ; Get jump counter
  1456.         CP  &12     ; Jump has finished when counter is &12
  1457.         JP  Z,L8EB0     ; Jump finished, set JUMPING to 6
  1458.         CP  &10
  1459.         JR  Z,L8E36     ; Check what Willy is standing on
  1460.         CP  &0D
  1461.         JP  NZ,&8FBC    ; Not 13 or 16, skip ahead to do movement
  1462. L8E36:      LD  A,(YPOSN)
  1463.         AND &0E
  1464.         JR  NZ,L8E62
  1465.         LD  HL,(POSITION)   ; Get Willy's position
  1466.         LD  DE,&0040
  1467.         ADD HL,DE       ; Point to block under Willy's feet
  1468.         BIT 1,H     ; Wrapped off the bottom of the screen?
  1469.         JP  NZ,GO_DOWN  ; Yes, so go downwards
  1470.         LD  A,(NASTY)   ; Get Nasty attribute
  1471.         CP  (HL)        ; Is a nasty under Willy?
  1472.         JR  Z,L8E62     ; Yes, kill Willy
  1473.         INC HL      ; Point to under Willy's right foot
  1474.         LD  A,(NASTY)   ; Get Nasty attribute superfluously
  1475.         CP  (HL)        ; Is a nasty under Willy?
  1476.         JR  Z,L8E62     ; Yes, kill Willy
  1477.         LD  A,(BACKGROUND)  ; Get the background attribute
  1478.         CP  (HL)        ; Is there 'nothing' under Willy?
  1479.         DEC HL      ; Point to under Willy's left foot
  1480.         JP  NZ,L8ED4    ; Something under Willy, stop falling
  1481.         CP  (HL)        ; Is there 'nothing' under Willy?
  1482.         JP  NZ,L8ED4    ; No, so jump to stop falling
  1483.  
  1484. L8E62:      LD  A,(FALLING) ; moving/falling?
  1485.         CP  &01
  1486.         JP  Z,&8FBC
  1487.         LD  HL,L85D0
  1488.         RES 1,(HL)
  1489.         LD  A,(FALLING)
  1490.         OR  A
  1491.         JP  Z,L8EB6
  1492.         INC A
  1493.         CP  &10
  1494.         JR  NZ,L8E7D
  1495.         LD  A,&0C
  1496. L8E7D:      LD  (FALLING),A
  1497.         RLCA
  1498.         RLCA
  1499.         RLCA
  1500.         RLCA
  1501.         LD  D,A
  1502.         LD  C,&20
  1503.         LD  A,(BORDER)
  1504.         OUT (&FE),A
  1505.         XOR &18
  1506.         LD  B,D
  1507. L8E8F:      DJNZ    L8E8F
  1508.         DEC C
  1509.         JR  NZ,&8E8A
  1510.         LD  A,(YPOSN)
  1511.         ADD A,&08
  1512.         LD  (YPOSN),A
  1513. L8E9C:      AND &F0
  1514.         LD  L,A
  1515.         XOR A
  1516.         RL  L
  1517.         ADC A,&5C
  1518.         LD  H,A
  1519.         LD  A,(POSITION)
  1520.         AND &1F
  1521.         OR  L
  1522.         LD  L,A
  1523.         LD  (POSITION),HL
  1524.         RET
  1525.  
  1526. L8EB0:      LD  A,&06
  1527.         LD  (FALLING),A
  1528.         RET
  1529.  
  1530. L8EB6:      LD  A,&02
  1531.         LD  (FALLING),A
  1532.         RET
  1533.  
  1534. L8EBC:      LD  A,(YPOSN)
  1535.         ADD A,&10
  1536.         AND &F0
  1537.         LD  (YPOSN),A
  1538.         CALL    L8E9C
  1539.         LD  A,&02
  1540.         LD  (FALLING),A
  1541.         LD  HL,L85D0
  1542.         RES 1,(HL)
  1543.         RET
  1544.  
  1545.  
  1546. ; Move Willy
  1547. ; ==========
  1548. L8ED4:      LD  E,&FF       ; Prepare E with 'not moving'
  1549.         LD  A,(ONROPE)
  1550.         DEC A
  1551.         BIT 7,A
  1552.         JR  Z,L8EFA
  1553.         LD  A,(FALLING)
  1554.         CP  &0C
  1555.         JP  NC,DIED1
  1556.         XOR A
  1557.         LD  (FALLING),A
  1558.         LD  A,(CONVEYOR)    ; Get conveyor attribute
  1559.         CP  (HL)        ; Check attribute under Willy
  1560.         JR  Z,L8EF4     ; Standing on a conveyor
  1561.         INC HL      ; Look under Willy's right foot
  1562.         CP  (HL)        ; Check attribute under Willy
  1563.         JR  NZ,&8EFA    ; Not standing on a conveyor
  1564. L8EF4:      LD  A,(CONV_DIR)    ; Get conveyor direction
  1565.         SUB &03     ; 0->bit1 clear, 1->bit0 clear
  1566.         LD  E,A     ; This also gives 2->sticky and 3->off
  1567.                     ; [ref]
  1568. L8EFA:      LD  BC,&DFFE
  1569.         IN  A,(C)
  1570.         AND &1F
  1571.         OR  &20
  1572.         AND E
  1573.         LD  E,A
  1574.         LD  A,(STATUS)
  1575.         AND &02
  1576.         RRCA
  1577.         XOR E
  1578.         LD  E,A
  1579.         LD  BC,&FBFE
  1580.         IN  A,(C)
  1581.         AND &1F
  1582.         RLC A
  1583.         OR  &01
  1584.         AND E
  1585.         LD  E,A
  1586.         LD  B,&E7
  1587.         IN  A,(C)
  1588.         RRCA
  1589.         OR  &F7
  1590.         AND E
  1591.         LD  E,A
  1592.         LD  B,&EF
  1593.         IN  A,(C)
  1594.         OR  &FB
  1595.         AND E
  1596.         LD  E,A
  1597.         IN  A,(C)
  1598.         RRCA
  1599.         OR  &FB
  1600.         AND E
  1601.         LD  E,A
  1602.         LD  A,(KEMPSTON)
  1603.         OR  A
  1604.         JR  Z,L8F42
  1605.         LD  BC,&001F
  1606.         IN  A,(C)
  1607.         AND &03
  1608.         CPL
  1609.         AND E
  1610.         LD  E,A
  1611. L8F42:      LD  C,&00
  1612.         LD  A,E
  1613.         AND &2A
  1614.         CP  &2A
  1615.         JR  Z,L8F51
  1616.         LD  C,&04
  1617.         XOR A
  1618.         LD  (COUNTDOWN),A
  1619. L8F51:      LD  A,E
  1620.         AND &15
  1621.         CP  &15
  1622.         JR  Z,L8F5E
  1623.         SET 3,C
  1624.         XOR A
  1625.         LD  (COUNTDOWN),A
  1626. L8F5E:      LD  A,(L85D0)
  1627.         ADD A,C
  1628.         LD  C,A
  1629.         LD  B,&00
  1630.         LD  HL,L8421
  1631.         ADD HL,BC
  1632.         LD  A,(HL)
  1633.         LD  (L85D0),A
  1634.         LD  BC,&7EFE
  1635.         IN  A,(C)
  1636.         AND &1F
  1637.         CP  &1F
  1638.         JR  NZ,L8F8F
  1639.         LD  B,&EF
  1640.         IN  A,(C)
  1641.         BIT 0,A
  1642.         JR  Z,L8F8F
  1643.         LD  A,(KEMPSTON)
  1644.         OR  A
  1645.         JR  Z,L8FBC
  1646.         LD  BC,&001F
  1647.         IN  A,(C)
  1648.         BIT 4,A
  1649.         JR  Z,L8FBC
  1650. L8F8F:      LD  A,(STATUS)
  1651.         BIT 1,A
  1652.         JR  NZ,L8FBC
  1653.         XOR A
  1654.         LD  (JUMPING),A
  1655.         LD  (COUNTDOWN),A
  1656.         INC A
  1657.         LD  (FALLING),A
  1658.         LD  A,(ONROPE)
  1659.         DEC A
  1660.         BIT 7,A
  1661.         JR  NZ,L8FBC
  1662.         LD  A,&F0
  1663.         LD  (ONROPE),A
  1664.         LD  A,(YPOSN)
  1665.         AND &F0
  1666.         LD  (YPOSN),A
  1667.         LD  HL,L85D0
  1668.         SET 1,(HL)
  1669.         RET
  1670.  
  1671. L8FBC:      LD  A,(L85D0)
  1672.         AND &02
  1673.         RET Z
  1674.         LD  A,(ONROPE)
  1675.         DEC A
  1676.         BIT 7,A
  1677.         RET Z
  1678.         LD  A,(L85D0)
  1679.         AND &01
  1680.         JP  Z,L9042
  1681.         LD  A,(FRAME)
  1682.         OR  A
  1683.         JR  Z,L8FDC
  1684.         DEC A
  1685.         LD  (FRAME),A
  1686.         RET
  1687.  
  1688. ; Move Willy leftwards
  1689. ; --------------------
  1690. L8FDC:      LD  A,(FALLING)
  1691.         LD  BC,&0000    ; 0 for no movement
  1692.         CP  &00     ;
  1693.         JR  NZ,L900A
  1694.         LD  HL,(POSITION)
  1695.         LD  BC,&0000    ; again?
  1696.         LD  A,(SLOPE_DIR)
  1697.         DEC A
  1698.         OR  &A1
  1699.         XOR &E0
  1700.         LD  E,A
  1701.         LD  D,&00
  1702.         ADD HL,DE       ; Point to under Willy's feet
  1703.         LD  A,(SLOPE)   ; Get slope attribute
  1704.         CP  (HL)        ; Willy standing on a slope?
  1705.         JR  NZ,L900A    ; No, jump ahead
  1706.         LD  BC,&0020    ; +32 for downwards
  1707.         LD  A,(SLOPE_DIR)
  1708.         OR  A
  1709.         JR  NZ,L900A
  1710.         LD  BC,&FFE0    ; -32 for upwards
  1711. L900A:      LD  HL,(POSITION)   ; Get Willy's current position
  1712.         LD  A,L    
  1713.         AND &1F     ; If Willy is in column zero,
  1714.         JP  Z,GO_LEFT   ; move left
  1715.         ADD HL,BC       ; Willy's potential new position
  1716.         DEC HL      ; Just left of Willy's head
  1717.         LD  DE,&0020    ; DE holds offset between lines
  1718.         ADD HL,DE       ; Just left of Willy's feet
  1719.         LD  A,(WALL)    ; Get wall attribute
  1720.         CP  (HL)        ; Is there a wall here?
  1721.         RET Z       ; If so, return without moving Willy
  1722.         LD  A,(YPOSN)   ; Get Willy's pixel-line position
  1723.         SRA C       ; Is Willy occupying three character
  1724.         ADD A,C     ; lines?
  1725.         LD  B,A
  1726.         AND &0F
  1727.         JR  Z,L9032     ; Only occupying two character lines
  1728.         LD  A,(WALL)    ; Get wall attribute
  1729.         ADD HL,DE       ; Point to left of Willy's feet on 3rd
  1730.         CP  (HL)        ; character line. Is there wall here?
  1731.         RET Z       ; If so, return without moving Willy
  1732.         OR  A
  1733.         SBC HL,DE       ; Move back to second character line
  1734. L9032:      OR  A       ; Back to new head-height position
  1735.         SBC HL,DE       ; Note: no check for wall block
  1736. IF WALLLEFT
  1737.         LD  A,(WALL)    ; Get wall attribute
  1738.         CP  (HL)        ; Check left of Willy's head
  1739.         RET Z       ; Return if wall
  1740.         LD  (POSITION),HL   ; Update Willy's position
  1741.         LD  A,&03       ; Set Willy's sprite to frame 3
  1742.         JP  L90AE       ; Jump to end of right movement
  1743. ELSE
  1744.         LD  (POSITION),HL   ; Update Willy's position
  1745.         LD  A,B
  1746.         LD  (YPOSN),A   ; Update pixel-line position
  1747.         LD  A,&03       ; Set Willy's sprite to frame 3
  1748.         LD  (FRAME),A
  1749.         RET
  1750. ENDIF
  1751.  
  1752. L9042:      LD  A,(FRAME)
  1753.         CP  &03
  1754.         JR  Z,L904E
  1755.         INC A
  1756.         LD  (FRAME),A
  1757.         RET
  1758.  
  1759. ; Move Willy rightwards
  1760. ; ---------------------
  1761. L904E:      LD  A,(FALLING)
  1762.         LD  BC,&0000    ; 0 for no movement
  1763.         OR  A
  1764.         JR  NZ,L9078
  1765.         LD  HL,(POSITION)
  1766.         LD  A,(SLOPE_DIR)
  1767.         DEC A
  1768.         OR  &9D
  1769.         XOR &BF
  1770.         LD  E,A
  1771.         LD  D,&00
  1772.         ADD HL,DE       ; Point to under Willy's feet
  1773.         LD  A,(SLOPE)   ; Get slope attribute
  1774.         CP  (HL)        ; Willy standing on a slope?
  1775.         JR  NZ,L9078    ; No, jump ahead
  1776.         LD  BC,&0020    ; +32 for downwards
  1777.         LD  A,(SLOPE_DIR)
  1778.         OR  A
  1779.         JR  Z,L9078
  1780.         LD  BC,&FFE0    ; -32 for upwards
  1781. L9078:      LD  HL,(POSITION)   ; Get's Willy's current position
  1782.         ADD HL,BC       ; Willy's potential new position
  1783.         INC HL
  1784.         INC HL      ; Just right of Willy's head
  1785.         LD  A,L
  1786.         AND &1F     ; If Willy's position about to wrap
  1787.         JP  Z,GO_RIGHT  ; round into column zero, move right
  1788.         LD  DE,&0020    ; DE holds offset between lines
  1789.         LD  A,(WALL)    ; Get wall attribute
  1790.         ADD HL,DE       ; Just right of Willy's feet
  1791.         CP  (HL)        ; Is there a wall here?
  1792.         RET Z       ; If so, return without moving Willy
  1793.         LD  A,(YPOSN)   ; Get Willy's pixel-line position
  1794.         SRA C       ; Is Willy occupying three character
  1795.         ADD A,C     ; lines?
  1796.         LD  B,A
  1797.         AND &0F
  1798.         JR  Z,L90A1     ; Only occupying two character lines
  1799.         LD  A,(WALL)    ; Get wall attribute
  1800.         ADD HL,DE       ; Point right of Willy's feet on third
  1801.         CP  (HL)        ; character line. Is there wall here?
  1802.         RET Z       ; If so, return without moving Willy
  1803.         OR  A
  1804.         SBC HL,DE       ; Move back to second character line
  1805. L90A1:      LD  A,(WALL)    ; Get wall attribute
  1806.         OR  A       ;
  1807.         SBC HL,DE       ; Now points to right of Willy's head
  1808.         CP  (HL)        ; Check if that square is a wall
  1809. IF WALLRIGHT
  1810.         NOP         ; Ignore wall at head-height
  1811. ELSE
  1812.         RET Z       ; Return without moving Willy
  1813. ENDIF
  1814.         DEC HL      ; Back to new head-height position
  1815.         LD  (POSITION),HL   ; Update Willy's position
  1816.         XOR A       ; Set Willy's sprite to frame 0
  1817. L90AE:      LD  (FRAME),A
  1818.         LD  A,B
  1819.         LD  (YPOSN),A   ; Update pixel-line position
  1820.         RET
  1821. ; Compare this with the left-movement code at L8FDC onwards. The left movement
  1822. ; code checks Willy's future position at foot height only, while the right
  1823. ; movement checks both at head height and at foot height. This is why wall
  1824. ; blocks at head height can be moved through going left, but not right.
  1825. ; [Andrew Broad, 11-12-2004]
  1826.  
  1827. DIED2:      POP HL
  1828. DIED1:      POP HL
  1829.         LD  A,&FF
  1830.         LD  (FALLING),A
  1831.         JP  L89F5
  1832.  
  1833.  
  1834. ; Update active guardians in current room
  1835. ; =======================================
  1836. UPDATEGUARD:    LD  IX,GUARDIAN ; Point to active guardian buffer
  1837. L90C4:      LD  A,(IX+&00)
  1838.         CP  &FF     ; End marker?
  1839.         RET Z       ; Exit when all done
  1840.         AND &03     ; Check guardian type
  1841.         JP  Z,L91B6     ; Type 0/4 -> jump to check next guardian
  1842.         CP  &01     ; Type 1/5?
  1843.         JP  Z,L9133     ; Horizontal guardian
  1844.         CP  &02     ; Type 2/6?
  1845.         JP  Z,L917F     ; Vertical guardian
  1846.  
  1847. ; We're now left with type 3 and type 7 guardians - ropes.
  1848. ; --------------------------------------------------------
  1849.         BIT 7,(IX+&00)  ; Check rope direction
  1850.         JR  Z,L90FF
  1851.         LD  A,(IX+&01)
  1852.         BIT 7,A
  1853.         JR  Z,L90F5
  1854.         SUB &02
  1855.         CP  &94
  1856.         JR  NC,L911D
  1857.         SUB &02
  1858.         CP  &80
  1859.         JR  NZ,L911D
  1860.         XOR A
  1861.         JR  L911D
  1862.  
  1863. L90F5:      ADD A,&02
  1864.         CP  &12
  1865.         JR  NC,L911D
  1866.         ADD A,&02
  1867.         JR  L911D
  1868.  
  1869. L90FF:      LD  A,(IX+&01)
  1870.         BIT 7,A
  1871.         JR  NZ,L9115
  1872.         SUB &02
  1873.         CP  &14
  1874.         JR  NC,L911D
  1875.         SUB &02
  1876.         OR  A
  1877.         JR  NZ,L911D
  1878.         LD  A,&80
  1879.         JR  L911D
  1880.  
  1881. L9115:      ADD A,&02
  1882.         CP  &92
  1883.         JR  NC,L911D
  1884.         ADD A,&02
  1885. L911D:      LD  (IX+&01),A
  1886.         AND &7F
  1887.         CP  (IX+&07)
  1888.         JP  NZ,L91B6
  1889.         LD  A,(IX+&00)
  1890.         XOR &80
  1891.         LD  (IX+&00),A
  1892.         JP  L91B6
  1893.  
  1894. ; Horizontal guardian
  1895. ; -------------------
  1896. L9133:      BIT 7,(IX+&00)  ; Get direction
  1897.         JR  NZ,L915C    ; Jump to move right
  1898.  
  1899. ; Move horizontal guardian left
  1900. ; -----------------------------
  1901.         LD  A,(IX+&00)
  1902.         SUB &20
  1903.         AND &7F
  1904.         LD  (IX+&00),A
  1905.         CP  &60
  1906.         JR  C,L91B6
  1907.         LD  A,(IX+&02)
  1908.         AND &1F
  1909.         CP  (IX+&06)
  1910.         JR  Z,L9156
  1911.         DEC (IX+&02)
  1912.         JR  L91B6
  1913.  
  1914. L9156:      LD  (IX+&00),&81
  1915.         JR  L91B6
  1916.  
  1917. ; Move horizontal guardian right
  1918. ; ------------------------------
  1919. L915C:      LD  A,(IX+&00)
  1920.         ADD A,&20
  1921.         OR  &80
  1922.         LD  (IX+&00),A
  1923.         CP  &A0
  1924.         JR  NC,L91B6
  1925.         LD  A,(IX+&02)
  1926.         AND &1F
  1927.         CP  (IX+&07)
  1928.         JR  Z,L9179
  1929.         INC (IX+&02)
  1930.         JR  L91B6
  1931.  
  1932. L9179:      LD  (IX+&00),&61
  1933.         JR  L91B6
  1934.  
  1935. ; Vertical guardian
  1936. ; -----------------
  1937. L917F:      LD  A,(IX+&00)
  1938.         XOR &08
  1939.         LD  (IX+&00),A
  1940.         AND &18
  1941.         JR  Z,L9193
  1942.         LD  A,(IX+&00)
  1943.         ADD A,&20
  1944.         LD  (IX+&00),A
  1945. L9193:      LD  A,(IX+&03)
  1946.         ADD A,(IX+&04)
  1947.         LD  (IX+&03),A
  1948.         CP  (IX+&07)
  1949.         JR  NC,L91AE
  1950.         CP  (IX+&06)
  1951.         JR  Z,L91A8
  1952.         JR  NC,L91B6
  1953. L91A8:      LD  A,(IX+&06)
  1954.         LD  (IX+&03),A
  1955. L91AE:      LD  A,(IX+&04)
  1956.         NEG
  1957.         LD  (IX+&04),A
  1958. L91B6:      LD  DE,&0008    ; Eight bytes per guardian
  1959.         ADD IX,DE       ; Point to next guardian
  1960.         JP  L90C4       ; Loop back to check all guardians
  1961.  
  1962.  
  1963. ; Draw guardians to screen buffer 2
  1964. ; =================================
  1965. DRAWGUARD:  LD  IX,GUARDIAN ; Point to guardian buffer
  1966. L91C2:      LD  A,(IX+&00)  ; Get guardian type
  1967.         CP  &FF     ; End marker?
  1968.         RET Z       ; Exit when all done
  1969.         AND &07     ; Check guardian type
  1970.         JP  Z,L93B3     ; Type 0 - null guardian
  1971.         CP  &03     ; Type 3? - a rope?
  1972.         JP  Z,L92A4     ; Jump to deal with ropes
  1973.         CP  &04     ; Type 4 - an arrow?
  1974.         JR  Z,L9237     ; Jump to deal with arrows
  1975.  
  1976. ; Horizontal and vertical guardians are both draw the same way. Once their
  1977. ; position has been updated, all they are is a sprite that needs to be placed
  1978. ; on the screen at a specified position.
  1979.  
  1980.         LD  E,(IX+&03)  ; Get Y position
  1981.         LD  D,PIXEL / 256   ; Index into pixel-line table
  1982.         LD  A,(DE)      ; Get low byte of Y position address
  1983.         LD  L,A     ; Pass to L for later
  1984.         LD  A,(IX+&02)  ; Get X position
  1985.         AND &1F     ; Reduce to 0-31
  1986.         ADD A,L     ; Add to Y position address
  1987.         LD  L,A     ; And store back into L
  1988.         LD  A,E     ; Convert this into an attribute buffer
  1989.         RLCA            ;  address
  1990.         AND &01
  1991.         OR  &5C
  1992.         LD  H,A     ; HL=address in attribute buffer 2
  1993.         LD  DE,&001F    ; Set DE to 31 for later adding
  1994.         LD  A,(IX+&01)  ; Get guardian's attribute
  1995.         AND &0F     ; b0-b3=INK, b4=BRIGHT
  1996.         ADD A,&38       ; Move BRIGHT up to bit 6
  1997.         AND &47     ; Keep INK and BRIGHT
  1998.         LD  C,A     ; Save in C
  1999.         LD  A,(HL)      ; Get attribute in this position
  2000.         AND &38     ; Keep PAPER
  2001.         XOR C       ; Merge in guardian's INK and BRIGHT
  2002.         LD  C,A     ; Pass back to C
  2003.         LD  (HL),C      ; Store attribute for 2x2 characters
  2004.         INC HL      ; Set attributes for top two cells
  2005.         LD  (HL),C
  2006.         ADD HL,DE       ; Add 31 to move to next line
  2007.         LD  (HL),C      ; Set attributes for bottom two cells
  2008.         INC HL
  2009.         LD  (HL),C
  2010.         LD  A,(IX+&03)  ; Get guardian's Y position
  2011.         AND &0E     ; Has it moved away from pixel-line 0?
  2012.         JR  Z,L920F     ; No, so only 2x2 blocks to colour
  2013.  
  2014. ; Guardian overlaps three character lines, so six attribute cells need to be
  2015. ; set to set it's colour.
  2016.  
  2017.         ADD HL,DE       ; Add 31 to move to next line
  2018.         LD  (HL),C      ; Set attributes on two move cells
  2019.         INC HL
  2020.         LD  (HL),C
  2021. L920F:      LD  C,&01       ; Don't ignore collisions
  2022.         LD  A,(IX+&01)  ; Construct sprite address
  2023.         AND (IX+&00)    ; Sprite address subpage bit7
  2024.         OR  (IX+&02)    ; X position top 3 bits
  2025.         AND &E0     ; 32 bytes per sprite
  2026.         LD  E,A     ; Set sprite address low byte
  2027.         LD  D,(IX+&05)  ; Get sprite address high byte
  2028.         LD  H,PIXEL / 256   ; Pixel-line buffer high byte
  2029.         LD  L,(IX+&03)  ; Get guardian's Y position
  2030.         LD  A,(IX+&02)  ; Get guardian's X position
  2031.         AND &1F     ; Resolve to 0-31
  2032.         OR  (HL)        ; Add to pixel-line start address low
  2033.         INC HL      ; Point to pixel-line address high
  2034.         LD  H,(HL)      ; Get high byte of address
  2035.         LD  L,A     ; HL is address to draw sprite
  2036.         CALL    DRAWSPRITE  ; Draw the sprite
  2037.         JP  NZ,DIED1    ; If the sprite collided, kill Willy
  2038.         JP  L93B3       ; Draw next guardian
  2039.  
  2040. ; Arrow
  2041. ; -----
  2042. L9237:      BIT 7,(IX+&00)  ; Arrow direction
  2043.         JR  NZ,L9244
  2044.         DEC (IX+&04)
  2045.         LD  C,&2C
  2046.         JR  L9249
  2047.  
  2048. L9244:      INC (IX+&04)
  2049.         LD  C,&F4
  2050. L9249:      LD  A,(IX+&04)
  2051.         CP  C
  2052.         JR  NZ,L9262
  2053.         LD  BC,&0280
  2054.         LD  A,(BORDER)
  2055. L9255:      OUT (&FE),A     ; Squawk!
  2056.         XOR &18
  2057. L9259:      DJNZ    L9259
  2058.         LD  B,C
  2059.         DEC C
  2060.         JR  NZ,L9255
  2061.         JP  L93B3
  2062.  
  2063. L9262:      AND &E0
  2064.         JP  NZ,L93B3
  2065.         LD  E,(IX+&02)
  2066.         LD  D,&82
  2067.         LD  A,(DE)
  2068.         ADD A,(IX+&04)
  2069.         LD  L,A
  2070.         LD  A,E
  2071.         AND &80
  2072.         RLCA
  2073.         OR  &5C
  2074.         LD  H,A
  2075.         LD  (IX+&05),&00
  2076.         LD  A,(HL)
  2077.         AND &07
  2078.         CP  &07
  2079.         JR  NZ,L9286
  2080.         DEC (IX+&05)
  2081. L9286:      LD  A,(HL)
  2082.         OR  &07
  2083.         LD  (HL),A
  2084.         INC DE
  2085.         LD  A,(DE)
  2086.         LD  H,A
  2087.         DEC H
  2088.         LD  A,(IX+&06)
  2089.         LD  (HL),A
  2090.         INC H
  2091.         LD  A,(HL)
  2092.         AND (IX+&05)
  2093.         JP  NZ,DIED1
  2094.         LD  (HL),&FF
  2095.         INC H
  2096.         LD  A,(IX+&06)
  2097.         LD  (HL),A
  2098.         JP  L93B3
  2099.  
  2100. L92A4:      LD  IY,PIXEL    ; Pixel-line table
  2101.         LD  (IX+&09),&00
  2102.         LD  A,(IX+&02)
  2103.         LD  (IX+&03),A
  2104.         LD  (IX+&05),&80
  2105. L92B6:      LD  A,(IY+&00)
  2106.         ADD A,(IX+&03)
  2107.         LD  L,A
  2108.         LD  H,(IY+&01)
  2109.         LD  A,(ONROPE)
  2110.         OR  A
  2111.         JR  NZ,L92D6
  2112.         LD  A,(IX+&05)
  2113.         AND (HL)
  2114.         JR  Z,L930E
  2115.         LD  A,(IX+&09)
  2116.         LD  (ONROPE),A
  2117.         SET 0,(IX+&0B)
  2118. L92D6:      CP  (IX+&09)
  2119.         JR  NZ,L930E
  2120.         BIT 0,(IX+&0B)
  2121.         JR  Z,L930E
  2122.         LD  B,(IX+&03)
  2123.         LD  A,(IX+&05)
  2124.         LD  C,&01
  2125.         CP  &04
  2126.         JR  C,L92FC
  2127.         LD  C,&00
  2128.         CP  &10
  2129.         JR  C,L92FC
  2130.         DEC B
  2131.         LD  C,&03
  2132.         CP  &40
  2133.         JR  C,L92FC
  2134.         LD  C,&02
  2135. L92FC:      LD  (FRAME),BC
  2136.         DEFB    &FD
  2137.         LD  A,L     ; LD A,IYL
  2138.         SUB &10
  2139.         LD  (YPOSN),A
  2140.         PUSH    HL
  2141.         CALL    L8E9C
  2142.         POP HL
  2143.         JR  L930E
  2144.  
  2145. L930E:      LD  A,(IX+&05)
  2146.         OR  (HL)
  2147.         LD  (HL),A
  2148.         LD  A,(IX+&09)
  2149.         ADD A,(IX+&01)
  2150.         LD  L,A
  2151.         SET 7,L
  2152.         LD  H,&83       ; Rope structure table
  2153.         LD  E,(HL)
  2154.         LD  D,&00
  2155.         ADD IY,DE
  2156.         RES 7,L
  2157.         LD  A,(HL)
  2158.         OR  A
  2159.         JR  Z,L9350
  2160.         LD  B,A
  2161.         BIT 7,(IX+&01)
  2162.         JR  Z,L9341
  2163. L9330:      RLC (IX+&05)
  2164.         BIT 0,(IX+&05)
  2165.         JR  Z,L933D
  2166.         DEC (IX+&03)
  2167. L933D:      DJNZ    L9330
  2168.         JR  L9350
  2169.  
  2170. L9341:      RRC (IX+&05)
  2171.         BIT 7,(IX+&05)
  2172.         JR  Z,L934E
  2173.         INC (IX+&03)
  2174. L934E:      DJNZ    L9341
  2175. L9350:      LD  A,(IX+&09)
  2176.         CP  (IX+&04)
  2177.         JR  Z,L935E
  2178.         INC (IX+&09)
  2179.         JP  L92B6
  2180.  
  2181. L935E:      LD  A,(ONROPE)
  2182.         BIT 7,A
  2183.         JR  Z,L936F
  2184.         INC A
  2185.         LD  (ONROPE),A
  2186.         RES 0,(IX+&0B)
  2187.         JR  L93B3
  2188.  
  2189. L936F:      BIT 0,(IX+&0B)
  2190.         JR  Z,L93B3
  2191.         LD  A,(L85D0)
  2192.         BIT 1,A
  2193.         JR  Z,L93B3
  2194.         RRCA
  2195.         XOR (IX+&00)
  2196.         RLCA
  2197.         RLCA
  2198.         AND &02
  2199.         DEC A
  2200.         LD  HL,ONROPE
  2201.         ADD A,(HL)
  2202.         LD  (HL),A
  2203.         LD  A,(UP)
  2204.         LD  C,A
  2205.         LD  A,(HERE)    ; Can't go up if UP goes to same room
  2206.         CP  C
  2207.         JR  NZ,L939B
  2208.         LD  A,(HL)
  2209.         CP  &0C
  2210.         JR  NC,L939B
  2211.         LD  (HL),&0C
  2212. L939B:      LD  A,(HL)
  2213.         CP  (IX+&04)
  2214.         JR  C,L93B3
  2215.         JR  Z,L93B3
  2216.         LD  (HL),&F0
  2217.         LD  A,(YPOSN)
  2218.         AND &F8
  2219.         LD  (YPOSN),A
  2220.         XOR A
  2221.         LD  (FALLING),A
  2222.         JR  L93B3
  2223.  
  2224. L93B3:      LD  DE,&0008
  2225.         ADD IX,DE       ; Point to next guardian
  2226.         JP  L91C2
  2227.  
  2228. ; Nothing seems to call this
  2229. ; ==========================
  2230. ; This sets the INK six attribute cells. This would be appropriate for a 32x32
  2231. ; sprite that has moved away from pixel-line 0 in a character cell, and so
  2232. ; overlaps three characters rows.
  2233. L93BB:      LD  (HL),A
  2234.         LD  A,(BACKGROUND)
  2235.         AND &F8
  2236.         OR  (HL)
  2237.         LD  (HL),A
  2238.         LD  DE,&001F
  2239.         INC HL
  2240.         LD  (HL),A
  2241.         ADD HL,DE
  2242.         LD  (HL),A
  2243.         INC HL
  2244.         LD  (HL),A
  2245.         ADD HL,DE
  2246.         LD  (HL),A
  2247.         INC HL
  2248.         LD  (HL),A
  2249.         RET
  2250.  
  2251.  
  2252. ; Process objects
  2253. ; ===============
  2254. CHKOBJECTS:
  2255. IF MOREROOMS
  2256.         LD  H,&A6       ; High byte of collection flags
  2257. ELSE
  2258.         LD  H,&A4       ; High byte of collection flags
  2259. ENDIF
  2260.         LD  A,(OBJECTS) ; Get 256-number of objects
  2261.         LD  L,A     ; HL points to collection flags
  2262. L93D7:
  2263. IF MOREROOMS
  2264.         BIT 6,(HL)      ; Is this object collected?
  2265.         JR  Z,L9452     ; Yes, jump to check next object
  2266.         DEC H
  2267.         DEC H       ; Point to object position
  2268.         CALL    L96F4       ; Draw this object if in this room
  2269. ELSE
  2270.         LD  C,(HL)      ; Get collection/room value
  2271.         RES 7,C     ; Lose bit4 of Y position
  2272.         LD  A,(HERE)    ; Get current room
  2273.         OR  &40     ; Fake in a 'not collected' bit
  2274.         CP  C       ; In this room and not collected?
  2275. ENDIF
  2276.         JR  NZ,L9452    ; No, jump to check next object
  2277.         LD  A,(HL)      ; Get object Y position bit 4
  2278.         RLCA            ; Move to bit 0
  2279.         AND &01
  2280.         ADD A,&5C       ; Object's screen half
  2281.         LD  D,A     ; Pass to D for later on
  2282.         INC H       ; Point to position X and Y b0-b3
  2283.         LD  E,(HL)      ; Pass to E
  2284. IF MOREROOMS
  2285.         INC H       ; Point back to collection flags
  2286. ELSE
  2287.         DEC H       ; Point back to collection flags
  2288. ENDIF
  2289.         LD  A,(DE)      ; Get attribute at object's position
  2290.         AND &07     ; Keep INK
  2291.         CP  &07     ; White indicating Willy there?
  2292.         JR  NZ,L9430    ; Not white, draw the object
  2293.         LD  IX,COLLECTED    ; Point to collected items string
  2294. L93F7:      INC (IX+&02)    ; Increment a digit
  2295.         LD  A,(IX+&02)  ; Get current digit
  2296.         CP  &3A     ; Wrapped past '0'?
  2297.         JR  NZ,L9409    ; No, continue to make a sound
  2298.         LD  (IX+&02),&30    ; Set current digit to '0'
  2299.         DEC IX      ; Point to next higher order digit
  2300.         JR  L93F7       ; Loop to increment this digit
  2301.  
  2302. ; Make a sound and collect an object
  2303. ; ----------------------------------
  2304. L9409:      LD  A,(BORDER)  ; Get border colour
  2305.         LD  C,&80
  2306. L940E:      OUT (&FE),A     ; Write to buzzer
  2307.         XOR &18     ; Toggle buzzer state
  2308.         LD  E,A
  2309.         LD  A,&90
  2310.         SUB C
  2311.         LD  B,A
  2312.         LD  A,E
  2313. L9418:      DJNZ    L9418       ; Pause a while
  2314.         DEC C
  2315.         DEC C
  2316.         JR  NZ,L940E    ; Loop to play a note
  2317.         LD  A,(REMAIN)  ; Get remaining items
  2318.         INC A
  2319.         LD  (REMAIN),A  ; Update remaining items
  2320.         JR  NZ,L942C    ; Jump if not all collected
  2321.         LD  A,&01
  2322.         LD  (STATUS),A  ; Set STATUS to 'collected'
  2323. L942C:      RES 6,(HL)      ; Clear 'not collected' flag
  2324.         JR  L9452       ; Loop to check next item
  2325.  
  2326. ; Draw object and 'wobble' its colours
  2327. ; ------------------------------------
  2328. L9430:      LD  A,(TICKER)  ; Wobble colours with game ticker
  2329.         ADD A,L     ; Add to object table offset
  2330.         AND &03     ; Keep b0-b1, colours are
  2331.         ADD A,&03       ;  magenta, green, cyan, yellow
  2332.         LD  C,A
  2333.         LD  A,(DE)      ; Get attributes under object
  2334.         AND &F8     ; Lose INK
  2335.         OR  C       ; Merge in wobbling INK
  2336.         LD  (DE),A      ; Store to attributes
  2337. IF MOREROOMS
  2338.         LD  A,D     ; Get object's Y position bit 4
  2339.         NOP         ; Already in bit 0
  2340. ELSE
  2341.         LD  A,(HL)      ; Get object's Y position bit 4
  2342.         RLCA            ; Move to bit 0
  2343. ENDIF
  2344.         RLCA
  2345.         RLCA            ; Move to bit 3, calculate screen
  2346.         RLCA            ;  address top third or middle third
  2347.         AND &08     ;  E already holds position with third
  2348.         ADD A,&60       ;  as it is the same as the attribute
  2349.         LD  D,A     ;  address low byte
  2350.         PUSH    HL      ; Save object table pointer
  2351.         LD  HL,OBJECT   ; Point to object's bitmap
  2352.         LD  B,&08       ; Eight pixel-lines
  2353.         CALL    PRMATRIX    ; Draw the object
  2354.         POP HL      ; Restore object table pointer
  2355. L9452:      INC L       ; Point to next item
  2356.         JR  NZ,L93D7    ; Loop until end of table reached
  2357.         RET
  2358.  
  2359.  
  2360. ; Draw a sprite
  2361. ; =============
  2362. ; DE=sprite address
  2363. ; HL=screen address
  2364. ; C=0 - ignore collisions, C=1 - don't ignore collisions
  2365. DRAWSPRITE: LD  B,&10       ; 16 pixel-lines
  2366. L9458:      BIT 0,C     ; Check collision flag
  2367.         LD  A,(DE)      ; Get byte from sprite
  2368.         JR  Z,L9461     ; If ignoring collision, jump to store
  2369.         AND (HL)        ; Mask with pixels on screen
  2370.         RET NZ      ; If any overlap, exit with NZ set
  2371.         LD  A,(DE)      ; Get byte from sprite again
  2372.         OR  (HL)        ; Merge with pixels on screen
  2373. L9461:      LD  (HL),A      ; Store byte to screen
  2374.         INC L       ; Point to right-hand screen byte
  2375.         INC DE      ; Point to next sprite byte
  2376.         BIT 0,C     ; Check collision flag
  2377.         LD  A,(DE)      ; Get byte from sprite
  2378.         JR  Z,L946D     ; If ignoring collision, jump to store
  2379.         AND (HL)        ; Mask with pixels on screen
  2380.         RET NZ      ; If any overlap, exit with NZ set
  2381.         LD  A,(DE)      ; Get byte from sprite again
  2382.         OR  (HL)        ; Merge with pixels on screen
  2383. L946D:      LD  (HL),A      ; Store byte to screen
  2384.         DEC L       ; Point back to left-hand screen byte
  2385.         INC H       ; Move down one pixel-line
  2386.         INC DE      ; Point to next sprite byte
  2387.         LD  A,H     ; Check screen address high byte to
  2388.         AND &07     ;  see if wrapped past pixel-line 7
  2389.         JR  NZ,L9486
  2390.         LD  A,H     ; Adjust screen address
  2391.         SUB &08
  2392.         LD  H,A
  2393.         LD  A,L
  2394.         ADD A,&20
  2395.         LD  L,A
  2396.         AND &E0
  2397.         JR  NZ,L9486
  2398.         LD  A,H
  2399.         ADD A,&08
  2400.         LD  H,A
  2401. L9486:      DJNZ    L9458       ; Loop for 16 pixel-lines
  2402.         XOR A       ; Ensure Z set
  2403.         RET         ; Exit
  2404.  
  2405.  
  2406. ; Move left
  2407. ; =========
  2408. GO_LEFT:    LD  A,(LEFT)    ; Get room through left exit
  2409.         LD  (HERE),A    ; Set current room
  2410.         LD  A,(POSITION)    ; Get Willy's position
  2411.         OR  &1F     ; Force into column 31
  2412.         AND &FE     ; Make it column 30
  2413.         LD  (POSITION),A    ; Store Willy's position
  2414.         POP HL      ; Lose return address
  2415.         JP  PLAYROOM    ; Enter the new current room
  2416.  
  2417. ; Move right
  2418. ; ==========
  2419. GO_RIGHT:   LD  A,(RIGHT)   ; Get room through right exit
  2420.         LD  (HERE),A    ; Set current room
  2421.         LD  A,(POSITION)    ; Get Willy's position
  2422.         AND &E0     ; Force into column 0
  2423.         LD  (POSITION),A    ; Store Willy's position
  2424.         POP HL      ; Lose return address
  2425.         JP  PLAYROOM    ; Enter the new current room
  2426.  
  2427. ; Move up
  2428. ; =======
  2429. GO_UP:      LD  A,(UP)      ; Get room through up exit
  2430.         LD  (HERE),A    ; Set current room
  2431.         LD  A,(POSITION)    ; Get Willy's position low byte
  2432.         AND &1F     ; Keep X position
  2433.         ADD A,&A0       ; Set Y position to line 13
  2434.         LD  (POSITION),A    ; Store Willy's position low byte
  2435.         LD  A,&5D       ; Put Willy in bottom half of screen
  2436.         LD  (POSITION+1),A  ; Set Willy's position high byte
  2437.         LD  A,&D0       ; Set Willy's Y position to line 13
  2438.         LD  (YPOSN),A
  2439.         XOR A       ; Clear movement flag
  2440.         LD  (FALLING),A ; Not falling, normal movement
  2441.         POP HL      ; Lose return address
  2442.         JP  PLAYROOM    ; Enter the new current room
  2443.  
  2444. ; Move down
  2445. ; =========
  2446. GO_DOWN:    LD  A,(DOWN)    ; Get room through down exit
  2447.         LD  (HERE),A    ; Set current room
  2448.         XOR A
  2449.         LD  (YPOSN),A   ; Set Willy's Y position to line 0
  2450.         LD  A,(FALLING) ; Get falling state
  2451.         CP  &0B
  2452.         JR  NC,&94E8
  2453.         LD  A,&02
  2454.         LD  (FALLING),A ; Set falling state to 2
  2455. L94E8:      LD  A,(POSITION)    ; Get Willy's position low byte
  2456.         AND &1F     ; Keep X position, set Y to 0
  2457.         LD  (POSITION),A    ; Store Willy's position low byte
  2458.         LD  A,&5C       ; Put Willy at top of screen
  2459.         LD  (POSITION+1),A  ; Set Willy's position high byte
  2460.         POP HL      ; Lose return address
  2461.         JP  PLAYROOM    ; Enter the new current room
  2462.  
  2463.  
  2464. ; Update conveyors appearance on screen
  2465. ; =====================================
  2466. UPDATECONV: LD  HL,(CONV_PSN)   ; Get conveyor's start position
  2467.         LD  A,H     ; Convert position to screen buffer 1
  2468.         AND &01     ;  address
  2469.         RLCA
  2470.         RLCA
  2471.         RLCA
  2472.         ADD A,&70
  2473.         LD  H,A     ; HL=address in screen buffer 1
  2474.         LD  E,L     ; Save in DE as well
  2475.         LD  D,H
  2476.         LD  A,(CONV_NUM)    ; Get conveyor length
  2477.         OR  A
  2478.         RET Z       ; No conveyor, so exit
  2479.         LD  B,A     ; Pass to B as loop counter
  2480.         LD  A,(CONV_DIR)    ; Get conveyor direction
  2481.         OR  A       ; Is it moving right?
  2482.         JR  NZ,L9526    ; Any non-zero direction rotates right
  2483.  
  2484. ; Rotate conveyor leftwards
  2485. ; -------------------------
  2486.         LD  A,(HL)      ; Get conveyor top pixel-line
  2487.         RLC A       ; Rotate left two bits
  2488.         RLC A
  2489.         INC H       ; Point two pixel-lines down
  2490.         INC H
  2491.         LD  C,(HL)      ; Get conveyor's third pixel-line
  2492.         RRC C       ; Rotate right two bits
  2493.         RRC C
  2494. L951F:      LD  (DE),A      ; Store updated top pixel-line
  2495.         LD  (HL),C      ; Store updated third pixel-line
  2496.         INC L       ; Point to next conveyor character
  2497.         INC E
  2498.         DJNZ    L951F       ; Loop for conveyor length
  2499.         RET
  2500.  
  2501. ; Rotate conveyor rightwards
  2502. ; --------------------------
  2503. L9526:      LD  A,(HL)      ; Get conveyor top pixel-line
  2504.         RRC A       ; Rotate right two bits
  2505.         RRC A
  2506.         INC H       ; Point to pixel-lines down
  2507.         INC H
  2508.         LD  C,(HL)      ; Get conveyor's third pixel-line
  2509.         RLC C       ; Rotate left two bits
  2510.         RLC C
  2511.         JR  L951F       ; Jump to update whole conveyor
  2512.  
  2513.  
  2514. ; Deal with special case rooms
  2515. ; ============================
  2516. SPECIAL:    LD  A,(HERE)    ; Get current room
  2517.         CP  &23     ; Master Bedroom?
  2518.         JR  NZ,L959A    ; No, jump to check for Bathroom
  2519.  
  2520. ; Special actions for The Master Bedroom
  2521. ; --------------------------------------
  2522. ; Draw Maria according to how far into the room Willy has got. This is
  2523. ; measured by Willy's Y position, so if he jumps, Maria raises her arm.
  2524.         LD  A,(STATUS)
  2525.         OR  A       ; Normal gameplay?
  2526.         JR  NZ,L9576    ; No, jump to check for the bed
  2527.         LD  A,(TICKER)  ; Animate Maria with the game ticker
  2528.         AND &02     ; Keep bit 1
  2529.         RRCA
  2530.         RRCA
  2531.         RRCA
  2532.         RRCA            ; Multiply by 16 to give 0 or 32
  2533.         OR  &80     ; &80, &A0 are the foot tapping Maria
  2534.         LD  E,A     ; Pass to E as sprite subpage value
  2535.         LD  A,(YPOSN)   ; Get Willy's Y position
  2536.         CP  &D0     ; Is Willy on the floor - line 13?
  2537.         JR  Z,DRAWMARIA ; Yes, jump to draw Maria
  2538.         LD  E,&C0       ; Point to Maria raising her hand
  2539.         CP  &C0     ; Has Willy started up the ramp?
  2540.         JR  NC,DRAWMARIA    ; Yes, jump to draw Maria
  2541.         LD  E,&E0       ; Otherwise, Maria with outstretched arm
  2542.  
  2543. DRAWMARIA:  LD  D,&9C       ; Maria sprite page
  2544.         LD  HL,&686E    ; Maria's position in buffer 2
  2545.         LD  C,&01       ; Don't ignore collisions
  2546.         CALL    DRAWSPRITE  ; Draw Maria sprite
  2547.         JP  NZ,DIED1    ; Kill Willy if Maria touched him
  2548.         LD  HL,&4545    ; Bright cyan on black
  2549.         LD  (&5D6E),HL  ; Set colours of Maria's top half
  2550.         LD  HL,&0707    ; White on black
  2551.         LD  (&5D8E),HL  ; Set colours of Maria's skirt
  2552.         RET
  2553.  
  2554. ; Check if Willy has got as far as the bed
  2555. ; ----------------------------------------
  2556. L9576:      LD  A,(POSITION)    ; Get Willy's position
  2557.         AND &1F     ; Get X coordinate
  2558.         CP  &06     ; Further left than X=6?
  2559.         RET NC      ; Not reached the bed yet
  2560.         LD  A,&02       ; Reached the bed
  2561.         LD  (STATUS),A  ; Set STATUS to 2 to indicate fleeing
  2562.         RET
  2563.  
  2564. ; Has Willy reached the toilet while fleeing?
  2565. ; -------------------------------------------
  2566. CHKTOILET:  LD  A,(HERE)    ; Get current room
  2567.         CP  &21     ; The Bathroom?
  2568.         RET NZ      ; No, exit
  2569.         LD  A,(POSITION)    ; Get Willy's position
  2570.         CP  &BC     ; Line 13 (or 5!), column 28?
  2571.         RET NZ      ; No, exit
  2572.         XOR A
  2573.         LD  (TICKER),A  ; Force ticker to zero
  2574.         LD  A,&03
  2575.         LD  (STATUS),A  ; Set STATUS to 3 to indicate vomiting
  2576.         RET
  2577.  
  2578. ; Special actions for The Bathroom
  2579. ; --------------------------------
  2580. ; Animate the toilet without killing Willy, or animate Willy communing with
  2581. ; the porcelain.
  2582. L959A:      LD  A,(HERE)    ; Get current room
  2583.         CP  &21     ; Bathroom?
  2584.         RET NZ      ; No, exit
  2585.         LD  A,(TICKER)  ; Animate toilet with the game ticker
  2586.         AND &01     ; Keep bit 0
  2587.         RRCA
  2588.         RRCA
  2589.         RRCA            ; Multiply by 32 to give &00 or &20
  2590.         LD  E,A     ; Pass to E as the sprite subpage
  2591.         LD  A,(STATUS)
  2592.         CP  &03     ; Is Willy throwing up?
  2593.         JR  NZ,DRAWTOILET   ; No, animate toilet
  2594.         SET 6,E     ; Point to Willy and the toilet
  2595.  
  2596. DRAWTOILET: LD  D,&A6       ; Toilet sprite page
  2597.         LD  IX,&82D0    ; Pixel-line address for line 13
  2598.         LD  BC,&101C    ; 16 pixel lines, X position is &1C
  2599.         CALL    L9668       ; Draw toilet with the DRAWWILLY
  2600.                     ; routine to merge with screen content
  2601.         LD  HL,&0707    ; White on black
  2602.         LD  (&5DBC),HL  ; Set toilet's colours
  2603.         LD  (&5DDC),HL
  2604.         RET
  2605.  
  2606.  
  2607. ; Update Willy's position and draw him to screen buffer 2
  2608. ; =======================================================
  2609. UPDATEWILLY:    LD  HL,(POSITION)   ; Get Willy's position
  2610.         LD  B,&00
  2611.         LD  A,(SLOPE_DIR)
  2612.         AND &01
  2613.         ADD A,&40
  2614.         LD  E,A
  2615.         LD  D,&00
  2616.         ADD HL,DE
  2617.         LD  A,(SLOPE)
  2618.         CP  (HL)
  2619.         JR  NZ,L95F8
  2620.         LD  A,(FALLING)
  2621.         OR  A
  2622.         JR  NZ,L95F8
  2623.         LD  A,(FRAME)
  2624.         AND &03
  2625.         RLCA
  2626.         RLCA
  2627.         LD  B,A
  2628.         LD  A,(SLOPE_DIR)
  2629.         AND &01
  2630.         DEC A
  2631.         XOR &0C
  2632.         XOR B
  2633.         AND &0C
  2634.         LD  B,A
  2635. L95F8:      LD  HL,(POSITION)
  2636.         LD  DE,&001F
  2637.         LD  C,&0F
  2638.         CALL    L961E
  2639.         INC HL
  2640.         CALL    L961E
  2641.         ADD HL,DE
  2642.         CALL    L961E
  2643.         INC HL
  2644.         CALL    L961E
  2645.         LD  A,(YPOSN)
  2646.         ADD A,B
  2647.         LD  C,A
  2648.         ADD HL,DE
  2649.         CALL    L961E
  2650.         INC HL
  2651.         CALL    L961E
  2652.         JR  DRAWWILLY   ; Display Willy
  2653.  
  2654. L961E:      LD  A,(BACKGROUND)  ; Background
  2655.         CP  (HL)
  2656.         JR  NZ,L962F
  2657.         LD  A,C
  2658.         AND &0F
  2659.         JR  Z,L962F
  2660.         LD  A,(BACKGROUND)
  2661.         OR  &07
  2662.         LD  (HL),A
  2663. L962F:      LD  A,(NASTY)
  2664.         CP  (HL)
  2665.         JP  Z,DIED2
  2666.         RET
  2667.  
  2668.  
  2669. ; Display Willy
  2670. ; =============
  2671. DRAWWILLY:  LD  A,(YPOSN)   ; Get Willy's Y position
  2672.         ADD A,B
  2673.         DEFB    &DD
  2674.         LD  H,PIXEL / 256   ; LD IXH,&82        ; Pixel-line buffer
  2675.         DEFB    &DD
  2676.         LD  L,A     ; LD IXL,A
  2677.         LD  A,(L85D0)
  2678.         AND &01
  2679.         RRCA
  2680.         LD  E,A
  2681.         LD  A,(FRAME)
  2682.         AND &03
  2683.         RRCA
  2684.         RRCA
  2685.         RRCA
  2686.         OR  E
  2687.         LD  E,A
  2688.         LD  D,&9D       ; Point to Willy sprites
  2689. IF ROOMSPRITE
  2690.         LD  A,(WILLYSP) ; Does room specify a player sprite?
  2691.         AND A
  2692.         JP  P,L9660     ; No, use Willy sprite
  2693.         LD  D,A     ; Use specified sprite
  2694.         NOP
  2695. ELSE
  2696.         LD  A,(HERE)    ; Get current room
  2697.         CP  &1D     ; In the Nightmare Room?
  2698.         JR  NZ,L9660    ; No, use Willy sprite
  2699.         LD  D,&B6       ; Point to flying pig
  2700. ENDIF
  2701.         LD  A,E     ; Reverse the sprite direction
  2702.         XOR &80     ; Willy sprites are Right/Left
  2703.         LD  E,A     ; All other sprites are Left/Right
  2704. L9660:      LD  B,&10       ; 16 pixel-lines
  2705.         LD  A,(POSITION)    ; Get Willy's position
  2706.         AND &1F     ; X position
  2707.         LD  C,A
  2708.  
  2709. L9668:      LD  A,(IX+&00)  ; Get pixel-line address of column 0
  2710.         LD  H,(IX+&01)
  2711.         OR  C       ; Add on X coordinate
  2712.         LD  L,A     ; HL=pixel-line address in buffer 2
  2713.         LD  A,(DE)      ; Get byte from sprite
  2714.         OR  (HL)        ; Merge with screen content
  2715.         LD  (HL),A      ; Store to screen
  2716.         INC HL      ; Move to next pixel cell
  2717.         INC DE      ; Move to next sprite byte
  2718.         LD  A,(DE)      ; Get byte from sprite
  2719.         OR  (HL)        ; Merge with screen content
  2720.         LD  (HL),A      ; Store to screen
  2721.         INC IX      ; Point to next pixel-line address
  2722.         INC IX
  2723.         INC DE      ; Point to next sprite byte
  2724.         DJNZ    L9668       ; Loop for 16 pixel-lines
  2725.         RET
  2726.  
  2727.  
  2728. ; Write a string to the screen
  2729. ; ============================
  2730. ; On entry: IX=>ASCII string
  2731. ;           DE=>Display address to write to
  2732. ;           C=  String length
  2733. PRMESSAGE:  LD  A,(IX+&00)  ; Get a character
  2734.         CALL    PRCHAR      ; Write to screen at DE
  2735.         INC IX      ; Move to next character
  2736.         INC E       ; Move to next screen cell
  2737.         LD  A,D     ; DE has been left pointing to the
  2738.         SUB &08     ;  'ninth' pixel line, so adjust
  2739.         LD  D,A     ;  D back to line 1
  2740.         DEC C       ; Decrement string length
  2741.         JR  NZ,PRMESSAGE    ; Loop for the string
  2742.         RET
  2743.  
  2744. ; Write a character to screen
  2745. ; ---------------------------
  2746. PRCHAR:     LD  H,&07
  2747.         LD  L,A     ; Copy character to L
  2748.         SET 7,L
  2749.         ADD HL,HL       ; Multiple HL by 8
  2750.         ADD HL,HL
  2751.         ADD HL,HL       ; HL=>character matrix at &3C00-&3F00
  2752.         LD  B,&08       ; Eight pixel-lines
  2753. PRMATRIX:   LD  A,(HL)      ; Get character line
  2754.         LD  (DE),A      ; Store in screen
  2755.         INC HL      ; Point to next character line
  2756.         INC D       ; Point to next pixel line
  2757.         DJNZ    PRMATRIX    ; Loop for all eight lines
  2758.         RET
  2759.  
  2760.  
  2761. ; Play introductory tune
  2762. ; ======================
  2763. L96A2:      LD  A,(HL)      ; Get current note
  2764.         CP  &FF     ; End of tune?
  2765.         RET Z       ; Yes, so exit
  2766.         LD  BC,&0064
  2767.         XOR A
  2768.         LD  E,(HL)
  2769.         LD  D,E
  2770. L96AC:      OUT (&FE),A
  2771.         DEC D
  2772.         JR  NZ,L96B4
  2773.         LD  D,E
  2774.         XOR &18
  2775. L96B4:      DJNZ    L96AC
  2776.         EX  AF,AF'
  2777.         LD  A,C
  2778.         CP  &32
  2779.         JR  NZ,L96BE
  2780.         RL  E
  2781. L96BE:      EX  AF,AF'
  2782.         DEC C
  2783.         JR  NZ,L96AC
  2784. IF GAMEEXIT
  2785.         CALL    L840D       ; Check ENTER/FIRE/SS-SPACE
  2786. ELSE
  2787.         CALL    L96C9       ; Is ENTER/FIRE pressed?
  2788. ENDIF
  2789.         RET NZ      ; Exit if so
  2790.         INC HL
  2791.         JR  L96A2
  2792.  
  2793.  
  2794. ; Check if ENTER/FIRE/0 pressed
  2795. ; On exit, NZ=ENTER, FIRE or 0 pressed
  2796. L96C9:      LD  A,(KEMPSTON)    ; Is kempston present?
  2797.         OR  A
  2798.         JR  Z,L96D4     ; No, jump to look at keyboard
  2799.         IN  A,(&1F)     ; Read joystick
  2800.         BIT 4,A     ; Check FIRE button
  2801.         RET NZ      ; Return if pressed
  2802. L96D4:      LD  BC,&AFFE    ; Look at ENTER and 0 keys
  2803.         IN  A,(C)
  2804.         AND &01
  2805.         CP  &01     ; Is ENTER/0 pressed?
  2806.         RET
  2807.  
  2808.  
  2809. ; Play a note from the sliding scale as intro message scrolls past
  2810. ; ================================================================
  2811. L96DE:      LD  E,A
  2812.         LD  C,&FE
  2813. L96E1:      LD  D,A
  2814.         RES 4,D
  2815.         RES 3,D
  2816.         LD  B,E
  2817. L96E7:      CP  B
  2818.         JR  NZ,L96EC
  2819.         LD  D,&18
  2820. L96EC:      OUT (C),D
  2821.         DJNZ    L96E7
  2822.         DEC A
  2823.         JR  NZ,L96E1
  2824.         RET
  2825.  
  2826.  
  2827. ; Unused code
  2828. ; ===========
  2829. ; This code space can be used for patches to the game engine.
  2830. ; The 7-bit room patch uses the space at &96F4-&96FF, and room 87 uses &97xx.
  2831. IF MOREROOMS
  2832. L96F4:      LD  C,(HL)      ; Get object's room number
  2833.         RES 7,C     ; Remove screen address bit8
  2834.         LD  A,(HERE)    ; Get current room
  2835.         CP  C       ; Is object in this room?
  2836.         RET Z       ; Yes, exit to collect
  2837.         INC H       ; Point HL back to 'collected' flags
  2838.         INC H
  2839.         RET         ; and exit to check next object
  2840.         NOP
  2841. ELSE
  2842. L96F4:      LD  HL,&5E00
  2843.         LD  DE,&5800
  2844.         LD  BC,&0200
  2845.         LDIR            ; Copy buffer 2 attributes to screen
  2846.         LD  HL,&4000
  2847.         LD  DE,&4001
  2848.         LD  BC,&0FFF
  2849.         LD  (HL),&18    ; Set display to vertical lines
  2850.         LDIR
  2851.         LD  BC,&FEFE    ; Read keyboard
  2852. L970F:      IN  A,(C)       ; Read V-C-X-Z-SHIFT
  2853.         BIT 2,A     ; Is X pressed?
  2854.         JP  Z,&0000     ; If pressed, jump to reset
  2855.         JR  L970F       ; Loop if no key pressed
  2856. ENDIF
  2857.  
  2858. ; Screen attributes
  2859. ; =================
  2860. ; The startup screen attributes define where the triangle will be displayed as well
  2861. ; as forming the words JET SET WILLY.
  2862.         DEFS ATTRS-$
  2863.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2864.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2865.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2866.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2867.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2868.         DEFB &00,&00,&28,&28,&05,&05,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2869.         DEFB &00,&00,&00,&00,&D3,&D3,&D3,&00,&D3,&D3,&D3,&00,&D3,&D3,&D3,&00
  2870.         DEFB &28,&D3,&D3,&D3,&25,&D3,&D3,&D3,&00,&D3,&D3,&D3,&00,&00,&00,&00
  2871.         DEFB &00,&00,&00,&00,&00,&D3,&00,&00,&D3,&00,&00,&00,&00,&D3,&28,&28
  2872.         DEFB &2D,&D3,&25,&25,&24,&D3,&00,&00,&00,&00,&D3,&00,&00,&00,&00,&00
  2873.         DEFB &00,&00,&00,&00,&00,&D3,&00,&00,&D3,&D3,&D3,&00,&28,&D3,&2D,&2D
  2874.         DEFB &25,&D3,&D3,&D3,&24,&D3,&D3,&D3,&00,&00,&D3,&00,&00,&00,&00,&00
  2875.         DEFB &00,&00,&00,&00,&00,&D3,&00,&00,&D3,&00,&28,&28,&2D,&D3,&25,&25
  2876.         DEFB &24,&24,&0C,&D3,&24,&D3,&00,&00,&00,&00,&D3,&00,&00,&00,&00,&00
  2877.         DEFB &00,&00,&00,&00,&D3,&D3,&00,&00,&D3,&D3,&D3,&2D,&25,&D3,&24,&24
  2878.         DEFB &04,&D3,&D3,&D3,&24,&D3,&D3,&D3,&00,&00,&D3,&00,&00,&00,&00,&00
  2879.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&29,&29,&2D,&2D,&2C,&2C,&04,&04
  2880.         DEFB &00,&00,&09,&09,&24,&24,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2881.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&09,&09,&29,&29,&2D,&2D,&05,&05
  2882.         DEFB &00,&00,&09,&09,&24,&24,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2883.         DEFB &00,&00,&00,&00,&00,&00,&D3,&00,&08,&08,&D3,&09,&D3,&29,&D3,&2D
  2884.         DEFB &05,&05,&D3,&09,&24,&D3,&00,&00,&00,&D3,&00,&00,&00,&00,&00,&00
  2885.         DEFB &00,&00,&00,&00,&00,&00,&D3,&00,&00,&00,&D3,&08,&D3,&09,&D3,&29
  2886.         DEFB &2D,&2D,&D3,&09,&24,&D3,&00,&00,&00,&D3,&00,&00,&00,&00,&00,&00
  2887.         DEFB &00,&00,&00,&00,&00,&00,&D3,&00,&D3,&00,&D3,&00,&D3,&08,&D3,&09
  2888.         DEFB &29,&29,&D3,&09,&24,&D3,&D3,&D3,&D3,&D3,&00,&00,&00,&00,&00,&00
  2889.         DEFB &00,&00,&00,&00,&00,&00,&D3,&00,&D3,&00,&D3,&00,&D3,&00,&D3,&08
  2890.         DEFB &09,&09,&D3,&09,&24,&24,&00,&D3,&00,&00,&00,&00,&00,&00,&00,&00
  2891.         DEFB &00,&00,&00,&00,&00,&00,&D3,&D3,&D3,&D3,&D3,&00,&D3,&00,&D3,&D3
  2892.         DEFB &D3,&08,&D3,&D3,&D3,&24,&00,&D3,&00,&00,&00,&00,&00,&00,&00,&00
  2893.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2894.         DEFB &00,&00,&08,&08,&04,&04,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2895.  
  2896. ; The attributes for the bottom third of the screen are used for the room name, items
  2897. ; collected line, and for the colours of the lives left Willys.
  2898.         DEFB &46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46    ; Room name
  2899.         DEFB &46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46,&46
  2900.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2901.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2902.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2903.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2904.         DEFB &01,&02,&03,&04,&05,&06,&07,&07,&07,&07,&07,&07,&07,&07,&07,&07    ; Items
  2905.         DEFB &07,&07,&07,&07,&07,&07,&07,&07,&07,&07,&06,&05,&04,&03,&02,&01
  2906.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2907.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2908.         DEFB &45,&45,&06,&06,&04,&04,&41,&41,&05,&05,&43,&43,&44,&44,&02,&02    ; Lives left
  2909.         DEFB &45,&45,&06,&06,&04,&04,&41,&41,&05,&05,&43,&43,&44,&44,&02,&02
  2910.         DEFB &45,&45,&06,&06,&04,&04,&41,&41,&05,&05,&43,&43,&44,&44,&02,&02
  2911.         DEFB &45,&45,&06,&06,&04,&04,&41,&41,&05,&05,&43,&43,&44,&44,&02,&02
  2912.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
  2913.         DEFB &00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement