10 REM ------------------------------------------ 20 REM Pixel Fandango Space Fighter X 30 REM ------------------------------------------ 40 REM ChangeLog (over V1) 50 REM + Multicolour entities 60 REM + High Score 70 REM + Stars 80 REM + Better sounds 90 REM + Aliens dont bomb near bottom of screen 100 REM + 2nd alien design 110 REM + 2nd aliens enter from RHS 120 REM + Bonus collection and modes 130 REM + Fix player explosion disappear 140 REM + Fix alternate wave bug 150 REM + High wave 160 REM ------------------------------------------ 170 MODE 1 180 ONERROR PROC_ShowError 190 REM Set sound envelopes... 200 ENVELOPE 1,1,4,-4,4,10,20,10,127,0,0,-1,100,100 210 ENVELOPE 2,129,3,5,2,10,20,10,127,0,0,-5,126,126 220 ENVELOPE 3,129,0,0,0,10,10,10,127,5,0,-5,126,126 230 REM Set colour palette... 240 VDU 19,1,5,0,0,0 250 VDU 19,2,6,0,0,0 260 VDU 19,3,3,0,0,0 270 COL_EXPLODE=3 280 REM Entity States... 290 DEAD_ENTITY=0 300 ALIEN_LIVE=20:ALIEN_EXPLODE=ALIEN_LIVE-1 310 ALIEN_RND_WAVE=22 320 BONUS_TIME=10 330 MIN_BOMB_HEIGHT=420 340 PLAYER_LIVE=250: PLAYER_EXPLODE=PLAYER_LIVE-1 350 REM Base entity field offsets... 360 eENTITY_SIZE=25 370 eTYPE=0 380 eSIZE=1 390 eIMAGE=2 400 eSTATE=6 410 eXPOS=7 420 eYPOS=11 430 eHWIDTH=15 440 eHHEIGHT=16 450 eXCENTRE=17 460 eYCENTRE=21 470 REM Special fields above base entity 480 eFLIGHT_PATH_INDEX=eENTITY_SIZE+0 490 eFLIGHT_PATH_SIDE=eENTITY_SIZE+1 500 REM Entity types 510 ePLAYER=0:eBULLET=1:eBOMB=2:eALIEN=3:eBONUS=4:eSHIELD=5 520 REM Entity part drawing instructions 530 dMOVE=1:dDRAW=2:dCOLOUR=3:dEND=0 540 REM Bonus Modes 550 bmNONE=0:bmLIFE=1:bmSHIELD=2:bm2SHOT=3:bmCONT=4 560 bmMAX=bmCONT:bmTIME=500:bmTIMESHOW=50:bmMSGSHOW=100 570 REM Other global settings... 580 BOMB_SPEED=12: BULLET_SPEED=20 590 PLAYER_START_X=600: PLAYER_START_Y=40 600 REM ------------------------------------------ 610 REM Populate static data for game 620 REM ------------------------------------------ 630 REM 640 REM Create alien flight path data... 650 DIM pathData% 550 660 FLIGHT_PATH_SIZE=255 670 FLIGHT_PATH_IX_LHS=220 680 FLIGHT_PATH_IX_RHS=1000 690 FLIGHT_PATH_IY=950 700 endOfPathData%=FN_InitFlightPattern(pathData%) 710 DIM starData% 64 720 STARS_SIZE=32 730 endOfStarDate%=FN_InitStars(starData%) 740 REM Add graphic image definitions... 750 DIM images% 450 760 workImage%=images% 770 rocketImage%=workImage% 780 workImage%=FN_AddRocketImage(rocketImage%) 790 alien1Image%=workImage% 800 workImage%=FN_AddAlien1Image(alien1Image%) 810 alien2Image%=workImage% 820 workImage%=FN_AddAlien2Image(alien2Image%) 830 bulletImage%=workImage% 840 workImage%=FN_AddBulletImage(bulletImage%) 850 explosionImage%=workImage% 860 workImage%=FN_AddExplosionImage(explosionImage%) 870 bigExplosionImage%=workImage% 880 workImage%=FN_AddBigExplosionImage(bigExplosionImage%) 890 bonusImage%=workImage% 900 workImage%=FN_AddBonusImage(bonusImage%) 910 shieldImage%=workImage% 920 workImage%=FN_AddShieldImage(shieldImage%) 930 REM Allocate entity space... 940 pNext%=0 950 DIM entities% 2800 960 REM ------------------------------------------ 970 REM Program control loop 980 REM ------------------------------------------ 990 HighScore%=1000 1000 HighWave%=10 1010 REPEAT 1020 REM Player's rocket... 1030 pRocket%=entities% 1040 rX%=PLAYER_START_X:rY%=PLAYER_START_Y 1050 pNext%=FN_InitEntity(ePLAYER, 0, pRocket%, rocketImage%, PLAYER_LIVE, rX%, rY%) 1060 REM Bonus object... 1070 pBonus%=pNext% 1080 pNext%=FN_InitEntity(eBONUS, 0, pBonus%, bonusImage%, 0, 0, 0) 1090 REM Shield object... 1100 pShield%=pNext% 1110 pNext%=FN_InitEntity(eSHIELD, 0, pShield%, shieldImage%, 0, 0, 0) 1120 REM Aliens... 1130 MaxAliens%=20 1140 pAliens%=pNext% 1150 FOR A=0 TO MaxAliens% 1160 pNext%=FN_InitAlien(eALIEN, pNext%, alien1Image%, DEAD_ENTITY, FLIGHT_PATH_IX_LHS, FLIGHT_PATH_IY, FLIGHT_PATH_SIZE, 0) 1170 NEXT A 1180 REM Bullets... 1190 MaxBullets%=30 1200 pBullets%=pNext% 1210 FOR B=0 TO MaxBullets% 1220 pNext%=FN_InitEntity(eBULLET, 0, pNext%, bulletImage%, 0, 0, 0) 1230 NEXT B 1240 pNextBullet%=pBullets% 1250 pEndBullets%=pNext% 1260 REM Bombs... 1270 MaxBombs%=50 1280 pBombs%=pNext% 1290 FOR B=0 TO MaxBombs% 1300 pNext%=FN_InitEntity(eBOMB, 0, pNext%, bulletImage%, 0, 0, 0) 1310 NEXT B 1320 pNextBomb%=pBombs% 1330 pEndBombs%=pNext% 1340 canFire%=0 1350 CLS:VDU 5 1360 MOVE 0, 328 1370 GCOL 0, 3 1380 REM Uncomment below to see object mem use... 1390 REM PRINT "images: "; workImage%-images% " bytes" 1400 REM PRINT "entities: "; pNext%-entities% " bytes" 1410 REM PRINT "fli-path: "; endOfPathData%-pathData% " bytes" 1420 MOVE 410,700:PRINT"PIXEL FANDANGO" 1430 MOVE 300,120:PRINT"www.PIXELFANDANGO.com" 1440 MOVE 265,70:PRINT"youTube:@pixel_fandango" 1450 GCOL 0, 1 1460 MOVE 395,640:PRINT"SPACE-FIGHTER-X" 1470 GCOL 0, 2 1480 MOVE 420,1000:PRINT "HI SCORE:";HighScore% 1490 MOVE 480,950:PRINT "HI WAVE:";HighWave% 1500 MOVE 380,550:PRINT"(Z) (X) (RETURN)" 1510 REM Pause then clear keyboard buffer... 1520 PROC_Pause(100) 1530 *FX 15 1540 MOVE 303,470:PRINT"PRESS ANY KEY TO PLAY" 1550 REM Init sound (some emulators pause on first sound call) 1560 SOUND 0,-1,200,1: SOUND 1,-1,200,1 1570 a%=GET 1580 SOUND 1,1,100,50 1590 CLS:VDU 5 1600 score%=0 1610 lastScore%=0 1620 lives%=3 1630 spawnSize%=4 1640 wave%=0 1650 bonusMode%=bmNONE 1660 bonusCountDown%=0 1670 msgCountDown%=0 1680 msgText$="" 1690 REM ------------------------------------------ 1700 REM Outer game loop... 1710 REM ------------------------------------------ 1720 cycle%=0 1730 REPEAT 1740 PROC_NewPlayer(pRocket%, rocketImage%) 1750 PROC_MoveEntityTo(pRocket%, rX%, rY%) 1760 alienSpawn%=0 1770 REM ---------------------------------------- 1780 REM Inner game loop... 1790 REM ---------------------------------------- 1800 REPEAT 1810 cycle%=cycle%+1 1820 PROC_DrawStars(starData%, cycle%) 1830 IF score%>HighScore% THEN MOVE 570,1000:GCOL 0,0:PRINT "HI:";HighScore%:HighScore%=score%: 1840 IF score%<>lastScore% THEN MOVE 200,1000:GCOL 0,0:PRINT "SCORE:";lastScore%:lastScore%=score% 1850 IF msgCountDown%>1 MOVE 460,550:GCOL 0,1:PRINT msgText$ 1860 IF msgCountDown%>0 THEN msgCountDown%=msgCountDown%-1 1870 IF msgCountDown%=1 THEN MOVE 460,550:GCOL 0,0:PRINT msgText$ 1880 IF bonusMode%=bmLIFE THEN MOVE 870,1000:GCOL 0,0:PRINT "LIVES:";lives%:lives%=lives%+1:bonusMode%=bmNONE 1890 IF bonusCountDown%>0 AND bonusMode%>bmLIFE THEN GCOL 0,0: MOVE 360,500:PRINT bonusCountDown% DIV bmTIMESHOW 1900 IF bonusCountDown%=1 THEN bonusMode%=bmNONE:SOUND 1,1,60,10 1910 IF bonusCountDown%>0 THEN bonusCountDown%=bonusCountDown%-1 1920 IF bonusCountDown%>0 AND bonusMode%>bmLIFE THEN GCOL 0,2: MOVE 360,500:PRINT bonusCountDown% DIV bmTIMESHOW 1930 IF bonusCountDown%>0 AND bonusCountDown% MOD bmTIMESHOW = 0 THEN SOUND 3,-15,200 - bonusCountDown% DIV bmTIMESHOW,5 1940 GCOL 0,3 1950 MOVE 200,1000:PRINT "SCORE:";score% 1960 MOVE 870,1000:PRINT "LIVES:";lives% 1970 IF score%=HighScore% GCOL 0,2 1980 MOVE 570,1000:PRINT "HI:";HighScore% 1990 pPlayerState%=pRocket%+eSTATE 2000 REM draw aliens... 2010 workAlien%=pAliens% 2020 nLiveAliens%=0 2030 FOR A=0 TO MaxAliens% 2040 REM Update explosion count (if in exploding state) 2050 pAlienState%=workAlien%+eSTATE 2060 IF ?(pAlienState%)=BONUS_TIME AND bonusMode%=0 AND RND(20)=1 THEN PROC_DropBonus(pBonus%,!(workAlien%+eXCENTRE),!(workAlien%+eYCENTRE)) 2070 IF ?(pAlienState%)=1 THEN PROC_ClearEntity(workAlien%):?(workAlien%+eSTATE)=0 2080 IF ?(pAlienState%)>0 AND ?(pAlienState%)=ALIEN_LIVE 2100 IF isAlive% AND ?(pPlayerState%)=PLAYER_LIVE AND !(workAlien%+eYPOS)>MIN_BOMB_HEIGHT AND RND(1000)<20 THEN pNextBomb%=FN_DropBomb(workAlien%, pNextBomb%,pBombs%, pEndBombs%) 2110 IF isAlive% THEN workAlien%=FN_UpdateAlien(workAlien%, pBullets%, pathData%, explosionImage%) ELSE workAlien%=FN_NextEntity(workAlien%) 2120 IF isAlive% THEN nLiveAliens%=nLiveAliens%+1 2130 NEXT A 2140 IF nLiveAliens%=0 AND alienSpawn%=0 THEN alienSpawn%=spawnSize%:wave%=wave%+1:IF spawnSize%0 THEN PROC_StartAlienForWave(pAliens%,wave%):alienSpawn%=alienSpawn%-1 2160 REM draw bullets... 2170 workBullet%=pBullets% 2180 FOR B=0 TO MaxBullets% 2190 workBullet%=FN_UpdateBullet(workBullet%, BULLET_SPEED) 2200 NEXT B 2210 workBomb%=pBombs% 2220 FOR B=0 TO MaxBombs% 2230 workBomb%=FN_UpdateBullet(workBomb%, BOMB_SPEED) 2240 NEXT B 2250 REM draw bonus object... 2260 PROC_UpdateBonus(pBonus%, pRocket%) 2270 REM handle user input... 2280 newX%=rX% 2290 IF INKEY(-98) THEN newX%=newX%-12:IF newX%<32 THEN newX%=32 2300 IF INKEY(-67) THEN newX%=newX%+12:IF newX%>1150 THEN newX%=1150 2310 IF INKEY(-74)=0 AND ?(pPlayerState%)=PLAYER_LIVE THEN canFire%=1 2320 IF bonusMode%=bmCONT AND ?(pPlayerState%)=PLAYER_LIVE AND canFire%=0 AND cycle% MOD 5 = 0 THEN canFire%=1 2330 IF bonusMode%=bm2SHOT AND canFire%=1 AND INKEY(-74) THEN pNextBullet%=FN_SetWingBullets(pNextBullet%,pBullets%,pEndBullets%,1,rX%+52,rY%+95):canFire%=0 2340 IF bonusMode%<>bm2SHOT AND canFire%=1 AND INKEY(-74) THEN pNextBullet%=FN_SetBullet(pNextBullet%,pBullets%,pEndBullets%,1,rX%+52,rY%+95):canFire%=0 2350 IF bonusMode%=bmSHIELD AND ?(pShield%+eSTATE)=0 THEN ?(pShield%+eSTATE)=1 2360 IF bonusMode%<>bmSHIELD AND ?(pShield%+eSTATE)=1 THEN ?(pShield%+eSTATE)=0:PROC_ClearEntity(pShield%) 2370 REM Wait for screen refresh sync... 2380 *FX19 2390 IF newX%<>rX% AND ?(pPlayerState%)=PLAYER_LIVE THEN PROC_MoveEntityTo(pRocket%, newX%, rY%):rX%=newX% 2400 IF bonusMode%=bmSHIELD THEN PROC_MoveEntityTo(pShield%, rX%, rY%) 2410 IF ?(pPlayerState%)bmSHIELD AND FN_IsPlayerCollision(pRocket%, pBombs%) THEN PROC_KillPlayer(pRocket%, bigExplosionImage%):canFire%=0 2430 UNTIL ?(pRocket%+eSTATE)=0 2440 MOVE 870,1000:GCOL 0,0:PRINT "LIVES:";lives% 2450 lives%=lives%-1 2460 UNTIL lives%=0 2470 GCOL 0,128:CLS 2480 GCOL 0,2 2490 VDU 5:MOVE 505,500:PRINT"GAME OVER" 2500 GCOL 0,3 2510 MOVE 200,1000:PRINT "SCORE:";score% 2520 MOVE 870,1000:PRINT "HI:";HighScore% 2530 IF wave%>HighWave% THEN HighWave%=wave%:GCOL0,1 2540 MOVE 350,600:PRINT"YOU REACHED WAVE ";wave% 2550 PROC_Pause(250) 2560 UNTIL 0 2570 END 2580 REM -------------------------------------------------- 2590 REM Functions to handle graphic image definitions 2600 REM -------------------------------------------------- 2610 REM 2620 REM -------------------------- 2630 REM Function to add image defn 2640 REM header information for 2650 REM collision detection 2660 REM -------------------------- 2670 DEF FN_AddImageHeader(address%, centreX%, centreY%, collnRadius%) 2680 ?(address%+0)=centreX% 2690 ?(address%+1)=centreY% 2700 ?(address%+2)=collnRadius% 2710 =address%+3 2720 REM -------------------------- 2730 REM Function to add an image 2740 REM part to defn at address 2750 REM type: 0=end 1=MOVE, 2=DRAW 2760 REM x,y are coords from TL 2770 REM Returns next free address 2780 REM -------------------------- 2790 DEF FN_AddImagePart(address%, type%, x%, y%) 2800 ?(address%+0)=type% 2810 ?(address%+1)=x% 2820 ?(address%+2)=y% 2830 =address%+3 2840 REM 2850 DEF FN_AddImagePartScaled(address%, type%, x%, y%, scale) 2860 ?(address%+0)=type% 2870 ?(address%+1)=INT(x%*scale) 2880 ?(address%+2)=INT(y%*scale) 2890 =address%+3 2900 REM 2910 DEF FN_AddImagePartColour(address%, colour%) 2920 ?(address%+0)=3 2930 ?(address%+1)=colour% 2940 =address%+2 2950 REM 2960 REM -------------------------- 2970 REM Functions to add images 2980 REM -------------------------- 2990 DEF FN_AddRocketImage(address%) 3000 rScale=0.8 3010 address%=FN_AddImageHeader(address%, INT(70*rScale), INT(55*rScale), INT(67*rScale)) 3020 address%=FN_AddImagePartColour(address%, 2) 3030 address%=FN_AddImagePartScaled(address%, dMOVE, 80, 40, rScale) 3040 address%=FN_AddImagePartScaled(address%, dDRAW, 100, 20, rScale) 3050 address%=FN_AddImagePartScaled(address%, dDRAW, 80, 0, rScale) 3060 address%=FN_AddImagePartScaled(address%, dDRAW, 60, 0, rScale) 3070 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 20, rScale) 3080 address%=FN_AddImagePartScaled(address%, dDRAW, 60, 40, rScale) 3090 address%=FN_AddImagePartScaled(address%, dDRAW, 80, 40, rScale) 3100 address%=FN_AddImagePartScaled(address%, dDRAW, 80, 80, rScale) 3110 address%=FN_AddImagePartScaled(address%, dDRAW, 100, 60, rScale) 3120 address%=FN_AddImagePartScaled(address%, dDRAW, 70, 120, rScale) 3130 address%=FN_AddImagePartScaled(address%, dDRAW, 80, 80, rScale) 3140 address%=FN_AddImagePartScaled(address%, dDRAW, 60, 80, rScale) 3150 address%=FN_AddImagePartScaled(address%, dDRAW, 70, 120, rScale) 3160 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 60, rScale) 3170 address%=FN_AddImagePartScaled(address%, dDRAW, 60, 80, rScale) 3180 address%=FN_AddImagePartScaled(address%, dDRAW, 60, 40, rScale) 3190 REM left wing 3200 address%=FN_AddImagePartColour(address%, 3) 3210 address%=FN_AddImagePartScaled(address%, dMOVE, 40, 20, rScale) 3220 address%=FN_AddImagePartScaled(address%, dDRAW, 5, 25, rScale) 3230 address%=FN_AddImagePartScaled(address%, dDRAW, 5, 35, rScale) 3240 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 60, rScale) 3250 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 20, rScale) 3260 REM right wing 3270 address%=FN_AddImagePartScaled(address%, dMOVE, 100, 20, rScale) 3280 address%=FN_AddImagePartScaled(address%, dDRAW, 135, 25, rScale) 3290 address%=FN_AddImagePartScaled(address%, dDRAW, 135, 35, rScale) 3300 address%=FN_AddImagePartScaled(address%, dDRAW, 100, 60, rScale) 3310 address%=FN_AddImagePartScaled(address%, dDRAW, 100, 20, rScale) 3320 ?(address%)=dEND 3330 =address%+1 3340 DEF FN_AddShieldImage(address%) 3350 rScale=0.8 3360 address%=FN_AddImageHeader(address%, INT(70*rScale), INT(60*rScale), INT(64*rScale)) 3370 address%=FN_AddImagePartColour(address%, 1) 3380 address%=FN_AddImagePartScaled(address%, dMOVE, 0, 90, rScale) 3390 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 130, rScale) 3400 address%=FN_AddImagePartScaled(address%, dDRAW, 100, 130, rScale) 3410 address%=FN_AddImagePartScaled(address%, dDRAW, 140, 90, rScale) 3420 ?(address%)=dEND 3430 =address%+1 3440 DEF FN_AddAlien1Image(address%) 3450 aScale=1.4 3460 address%=FN_AddImageHeader(address%, INT(25*aScale), INT(20*aScale), INT(24*aScale)) 3470 address%=FN_AddImagePartColour(address%, 1) 3480 address%=FN_AddImagePartScaled(address%, dMOVE, 40, 30, aScale) 3490 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 10, aScale) 3500 address%=FN_AddImagePartScaled(address%, dDRAW, 50, 0, aScale) 3510 address%=FN_AddImagePartScaled(address%, dDRAW, 50, 20, aScale) 3520 address%=FN_AddImagePartScaled(address%, dDRAW, 30, 40, aScale) 3530 address%=FN_AddImagePartScaled(address%, dDRAW, 20, 40, aScale) 3540 address%=FN_AddImagePartScaled(address%, dDRAW, 0, 20, aScale) 3550 address%=FN_AddImagePartScaled(address%, dDRAW, 0, 0, aScale) 3560 address%=FN_AddImagePartScaled(address%, dDRAW, 10, 10, aScale) 3570 address%=FN_AddImagePartScaled(address%, dDRAW, 10, 30, aScale) 3580 address%=FN_AddImagePartScaled(address%, dDRAW, 10, 10, aScale) 3590 address%=FN_AddImagePartScaled(address%, dDRAW, 20, 0, aScale) 3600 address%=FN_AddImagePartScaled(address%, dDRAW, 30, 0, aScale) 3610 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 10, aScale) 3620 address%=FN_AddImagePartColour(address%, 3) 3630 address%=FN_AddImagePartScaled(address%, dMOVE, 15, 20, aScale) 3640 address%=FN_AddImagePartScaled(address%, dDRAW, 35, 20, aScale) 3650 address%=FN_AddImagePartScaled(address%, dDRAW, 35, 30, aScale) 3660 address%=FN_AddImagePartScaled(address%, dDRAW, 25, 20, aScale) 3670 address%=FN_AddImagePartScaled(address%, dDRAW, 15, 30, aScale) 3680 address%=FN_AddImagePartScaled(address%, dDRAW, 15, 20, aScale) 3690 address%=FN_AddImagePartColour(address%, 2) 3700 address%=FN_AddImagePartScaled(address%, dDRAW, 25, 10, aScale) 3710 address%=FN_AddImagePartScaled(address%, dDRAW, 35, 20, aScale) 3720 ?(address%)=dEND 3730 =address%+1 3740 DEF FN_AddAlien2Image(address%) 3750 aScale=1.4 3760 address%=FN_AddImageHeader(address%, INT(25*aScale), INT(20*aScale), INT(24*aScale)) 3770 address%=FN_AddImagePartColour(address%, 1) 3780 address%=FN_AddImagePartScaled(address%, dMOVE, 20, 40, aScale) 3790 address%=FN_AddImagePartScaled(address%, dDRAW, 30, 40, aScale) 3800 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 30, aScale) 3810 address%=FN_AddImagePartScaled(address%, dDRAW, 40, 10, aScale) 3820 address%=FN_AddImagePartScaled(address%, dDRAW, 30, 0, aScale) 3830 address%=FN_AddImagePartScaled(address%, dDRAW, 20, 0, aScale) 3840 address%=FN_AddImagePartScaled(address%, dDRAW, 10, 10, aScale) 3850 address%=FN_AddImagePartScaled(address%, dDRAW, 10, 30, aScale) 3860 address%=FN_AddImagePartScaled(address%, dDRAW, 20, 40, aScale) 3870 address%=FN_AddImagePartColour(address%, 3) 3880 address%=FN_AddImagePartScaled(address%, dMOVE, 15, 30, aScale) 3890 address%=FN_AddImagePartScaled(address%, dDRAW, 25, 25, aScale) 3900 address%=FN_AddImagePartScaled(address%, dDRAW, 35, 30, aScale) 3910 address%=FN_AddImagePartScaled(address%, dDRAW, 35, 20, aScale) 3920 address%=FN_AddImagePartScaled(address%, dDRAW, 15, 20, aScale) 3930 address%=FN_AddImagePartScaled(address%, dDRAW, 15, 30, aScale) 3940 address%=FN_AddImagePartColour(address%, 2) 3950 address%=FN_AddImagePartScaled(address%, dMOVE, 15, 15, aScale) 3960 address%=FN_AddImagePartScaled(address%, dDRAW, 35, 15, aScale) 3970 address%=FN_AddImagePartColour(address%, 3) 3980 address%=FN_AddImagePartScaled(address%, dMOVE, 0, 10, aScale) 3990 address%=FN_AddImagePartScaled(address%, dDRAW, 5, 20, aScale) 4000 address%=FN_AddImagePartScaled(address%, dDRAW, 0, 30, aScale) 4010 address%=FN_AddImagePartScaled(address%, dMOVE, 50, 10, aScale) 4020 address%=FN_AddImagePartScaled(address%, dDRAW, 45, 20, aScale) 4030 address%=FN_AddImagePartScaled(address%, dDRAW, 50, 30, aScale) 4040 ?(address%)=dEND 4050 =address%+1 4060 DEF FN_AddBulletImage(address%) 4070 address%=FN_AddImageHeader(address%, 3, 8, 5) 4080 address%=FN_AddImagePartColour(address%, 3) 4090 address%=FN_AddImagePart(address%, dMOVE, 0, 0) 4100 address%=FN_AddImagePart(address%, dDRAW, 6, 0) 4110 address%=FN_AddImagePart(address%, dDRAW, 6, 16) 4120 address%=FN_AddImagePart(address%, dDRAW, 0, 16) 4130 address%=FN_AddImagePart(address%, dDRAW, 0, 0) 4140 ?(address%)=dEND 4150 =address%+1 4160 DEF FN_AddExplosionImage(address%) 4170 address%=FN_AddImageHeader(address%, 25, 25, 25) 4180 address%=FN_AddImagePartColour(address%, 1) 4190 address%=FN_AddImagePart(address%, dMOVE, 0, 0) 4200 address%=FN_AddImagePart(address%, dDRAW, 10, 20) 4210 address%=FN_AddImagePart(address%, dDRAW, 0, 30) 4220 address%=FN_AddImagePart(address%, dDRAW, 15, 30) 4230 address%=FN_AddImagePart(address%, dDRAW, 20, 50) 4240 address%=FN_AddImagePart(address%, dDRAW, 30, 30) 4250 address%=FN_AddImagePart(address%, dDRAW, 50, 40) 4260 address%=FN_AddImagePart(address%, dDRAW, 40, 20) 4270 address%=FN_AddImagePart(address%, dDRAW, 50, 10) 4280 address%=FN_AddImagePart(address%, dDRAW, 35, 10) 4290 address%=FN_AddImagePart(address%, dDRAW, 30, 0) 4300 address%=FN_AddImagePart(address%, dDRAW, 20, 10) 4310 address%=FN_AddImagePart(address%, dDRAW, 0, 0) 4320 ?(address%)=dEND 4330 =address%+1 4340 DEF FN_AddBigExplosionImage(address%) 4350 address%=FN_AddImageHeader(address%, 50, 50, 50) 4360 address%=FN_AddImagePartColour(address%, 2) 4370 address%=FN_AddImagePart(address%, dMOVE, 0, 0) 4380 address%=FN_AddImagePart(address%, dDRAW, 20, 40) 4390 address%=FN_AddImagePart(address%, dDRAW, 0, 60) 4400 address%=FN_AddImagePart(address%, dDRAW, 30, 60) 4410 address%=FN_AddImagePart(address%, dDRAW, 40, 100) 4420 address%=FN_AddImagePart(address%, dDRAW, 60, 60) 4430 address%=FN_AddImagePart(address%, dDRAW, 100, 80) 4440 address%=FN_AddImagePart(address%, dDRAW, 80, 40) 4450 address%=FN_AddImagePart(address%, dDRAW, 100, 20) 4460 address%=FN_AddImagePart(address%, dDRAW, 70, 20) 4470 address%=FN_AddImagePart(address%, dDRAW, 60, 0) 4480 address%=FN_AddImagePart(address%, dDRAW, 40, 20) 4490 address%=FN_AddImagePart(address%, dDRAW, 0, 0) 4500 ?(address%)=dEND 4510 =address%+1 4520 DEF FN_AddBonusImage(address%) 4530 address%=FN_AddImageHeader(address%, 20, 20, 20) 4540 address%=FN_AddImagePartColour(address%, 2) 4550 address%=FN_AddImagePart(address%, dMOVE, 20, 40) 4560 address%=FN_AddImagePart(address%, dDRAW, 0, 20) 4570 address%=FN_AddImagePart(address%, dDRAW, 20, 0) 4580 address%=FN_AddImagePart(address%, dDRAW, 40, 20) 4590 address%=FN_AddImagePart(address%, dDRAW, 20, 40) 4600 address%=FN_AddImagePart(address%, dDRAW, 10, 10) 4610 address%=FN_AddImagePart(address%, dDRAW, 30, 10) 4620 address%=FN_AddImagePart(address%, dDRAW, 20, 40) 4630 ?(address%)=dEND 4640 =address%+1 4650 REM 4660 REM -------------------------- 4670 REM Proc to draw image from 4680 REM data at address in pos x,y 4690 REM -------------------------- 4700 DEF PROC_DrawImage(pImage%, x%, y%) 4710 REM Skip the header information... 4720 pImage%=pImage%+3 4730 REM Draw each image part... 4740 REPEAT 4750 pImage%=FN_DrawImagePart(pImage%, x%, y%) 4760 UNTIL pImage%=0 4770 ENDPROC 4780 REM -------------------------- 4790 REM Proc to clear image 4800 REM -------------------------- 4810 DEF PROC_ClearImage(pImage%, x%, y%) 4820 REM Skip the header information... 4830 pImage%=pImage%+3 4840 REM Clear each image part... 4850 GCOL 0,0 4860 REPEAT 4870 pImage%=FN_ClearImagePart(pImage%, x%, y%) 4880 UNTIL pImage%=0 4890 ENDPROC 4900 REM 4910 REM -------------------------- 4920 REM Function to draw part 4930 REM -------------------------- 4940 DEF FN_DrawImagePart(pPart%, x%, y%) 4950 =FN_RenderImagePart(pPart%, x%, y%) 4960 REM -------------------------- 4970 REM Function to clear part 4980 REM -------------------------- 4990 DEF FN_ClearImagePart(pPart%, x%, y%) 5000 REM Ignore colour change instructions 5010 IF ?(pPart%)=dCOLOUR THEN =pPart%+2 5020 =FN_RenderImagePart(pPart%, x%, y%) 5030 REM -------------------------- 5040 REM Function to draw single 5050 REM part of an image defn 5060 REM and return next address 5070 REM or 0 if its the last part 5080 REM -------------------------- 5090 DEF FN_RenderImagePart(pPart%, x%, y%) 5100 REM Return 0 if this item is an end marker 5110 IF ?pPart%=dEND THEN =0 5120 REM Either move or draw to a point in background colour 5130 IF ?(pPart%)=dMOVE THEN MOVE ?(pPart%+1)+x%, ?(pPart%+2)+y% 5140 IF ?(pPart%)=dDRAW THEN DRAW ?(pPart%+1)+x%, ?(pPart%+2)+y% 5150 IF ?(pPart%)=dCOLOUR THEN GCOL 0, ?(pPart%+1): =pPart%+2 5160 REM return next address 5170 =pPart%+3 5180 REM 5190 REM -------------------------------------------------- 5200 REM Functions to handle game entities 5210 REM -------------------------------------------------- 5220 REM 5230 REM -------------------------- 5240 REM Initialise a new entity 5250 REM Return next address 5260 REM -------------------------- 5270 DEF FN_InitEntity(typeId%, addSize%, pEntity%, pImage%, state%, x%, y%) 5280 REM Record basic entity parameters 5290 ?pEntity%=typeId% 5300 ?(pEntity%+eSIZE)=eENTITY_SIZE+addSize% 5310 !(pEntity%+eIMAGE)=pImage% 5320 ?(pEntity%+eSTATE)=state% 5330 !(pEntity%+eXPOS)=x% 5340 !(pEntity%+eYPOS)=y% 5350 REM Calc offsets for collision detection... 5360 ?(pEntity%+eHWIDTH)=?(!(pEntity%+eIMAGE)+0) 5370 ?(pEntity%+eHHEIGHT)=?(!(pEntity%+eIMAGE)+1) 5380 REM Reserve space for centreX and centreY 5390 REM calcs on move for collision detection 5400 !(pEntity%+eXCENTRE)=0 5410 !(pEntity%+eYCENTRE)=0 5420 REM Anything after this is specific to entity type 5430 =pEntity%+?(pEntity%+eSIZE) 5440 REM -------------------------- 5450 REM Draw or clear an entity 5460 REM -------------------------- 5470 DEF PROC_DrawEntity(pEntity%) 5480 PROC_DrawImage(!(pEntity%+eIMAGE), !(pEntity%+eXPOS), !(pEntity%+eYPOS)) 5490 ENDPROC 5500 DEF PROC_ClearEntity(pEntity%) 5510 GCOL 0,0 5520 PROC_ClearImage(!(pEntity%+eIMAGE), !(pEntity%+eXPOS), !(pEntity%+eYPOS)) 5530 ENDPROC 5540 REM 5550 REM -------------------------- 5560 REM Calc collision range 5570 REM based on position, width, 5580 REM height and radius. 5590 REM -------------------------- 5600 DEF PROC_SetCollnCentre(pEntity%) 5610 !(pEntity%+eXCENTRE)=!(pEntity%+eXPOS)+?(pEntity%+eHWIDTH) 5620 !(pEntity%+eYCENTRE)=!(pEntity%+eYPOS)+?(pEntity%+eHHEIGHT) 5630 ENDPROC 5640 REM 5650 REM -------------------------- 5660 REM Move an entity (relative) 5670 REM -------------------------- 5680 DEF FN_MoveEntity(pEntity%, dx, dy) 5690 REM Only move if state > 0 (is active) 5700 IF ?(pEntity%+eSTATE)=0 THEN =pEntity%+?(pEntity%+eSIZE) 5710 PROC_ClearEntity(pEntity%) 5720 pX%=!(pEntity%+eXPOS)+dx 5730 pY%=!(pEntity%+eYPOS)+dy 5740 IF pX%>1280 THEN pX%=pX%-1280 5750 IF pX%<0 THEN pX%=pX%+1280 5760 IF pY%>1024 THEN pY%=pY%-1024 5770 IF pY%<0 THEN pY%=pY%+1024 5780 !(pEntity%+eXPOS)=pX% 5790 !(pEntity%+eYPOS)=pY% 5800 PROC_SetCollnCentre(pEntity%) 5810 PROC_DrawEntity(pEntity%) 5820 =pEntity%+?(pEntity%+eSIZE) 5830 REM 5840 REM -------------------------- 5850 REM Move an entity (absolute) 5860 REM -------------------------- 5870 DEF PROC_MoveEntityTo(pEntity%, x%, y%) 5880 REM Only move if state > 0 (is active) 5890 IF ?(pEntity%+eSTATE)=0 THEN ENDPROC 5900 PROC_ClearEntity(pEntity%) 5910 !(pEntity%+eXPOS)=x% 5920 !(pEntity%+eYPOS)=y% 5930 PROC_SetCollnCentre(pEntity%) 5940 PROC_DrawEntity(pEntity%) 5950 ENDPROC 5960 REM 5970 REM -------------------------- 5980 REM Get pointer to next entity 5990 REM -------------------------- 6000 DEF FN_NextEntity(pEntity%) 6010 =pEntity%+?(pEntity%+eSIZE) 6020 REM 6030 REM -------------------------- 6040 REM Collision Detection 6050 REM lhs, rhs, top, bot collision 6060 REM range pre calc'd on entity move 6070 REM -------------------------- 6080 DEF FN_IsCollision(pEntity1%, pEntity2%, radius%) 6090 REM Only check if both entities are active 6100 IF ?(pEntity1%+eSTATE)=0 OR ?(pEntity2%+eSTATE)=0 = 0 6110 dX=ABS(!(pEntity1%+eXCENTRE)-!(pEntity2%+eXCENTRE)) 6120 dY=ABS(!(pEntity1%+eYCENTRE)-!(pEntity2%+eYCENTRE)) 6130 IF dX1000 OR !(pBullet%+eYPOS)<24 THEN ?(pState%)=3 6260 =pBullet%+?(pBullet%+eSIZE) 6270 REM -------------------------------------------------- 6280 DEF FN_SetBullet(pBullet%, pStartBMem%, pEndBMem%, state%, x%, y%) 6290 ?(pBullet%+eSTATE)=state% 6300 !(pBullet%+eXPOS)=x% 6310 !(pBullet%+eYPOS)=y% 6320 PROC_SetCollnCentre(pBullet%) 6330 IF state%=1 THEN SOUND 2,2,100,1 6340 IF(pBullet%+?(pBullet%+eSIZE)>=pEndBMem%) THEN =pStartBMem% 6350 =pBullet%+?(pBullet%+eSIZE) 6360 REM -------------------------------------------------- 6370 DEF FN_SetWingBullets(pBullet%, pStartBMem%, pEndBMem%, state%, x%, y%) 6380 pNext%=FN_SetBullet(pBullet%, pStartBMem%, pEndBMem%, state%, x%-50, y%-50) 6390 =FN_SetBullet(pNext%, pStartBMem%, pEndBMem%, state%, x%+50, y%-50) 6400 REM -------------------------------------------------- 6410 DEF FN_InitAlien(type%, pEntity%, pImage%, state%, x%, y%, pathIndex%, pathSide%) 6420 endAddress%=FN_InitEntity(type%, 2, pEntity%, pImage%, state%, x%, y%) 6430 ?(pEntity%+eFLIGHT_PATH_INDEX)=pathIndex% 6440 ?(pEntity%+eFLIGHT_PATH_SIDE)=pathSide% 6450 =endAddress% 6460 REM -------------------------------------------------- 6470 DEF PROC_AlienHit(pAlien%, pBullet%) 6480 PROC_ClearEntity(pAlien%) 6490 ?(pAlien%+eSTATE)=ALIEN_EXPLODE 6500 !(pAlien%+eIMAGE)=pExplosionImage% 6510 ?(pBullets%+eSTATE)=3 6520 SOUND 0,3,75,1 6530 score%=score%+10 6540 ENDPROC 6550 REM -------------------------------------------------- 6560 DEF PROC_CheckAlienCollision(pAlien%, pBullets%, pExplosionImage%) 6570 REM If alien is exploding (or dead) then ignore 6580 cRadius%=?(!(pAlien%+eIMAGE)+2) 6590 IF ?(pAlien%+eSTATE)<20 ENDPROC 6600 FOR B=0 TO MaxBullets% 6610 IF ?(pBullets%+eSTATE)>0 AND FN_IsCollision(workAlien%, pBullets%, cRadius%) PROC_AlienHit(pAlien%, pBullets%):ENDPROC 6620 pBullets%=pBullets%+?(pBullets%+eSIZE) 6630 NEXT B 6640 ENDPROC 6650 REM -------------------------------------------------- 6660 DEF FN_IsPlayerCollision(pRocket%, pBombs%) 6670 cRadius%=?(!(pRocket%+eIMAGE)+2) 6680 FOR B=0 TO MaxBombs% 6690 IF ?(pBombs%+eSTATE)>0 AND FN_IsCollision(pRocket%, pBombs%, cRadius%) THEN ?(pBombs%+eSTATE)=3: =1 6700 pBombs%=pBombs%+?(pBombs%+eSIZE) 6710 NEXT B 6720 =0 6730 REM -------------------------------------------------- 6740 DEF FN_UpdateAlien(pAlien%, pBullets%, pFlightPath%, pExplosionImage%) 6750 PROC_CheckAlienCollision(pAlien%, pBullets%, explosionImage%) 6760 fpi%=?(pAlien%+eFLIGHT_PATH_INDEX) 6770 fpi%=fpi%+1 6780 IF fpi%>=FLIGHT_PATH_SIZE THEN fpi%=0 6790 IF fpi%=0 AND ?(pAlien%+eFLIGHT_PATH_SIDE)=0 PROC_MoveEntityTo(pAlien%,FLIGHT_PATH_IX_RHS, FLIGHT_PATH_IY) 6800 IF fpi%=0 AND ?(pAlien%+eFLIGHT_PATH_SIDE)=1 PROC_MoveEntityTo(pAlien%,FLIGHT_PATH_IX_LHS, FLIGHT_PATH_IY) 6810 ?(pAlien%+eFLIGHT_PATH_INDEX)=fpi% 6820 pLookUp%=pFlightPath%+(fpi%*2) 6830 dX=?(pLookUp%):IF dX>128 THEN dX=128-dX 6840 IF ?(pAlien%+eFLIGHT_PATH_SIDE)=0 THEN dX=-dX 6850 dY=?(pLookUp%+1):IF dY>128 THEN dY=128-dY 6860 =FN_MoveEntity(pAlien%, dX, dY) 6870 REM -------------------------------------------------- 6880 DEF FN_DropBomb(pAlien%,pNextBomb%,pStartBMem%, pEndBMem%) 6890 =FN_SetBullet(pNextBomb%,pStartBMem%, pEndBMem%,2,!(workAlien%+eXCENTRE),!(workAlien%+eYCENTRE)) 6900 REM -------------------------------------------------- 6910 DEF PROC_KillPlayer(pPlayer%, pExplosionImage%) 6920 PROC_ClearEntity(pPlayer%) 6930 IF ?(pPlayer%+eSTATE)0 OR y%<400 THEN ENDPROC 7350 pNext%=FN_InitEntity(eBONUS, 0, pBonus%, !(pBonus%+eIMAGE), 1, x%, y%) 7360 ENDPROC 7370 REM 7380 DEF PROC_UpdateBonus(pBonus%, pPlayer%) 7390 IF ?(pBonus%+eSTATE)=0 THEN ENDPROC 7400 IF !(pBonus%+eYPOS)<10 THEN ?(pBonus%+eSTATE)=0:PROC_ClearEntity(pBonus%):ENDPROC 7410 pNext%=FN_MoveEntity(pBonus%,0,-3) 7420 radius%=25+?(!(pPlayer%+eIMAGE)+2) 7430 IF ?(pPlayer%+eSTATE)bmLIFE bonusCountDown%=bmTIME 7480 IF bonusMode%=bmLIFE THEN PROC_ShowMessage(" EXTRA LIFE!") 7490 IF bonusMode%=bmSHIELD THEN PROC_ShowMessage(" SHIELDS UP!") 7500 IF bonusMode%=bm2SHOT THEN PROC_ShowMessage(" DOUBLE SHOT!") 7510 IF bonusMode%=bmCONT THEN PROC_ShowMessage(" SUPER FIRE!") 7520 ?(pBonus%+eSTATE)=0:PROC_ClearEntity(pBonus%) 7530 ENDPROC 7540 REM -------------------------------------------------- 7550 REM Star background functions 7560 REM -------------------------------------------------- 7570 DEF FN_InitStars(address%) 7580 FOR N=1 TO STARS_SIZE 7590 ?(address%)=RND(255) 7600 ?(address%+1)=RND(255) 7610 address%=address%+2 7620 NEXT N 7630 =address% 7640 REM 7650 DEF PROC_DrawStars(address%, offset%) 7660 offset%=offset% MOD 1024 7670 FOR N=0 TO STARS_SIZE 7680 sX%=?(address%)*5 7690 sY%=1024-((?(address%+1)+offset%)*4) MOD 1024 7700 REM Don't show stars at bottom where player is 7710 REM otherwise we have to keep redrawing player 7720 IF sY%>146 THEN GCOL 0,0:PLOT 69,sX%,sY%+4 7730 IF sY%>150 THEN GCOL 0,(N+offset%) DIV 8:PLOT 69,sX%,sY% 7740 address%=address%+2 7750 NEXT N 7760 ENDPROC 7770 REM -------------------------------------------------- 7780 REM Other useful procedures 7790 REM -------------------------------------------------- 7800 DEF PROC_ShowMessage(message$) 7810 IF msgCountDown%>0 THEN ENDPROC 7820 msgCountDown%=bmMSGSHOW 7830 msgText$=message$ 7840 ENDPROC 7850 DEF PROC_Pause(cycles%) 7860 FOR C=1 TO cycles% 7870 *FX19 7880 NEXT C 7890 ENDPROC 7900 DEF PROC_ShowError 7910 MODE 0 7920 *FX15 7930 PRINT "-------------------------------" 7940 PRINT "PIXEL FANDANGO SPACE FIGHTER X" 7950 PRINT " www.PixelFandango.com" 7960 PRINT "-------------------------------" 7970 REPORT:PRINT " at line ";ERL 7980 END