Advertisement
Shaun_B

Shoot - a game for the Sinclair ZX81

Jan 23rd, 2012
930
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 26.70 KB | None | 0 0
  1. /**
  2.  *  Shoot, a game by Donkeysoft MMXII Written for
  3.  *  the Sinclair ZX81, requires 16K of RAM to run.
  4.  *  Public beta V0.000000000000 */
  5. #include <zx81.h>
  6. #include <stdio.h>
  7. #include <input.h>
  8. // Definitions for ROM calls:
  9. #define  POKEY      0x4005
  10. #define  PRINTAT        0x08f5
  11. #define  PRINT      0x10
  12. // To save a whole other conversion routine, it'd just be easier
  13. // to define the character codes for the ZX81's "graphical" chars,
  14. // especially as these are not available on the PC:
  15. #define  BORDER     0x80
  16. #define  INNER      0x08
  17. #define  PLAYERL        0x12
  18. #define PLAYERT     0x3b
  19. // Function prototypes:
  20. // Here is our main entry:
  21. static void main(void);
  22. // This will display the title screen:
  23. static void title(void);
  24. // This function will scroll the text in our scrolly:
  25. static void scroll(void);
  26. // This clears the play area rather than clearing the screen and
  27. // resetting the DFILE:
  28. static void clearcanvas(void);
  29. // This will update the score and lives display:
  30. static void scoreandlives(void);
  31. // This is where most of the game mechanics are:
  32. static void play(void);
  33. // This updates the movements of the player on the vertical plane:
  34. static void playerposv(void);
  35. // Same as above but for the horizontal plane:
  36. static void playerposh(void);
  37. // This places our wormholes onto the screen:
  38. static void wormholes(void);
  39. // This allows upto four shots moving vertically:
  40. static void shootvert(void);
  41. // As above, but shots moving horizontally:
  42. static void shoothorz(void);
  43. // This starts the convoys:
  44. static void startwave(void);
  45. // and this will start each bomb attack:
  46. static void startattack(void);
  47. // Will check if the bomb has hit the drones:
  48. static void checkbomb(void);
  49. // This will check for inverse conditions
  50. static void checkinverse(char x, char y);
  51. // This will check if any of the convoys have been hit:
  52. static void checkhit(char a, char z);
  53. // Checks for high score, and if so, the player gets
  54. // to enter their initials for prosperity:
  55. static void highscorecheck(int c);
  56. // This places our character according to X and Y position:
  57. static void printat(char x, char y);
  58. // This will output our character to the screen:
  59. static void print(char c);
  60. // This allows a character to be printed inverse or not:
  61. static void printc(char ch, uchar inverse);
  62. // Global variables:
  63. static uchar x=0;
  64. static uchar y=0;
  65. // Level placements of wormholes:
  66. static char wormstart[]=
  67. {
  68.     9,9,9,8,8,8,7,9,7,8,8,7,6,6,6,6,6,5,5,5
  69. };
  70. static char wormend[]=
  71. {
  72.     8,16,7,16,7,15,7,14,7,13,8,12,9,11,10,10,11,9,12,8
  73. };
  74. // This will identify our ship, inside the game code, when
  75. // the correct conditions are met, it will either be a space
  76. // rogue O or a legal trader *
  77. static char ship[]=
  78. {
  79.     0,0,0,0
  80. };
  81. // Using simple normalisation principles, this will track the
  82. // each ship as it moves on the X and Y plane:
  83. static char ex[]=
  84. {
  85.     0,0,0,0
  86. };
  87. static char ey[]=
  88. {
  89.     0,0,0,0
  90. };
  91. // Bomb's X and Y position, bombs are zeros on the display:
  92. static char bx[]=
  93. {
  94.     0,0,0,0
  95. };
  96. static char by[]=
  97. {
  98.     0,0,0,0
  99. };
  100. // Old x and y position of bombs, again using simple normalisation
  101. // principles, for the love of Codd:
  102. static char tx[]=
  103. {
  104.     0,0,0,0
  105. };
  106. static char ty[]=
  107. {
  108.     0,0,0,0
  109. };
  110. // And here's our bomb, so if not null essentially (as it's a zero
  111. // char on the display, and not a number) then the bomb exists:
  112. static char bomb[]=
  113. {
  114.     0,0,0,0
  115. };
  116. // This is the target for each bomb, the code will keep track each
  117. // time the bomb movement code is called:
  118. static char targ[]=
  119. {
  120.     0,0,0,0
  121. };
  122. // This will store which target for each bomb, ie, if 0 then the
  123. // top drone and if 1 then the bottom drone, remembering whilst
  124. // the bomb is true (not null), if that makes sense:
  125. static char target=0;
  126. // Boolean for starting the attack:
  127. static char attackstart=0;
  128. // This will increase our level counter, once all of the levels
  129. // have cycled through, it becomes -2 to cycle back through each
  130. // level:
  131. static char levelchange=2;
  132. // This says that the convoys have started:
  133. static char wavecounter=0;
  134. // This keeps track on how many attacks have happened:
  135. static char attackcounter=0;
  136. // Here is our internal counter, which is increased for each pass of
  137. // the main game engine room, ie, while not dead:
  138. static char counter=1;
  139. // This is the speed of the wave generator:
  140. static char speed=47;
  141. // And here is the speed of the bomb generator:
  142. static char bombspeed=48;
  143. // Here is how often the waves are updated:
  144. static char wavetimer=13;
  145. // And here is how often the bombs are updated:
  146. static char attacktimer=14;
  147. // A boolean to say whether or not the wave has started:
  148. static char wavestart=0;
  149. // Skill level: Higher means more space between the worm holes:
  150. static char skill=9;
  151. // Level number:
  152. static char level=0;
  153. // This is used as a boolean to say that a new level is ready:
  154. static char newlevel=0;
  155. // Current highest score - char position 3, 4, and 5 will be changed
  156. // if the high score is beaten and 7, 8, 9 and 10 will be for the
  157. // updated score:
  158. static char hiscore[]="HI MUM 0015";
  159. // Player's X and Y position:
  160. static char x0=16;
  161. static char y0=11;
  162. // Player's old X and Y position (set to zero for now):
  163. static char x1=0;
  164. static char y1=0;
  165. static char ch=0;
  166. // Reusable counter:
  167. static char i=0;
  168. static int c=0;
  169. // Used for reading the keyboard:
  170. static uchar key=0;
  171. // used for determining maximum number of horizontal
  172. // and vertical shots:
  173. static char vert=0;
  174. static char shootv=0;
  175. static char horz=0;
  176. static char shooth=0;
  177. // These arrays will keep track of each bullet on the X and Y plane:
  178. static char shootvpos[]=
  179. {
  180.     0,0,0,0
  181. };
  182. static char downpos[]=
  183. {
  184.     3,3,3,3
  185. };
  186. static char shoothpos[]=
  187. {
  188.     0,0,0,0
  189. };
  190. static char acrosspos[]=
  191. {
  192.     3,3,3,3
  193. };
  194. // Dead or alive boolean:
  195. static char dead=0;
  196. // Inverse text boolean:
  197. static uchar inverse=0;
  198. // Title texts:
  199. static uchar donkey[]="DONKEYSOFT MMXII";
  200. static uchar presents[]="PRESENTS";
  201. static uchar gamename[]="SHOOT.";
  202. static uchar lrkeys[]="5, 8 MOVES LEFT AND RIGHT";
  203. static uchar udkeys[]="6, 7 MOVES UP AND DOWN";
  204. static uchar firekeys[]="3, 0 SHOOTS";
  205. static uchar scrolly[]="..........IN JANUARY 1981, AN ALIEN RACE CRASH-LANDED NEAR CAMBRIDGE. REQUIRING ADVANCED TECHNOLOGIES TO FIX THEIR NAVIGATIONAL COMPUTER, THE ALIENS SECRETLY MET WITH SIR CLIVE SINCLAIR, WHO OFFERED THEM A FEW ZX81 PROTOTYPES IN EXCHANGE FOR THOUSANDS OF SALVAGED BUT DODGY RAM CHIPS. THE TRADE WAS MADE AND THE ALIENS LEFT WITH THE NEW SINCLAIR SUPER COMPUTERS GUIDING THEM HOME. THE ZX81S WERE THEN USED BY THE ALIENS TO CONTROL THEIR OUTER DEFENCES, GUARDING THE WORMHOLES NEAREST TO THEIR HOME AGAINST THEIR FOES AND PIRATE TRADERS. CONTROL THE DRONES TO OBLITERATE THE INVADERS. DO NOT DESTROY * AS THESE ARE LEGAL TRADERS. SHOOT (C) DONKEYSOFT MMXII..........$";
  206. // Displayed if there's a new high score:
  207. static uchar newhighscore[]="ENTER INITIALS:";
  208. // Default high score:
  209. static int highscore=15;
  210. // Booleans used to tell the game to update the score and lives:
  211. static char scoreupdate=1;
  212. static char points=0;
  213. static char livesupdate=1;
  214. // Other messages on the display panel:
  215. static uchar lives[]="DRONES:";
  216. static uchar score[]="SCORE:";
  217. static char sc[]="0000";
  218. // I've been generous with the lives, but this could be changed to
  219. // fewer:
  220. static uchar livesremaining=7;
  221. // Main function:
  222. void main()
  223. {
  224.     if(!dead)
  225.     {
  226.         // This might be helpful for machines >16K - easy enough
  227.         // to comment out or remove:
  228.         #asm
  229.         PUSH    HL
  230.         LD      HL,(POKEY)
  231.         LD      A,$ff
  232.         LD      (HL),A
  233.         POP     HL
  234.         #endasm
  235.         // This will clear the screen using the z88dk default:
  236.         printk("%c ",12);
  237.         // Prints the border:
  238.         for(i=0;i<29;i=i+1)
  239.         {
  240.             printat(i,0);
  241.             print(BORDER);
  242.             if(i>=2 && i<=26)
  243.             {
  244.                 printat(i,1);
  245.                 print(INNER);
  246.                 printat(i,20);
  247.                 print(INNER);
  248.                 printat(i,18);
  249.                 print(INNER);
  250.             }
  251.             if(i<21)
  252.             {
  253.                 printat(0,i);
  254.                 print(BORDER);
  255.                 print(INNER);
  256.                 printat(27,i);
  257.                 print(INNER);
  258.                 print(BORDER);
  259.             }
  260.             printat(i,21);
  261.             print(BORDER);
  262.         }
  263.     }
  264.     // If the game has been played more than once then everything
  265.     // will need to be reset:
  266.     if(dead)
  267.     {
  268.         for(i=0;i<4;i=i+1)
  269.         {
  270.             // Clears all objects in the game world
  271.             ship[i]=0; ex[i]=0; ey[i]=0;
  272.             bx[i]=0; by[i]=0; bomb[i]=0;
  273.             // Restores default positions:
  274.             shootvpos[i]=0;
  275.             downpos[i]=3;
  276.             shoothpos[i]=0;
  277.             acrosspos[i]=3;
  278.             // Resets the score:
  279.             sc[i]='0';
  280.         }
  281.         // Remaining variables reset:
  282.         wavecounter=0;
  283.         attackcounter=0;
  284.         shooth=0;
  285.         horz=0;
  286.         shootv=0;
  287.         vert=0;
  288.         speed=47;
  289.         bombspeed=48;
  290.         wavetimer=13;
  291.         attacktimer=14;
  292.         wavestart=0;
  293.         level=0;
  294.         x0=16;
  295.         y0=11;
  296.         scoreupdate=1;
  297.         livesupdate=1;
  298.         livesremaining=7;
  299.         skill=9;
  300.         dead=0;
  301.     }
  302.     title();
  303. }
  304. static void title()
  305. {
  306.     // This will output the title screen messages:
  307.     for(i=0;i<25;i=i+1)
  308.     {
  309.         printat(2+i,10);
  310.         printc(lrkeys[i],0);
  311.         if(i<17)
  312.         {
  313.             printat(6+i,4);
  314.             printc(donkey[i],0);
  315.             printat(5+i,13);
  316.             print(0);
  317.         }
  318.         if(i<8)
  319.         {
  320.             printat(10+i,6);
  321.             printc(presents[i],0);
  322.         }
  323.         if(i<6)
  324.         {
  325.             printat(11+i,8);
  326.             printc(gamename[i],1);
  327.         }
  328.         if(i<23)
  329.         {
  330.             printat(3+i,11);
  331.             printc(udkeys[i],0);
  332.         }
  333.         if(i<11)
  334.         {
  335.             printat(8+i,12);
  336.             printc(firekeys[i],0);
  337.             printat(8+i,14);
  338.             printc(hiscore[i],1);
  339.         }
  340.     }
  341.     // This is a conditional loop which will end when a key is pressed:
  342.     while(!key)
  343.     {
  344.         printat(2,19);
  345.         // Gets last key press and stores it into key variable:
  346.         key=in_Inkey();
  347.         // Prints out the first 28 chars of the scrolly text using
  348.         // inversed characters:
  349.         for(i=0;i<25;i=i+1)
  350.         {
  351.             printc(scrolly[i],1);
  352.         }
  353.         // Moves the message one char to the 2
  354.         scroll();
  355.     }
  356.     // Clears the playfield ready to start the game:
  357.     clearcanvas();
  358. }
  359. void scroll()
  360. {
  361.     // Sets counter to zero
  362.     c=0;
  363.     // The buffer will preserve the first char otherwise the
  364.     // scrolling won't wrap around
  365.     ch=scrolly[c];
  366.     // Loop will happen whilst the terminator hasn't been reached:
  367.     while(scrolly[c]!='$')
  368.     {
  369.         // Moves each character one element to the 2:
  370.         scrolly[c]=scrolly[c+1];
  371.         // Increase our counter
  372.         c=c+1;
  373.     }
  374.     // Puts the old first character from the start to the end so
  375.     // it wraps around:
  376.     scrolly[c-1]=ch;
  377.     // Checks to see if the terminator has been over-written, if not
  378.     // then it's restored, but the code is fine so commented out:
  379.     /**if(scrolly[c]!='$')
  380.     {
  381.         scrolly[c]='$';
  382.     }*/
  383. }
  384. void clearcanvas()
  385. {
  386.     for(i=17;i>1;i=i-1)
  387.     {
  388.         for(x=26;x>1;x=x-1)
  389.         {
  390.             printat(x,i);
  391.             print(0);
  392.         }
  393.     }
  394.     // Because this function is called once the player is dead
  395.     // we don't want the following to happen after this condition:
  396.     if(dead)
  397.     {
  398.         key=0;
  399.         return;
  400.     }
  401.     // This adds to the skill level dependant on what key you've
  402.     // pressed:
  403.     skill=skill+(key%6);
  404.     wavetimer=wavetimer+(key%3);
  405.     attacktimer=attacktimer+(key%3);
  406.     // Blanks out part of the status bar:
  407.     printat(13,19);
  408.     print(BORDER); print(BORDER);
  409.     scoreandlives();
  410.     play();
  411. }
  412. // This will update our score and lives display:
  413. void scoreandlives()
  414. {
  415.     for(i=0;i<7;i=i+1)
  416.     {
  417.         printat(13+i,19);
  418.         printc(lives[i],1);
  419.         if(i<6)
  420.         {
  421.             printat(2+i,19);
  422.             printc(score[i],1);
  423.         }
  424.     }
  425.     /**if (sc[3]=='8' && sc[2]=='9' && sc[1]=='9' && sc[0]=='9')
  426.     {
  427.         ;; // This will eventually be our winning code.
  428.     }*/
  429.     // Logic to increase the score, as we're not using numbers, but
  430.     // characters, then we need to work out which chars in the array
  431.     // need updating:
  432.     while(points!=0)
  433.     {
  434.         if(sc[1]=='9' && sc[2]=='9' && sc[3]=='9')
  435.         {
  436.             sc[3]=sc[3]+1;
  437.             sc[2]=sc[2]+1;
  438.             sc[1]=sc[1]+1;
  439.             sc[0]=sc[0]+1;
  440.         }
  441.         else
  442.             if(sc[2]=='9' && sc[3]=='9')
  443.             {
  444.                 sc[3]=sc[3]+1;
  445.                 sc[2]=sc[2]+1;
  446.                 sc[1]=sc[1]+1;
  447.             }
  448.         else
  449.             if(sc[3]=='9')
  450.             {
  451.                 sc[3]=sc[3]+1;
  452.                 sc[2]=sc[2]+1;
  453.             }
  454.         else
  455.             {
  456.                 sc[3]=sc[3]+1;
  457.             }
  458.         // This does a wrap-around so that the char doesn't continue
  459.         // past 9:
  460.         for(i=0;i<4;i=i+1)
  461.         {
  462.             if(sc[i]>'9')
  463.             {
  464.                 sc[i]='0';
  465.             }
  466.         }
  467.         // Converts the score to an integer number:
  468.         c=(1000*(sc[0]-48))+(100*(sc[1]-48))+(10*(sc[2]-48))+(sc[3]-48);
  469.         // Increases the level for every 12 points scored:
  470.         if(c%12==0)
  471.         {
  472.             // Clears the old worm holes before increasing the level
  473.             // and so displaying the new worm hole positions:
  474.             printat(wormstart[level],wormstart[level+1]);
  475.             print(0);
  476.             printat(wormend[level]+skill,wormend[level+1]);
  477.             print(0);
  478.             level=level+levelchange;
  479.             // Works out whether to increase the level count or
  480.             // decrease it, to keep in the bounds of the array:
  481.             if(level>17)
  482.             {
  483.                 levelchange=-2;
  484.             }
  485.             if(level<1)
  486.             {
  487.                 levelchange=2;
  488.             }
  489.             // These could be changed to increase the rate at which
  490.             // the bombs and convoys are unleashed:
  491.             if(speed>20)
  492.             {
  493.                 speed=speed-1;
  494.                 bombspeed=bombspeed-1;
  495.             }
  496.             // This says how often to update the display to move each
  497.             // of the elements on the screen:
  498.             if(wavetimer>2)
  499.             {
  500.                 wavetimer=wavetimer-1;
  501.                 attacktimer=attacktimer-1;
  502.             }
  503.             // Places new worm holes:
  504.             wormholes();
  505.         }
  506.         // This is not decreasing the points, what it's doing is
  507.         // decreasing the boolean, so if points=2 this will be called
  508.         // twice:
  509.         points=points-1;
  510.     }
  511.     // This will update the score display:
  512.     while(scoreupdate)
  513.     {
  514.         // Prints score:
  515.         printat(8,19);
  516.         for(i=0;i<4;i=i+1)
  517.         {
  518.             printc(sc[i],1);
  519.         }
  520.         print(BORDER);
  521.         // Resets the boolean:
  522.         scoreupdate=scoreupdate-1;
  523.     }
  524.     // This will update the lives display:
  525.     while(livesupdate)
  526.     {
  527.         printat(20,19);
  528.         // Error checking as livesremaining is a char, so 0-1=255,
  529.         // which is greater than 7, but is -1 twos compliment:
  530.         if(livesremaining<=0 || livesremaining>7)
  531.         {
  532.             dead=1;
  533.             print(BORDER);
  534.             livesremaining=0;
  535.         }
  536.         // This displays the number of lives remaining:
  537.         for(i=livesremaining;i!=0;i=i-1)
  538.         {
  539.             printc('X',1);
  540.         }
  541.         // Prints an inversed space to clear off any lives
  542.         // that have been lost:
  543.         if(livesremaining<7 && !dead)
  544.         {
  545.             for(i=7-livesremaining;i!=0;i=i-1)
  546.             {
  547.                 print(BORDER);
  548.             }
  549.         }
  550.         // Resets the boolean:
  551.         livesupdate=livesupdate-1;
  552.     }
  553. }
  554. // Most of the game engine:
  555. void play()
  556. {
  557.     // This stops spaces been drawn in odd places:
  558.     x1=x0-1; y1=y0-1;
  559.     // Displays player's position:
  560.     playerposv();
  561.     playerposh();
  562.     // Displays wormholes:
  563.     wormholes();
  564.     // All of this happens while not dead:
  565.     while(!dead)
  566.     {
  567.         key=in_Inkey();
  568.         // This allows four shots on the horizontal plane:
  569.         if(key=='0' && horz<4)
  570.         {
  571.             shooth=shooth+1;
  572.             acrosspos[horz]=3;
  573.             shoothpos[horz]=y0;
  574.             horz=horz+1;
  575.         }
  576.         // 7 and 6 is up and down:
  577.         if(key=='7' && y0>3)
  578.         {
  579.             y1=y0; y0=y0-1;
  580.             playerposv();
  581.         }
  582.         if(key=='6' && y0<17)
  583.         {
  584.             y1=y0; y0=y0+1;
  585.             playerposv();
  586.         }
  587.         // 5 and 8 is left and right:
  588.         if(key=='5' && x0>3)
  589.         {
  590.             x1=x0; x0=x0-1;
  591.             playerposh();
  592.         }
  593.         if(key=='8' && x0<26)
  594.         {
  595.             x1=x0; x0=x0+1;
  596.             playerposh();
  597.         }
  598.         // This is the other fire button:
  599.         if(key=='3' && vert<4)
  600.         {
  601.             downpos[vert]=x0;
  602.             shootvpos[vert]=3;
  603.             vert=vert+1;
  604.             shootv=1;
  605.         }
  606.         // This works out which ship to display on the convoys,
  607.         // so 0 is a pirate and 1 is a legal trader:
  608.         i=(x0+y0+wavecounter)%2;
  609.         // If counter has counted up to speed then the convoys
  610.         // will start:
  611.         if(counter%speed==0 && wavecounter<4)
  612.         {
  613.             ex[wavecounter]=wormstart[level];
  614.             ey[wavecounter]=wormstart[level+1];
  615.             // Sets convoys:
  616.             if(i==0)
  617.             {
  618.                 ship[wavecounter]='O';
  619.             }
  620.             else
  621.                 {
  622.                     ship[wavecounter]='*';
  623.                 }
  624.             // Increases wave counter and tells the program to
  625.             // call the wave function:
  626.             wavecounter=wavecounter+1;
  627.             wavestart=1;
  628.         }
  629.         // Will start the bombs from level 1 onwards (starting at
  630.         // level zero, of course):
  631.         if(level && attackcounter<4 && counter%bombspeed==0)
  632.         {
  633.             attackstart=1;
  634.             bomb[attackcounter]='0';
  635.             if(i==1)
  636.             {
  637.                 bx[attackcounter]=wormstart[level];
  638.                 by[attackcounter]=wormstart[level+1];
  639.             }
  640.             else
  641.                 {
  642.                     bx[attackcounter]=wormend[level]+skill;
  643.                     by[attackcounter]=wormend[level+1];
  644.                 }
  645.             // We could re-use the i variable above to decide
  646.             // which of the drones is being targetted by the bomb:
  647.             target=((x0+y0+attackcounter)%2);
  648.             targ[attackcounter]=target;
  649.             attackcounter=attackcounter+1;
  650.         }
  651.         // Increases internal counter:
  652.         counter=counter+1;
  653.         // Calls functions:
  654.         if(wavestart && counter%wavetimer==0)
  655.         {
  656.             startwave();
  657.         }
  658.         if(attackstart && counter%attacktimer==0)
  659.         {
  660.             startattack();
  661.             checkbomb();
  662.         }
  663.         if(scoreupdate || livesupdate)
  664.         {
  665.             scoreandlives();
  666.         }
  667.         if(shooth)
  668.         {
  669.             shoothorz();
  670.         }
  671.         // This will slow things down whilst the screen isn't so busy
  672.         // so that the player's movement do not significantly increase:
  673.         else
  674.             {
  675.                 in_Wait(6);
  676.             }
  677.         if(shootv)
  678.         {
  679.             shootvert();
  680.         }
  681.         else
  682.             {
  683.                 in_Wait(6);
  684.             }
  685.         if(!wavecounter)
  686.         {
  687.             in_Wait(6);
  688.         }
  689.         if(!attackcounter)
  690.         {
  691.             in_Wait(6);
  692.         }
  693.         // This simply stops the auto-fire thingy if one of the fire
  694.         // buttons has been depressed for a fraction of a second too
  695.         // long:
  696.         if(key=='0' || key=='3')
  697.         {
  698.             key=in_Inkey();
  699.             key=in_Inkey();
  700.             key=0;
  701.         }
  702.     }
  703.     // Okay, so the player is dead, let's clear the canvas before
  704.     // working out the final score, checking against the current
  705.     // high score and then returning to the main routine:
  706.     clearcanvas();
  707.     c=(1000*(sc[0]-48))+(100*(sc[1]-48))+(10*(sc[2]-48))+(sc[3]-48);
  708.     highscorecheck(c);
  709.     main();
  710. }
  711. // Updates player's vertical position:
  712. void playerposv()
  713. {
  714.     printat(2,y0);
  715.     print(PLAYERL);
  716.     printat(2,y1);
  717.     print(0);
  718. }
  719. // Updates the player's horizontal position:
  720. void playerposh()
  721. {
  722.     printat(x0,2);
  723.     print(PLAYERT);
  724.     printat(x1,2);
  725.     print(0);
  726. }
  727. // Display's the worm holes:
  728. void wormholes()
  729. {
  730.     printat(wormstart[level],wormstart[level+1]);
  731.     print(BORDER);
  732.     printat(wormend[level]+skill,wormend[level+1]);
  733.     print(BORDER);
  734. }
  735. // This will happen if the player has fired a shot on the vertical
  736. // plane:
  737. void shootvert()
  738. {
  739.     for(i=0; i<vert; i=i+1)
  740.     {
  741.         // To speed things up a bit, the boundary of the bullet if
  742.         // the Y position of the worm hole:
  743.         if(shootvpos[i]<wormend[level+1]+1)
  744.         {
  745.             // Check if the bullet is passing over the worm hole:
  746.             checkinverse(downpos[i],shootvpos[i]);
  747.             // Displays the bullets:
  748.             printat(downpos[i],shootvpos[i]);
  749.             printc('\"',inverse);
  750.         }
  751.         // Take a copy of the old bullet location
  752.         x=downpos[i]; y=shootvpos[i]-1;
  753.         // This checks if one of the convoys has been hit:
  754.         checkhit(downpos[i],shootvpos[i]);
  755.         if(ch)
  756.         {
  757.             // ch is true if a bullet has hit something, so it
  758.             // sets the vertical position out of bounds:
  759.             shootvpos[i]=wormend[level+1]+1;
  760.         }
  761.         // Clears bullet:
  762.         if(y>2 && y<=wormend[level+1])
  763.         {
  764.             checkinverse(x,y);
  765.             printat(x,y);
  766.             printc(0,inverse);
  767.         }
  768.         // Increases position of bullet:
  769.         if(shootvpos[i]<=wormend[level+1]+1)
  770.         {
  771.             shootvpos[i]=shootvpos[i]+1;
  772.         }
  773.     }
  774.     // Checks to see if all of the bullets have been spent:
  775.     c=wormend[level+1]+1;
  776.     if(vert==4 && shootvpos[0]>c && shootvpos[1]>c && shootvpos[2]>c && shootvpos[3]>c)
  777.     {
  778.         vert=0; shootv=0;
  779.     }
  780. }
  781. // And as above but for the horizontal bullets:
  782. void shoothorz()
  783. {
  784.     for(i=0; i<horz; i=i+1)
  785.     {
  786.         if(acrosspos[i]<wormend[level]+skill+1)
  787.         {
  788.             checkinverse(acrosspos[i],shoothpos[i]);
  789.             printat(acrosspos[i],shoothpos[i]);
  790.             printc('-',inverse);
  791.         }
  792.         // Take a copy of the old bullet location
  793.         x=acrosspos[i]-1; y=shoothpos[i];
  794.         // This checks if one of the convoy has been hit:
  795.         checkhit(acrosspos[i],shoothpos[i]);
  796.         if(ch)
  797.         {
  798.             acrosspos[i]=wormend[level]+skill+2;
  799.         }
  800.         if(x>2 && x<=wormend[level]+skill)
  801.         {
  802.             checkinverse(x,y);
  803.             printat(x,y);
  804.             printc(0,inverse);
  805.         }
  806.         if(acrosspos[i]<=wormend[level]+skill+1)
  807.         {
  808.             acrosspos[i]=acrosspos[i]+1;
  809.         }
  810.     }
  811.     c=wormend[level]+skill+1;
  812.     if(horz==4 && acrosspos[0]>c && acrosspos[1]>c && acrosspos[2]>c && acrosspos[3]>c)
  813.     {
  814.         horz=0; shooth=0;
  815.     }
  816. }
  817. // This starts the convoys:
  818. void startwave()
  819. {
  820.     for(i=0;i<wavecounter;i=i+1)
  821.     {
  822.         checkinverse(ex[i],ey[i]);
  823.         if(ex[i]==wormend[level]+skill && ey[i]==wormend[level+1])
  824.         {
  825.             printat(ex[i],ey[i]);
  826.             printc(ship[i],inverse);
  827.             ship[i]=0;
  828.         }
  829.         printat(ex[i],ey[i]);
  830.         printc(ship[i],inverse);
  831.         c=((counter+ship[i])%8);
  832.         // Old position of the enemy:
  833.         x=ex[i]; y=ey[i];
  834.         if((c==4 || c==3 || c==7) && ex[i]<wormend[level]+skill && ship[i]!=0)
  835.         {
  836.             ex[i]=ex[i]+1;
  837.         }
  838.         else
  839.             if((c==2 || c==5) && ey[i]<wormend[level+1] && ship[i]!=0)
  840.             {
  841.                 ey[i]=ey[i]+1;
  842.             }
  843.         else
  844.             if((c==0 || c==1 || c==6) && ex[i]<wormend[level]+skill && ey[i]<wormend[level+1] && ship[i]!=0)
  845.             {
  846.                 ex[i]=ex[i]+1;
  847.                 ey[i]=ey[i]+1;
  848.             }
  849.         else
  850.             if(ex[i]<wormend[level]+skill && ship[i]!=0)
  851.             {
  852.                 ex[i]=ex[i]+1;
  853.             }
  854.         else
  855.             if(ey[i]<wormend[level+1]-1 && ship[i]!=0)
  856.             {
  857.                 ey[i]=ey[i]+1;
  858.             }
  859.         if(ex[i]>wormend[level]+skill || ey[i]>wormend[level+1])
  860.         {
  861.             ex[i]=ex[i]-1;
  862.             ey[i]=ey[i]-1;
  863.         }
  864.         for(c=0;c<wavecounter;c=c+1)
  865.         {
  866.             if(ex[i]==ex[c] && ey[i]==ey[c] && i!=c && ship[c]!=0)
  867.             {
  868.                 ex[i]=x; ey[i]=y;
  869.             }
  870.         }
  871.         checkinverse(x,y);
  872.         if(x!=ex[i] || y!=ey[i])
  873.         {
  874.             printat(x,y);
  875.             printc(0,inverse);
  876.         }
  877.         if(ship[i])
  878.         {
  879.             checkinverse(ex[i],ey[i]);
  880.             printat(ex[i],ey[i]);
  881.             printc(ship[i],inverse);
  882.         }
  883.     }
  884.     if(!ship[0] && !ship[1] && !ship[2] && !ship[3])
  885.     {
  886.         wavecounter=0;
  887.     }
  888. }
  889. // This starts the bomb attacks:
  890. void startattack()
  891. {
  892.     for(i=0;i<attackcounter;i=i+1)
  893.     {
  894.         // This will update each bomb target every
  895.         // time the function is called:
  896.         if(targ[i])
  897.         {
  898.             tx[i]=x0; ty[i]=2;
  899.         }
  900.         else
  901.             {
  902.                 tx[i]=2; ty[i]=y0;
  903.             }
  904.         checkinverse(bx[i],by[i]);
  905.         // Checks if bomb exists (ie, not zero)
  906.         if(bomb[i]!=0)
  907.         {
  908.             printat(bx[i],by[i]);
  909.             printc(bomb[i],inverse);
  910.             c=((counter+level+x0+y0)%12);
  911.             // Old position of the enemy:
  912.             x=bx[i]; y=by[i];
  913.             if(targ[i]==0 && bomb[i]!=0)
  914.             {
  915.                 if(c>=6 && by[i]<ty[i])
  916.                 {
  917.                     by[i]=by[i]+1;
  918.                 }
  919.                 else
  920.                     if(c<6 && by[i]>ty[i])
  921.                     {
  922.                         by[i]=by[i]-1;
  923.                     }
  924.                 if(bx[i]>2 && c==0)
  925.                 {
  926.                     bx[i]=bx[i]-1;
  927.                 }
  928.             }
  929.             if(targ[i]==1 && bomb[i]!=0)
  930.             {
  931.                 if(c>=6 && bx[i]<tx[i])
  932.                 {
  933.                     bx[i]=bx[i]+1;
  934.                 }
  935.                 else
  936.                     if(bx[i]>tx[i] && c<6)
  937.                     {
  938.                         bx[i]=bx[i]-1;
  939.                     }
  940.                 if(by[i]>2 && c==0)
  941.                 {
  942.                     by[i]=by[i]-1;
  943.                 }
  944.             }
  945.             checkinverse(x,y);
  946.             if(x!=bx[i] || y!=by[i])
  947.             {
  948.                 printat(x,y);
  949.                 printc(0,inverse);
  950.             }
  951.             if(bomb[i])
  952.             {
  953.                 checkinverse(bx[i],by[i]);
  954.                 printat(bx[i],by[i]);
  955.                 printc(bomb[i],inverse);
  956.             }
  957.         }
  958.     }
  959.     if(!bomb[0] && !bomb[1] && !bomb[2] && !bomb[3])
  960.     {
  961.         attackcounter=0;
  962.     }
  963. }
  964. // This will check to see if either of the drones has been hit:
  965. void checkbomb()
  966. {
  967.     for(c=0;c<=attackcounter;c=c+1)
  968.     {
  969.         for(i=0;i<=attackcounter;i=i+1)
  970.         {
  971.             if(bx[c]==tx[i] && by[c]==ty[i] && bomb[c])
  972.             {
  973.                 bomb[c]=0;
  974.                 livesupdate=livesupdate+1;
  975.                 livesremaining=livesremaining-1;
  976.                 playerposv();
  977.                 playerposh();
  978.             }
  979.         }
  980.     }
  981. }
  982. // This will check the position to see X or Y have passed over one
  983. // of the worm holes:
  984. void checkinverse(char x, char y)
  985. {
  986.     if((x==wormstart[level] && y==wormstart[level+1]) || (x==wormend[level]+skill && y==wormend[level+1]))
  987.     {
  988.         inverse=1;
  989.     }
  990.     else
  991.         {
  992.             inverse=0;
  993.         }
  994. }
  995. // This checks if the bullets have hit any objects on the screen:
  996. void checkhit(char a, char z)
  997. {
  998.     ch=0;
  999.     for(c=0;c<=4;c=c+1)
  1000.     {
  1001.         if((a==ex[c] && z==ey[c] && ship[c]=='O') || (a==bx[c] && z==by[c] && bomb[c]=='0'))
  1002.         {
  1003.             if(a==ex[c] && z==ey[c])
  1004.             {
  1005.                 ship[c]=0;
  1006.             }
  1007.             else
  1008.                 {
  1009.                     bomb[c]=0;
  1010.                 }
  1011.             printat(a,z);
  1012.             printc(' ',inverse);
  1013.             scoreupdate=scoreupdate+1;
  1014.             points=points+1;
  1015.             ch=1;
  1016.         }
  1017.         if(a==ex[c] && z==ey[c] && ship[c]=='*')
  1018.         {
  1019.             ship[c]=0;
  1020.             printat(a,z);
  1021.             printc(' ',inverse);
  1022.             livesupdate=livesupdate+1;
  1023.             livesremaining=livesremaining-1;
  1024.             ch=1;
  1025.         }
  1026.     }
  1027. }
  1028. // Checks the score:
  1029. void highscorecheck(int c)
  1030. {
  1031.     if(c<highscore+1)
  1032.     {
  1033.         return;
  1034.     }
  1035.     highscore=c;
  1036.     for(i=0;i<15;i=i+1)
  1037.     {
  1038.         if(i<4)
  1039.         {
  1040.             hiscore[7+i]=sc[i];
  1041.         }
  1042.         printat(6+i,13);
  1043.         printc(newhighscore[i],0);
  1044.         if(i<11)
  1045.         {
  1046.             printat(8+i,14);
  1047.             printc(hiscore[i],1);
  1048.         }      
  1049.     }
  1050.     c=0;
  1051.     while(c<3)
  1052.     {
  1053.         key=in_Inkey();
  1054.         if(key=='5' || key=='6')
  1055.         {
  1056.             hiscore[3+c]=hiscore[3+c]-1;
  1057.         }
  1058.         if(key=='7' || key=='8')
  1059.         {
  1060.             hiscore[3+c]=hiscore[3+c]+1;
  1061.         }
  1062.         if(key=='3' || key=='0')
  1063.         {
  1064.             c=c+1;
  1065.         }
  1066.         if(hiscore[3+c]<'A' && c!=3)
  1067.         {
  1068.             hiscore[3+c]='Z';
  1069.         }
  1070.         if(hiscore[3+c]>'Z' && c!=3)
  1071.         {
  1072.             hiscore[3+c]='A';
  1073.         }
  1074.         in_Wait(48);
  1075.         printat(11+c,14);
  1076.         printc(hiscore[3+c],1);
  1077.         if(key=='3' || key=='0')
  1078.         {
  1079.             key=in_Inkey();
  1080.             in_WaitForKey();
  1081.         }
  1082.         key=0;
  1083.     }
  1084. }
  1085. // This sets the X and Y position of the cursor:
  1086. void printat(char x, char y)
  1087. {
  1088.     // Error checking if needed:
  1089.     /**if((x<0 || x>31) || (y<0 || y>21))
  1090.     {
  1091.         printk("OUT OF BOUNDS ERROR ON X/Y POSITION");
  1092.         return -1;
  1093.     }*/
  1094.     #asm
  1095.     PUSH    BC
  1096.     PUSH    HL
  1097.     LD      HL,6
  1098.     ADD     HL,SP
  1099.     LD      B,(HL)
  1100.     INC     HL
  1101.     INC     HL
  1102.     LD      C,(HL)
  1103.     CALL    PRINTAT
  1104.     POP     HL
  1105.     POP     BC
  1106.     RET
  1107.     #endasm
  1108. }
  1109. // This will print out a char, may need conversion if not a valid
  1110. // character code for the ZX81, see below for the conversion:
  1111. void print(char c)
  1112. {
  1113.     #asm
  1114.     PUSH    AF
  1115.     PUSH    HL
  1116.     LD      HL,6
  1117.     ADD     HL,SP
  1118.     LD      A,(HL)
  1119.     RST     PRINT
  1120.     POP     HL
  1121.     POP     AF
  1122.     RET
  1123.     #endasm
  1124. }
  1125. // This function does the necessary conversion from the way that
  1126. // strings are stored using the z88dk to something that the ZX81
  1127. // will understand with our simple print(); function above:
  1128. void printc(char ch, uchar inverse)
  1129. {
  1130.     // As the char codes are stored in bytes differently from the
  1131.     // chr$ codes, and there are different sets too, then there's
  1132.     // a lot of working out to do. I've grouped each char as
  1133.     // appropriate:
  1134.     c=0;
  1135.     if(ch>='A' && ch<='Z')
  1136.     {
  1137.         c=27;
  1138.     }
  1139.     else
  1140.         if(ch>='0' && ch<='9')
  1141.         {
  1142.             c=20;
  1143.         }
  1144.     else
  1145.         if(ch==' ')
  1146.         {
  1147.             c=32;
  1148.         }
  1149.     else
  1150.         // 59 is semi-colon
  1151.         if(ch==59)
  1152.         {
  1153.             c=34;
  1154.         }
  1155.         if(ch=='(' || ch==')')
  1156.         {
  1157.             c=24;
  1158.         }
  1159.     else
  1160.         // * and .
  1161.         if(ch==42 || ch==46)
  1162.         {
  1163.             c=19;
  1164.         }
  1165.     else
  1166.         if(ch=='+')
  1167.         {
  1168.             c=22;
  1169.         }
  1170.     else
  1171.         if(ch==',')
  1172.         {
  1173.             c=18;
  1174.         }
  1175.     else
  1176.         // 45 is minus, 47 is / and 36 is $
  1177.         if(ch==45 || ch==47 || ch==36 || ch=='\"')
  1178.         {
  1179.             c=23;
  1180.         }
  1181.     else
  1182.         // 58 is : and 62 is >
  1183.         if(ch==58 || ch==62)
  1184.         {
  1185.             c=44;
  1186.         }
  1187.     else
  1188.         if(ch=='<' || ch=='=')
  1189.         {
  1190.             c=41;
  1191.         }
  1192.     else
  1193.         if(ch=='?')
  1194.         {
  1195.             c=48;
  1196.         }
  1197.     else
  1198.         if(ch=='£')
  1199.         {
  1200.             c=151;
  1201.         }
  1202.     /**if(a==0)
  1203.     {
  1204.         printk("?ILLEGAL CHAR ERROR");
  1205.         return;
  1206.     }*/
  1207.     // Okay for normal and inverse:
  1208.     ch=ch-c;
  1209.     if(inverse)
  1210.     {
  1211.         ch=ch+128;
  1212.     }
  1213.     print(ch);
  1214. }
  1215. // Compile with:
  1216. // zcc +zx81 -startup=2 -create-app -DTEXT -o SHOOT Shoot.c
  1217. // (C) 2012 Donkeysoft
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement