%begin %const %byte TRUE = 1, FALSE = 0 { preserve semantics of A & B, A ! B } %byte %array charvec(*) = %c '0', 4, 16_ae, 16_e4, 16_40, 16_0a, '1', 1, 16_2c, '2', 5, 16_ae, 16_e9, 16_95, 16_50, 16_04, '3', 4, 16_04, 16_79, 16_4e, 16_ea, !#ifdef GTCHARS '4', 3, 16_a5, 16_59, 16_72, { mine } !#else ! '4', 3, 16_5a, 16_59, 16_4e, { orig } !#endif '5', 5, 16_04, 16_49, 16_95, 16_5a, 16_ae, '6', 4, 16_59, 16_94, 16_40, 16_0a, '7', 2, 16_2e, 16_ea, '8', 5, 16_04, 16_ae, 16_59, 16_e4, 16_a0, '9', 4, 16_ea, 16_a5, 16_59, 16_e4, 'A', 4, 16_4e, 16_ae, 16_59, 16_a0, 'B', 5, 16_69, 16_04, 16_4e, 16_ea, 16_b1, 'C', 3, 16_ae, 16_40, 16_0a, !#ifdef GTCHARS 'D', 5, 16_ad, 16_d9, 16_93, 16_30, 16_0a, !#else ! 'D', 4, 16_ae, 16_e4, 16_40, 16_1b, !#endif 'E', 4, 16_40, 16_0a, 16_57, 16_ae, 'F', 3, 16_0a, 16_57, 16_ae, 'G', 5, 16_79, 16_94, 16_40, 16_0a, 16_ae, 'H', 3, 16_0a, 16_59, 16_4e, 'I', 1, 16_2c, 'J', 4, 16_50, 16_03, 16_3d, 16_be, 'K', 3, 16_0a, 16_e5, 16_54, 'L', 2, 16_0a, 16_04, 'M', 4, 16_0a, 16_a7, 16_7e, 16_e4, 'N', 3, 16_0a, 16_a4, 16_4e, 'O', 4, 16_ae, 16_e4, 16_40, 16_0a, 'P', 4, 16_0a, 16_ae, 16_e9, 16_95, 'Q', 5, 16_0a, 16_ae, 16_e4, 16_40, 16_48, 'R', 5, 16_48, 16_59, 16_9e, 16_ea, 16_a0, 'S', 5, 16_04, 16_49, 16_95, 16_5a, 16_ae, 'T', 2, 16_ae, 16_c2, 'U', 3, 16_0a, 16_04, 16_4e, 'V', 2, 16_a2, 16_2e, 'W', 4, 16_a1, 16_17, 16_73, 16_3e, 'X', 2, 16_0e, 16_a4, 'Y', 3, 16_27, 16_7a, 16_7e, 'Z', 3, 16_ae, 16_e0, 16_04, 0 %byte %name nibbles(256) %routine initchars ;! rewrite this in Imp style %byte i %byte %name s == charvec(0) nibbles(i) = 0{NULL} %for i = 0, 1, 255 %cycle %exit %if s = 0 nibbles(s) == BYTE(ADDR(s) + 1) s == BYTE(ADDR(s) + 1) s = BYTE(ADDR(s) + s + 1) %repeat %end %const %byte %array lookupx(16) = %c 16_00, 16_04, 16_08, 16_0c, 16_10, 16_00, 16_04, 16_08, 16_0c, 16_10, 16_00, 16_04, 16_08, 16_0c, 16_10, 0 %const %byte %array lookupy(16) = %c 16_00, 16_00, 16_00, 16_00, 16_00, 16_0c, 16_0c, 16_0c, 16_0c, 16_0c, 16_18, 16_18, 16_18, 16_18, 16_18, 0 %byte curx = 0, cury = 0, curcol = 15 %routine vecmoveto(%byte x, y) curx = x; cury = y %end %routine veccol(%byte col) curcol = col %end %routine printchar(%byte c) %byte %name nibblep == nibbles(c&255) %byte i, nibble, from, to, len %if nibblep = 0{NULL} %start curx = curx + 16_18 { space } %return %finish len = nibblep; nibblep == BYTE(ADDR(nibblep)+1) %for i = 0, 1, len-1 %cycle nibble = *nibblep++ to = nibble&15; from = (nibble>>4)&15 CinemaVectorData(curx+lookupx(from), cury+lookupy(from), curx+lookupx(to), cury+lookupy(to), curcol) !#ifdef DEBUG ! fprintf(stdout, "%01x to %01x\n", from, to) ! fprintf(stdout, "(%d,%d) to (%d,%d) at %d\n", curx+lookupx(from), cury+lookupy(from), ! curx+lookupx(to), cury+lookupy(to), ! 7) !#endif %repeat curx = curx + 16_18 ! at current x y and do implicit move %end %routine printstring(%byte %name s) printchar(s) %and s == BYTE(ADDR(s) + 1) %while s ## 0{NULL} %end %unsigned %byte rectangle_lookup_x(8) = %c 16_47, 16_b9, 16_b9, 16_47, 16_3f, 16_c1, 16_c1, 16_3f %unsigned %byte rectangle_lookup_y(8) = %c 16_9b, 16_9b, 16_65, 16_65, 16_a3, 16_a3, 16_5d, 16_5d %unsigned %byte rectangle_lookup_z(8) = %c 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80 %unsigned %byte rectangles(9) = %c 16_01, 16_12, 16_23, 16_30, 16_45, 16_56, 16_67, 16_74, 16_ff %routine print_rectangles_seg(%byte c) %unsigned %byte %name coords == rectangles(0) %byte fromx, fromy, fromz, tox, toy, toz %byte nib1 = c >> 4, nib2 = c&7 fromx = rectangle_lookup_x(nib1) fromy = rectangle_lookup_y(nib1) fromz = rectangle_lookup_z(nib1) tox = rectangle_lookup_x(nib2) toy = rectangle_lookup_y(nib2) toz = rectangle_lookup_z(nib2) CinemaVectorData(curx+fromx, cury+fromy, curx+tox, cury+toy, 15) %end %routine print_rectangles %byte *s = rectangles %unsigned %byte ch = *s %while ch # 16_ff %cycle print_rectangles_seg(ch) s += 1 ch = *s %repeat %end %unsigned %byte tg1_lookup_x(16) = %c 16_5d, 16_6d, 16_65, 16_65, 16_71, 16_77, 16_7d, 16_74, 16_7a, 16_89, 16_89, 16_95, 16_95, 16_a1, 16_a7, 16_a7 %unsigned %byte tg1_lookup_y(16) = %c 16_95, 16_95, 16_95, 16_83, 16_83, 16_95, 16_83, 16_8c, 16_8c, 16_83, 16_95, 16_95, 16_83, 16_83, 16_7d, 16_6b %unsigned %byte tg1_lookup_z(16) = %c 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80 %unsigned %byte tg1 = %c 16_01, 16_23, 16_45, 16_56, 16_78, 16_9a, 16_bc, 16_cd, 16_ef, 16_ff %unsigned %byte tg2_lookup_x(16) = %c 16_a7, 16_b3, 16_b3, 16_b0, 16_b3, 16_a7, 16_a1, 16_95, 16_95, 16_a1, 16_9b, 16_95, 16_8f, 16_8f, 16_83, 16_83 %unsigned %byte tg2_lookup_y(16) = %c 16_7d, 16_7d, 16_74, 16_74, 16_6b, 16_74, 16_6b, 16_6b, 16_7d, 16_7d, 16_74, 16_74, 16_7d, 16_6b, 16_7d, 16_6b %unsigned %byte tg2_lookup_z(16) = %c 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80 %unsigned %byte tg2 = %c 16_01, 16_12, 16_34, 16_25, 16_67, 16_78, 16_89, 16_ab, 16_cd, 16_de, 16_ef, 16_ff %unsigned %byte tg3_lookup_x(16) = %c 16_7d, 16_7d, 16_71, 16_71, 16_6b, 16_6b, 16_5f, 16_5f, 16_5c, 16_56, 16_59, 16_59, 16_4d, 16_4d, 16_59 %unsigned %byte tg3_lookup_y(16) = %c 16_7d, 16_6b, 16_7d, 16_6b, 16_7d, 16_6b, 16_6b, 16_7d, 16_72, 16_72, 16_72, 16_6b, 16_6b, 16_7d, 16_7d %unsigned %byte tg3_lookup_z(16) = %c 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80, 16_80 %unsigned %byte tg3 = %c 16_01, 16_12, 16_23, 16_45, 16_56, 16_67, 16_89, 16_ab, 16_bc, 16_cd, 16_de, 16_ff %routine print_tg_seg(%byte c, %unsigned %byte %name tg_lookup_x, %unsigned %byte *tg_lookup_y, %unsigned %byte *tg_lookup_z) %byte *coords = rectangles %byte fromx, fromy, fromz, tox, toy, toz %byte nib1 = (c >> 4)&15, nib2 = c&15 fromx = tg_lookup_x(nib1) fromy = tg_lookup_y(nib1) fromz = tg_lookup_z(nib1) tox = tg_lookup_x(nib2) toy = tg_lookup_y(nib2) toz = tg_lookup_z(nib2) CinemaVectorData(curx+fromx, cury+fromy, curx+tox, cury+toy, 15) %end %routine print_tg_word(%unsigned %byte *tg, %unsigned %byte *tg_lookup_x, %unsigned %byte *tg_lookup_y, %unsigned %byte *tg_lookup_z) %byte *s = tg %unsigned %byte ch = *s %while ch # 16_ff %cycle print_tg_seg(ch, tg_lookup_x, tg_lookup_y, tg_lookup_z) s += 1 ch = *s %repeat %end %routine print_tg print_tg_word(tg1, tg1_lookup_x, tg1_lookup_y, tg1_lookup_z) print_tg_word(tg2, tg2_lookup_x, tg2_lookup_y, tg2_lookup_z) print_tg_word(tg3, tg3_lookup_x, tg3_lookup_y, tg3_lookup_z) %end %routine starplot(%byte x, %byte y) CinemaVectorData(x, y, x+1, y+1, 7) %end { The screen is divided up into 8 sectors: \ | / \|/ --+-- /|\ / | \ We want 16 stars on screen at all times. At any time, each sector must have 2 stars active in it. To provide variety, we will have 4 tracks through each sector, and cycle them as each star finishes its journey. } %const %integer star_x1(32) = %c 0, 0, 0, 0, 25, 125, 225, 325, 425, 525, 625, 725, 1000, 1000, 1000, 1000, 0, 0, 0, 0, 25, 125, 225, 325, 425, 525, 625, 725, 1000, 1000, 1000, 1000 %const %integer star_y1(32) = %c 25, 125, 225, 325, 0,0,0,0, 0,0,0,0, 35, 135, 235, 335, 425,525,62,725, 800,800,800,800, 800,800,800,800, 425,525,62,725 %byte clipoff(%byte x, %byte y); ! would be nice to do %predicate with CC %if 16_1b0 < x <= 16_250 %and 16_140 <= y <= 16_1c0 %start %result = TRUE %finish %else %start %result = FALSE %finish %end {************************************************************************** * line_fast * * draws a line using Bresenham's line-drawing algorithm, which uses * * no multiplication or division. * **************************************************************************} !#define sgn(x) ((x<0)?-1:((x>0)?1:0)) { macro to return the sign of a number } %routine plot_star(%byte starno) %own %byte i(16),dx(16),dy(16),x(16),y(16),px(16),py(16),dxabs(16),dyabs(16),sdx(16),sdy(16) %own %byte state(16) = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 %own %byte flip(16) = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 %own %byte maxspeed(16), ticks(16) %byte speed, done=FALSE %integer x1 = star_x1((starno<<1)+flip(starno)), y1 = star_y1((starno<<1)+flip(starno)), x2 = 16_200, y2 = 16_180 %if state(starno) = 0 %start { initialise } dx(starno)=x2-x1; { the horizontal distance of the line } dy(starno)=y2-y1; { the vertical distance of the line } dxabs(starno)=abs(dx(starno)) dyabs(starno)=abs(dy(starno)) sdx(starno)=sgn(dx(starno)) sdy(starno)=sgn(dy(starno)) x(starno)=dyabs(starno)>>1 y(starno)=dxabs(starno)>>1 px(starno)=x1 py(starno)=y1 state(starno) = 1; maxspeed(starno) = 9 { critical, depends on vector length } ticks(starno) = 0 { and draw first pixel } starplot(px(starno),py(starno)) i(starno) = 0; { initialise 'loop' counter } %return %finish %if dxabs(starno)>=dyabs(starno) %start { the line is more horizontal than vertical } %for speed = 0, 1, maxspeed(starno)-1 %cycle y(starno)+=dyabs(starno) %if y(starno)>=dxabs(starno)) %start y(starno)-=dxabs(starno) py(starno)+=sdy(starno) %finish px(starno)+=sdx(starno) i(starno) += 1 %if done = (i(starno) >= dxabs(starno)) %start %exit %finish %repeat %finish %else %start { the line is more vertical than horizontal } done = FALSE %for speed = 0, 1, maxspeed(starno)-1 %cycle x(starno)+=dxabs(starno) %if x(starno)>=dyabs(starno) %start x(starno)-=dyabs(starno) px(starno)+=sdx(starno) %finish py(starno)+=sdy(starno) i(starno) += 1 %if i(starno) >= dyabs(starno) %start done = TRUE %exit %finish %repeat %finish %if done=TRUE %start state(starno) = 0; { Done! } flip(starno) = 1-flip(starno) %start ticks(starno) += 1 %if ticks(starno) = 12 %start ticks(starno) = 0 maxspeed(starno) -= 1 %finish maxspeed(starno) = 1 %if maxspeed(starno) <= 0) %if clipoff(px(starno), py(starno))=TRUE %start state(starno) = 0 flip(starno) = 1-flip(starno) %finish %else %start starplot(px(starno),py(starno)) { for moving stars we just do one of these each time increment } { this is in effect a very slow line draw } %finish %end %routine stars(%byte speed) %own %byte started = 0 %byte star %if started = 0 %start %byte laststar %for laststar = 1, 1, 16 %cycle { skew } %byte i %for i = 0, 1, 20-1 %cycle { gap between skew } plot_star(star) %for star = 0, 1, laststar-1 %repeat %repeat started = 1 %finish %else %start %byte i %for i = 0, 1, speed-1 %cycle plot_star(star) %for star = 0, 1, 16-1 %repeat %finish %end %own %byte firex(2) %own %byte firey(2) { MISTAKE HERE - we need a line drawing algorithm which increments in one Y unit each call, *NOT* one X unit. } { returns true if drawn to end of vector, false if should call again } %byte plot_fire(%byte lr, %byte x1, %byte y1, %byte x2, %byte y2) %byte i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py dx=x2-x1; { the horizontal distance of the line } dy=y2-y1; { the vertical distance of the line } dxabs=abs(dx) dyabs=abs(dy) sdx=sgn(dx) sdy=sgn(dy) x=dyabs>>1 y=dxabs>>1 px=x1 py=y1 CinemaVectorData(px, py, px+1, py+1, 15) %if dxabs>=dyabs) %start { the line is more horizontal than vertical } %for i = 0, 1, dxabs-1 %cycle y+=dyabs %if y>=dxabs %start y-=dxabs py+=sdy %finish px+=sdx %if i <= 25 %start CinemaVectorData(px, py, px+1, py+1, 15) firex(lr) = px; firey(lr) = py %finish %if i = 50 %then firex(lr) = px %and firey(lr) = py { draw next line 100 pixels in from this one } %repeat %finish %else %start { the line is more vertical than horizontal } %for i = 0, 1, dyabs-1 %cycle x+=dxabs %if x>=dyabs %start x-=dyabs px+=sdx %finish py+=sdy %if i <= 25 %start CinemaVectorData(px, py, px+1, py+1, 15) firex(lr) = px; firey(lr) = py %finish %if i = 50 %then firex(lr) = px %and firey(lr) = py %repeat %finish %if i <= 30 %then %result = TRUE %else %result = FALSE; ! %predicate? %end %const %unsigned %byte crosshair(40) = %c 16_63, 16_80, 16_9e, 16_80, 16_94, 16_76, 16_94, 16_8a, 16_8a, 16_94, 16_76, 16_94, 16_80, 16_9e, 16_80, 16_62, 16_8a, 16_6c, 16_76, 16_6c, 16_6c, 16_76, 16_6c, 16_8a, 16_7b, 16_8a, 16_85, 16_8a, 16_8a, 16_85, 16_8a, 16_7b, 16_85, 16_76, 16_7b, 16_76, 16_76, 16_7b, 16_76, 16_85 %const %unsigned %byte shieldvec(26) = %c 16_c0, 16_a0, 16_e0, 16_80, 16_80, 16_20, 16_20, 16_80, 16_40, 16_a0, 16_80, 16_60, 16_c0, 16_20, 16_e0, 16_40, 16_80, 16_a0, 16_20, 16_40, 16_40, 16_20, 16_80, 16_60, 16_c0, 16_a0 %routine draw_shields %byte i %for i = 0, 1, 12-1 %cycle CinemaVectorData((shieldvec(i*2)<<2) - 16_30, shieldvec(i*2+1)<<2, (shieldvec(i*2+2)<<2) - 16_30, shieldvec(i*2+3)<<2, curcol) %repeat %end %routine draw_crosshair(%byte x, %byte y) %byte i %for i = 0, 1, 9 %cycle CinemaVectorData(x + (crosshair(i*4)) - 16_40, y + crosshair(i*4+1) - 16_80, x + (crosshair(i*4+2)) - 16_40, y + crosshair(i*4+3) - 16_80, curcol) %repeat %end %const %byte PREGAME = 1 %const %byte COINED = 2 %const %byte PLAYING = 3 %own %byte state = PREGAME %own %byte credits = 0 %own %byte passed = 0 %own %byte shields(3) = '8', 0, 0 ! MAIN %byte i %byte start = 0 %byte shieldtick = 0 %byte firing = FALSE %byte reloaded = TRUE %byte firedone1, firedone2 initchars init_graph CinemaClearScreen; { Initialise ioInputs etc before game starts } { CinemaVectorData(50,50, 300,300, 7); } %cycle ->case(state) case(PREGAME): ! vecmoveto(16_190, 210); for (i = 0; i <= '9'; i++) printchar(i) ! vecmoveto(200, 270); for (i = 'A'; i <= 'Z'; i++) printchar(i) vecmoveto(16_96, 16_28a); printstring("SCORE") vecmoveto(16_b8, 16_258); printstring(" 00") vecmoveto(16_2bc, 16_28a); printstring("HIGH(SCORE") vecmoveto(16_2f8, 16_258); printstring(" 00") { Display 'tailgunner' rectangle. Rotate it one increment. If it is facing away, discard the text, just keep the rectangles } { do a cycle of : } vecmoveto(16_180, 16_100); { This will also need to be changed when applying scaling } print_rectangles; { needs rotation applied } print_tg; { identical matrix needed } { when rectangle at maximum size, stop it and flash intensity } { followed by a cycle of: move and show ships (quit when all 3 pass the screen) } { move existing stars in by a time unit, remove old stars that hit internal rectangle, replace with new stars on outer border. This is independent of game state } stars(1) ->donesw case(COINED): !vecmoveto(16_190, 210); for (i = 0; i <= '9'; i++) printchar(i) !vecmoveto(200, 270); for (i = 'A'; i <= 'Z'; i++) printchar(i) vecmoveto(16_96, 16_28a); printstring("SCORE") vecmoveto(16_b8, 16_258); printstring(" 00") vecmoveto(16_2bc, 16_28a); printstring("HIGH SCORE") vecmoveto(16_2f8, 16_258); printstring(" 00") start = (start + 1) & 31 veccol(start >= 16 ? 15 : 7) vecmoveto(16_190, 16_190) printstring("PUSH START") veccol(15) vecmoveto(16_190, 16_32); printstring("CREDITS") vecmoveto(16_258, 16_32); printstring(" "); printchar(credits > '9' ? '9' : credits) { move existing stars in by a time unit, remove old stars that hit internal rectangle, replace with new stars on outer border. This is independent of game state } stars(1) ->donesw case(PLAYING): vecmoveto(16_b8, 16_258); printstring(" 00"); { score } vecmoveto(16_2f8+16_18, 16_258); printchar(passed); { ships passed } vecmoveto(16_1cc, 16_28a); printstring(shields); { shields value } { PLAY ONE FRAME OF GAME HERE } { move existing stars in by a time unit, remove old stars that hit internal rectangle, replace with new stars on outer border. This is independent of game state } %begin %own %byte passing = 0 passing = passing + 1 %if passing >= 500 %start %if passing = 500 %start passed += 3 %if passed > '9' %start passed = 0; credits -= 1 %if credits = 0) state = PREGAME; else state = COINED firing = FALSE %finish %finish stars(2) %finish %else stars(1) passing = 0 %if passing = 540 %end { move and show ships } vecmoveto((mouse_x*5)/4+16_30, 640-((mouse_y*10)/8)); draw_crosshair(curx, cury) %if mouse_b&1 # 0 %start %if firing#TRUE %and reloaded=TRUE %start { initiate fire } firing = TRUE; reloaded = FALSE firedone1 = plot_fire(0, 40,40, (mouse_x*5)/4+16_70, 640-((mouse_y*10)/8)) firedone2 = plot_fire(1, 1000,40, (mouse_x*5)/4+16_70, 640-((mouse_y*10)/8)) %finish %else %start %if firedone1#TRUE %start firedone1 = plot_fire(0, firex(0), firey(0), (mouse_x*5)/4+16_70, 640-((mouse_y*10)/8)) %finish %if firedone2#TRUE %start firedone2 = plot_fire(1, firex(1), firey(1), (mouse_x*5)/4+16_70, 640-((mouse_y*10)/8)) %finish firing = (~firedone1) ! (~firedone2) %finish %finish %else %start %if firing=TRUE %start { Finish off the last shot } %if firedone1#TRUE %start firedone1 = plot_fire(0, firex(0), firey(0), (mouse_x*5)/4+16_70, 640-((mouse_y*10)/8)) %finish %if firedone2#TRUE %start firedone2 = plot_fire(1, firex(1), firey(1), (mouse_x*5)/4+16_70, 640-((mouse_y*10)/8)) %finish firing = ~(firedone1 & firedone2) %finish %else reloaded = TRUE %finish { we might need a debouncing algorithm here to match the behaviour of the real game } %if mouse_b&2 # 0 %and (shields(0) # 0 %or shields(1) # 0) %start draw_shields %if shieldtick = 0 %start shields(1) -= 1 %if shields(1) < 0 %start shields(1) = '9'; shields(0) -= 1 %if shields(0) < 0 %start shields(0) = shields(1) = 0 %finish %finish shieldtick = 8 %finish %else shieldtick -= 1 %finish %else shieldtick = 0 ->donesw ! End switch donesw: CinemaClearScreen %if keypressed %start %byte k = readkey & 16_7f %if k = 27 %start end_graph %stop %finish %else %if k = '3' %start state = COINED; credits += 1 %finish %else %if k = '1' %start state = PLAYING %if state = COINED %finish %else %if k = ' ' %start %if state = PLAYING %start credits -= 1 %if credits = 0 %then state = PREGAME %else state = COINED %finish %finish %finish %repeat %endofprogram