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