Prev: 6CEE Up: Map Next: 6EF8
6DCF: Handler: Shield
Used by the routine at Handler_PlayerDeathGameOver.
Handler_Shield 6DCF CALL CheckCollision Call CheckCollision.
6DD2 LD A,($66ED) A=*PlayerAttributeBufferPosition.
6DD5 PUSH AF Stash the player position on the stack.
6DD6 LD HL,$6694 Jump to Shield_CheckDemoMode if *ShieldTimer isn't active.
6DD9 LD A,(HL)
6DDA OR A
6DDB JR Z,Shield_CheckDemoMode
The players shield is active, so decrease the shield timer.
6DDD DEC (HL) Decrease *ShieldTimer by one.
Check if the timer has "wrapped around" to FF i.e. finished counting down.
6DDE BIT 7,(HL) Jump to PlayShieldSound if bit 7 of *ShieldTimer is set.
6DE0 JR NZ,PlayShieldSound
6DE2 XOR A Write 00 ("inactive") to *Flag_Shield.
6DE3 LD ($6693),A
6DE6 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 6DE8 LD A,($66F3) Jump to Shield_CheckKempston if *Flag_ActiveDemoMode is not active.
6DEB OR A
6DEC JR Z,Shield_CheckKempston
Demo mode is active, so use a random number to decide whether to activate the shield or not.
6DEE CALL GenerateRandomNumber Call GenerateRandomNumber.
6DF1 OR A Jump to Shield_ActivateShield if the generated random number is zero.
6DF2 JR Z,Shield_ActivateShield
6DF4 JR PlayShieldSound Jump to PlayShieldSound.
Check if the control method is the Kempston joystick?
Shield_CheckKempston 6DF6 LD A,($66F6) Jump to Shield_CheckAGF if *ControlMethod is not the Kempston joystick.
6DF9 CP $02
6DFB JR NZ,Shield_CheckAGF
The control method is Kempston joystick, so test for "down" being pressed.
6DFD IN A,($1F) A=read from the Kempston joystick port.
6DFF AND %00000100 Jump to Shield_ActivateShield if "down" (bit 2) is being pressed.
6E01 JR NZ,Shield_ActivateShield
6E03 JR PlayShieldSound Jump to PlayShieldSound.
Check if the control method is the AGF joystick?
Shield_CheckAGF 6E05 CP $01 Jump to Shield_CheckKeyboard if *ControlMethod is not the AGF joystick.
6E07 JR NZ,Shield_CheckKeyboard
The control method is the AGF joystick, so test for "down" being pressed.
6E09 LD A,$EF Read from the keyboard;
Port Number Bit
0 1 2 3 4
EF 0 9 8 7 6
6E0B IN A,($FE)
6E0D BIT 4,A Jump to Shield_ActivateShield if "down" ("4") was pressed.
6E0F JR Z,Shield_ActivateShield
6E11 JR PlayShieldSound Jump to PlayShieldSound.
Else, the only control option left is the keyboard.
Shield_CheckKeyboard 6E13 LD A,$BF Read from the keyboard;
Port Number Bit
0 1 2 3 4
BF ENTER L K J H
6E15 IN A,($FE)
6E17 AND %00000001 Jump to PlayShieldSound if "ENTER" isn't being pressed.
6E19 JR NZ,PlayShieldSound
Activate the shield.
Shield_ActivateShield 6E1B LD (HL),$FF Write FF to *ShieldTimer.
6E1D DEC HL Write 01 to *Flag_Shield to activate it.
6E1E LD (HL),$01
Play a sound when the shield is active (but not in demo mode).
PlayShieldSound 6E20 LD A,($6693) Jump to Handler_ShipMovement if *Flag_Shield is not active.
6E23 OR A
6E24 JP Z,Handler_ShipMovement
6E27 LD A,($66F3) Jump to DrawShield if *Flag_ActiveDemoMode is active.
6E2A OR A
6E2B JR NZ,DrawShield
Play an iteration of the shield sound effect.
6E2D LD A,($6694) A=*ShieldTimer.
6E30 AND %00000111 Calculate the sound pitch: 00DE + ((*ShieldTimer & 07) × 04).
6E32 ADD A,A
6E33 ADD A,A
6E34 LD HL,$00DE
6E37 LD D,H
6E38 LD E,A
6E39 ADD HL,DE
6E3A LD E,$04 Set the duration in E to 04.
6E3C CALL $03B5 Call BEEPER.
6E3F 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 6E40 LD HL,($66ED) Load the player position from PlayerAttributeBufferPosition into HL.
6E43 LD H,$52 Set H to 52 (attribute buffer base address).
6E45 LD B,$02 Set counter in B for 02 shield segments (left and right).
6E47 LD A,($66A6) Load the movement animation frame counter from MovementAnimationFrameCounter into A.
6E4A 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 6E4B OR A Test if the movement animation frame counter value in A is zero.
6E4C LD DE,$0000 Initialise the value to 0000 ("NOP NOP").
6E4F JR NZ,DrawShield_SetAttribute Jump to DrawShield_SetAttribute if the movement animation frame counter is zero (use default value).
6E51 LD A,($6694) Jump to DrawShield_SetAttribute if bit 2 of the shield state at *ShieldTimer is not set (shield not active).
6E54 BIT 2,A
6E56 JR Z,DrawShield_SetAttribute
6E58 LD DE,$0136 Set the value to 0136 ("LD (HL),01").
6E5B LD A,B Jump to DrawShield_SetAttribute if this is not the second segment (B is not 01).
6E5C CP $01
6E5E JR NZ,DrawShield_SetAttribute
6E60 LD D,$80 Set the high byte of the value to 80 for the second segment.
Store the calculated value for both shield segments using self-modifying code.
DrawShield_SetAttribute 6E62 LD ($6E87),DE Write the self-modifying code to the address used by the left segment (6E87).
6E66 LD ($6E9A),DE Write the self-modifying code to the address used by the right segment (6E9A).
6E6A POP AF Restore the movement animation frame counter from the stack.
6E6B INC A Increment the movement animation frame counter value in A.
6E6C PUSH BC Stash BC on the stack.
6E6D LD B,A Set the loop counter in B to the movement animation frame counter value.
6E6E PUSH HL Stash the attribute buffer address in HL on the stack.
6E6F LD HL,$6E86 Load the address of the left segment code to modify at (6E86).
Calculate an attribute byte value based on the movement animation frame counter.
6E72 LD A,($6694) Load the shield state from *ShieldTimer.
6E75 BIT 2,A Test bit 2 of the shield state to check if the shield is active.
6E77 LD A,$7E Set the base attribute value to INK:YELLOW, PAPER:WHITE (BRIGHT).
6E79 JR Z,DrawShield_AttributeLoop Jump to DrawShield_AttributeLoop if the shield is not active (use base value).
6E7B ADD A,$40 Add 40 to the base attribute value (set BRIGHT bit).
DrawShield_AttributeLoop 6E7D ADD A,$08 Add 08 to the attribute value (increment PAPER colour).
6E7F DJNZ DrawShield_AttributeLoop Decrease counter by one and loop back to DrawShield_AttributeLoop until counter is zero.
6E81 LD (HL),A Write the calculated attribute byte to the storage location.
6E82 POP HL Restore the attribute buffer address from the stack.
Draw the left shield segment.
6E83 LD B,$06 Set a counter in B for 06 lines of the left shield segment.
DrawShield_LeftSegment_Loop 6E85 SET 0,(HL) Set bit 0 of the attribute byte at *HL (set INK bit 0).
Modified by the code at DrawShield_SetAttribute.
6E87 LD (HL),$01 Write 01 to the attribute buffer at *HL.
6E89 INC H Move down one line in the attribute buffer.
6E8A DJNZ DrawShield_LeftSegment_Loop Decrease the left segment loop counter by one and loop back to DrawShield_LeftSegment_Loop until all 06 lines are drawn.
6E8C LD A,($6E86) Load the attribute value from the storage location.
6E8F LD ($6E99),A Store the attribute value at the address used by the right segment.
6E92 SET 5,L Move to the right segment position (set bit 5 of L, add 20).
6E94 LD H,$50 Set H to 50 (screen buffer base address).
Draw the right shield segment.
6E96 LD B,$08 Set a counter in B for 08 lines of the right shield segment.
DrawShield_RightSegment_Loop 6E98 SET 0,(HL) Set bit 0 of the pixel data at *HL (set pixel bit 0).
Modified by the code at 6E66.
6E9A LD (HL),$01 Write 01 to the screen buffer at *HL.
6E9C INC H Move down one pixel line in the screen buffer.
6E9D DJNZ DrawShield_RightSegment_Loop Decrease the right segment loop counter by one and loop back to DrawShield_RightSegment_Loop until all 08 lines are drawn.
6E9F LD HL,($66ED) Reload the player position from PlayerAttributeBufferPosition.
6EA2 LD H,$52 Set H back to 52 (attribute buffer base address).
6EA4 INC L Move to the next shield segment position (increment L by two).
6EA5 INC L
6EA6 POP BC Restore BC from the stack.
6EA7 LD A,($66A6) Reload the movement animation frame counter from MovementAnimationFrameCounter into A.
6EAA PUSH AF Stash AF on the stack.
6EAB SUB $07 Decrease the movement animation frame counter by 07 to adjust for the next iteration.
6EAD 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.
6EAF POP AF Restore AF from the stack.
6EB0 LD A,($6694) Load the shield state from *ShieldTimer.
6EB3 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.
6EB5 LD HL,$6014 Set HL to point to the first shield sprite at Graphics_Shield_01.
6EB8 JR Z,DrawShield_CopySprite Jump to DrawShield_CopySprite if the shield is not active (use first sprite).
6EBA LD HL,$601D Set HL to point to the second shield sprite at Graphics_Shield_02.
Copy the shield sprite data (09 bytes) to the work buffer at 617B.
DrawShield_CopySprite 6EBD LD DE,$617B Set DE to point to the work buffer at 617B.
6EC0 LD C,$09 Set the shield byte count in C to 09.
6EC2 LDIR Copy the shield sprite data from HL to the work buffer.
6EC4 LD A,($66A6) Jump to DrawPlayersShip if the movement animation frame counter at *MovementAnimationFrameCounter is zero (skip bit manipulation).
6EC7 OR A
6EC8 JR Z,DrawPlayersShip
Apply bit manipulation to the shield graphic data based on the movement animation frame counter value.
6ECA LD B,A Load the movement animation frame counter from *MovementAnimationFrameCounter into B (outer loop counter).
DrawShield_RotateLoop 6ECB PUSH BC Stash the outer loop counter on the stack.
6ECC LD HL,$617B Set HL to point to the work buffer at 617B.
6ECF LD B,$09 Set counter in B for 09 bytes (one complete pass).
DrawShield_RotateByte 6ED1 SLA (HL) Shift the byte at *HL left by one bit.
6ED3 INC HL Move to the next byte in the work buffer.
6ED4 BIT 7,(HL) Test bit 7 of the next byte.
6ED6 DEC HL Move back to the previous byte.
6ED7 JR Z,DrawShield_RotateNext Jump to DrawShield_RotateNext if bit 7 was not set (no carry to propagate).
6ED9 SET 0,(HL) Set bit 0 of the current byte (propagate the carry).
DrawShield_RotateNext 6EDB INC HL Move to the next byte in the work buffer.
6EDC DJNZ DrawShield_RotateByte Decrease counter by one and loop back to DrawShield_RotateByte until all 09 bytes are processed.
6EDE POP BC Restore the outer loop counter from the stack.
6EDF 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 617B, which may have been modified by the shield bit manipulation routine.
DrawPlayersShip 6EE1 LD DE,($66ED) Load the player position from PlayerAttributeBufferPosition.
6EE5 LD D,$50 Set D to 50 (screen buffer base address).
6EE7 LD HL,$617B Set HL to point to the ship graphic data in the work buffer at 617B.
6EEA LD B,$03 Set counter in B for 03 pixel rows (ship sprite height).
Draw each row of the ship sprite (3 bytes per row, 3 rows total).
DrawPlayersShip_Loop 6EEC PUSH BC Stash the row counter and screen position on the stack.
6EED PUSH DE
6EEE LD BC,$0003 Set a row counter in BC to 0003 bytes.
6EF1 LDIR Copy the ship graphic row from HL to the screen buffer.
6EF3 POP DE Restore the screen position from the stack.
6EF4 INC D Move down one pixel line in the screen buffer.
6EF5 POP BC Restore the row counter from the stack.
6EF6 DJNZ DrawPlayersShip_Loop Decrease counter by one and loop back to DrawPlayersShip_Loop until all 03 rows are drawn.
Continue on to Handler_ShipMovement.
Prev: 6CEE Up: Map Next: 6EF8