Prev: 27886 Up: Map Next: 28408
28111: Handler: Shield
Used by the routine at Handler_PlayerDeathGameOver.
Handler_Shield 28111 CALL CheckCollision Call CheckCollision.
28114 LD A,(26349) A=*PlayerAttributeBufferPosition.
28117 PUSH AF Stash the player position on the stack.
28118 LD HL,26260 Jump to Shield_CheckDemoMode if *ShieldTimer isn't active.
28121 LD A,(HL)
28122 OR A
28123 JR Z,Shield_CheckDemoMode
The players shield is active, so decrease the shield timer.
28125 DEC (HL) Decrease *ShieldTimer by one.
Check if the timer has "wrapped around" to 255 i.e. finished counting down.
28126 BIT 7,(HL) Jump to PlayShieldSound if bit 7 of *ShieldTimer is set.
28128 JR NZ,PlayShieldSound
28130 XOR A Write 0 ("inactive") to *Flag_Shield.
28131 LD (26259),A
28134 JR PlayShieldSound Jump to PlayShieldSound.
Check for shield activation player inputs.
Start by checking if the game is running in demo mode or not?
Shield_CheckDemoMode 28136 LD A,(26355) Jump to Shield_CheckKempston if *Flag_ActiveDemoMode is not active.
28139 OR A
28140 JR Z,Shield_CheckKempston
Demo mode is active, so use a random number to decide whether to activate the shield or not.
28142 CALL GenerateRandomNumber Call GenerateRandomNumber.
28145 OR A Jump to Shield_ActivateShield if the generated random number is zero.
28146 JR Z,Shield_ActivateShield
28148 JR PlayShieldSound Jump to PlayShieldSound.
Check if the control method is the Kempston joystick?
Shield_CheckKempston 28150 LD A,(26358) Jump to Shield_CheckAGF if *ControlMethod is not the Kempston joystick.
28153 CP 2
28155 JR NZ,Shield_CheckAGF
The control method is Kempston joystick, so test for "down" being pressed.
28157 IN A,(31) A=read from the Kempston joystick port.
28159 AND %00000100 Jump to Shield_ActivateShield if "down" (bit 2) is being pressed.
28161 JR NZ,Shield_ActivateShield
28163 JR PlayShieldSound Jump to PlayShieldSound.
Check if the control method is the AGF joystick?
Shield_CheckAGF 28165 CP 1 Jump to Shield_CheckKeyboard if *ControlMethod is not the AGF joystick.
28167 JR NZ,Shield_CheckKeyboard
The control method is the AGF joystick, so test for "down" being pressed.
28169 LD A,239 Read from the keyboard;
Port Number Bit
0 1 2 3 4
239 0 9 8 7 6
28171 IN A,(254)
28173 BIT 4,A Jump to Shield_ActivateShield if "down" ("4") was pressed.
28175 JR Z,Shield_ActivateShield
28177 JR PlayShieldSound Jump to PlayShieldSound.
Else, the only control option left is the keyboard.
Shield_CheckKeyboard 28179 LD A,191 Read from the keyboard;
Port Number Bit
0 1 2 3 4
191 ENTER L K J H
28181 IN A,(254)
28183 AND %00000001 Jump to PlayShieldSound if "ENTER" isn't being pressed.
28185 JR NZ,PlayShieldSound
Activate the shield.
Shield_ActivateShield 28187 LD (HL),255 Write 255 to *ShieldTimer.
28189 DEC HL Write 1 to *Flag_Shield to activate it.
28190 LD (HL),1
Play a sound when the shield is active (but not in demo mode).
PlayShieldSound 28192 LD A,(26259) Jump to Handler_ShipMovement if *Flag_Shield is not active.
28195 OR A
28196 JP Z,Handler_ShipMovement
28199 LD A,(26355) Jump to DrawShield if *Flag_ActiveDemoMode is active.
28202 OR A
28203 JR NZ,DrawShield
Play an iteration of the shield sound effect.
28205 LD A,(26260) A=*ShieldTimer.
28208 AND %00000111 Calculate the sound pitch: 0222 + ((*ShieldTimer & 7) × 4).
28210 ADD A,A
28211 ADD A,A
28212 LD HL,222
28215 LD D,H
28216 LD E,A
28217 ADD HL,DE
28218 LD E,4 Set the duration in E to 4.
28220 CALL 949 Call BEEPER.
28223 DI Disable interrupts.
Draws the shield graphic around the ship in the attribute buffer and screen buffer. The shield consists of two segments (left and right) that are drawn when the shield is active.
DrawShield 28224 LD HL,(26349) Load the player position from PlayerAttributeBufferPosition into HL.
28227 LD H,82 Set H to 82 (attribute buffer base address).
28229 LD B,2 Set counter in B for 2 shield segments (left and right).
28231 LD A,(26278) Load the movement animation frame counter from MovementAnimationFrameCounter into A.
28234 PUSH AF Stash the movement animation frame counter on the stack.
Calculate a value to be used for this shield segment based on the shield state and movement animation frame counter.
DrawShield_SegmentLoop 28235 OR A Test if the movement animation frame counter value in A is zero.
28236 LD DE,0 Initialise the value to 0000 ("NOP NOP").
28239 JR NZ,DrawShield_SetAttribute Jump to DrawShield_SetAttribute if the movement animation frame counter is zero (use default value).
28241 LD A,(26260) Jump to DrawShield_SetAttribute if bit 2 of the shield state at *ShieldTimer is not set (shield not active).
28244 BIT 2,A
28246 JR Z,DrawShield_SetAttribute
28248 LD DE,310 Set the value to 0310 ("LD (HL),1").
28251 LD A,B Jump to DrawShield_SetAttribute if this is not the second segment (B is not 1).
28252 CP 1
28254 JR NZ,DrawShield_SetAttribute
28256 LD D,128 Set the high byte of the value to 128 for the second segment.
Store the calculated value for both shield segments using self-modifying code.
DrawShield_SetAttribute 28258 LD (28295),DE Write the self-modifying code to the address used by the left segment (28295).
28262 LD (28314),DE Write the self-modifying code to the address used by the right segment (28314).
28266 POP AF Restore the movement animation frame counter from the stack.
28267 INC A Increment the movement animation frame counter value in A.
28268 PUSH BC Stash BC on the stack.
28269 LD B,A Set the loop counter in B to the movement animation frame counter value.
28270 PUSH HL Stash the attribute buffer address in HL on the stack.
28271 LD HL,28294 Load the address of the left segment code to modify at (28294).
Calculate an attribute byte value based on the movement animation frame counter.
28274 LD A,(26260) Load the shield state from *ShieldTimer.
28277 BIT 2,A Test bit 2 of the shield state to check if the shield is active.
28279 LD A,126 Set the base attribute value to INK:YELLOW, PAPER:WHITE (BRIGHT).
28281 JR Z,DrawShield_AttributeLoop Jump to DrawShield_AttributeLoop if the shield is not active (use base value).
28283 ADD A,64 Add 64 to the base attribute value (set BRIGHT bit).
DrawShield_AttributeLoop 28285 ADD A,8 Add 8 to the attribute value (increment PAPER colour).
28287 DJNZ DrawShield_AttributeLoop Decrease counter by one and loop back to DrawShield_AttributeLoop until counter is zero.
28289 LD (HL),A Write the calculated attribute byte to the storage location.
28290 POP HL Restore the attribute buffer address from the stack.
Draw the left shield segment.
28291 LD B,6 Set a counter in B for 6 lines of the left shield segment.
DrawShield_LeftSegment_Loop 28293 SET 0,(HL) Set bit 0 of the attribute byte at *HL (set INK bit 0).
Modified by the code at DrawShield_SetAttribute.
28295 LD (HL),1 Write 1 to the attribute buffer at *HL.
28297 INC H Move down one line in the attribute buffer.
28298 DJNZ DrawShield_LeftSegment_Loop Decrease the left segment loop counter by one and loop back to DrawShield_LeftSegment_Loop until all 6 lines are drawn.
28300 LD A,(28294) Load the attribute value from the storage location.
28303 LD (28313),A Store the attribute value at the address used by the right segment.
28306 SET 5,L Move to the right segment position (set bit 5 of L, add 32).
28308 LD H,80 Set H to 80 (screen buffer base address).
Draw the right shield segment.
28310 LD B,8 Set a counter in B for 8 lines of the right shield segment.
DrawShield_RightSegment_Loop 28312 SET 0,(HL) Set bit 0 of the pixel data at *HL (set pixel bit 0).
Modified by the code at 28262.
28314 LD (HL),1 Write 1 to the screen buffer at *HL.
28316 INC H Move down one pixel line in the screen buffer.
28317 DJNZ DrawShield_RightSegment_Loop Decrease the right segment loop counter by one and loop back to DrawShield_RightSegment_Loop until all 8 lines are drawn.
28319 LD HL,(26349) Reload the player position from PlayerAttributeBufferPosition.
28322 LD H,82 Set H back to 82 (attribute buffer base address).
28324 INC L Move to the next shield segment position (increment L by two).
28325 INC L
28326 POP BC Restore BC from the stack.
28327 LD A,(26278) Reload the movement animation frame counter from MovementAnimationFrameCounter into A.
28330 PUSH AF Stash AF on the stack.
28331 SUB 7 Decrease the movement animation frame counter by 7 to adjust for the next iteration.
28333 DJNZ DrawShield_SegmentLoop Decrease counter by one and loop back to DrawShield_SegmentLoop until both shield segments are drawn.
Process the shield graphic data: copy the appropriate shield sprite to the work buffer and apply bit manipulation if the shield timer is active.
28335 POP AF Restore AF from the stack.
28336 LD A,(26260) Load the shield state from *ShieldTimer.
28339 BIT 2,A Test bit 2 of the shield state to check if the shield is active.
Select which shield sprite to use based on the shield state.
28341 LD HL,24596 Set HL to point to the first shield sprite at Graphics_Shield_01.
28344 JR Z,DrawShield_CopySprite Jump to DrawShield_CopySprite if the shield is not active (use first sprite).
28346 LD HL,24605 Set HL to point to the second shield sprite at Graphics_Shield_02.
Copy the shield sprite data (9 bytes) to the work buffer at 24955.
DrawShield_CopySprite 28349 LD DE,24955 Set DE to point to the work buffer at 24955.
28352 LD C,9 Set the shield byte count in C to 9.
28354 LDIR Copy the shield sprite data from HL to the work buffer.
28356 LD A,(26278) Jump to DrawPlayersShip if the movement animation frame counter at *MovementAnimationFrameCounter is zero (skip bit manipulation).
28359 OR A
28360 JR Z,DrawPlayersShip
Apply bit manipulation to the shield graphic data based on the movement animation frame counter value.
28362 LD B,A Load the movement animation frame counter from *MovementAnimationFrameCounter into B (outer loop counter).
DrawShield_RotateLoop 28363 PUSH BC Stash the outer loop counter on the stack.
28364 LD HL,24955 Set HL to point to the work buffer at 24955.
28367 LD B,9 Set counter in B for 9 bytes (one complete pass).
DrawShield_RotateByte 28369 SLA (HL) Shift the byte at *HL left by one bit.
28371 INC HL Move to the next byte in the work buffer.
28372 BIT 7,(HL) Test bit 7 of the next byte.
28374 DEC HL Move back to the previous byte.
28375 JR Z,DrawShield_RotateNext Jump to DrawShield_RotateNext if bit 7 was not set (no carry to propagate).
28377 SET 0,(HL) Set bit 0 of the current byte (propagate the carry).
DrawShield_RotateNext 28379 INC HL Move to the next byte in the work buffer.
28380 DJNZ DrawShield_RotateByte Decrease counter by one and loop back to DrawShield_RotateByte until all 9 bytes are processed.
28382 POP BC Restore the outer loop counter from the stack.
28383 DJNZ DrawShield_RotateLoop Decrease the outer loop counter by one and loop back to DrawShield_RotateLoop until the shield timer value is reached.
Draws the player's ship sprite to the screen buffer. The ship graphic is copied from the work buffer at 24955, which may have been modified by the shield bit manipulation routine.
DrawPlayersShip 28385 LD DE,(26349) Load the player position from PlayerAttributeBufferPosition.
28389 LD D,80 Set D to 80 (screen buffer base address).
28391 LD HL,24955 Set HL to point to the ship graphic data in the work buffer at 24955.
28394 LD B,3 Set counter in B for 3 pixel rows (ship sprite height).
Draw each row of the ship sprite (3 bytes per row, 3 rows total).
DrawPlayersShip_Loop 28396 PUSH BC Stash the row counter and screen position on the stack.
28397 PUSH DE
28398 LD BC,3 Set a row counter in BC to 0003 bytes.
28401 LDIR Copy the ship graphic row from HL to the screen buffer.
28403 POP DE Restore the screen position from the stack.
28404 INC D Move down one pixel line in the screen buffer.
28405 POP BC Restore the row counter from the stack.
28406 DJNZ DrawPlayersShip_Loop Decrease counter by one and loop back to DrawPlayersShip_Loop until all 3 rows are drawn.
Continue on to Handler_ShipMovement.
Prev: 27886 Up: Map Next: 28408