;-----------------------------------------------------------; ; ; ; Invaded ; ; Version 1.0 ; ; Main Game Loop Routines, etc. ; ; ; ;-----------------------------------------------------------; newGame: ; Ini vars xor a ld (cpX),a sbc hl,hl ; HL = 0 ld (score),hl ld a,2 ld (lives),a ; Get all required pointers, etc. ld hl,(dataPtr) ; HL => Start of Levelset header data ld a,(hl) ; A = Number of levels ld (noLevels),a inc hl ld a,(hl) ; A = Number of enemies ld (noEnemies),a inc hl ld e,(hl) inc hl ld d,(hl) ; DE = High score ld (hiScore),de ld de,LEVELSET_HEADER_LENGTH-3 add hl,de ; HL => Start of compressed files ld (cmpPtr),hl ld ix,gbuf ld de,enemyData ld b,0 call huffExtr ; Extract enemy data xor a ld (level),a ; Start on first level ; Now calculate how many points each enemy is worth ld hl,enemyData+18 ld ix,enemyScoreTable ld a,(noEnemies) ld b,a calcEnemyPoints: push hl ld a,(hl) call divAby8 srl a ; A = A / 16 ld l,a ld h,0 add hl,hl ld de,enemyPoints add hl,de ld a,(hl) ld (ix),a inc hl ld a,(hl) ld (ix+1),a pop hl ld de,ENEMY_DATA_LENGTH add hl,de inc ix inc ix djnz calcEnemyPoints newLife: ; Ini some more vars, these vars are initialised after dying xor a ld (orb),a ld (specialWeapon),a iniLevel: ; Ini some vars, these ones are initialised at the start of a new level ld a,(cpX) ld (xBlock),a ld l,a ld h,0 add hl,hl add hl,hl add hl,hl ld (xScr),hl ld de,8 add hl,de ld (x),hl xor a ld (beam),a ld (frame),a ld (guardian),a ld (dead),a ld (gEnemyCnt),a sbc hl,hl ; HL = 0 ld (gAICnt1),hl ; Reset both AI1 & AI2 counters in one instruction ;) ld a,3*8+2 ld (y),a call clearAnimationArray call clearBulletArray call clearEBulletArray call clearEnemyArray call clearPickupArray ; Show screen before starting level bcall(_clrscrnfull) ld hl,strPreLevel ld de,0*256+0 call puts ; "LEVELSET:" ld de,0*256+1 call puts ; "HI-SCORE:" ld de,0*256+3 call puts ; "Level:" ld de,0*256+4 call puts ; "Lives:" ld de,0*256+5 call puts ; "Score:" ld hl,levelsetName ld de,11*256+0 call puts ; Show Levelset name ld hl,(hiScore) ld bc,5*256+1 call showHL ld de,10*256+1 call puts ; Show Hi-Score ld hl,(level) inc l ld h,0 ld bc,1*256+0 call showHL ld de,15*256+3 call puts ; Show Level number ld hl,(lives) ld h,0 ld bc,1*256+0 call showHL ld de,15*256+4 call puts ; Show Lives left ld hl,(score) ld bc,5*256+1 call showHL ld de,10*256+5 call puts ; Show Score call waitKeyA ; Now load the level and show it :) ld a,(level) call loadLevel ; Load level A ; Search through enemy placement data to find the checkpoint we're starting from ld hl,(enemyIni) ld a,(numEnemiesThisLevel) ld b,a or a jr z,foundEnemyIni ld a,(xBlock) ld de,4 searchEnemyIni: cp (hl) jr c,foundEnemyIni add hl,de djnz searchEnemyIni foundEnemyIni: ld (enemyIni),hl ld a,b ld (numEnemiesThisLevel),a mainGameLoop: ;------------------------------------------------ ; MAIN GAME LOOP ; ; The main loop does the following things (in this order): ; 1. Reset APD timer, increment frame counter. ; 2. Check if player is dead, if so, ensure Orb is disabled ; 3. Checks to see if any new enemies are to be created. ; 4. Check to see if player is dead, if so and animation is complete, leave main loop. ; 5. Scroll screen (only every 4th frame). ; 6. Calculate player screen X Coorinate and save it (saves having to calc. it every time it's needed) ; 7. Show beam power on status bar. ; 8. Move Orb (if it's on screen) ; 9. Move item pickups. ; 10. Check to see if player is picking up any pickups ; 11. Move players bullets. ; 12. Check to make sure all player bullets are still on screen ; 13. Check to see if any player bullets are hitting solid tiles ; 14. Check to see if end-of-level boss if being damaged (if fighting one), if it's dead go to next level. ; 15. Move end-of-level boss (if fighting one), only every 2nd frame. ; 16. Produce a normal enemy from the end-of-level boss (if fighting one that does so). ; 17. Check to see if any enemies are being damaged. ; 18. Move enemies. ; 19. Check to see if any enemies have fallen off the screen, if so, remove them. ; 20. Move enemy bullets. ; 21. Check to see if any enemy bullets have fallen off the screen, if so, remove them. ; 22. Check to see if any enemy bullets are hitting solid tiles ; 23. Check to see if any enemy bullets have been hit by the Orb ; 24. Update explosion animations. ; 25. Check for collisions between player and enemies ; 26. Check for collisions between player and end-of-level boss (if fighting one) ; 27. Check for collisions between player and enemy bullets ; 28. Draw pickups. ; 29. Draw player bullets. ; 30. Draw enemy bullets. ; 31. Draw explosion animations. ; 32. Draw enemies. ; 33. Draw end-of-level boss if fighting one. ; 34. Draw player. ; 35. Draw orb (if it's on screen). ; 36. Copy video buffer to lcd. ; 37. Erase orb (if it's on screen). ; 38. Erase player. ; 39. Erase end-of-level boss if fighting one. ; 40. Erase enemies. ; 41. Erase explosion animations. ; 42. Erase enemy bullets. ; 43. Erase player bullets. ; 44. Erase pickups. ; 45. Check to see if player is dead, if so, skip key press checking. ; 46. Check for movement. ; 47. Check for teacher key. ; 48. Check for shooting off Orb. ; 49. Check for pausing. ; 50. Check for shooting. ; 51. Check for quitting. ; 52. If necessary, wait a bit to make frames even. ; 53. Return to start of loop. ;------------------------------------------------ xor a ld (timer),a ; Reset APD timer ld hl,frame inc (hl) ; Increment frame counter ld a,(dead) or a jr z,afterCheckDisableOrb xor a ld (orb),a afterCheckDisableOrb: ; Search to see if there should be any enemies created ld hl,(enemyIni) ; HL => Start of enemy initialisation array ld a,(numEnemiesThisLevel) or a jr z,afterFindNewEnemies findNewEnemies: ld a,(xBlock) cp (hl) jr nz,afterFindNewEnemies call newEnemy ld a,(numEnemiesThisLevel) dec a ld (numEnemiesThisLevel),a jr nz,findNewEnemies afterFindNewEnemies: ld (enemyIni),hl ld a,(dead) ; A = Dead counter or a jr z,afterDecDead dec a jp z,playerDead ld (dead),a ; If it wasn't 0 or 1, save the decremented value afterDecDead: ;------------------------------------------------ ; Scroll screen every 4th frame (unless in guardian mode) ;------------------------------------------------ xor a ld (scrolled),a ld a,(frame) and $03 call z,scrollScreen call getPlayerScreenX ld (pScreenX),a ;------------------------------------------------ ; Perform updates on enemies, bullets, etc. and some other stuff ;------------------------------------------------ call showBeamPower ; Show the Beam power call moveOrb ; Move orb (if it's on screen) call movePickups ; Move item pickups call checkGetPickups ; Check to see if player is picking up any pickups call moveBullets ; Move player bullets call checkBulletsOnScreen ; Check to see if any player bullets have fallen off the screen call checkBulletsHitSolid ; Check to see if any player bullets are hitting a solid tile call checkGuardianDamage ; Check to see if end-of-level boss is being damaged (if fighting one) jp c,endLevel ; If end-of-level boss dead, go to next level call moveGuardian ; Move end-of-level boss (if fighting one) call guardianMakeEnemy ; Make an enemy from the end-of-level boss (if fighting one that does so) call checkEnemyDamage ; Check to see if any enemies are being damaged call moveEnemies ; Move enemies call checkEnemiesOnScreen ; Check to see if all enemies are still on screen call moveEBullets ; Move enemy bullets call checkEBulletsOnScreen ; Check to see if all enemy bullets are still on screen call checkEBulletsHitSolid ; Chekc to see if any enemy bullets are hitting a solid tile call checkOrbEBulletsCollisions ; Check to see if any enemy bullets have been hit by the Orb call updateAnimations ; Update explosion animations call checkPlayerEnemyCollisions ; Check for collisions between player and enemies call checkPlayerGuardianCollisions ; Check for collisions between player and end-of-level boss (if fighting one) call checkPlayerEBulletCollisions ; Check for collisions between player and enemy bullets ;------------------------------------------------ ; Put all sprites on gbuf, copy gbuf to video mem then remove sprites again ;------------------------------------------------ call drawPickups ; Draw pickups call drawBullets ; Draw player bullets to gbuf call drawEBullets ; Draw enemy bullets to gbuf call drawAnimations ; Draw explosion animations call drawEnemies ; Draw enemies to gbuf call drawGuardian ; Draw end-of-level boss call drawPlayer ; Draw player and orb if there is one call drawOrb ; Draw orb (if it's on screen) call ionFastCopy ; Copy gbuf to lcd ei ; ionFastCopy disables interrupts call eraseOrb ; Erase orb (if it's on screen) call erasePlayer ; Erase player from gbuf call eraseGuardian ; Erase end-of-level boss call eraseEnemies ; Erase enemies from gbuf call drawAnimations ; Erase explosion animations call drawEBullets ; Erase enemy bullets from gbuf call drawBullets ; Erase player bullets from gbuf call drawPickups ; Erase pickups ld a,(dead) or a jp nz,afterCheckShooting ; If player dead, don't check movement/shooting ld a,KG_ARROW call directIn ; Get key presses from arrow pad push af bit DI_UP,a ; [Up] call z,moveUp pop af push af bit DI_DOWN,a ; [Down] call z,moveDown pop af push af bit DI_LEFT,a ; [Left] call z,moveLeft pop af bit DI_RIGHT,a ; [Right] call z,moveRight ld a,KG_1 call directIn ; Get key pressed from 1st column (far left column) push af bit DI_MATH,a ; [MATH] call z,teacherKey pop af bit DI_ALPHA,a ; [ALPHA] call z,tryShootOffOrb ld a,KG_TOP call directIn ; Get key presses from top key group push af bit DI_MODE,a call z,pause pop af bit DI_2ND,a ; [2nd] ld hl,afterCheckShooting push hl ; Save where to RET to jp z,incBeamPower ; If [2nd] pressed, try to increment beam power pop hl ; Get rid of RET value ld hl,beam ; HL => Beam power ld a,(hl) or a ; Is it 0? jp z,afterCheckShooting ; If so, don't shoot ; Player is shooting, create necessary bullets call divAby8 srl a ; A = A / 16 inc a ; Make sure it isn't 0 ld d,a ; D = Bullet type ld (hl),0 ; Reset beam power ld a,(pScreenX) ; Get player X coordinate on screen ld bc,(y) ; C = YCoord ld b,a ; B = XCoord ld a,d ; A = Bullet type ld d,15 ; D = Direction call newBullet ; Try to create a new bullet ; If player isn't wearing Orb, it shoots as well :) ld a,(orb) or a ; Is the Orb on screen? jp z,afterCheckShooting ; If not, we've finished creating bullets bit 1,a ; Is player wearing Orb or is it floating around? ld a,(specialWeapon) ; A = Special weapon jr nz,tryShootingPowerGun ; If wearing Orb, try to shoot a special weapon or a ; Is Orb armed with a special weapon? jr nz,orbShootingLots ; If so, shoot 5 bullets out ld a,5 ld bc,(orbY) ld d,15 call newBullet ; Create single bullet coming out of the front of the Orb jr afterCheckShooting orbShootingLots: ld b,4 ld hl,orbBulletDirections orbShootingLoop: push bc push hl ld a,5 ; A = Type ld d,(hl) ; D = Direction ld bc,(orbY) ; B = X, C = Y call newBullet pop hl pop bc inc hl djnz orbShootingLoop jr afterCheckShooting tryShootingPowerGun: or a ; Is Orb armed with a special weapon? jr z,afterCheckShooting ; If not, we're finished shooting dec a ; Is it the Power Gun? jr nz,tryShootingTwoWayGun ; If not, try next weapon ld bc,(orbY) ld a,(orb) bit 2,a ld d,15 jr z,shootPowerGun dec d shootPowerGun: ld a,6 call newBullet ; Create Power Gun bullet jr afterCheckShooting tryShootingTwoWayGun: dec a ; Is it the Two-Way Gun? jr nz,shootVerticalGun ; If not, it's the Vertical Gun ld a,(orb) bit 2,a ld de,7*256+1 ld a,7 jr z,shootTwoWayGun ld de,10*256+4 ld a,8 shootTwoWayGun: ld bc,(orbY) call newBullet ld d,e xor $0F call newBullet jr afterCheckShooting shootVerticalGun: ld bc,(orbY) ld a,9 ld d,12 call newBullet inc a inc d call newBullet afterCheckShooting: ld a,KG_5 call directIn ; Get key presses from 5th column (far right column) bit DI_CLEAR,a ; [CLEAR] jr z,quitGame ld hl,timer ; HL => APD timer jr noHalt ; We might not need a HALT mainLoopWait: halt ; Wait a bit noHalt: ld a,(hl) ; A = Timer value neg ; Negate it because it count's backwards cp 2 ; Has a certain amount of time passed during this frame? _speed = $-1 jr c,mainLoopWait ; If not, wait a bit longer jp mainGameLoop ; Back to start of loop quitGame: xor a ld (lives),a jr gameOver endLevel: xor a ld (cpX),a ld hl,level inc (hl) ld l,(hl) ld h,200 bcall(_htimesl) ex de,hl call updateScore ; Add heaps of points to score ; Now show end-of-level screen bcall(_grbufclr) ld bc,44*256+30 ld hl,sprPlayer call PutSprite ; Draw player ship call ionFastCopy ld hl,2*256+1 ld (currow),hl ld hl,(level) ld h,0 bcall(_disphl) ; Show level number completed ld de,0*256+1 ld hl,strLevelComplete call puts ld de,8*256+1 call puts ld b,250 #ifdef MIRAGE call delayB #else ei endLevelLoop: halt djnz endLevelLoop #endif ld hl,level ld a,(noLevels) cp (hl) jp nz,iniLevel levelsetComplete: bcall(_clrscrnfull) ld de,3*256+2 ld hl,strLevelsetComplete call puts call waitKey gameOver: bcall(_clrscrnfull) ld de,3*256+1 ld hl,strGameOver call puts ; "GAME OVER" ld de,0*256+4 call puts ; "Score:" ld hl,(lives) ld h,200 ; Get 2000 bonus points for each life left bcall(_htimesl) ld de,(score) add hl,de ld (score),hl ld bc,5*256+1 call showHL ld de,10*256+4 call puts ld de,(score) ld hl,(hiScore) bcall(_cphlde) jr nc,noNewHiScore ld (hiScore),de ld hl,(dataPtr) inc hl inc hl ; HL => Where to save hiScore in Levelset file ld (hl),e ; Save LSB of hiScore inc hl ld (hl),d ; Save MSB of hiScore ld de,1*256+6 ld hl,strNewHiScore call puts noNewHiScore: ld b,100 #ifdef MIRAGE call delayB #else ei gameOverLoop: halt djnz gameOverLoop #endif call waitKeyA jp startVAT .end