Cave Blaster.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Cave Blaster, an example of arcade game written in C
  2. // You need the TIGCC cross-compiler to compile it
  3. // Compile for TI-89 only
  4. #define USE_TI89
  5. #define MIN_AMS 100
  6. #define SAVE_SCREEN
  7. #include <string.h>
  8. #include <graph.h>
  9. #include <kbd.h>
  10. #include <system.h>
  11. #include <printf.h>
  12. #include <peekpoke.h>
  13. #define ARROWS_ROW 0xfffe // Constants for low-level keyboard access
  14. #define LEFT_KEY 2
  15. #define RIGHT_KEY 8
  16. #define UP_KEY 1
  17. #define DOWN_KEY 4
  18. #define SECOND_KEY 16
  19. #define ESC_ROW 0xffbf
  20. #define ESC_KEY 1
  21. typedef struct
  22. {
  23. char name[10];
  24. unsigned long score;
  25. } HSC_ITEM;
  26. SCR_RECT screen_area={{0,0,159,99}};
  27. unsigned int rand_seed=0;
  28. void draw_str(int x,int y,const char *str)
  29. {
  30. DrawStr(x,y,str,A_REPLACE);
  31. }
  32. // Look at the following 4 routines: do you know why C is a write-only language?
  33. // In my opinion, even assembler is often more readable!
  34. #define LCD_HARD_BYTE_WIDTH 30
  35. #define LCD_BYTE_WIDTH 20
  36. #define START_ROW 10
  37. #define END_ROW 99
  38. void scroll_left(void)
  39. {
  40. register char *ptr=LCD_MEM+LCD_HARD_BYTE_WIDTH*START_ROW;
  41. register int i;
  42. while(ptr<=(char*)LCD_MEM+LCD_HARD_BYTE_WIDTH*END_ROW)
  43. {
  44. for(i=0;i<LCD_BYTE_WIDTH/4;i++,ptr+=4)
  45. poke_l(ptr,(peek_l(ptr)<<1)+(speek_l(ptr+4)<0));
  46. ptr+=LCD_HARD_BYTE_WIDTH-LCD_BYTE_WIDTH;
  47. }
  48. }
  49. #undef START_ROW
  50. #undef END_ROW
  51. int get_pixel(int x,int y) // Faster replacement for GetPix from TIOS
  52. {
  53. return !!(peek(0x4c00+30*y+(x>>3))&(1<<(~x&7)));
  54. }
  55. void invert_scr(void)
  56. {
  57. register long *ptr;
  58. for(ptr=(long*)0x4c00;(unsigned long)ptr<=0x57b8;*ptr++^=-1);
  59. }
  60. // Yet another ugly-looking but very efficient routine follows: it puts a
  61. // sprite (in EXOR mode) defined by "sprite" at position (x,y). Returns 1 if
  62. // OK, or 0 if there is a collision with at least one pixel drawn on screen.
  63. int put_sprite(int x,int y,int sprite[])
  64. {
  65. register long addr=0x4c00+30*y+((x>>3)&0xfffe),collision=0,data;
  66. register int i,cnt=16-(x&15);
  67. for(i=0;i<=7;i++,addr+=30)
  68. collision|=((data=(long)sprite[i]<<cnt)&peek_l(addr)),*(long*)addr^=data;
  69. return !collision;
  70. }
  71. int random(int x) // Returns a random number between 0 and x-1
  72. {
  73. return ((rand_seed=(75*rand_seed+1))>>4)%x;
  74. }
  75. void randomize(unsigned int x)
  76. {
  77. rand_seed=x;
  78. }
  79. void draw_border(void)
  80. {
  81. int i;
  82. ClrScr();
  83. for(i=0;i<=4;i+=2)
  84. DrawClipRect(MakeWinRect(i,i,159-i,99-i),&screen_area,A_NORMAL);
  85. }
  86. long game(int speed) // Main game; returns score
  87. {
  88. int up=20,down=90,fire=0,laser=250;
  89. int scr_cnt=30,level_cnt=0,level=1,met_loc=0,met_freq=150;
  90. int x,y,old_x,old_y,i,rnd,rl,cnt=0,mxcnt=0,key,lives,f_sum,crash;
  91. unsigned long score=0,extra=1;
  92. static int plane[]={0,0x3800,0x1c38,0x0efc,0x3fff,0x7fff,0x1ffe,0x1f00};
  93. ClrScr();
  94. OSSetSR(0x0400); // Disable interrupts below Auto-Int 5
  95. for(i=1;i<=120;i+=2)
  96. DrawClipEllipse(80,50,i,i,&screen_area,1);
  97. ClrScr();
  98. for(lives=5;lives>0;lives--)
  99. {
  100. ClrScr();
  101. FontSetSys(F_4x6);
  102. DrawClipRect(&(WIN_RECT){0,0,158,8},&screen_area,A_NORMAL);
  103. put_sprite(x=100,y=50,plane);
  104. crash=0;
  105. while(!crash)
  106. {
  107. if(_rowread(ESC_ROW)&ESC_KEY) return score;
  108. scroll_left();
  109. put_sprite(x-1,y,plane);
  110. if(!put_sprite(x,y,plane))
  111. {
  112. for(i=1;i<=100;i++) invert_scr();
  113. crash=1;
  114. }
  115. while(!OSTimerExpired(6)); // Delay
  116. OSTimerRestart(6);
  117. old_x=x; old_y=y;
  118. key=_rowread(ARROWS_ROW);
  119. if(key&SECOND_KEY&&laser)
  120. {
  121. DrawLine(x+16,y+5,159,y+5,A_XOR);
  122. fire=1; f_sum=0; laser--;
  123. for(i=x+10;i<=159;i++) f_sum+=!get_pixel(i,y+5);
  124. score+=f_sum*3;
  125. }
  126. if(scr_cnt++==30)
  127. {
  128. printf_xy(3,2,"Lives: %d Zone: %c Laser: %d Score: %ld ",
  129. lives,64+level,laser,score);
  130. scr_cnt=0; score+=speed+(level<<1)+x/15;
  131. if(score>extra*5000) lives++,extra+=2;
  132. if(level_cnt++==30)
  133. {
  134. level_cnt=0; level++; up++; down--;
  135. met_freq=30+160/level; laser=200+50*level;
  136. for(i=1;i<=12;i++) invert_scr();
  137. }
  138. }
  139. x+=((x<142)&&(key&RIGHT_KEY))-((x>2)&&(key&LEFT_KEY));
  140. y+=((y<92)&&(key&DOWN_KEY))-((y>1)&&(key&UP_KEY));
  141. if(old_x!=x||old_y!=y)
  142. {
  143. put_sprite(x,y,plane); put_sprite(old_x,old_y,plane);
  144. score++;
  145. }
  146. DrawLine(159,10,159,up,A_SHADE_H);
  147. DrawLine(159,99,159,down,A_SHADE_H);
  148. rnd=random((level+1)|1)-((level+1)>>1);
  149. up+=rnd; down+=rnd;
  150. if(up<10||down>98) up-=rnd,down-=rnd;
  151. if(!random(met_freq))
  152. mxcnt=cnt=4+random(8), met_loc=((up+down)>>1)+random(7)-3;
  153. if(--cnt>0&&met_loc)
  154. {
  155. rl=1+random(2+((cnt>mxcnt/2)?(mxcnt-cnt):cnt));
  156. DrawLine(159,met_loc-rl,159,met_loc+rl,A_NORMAL);
  157. }
  158. if(fire)
  159. {
  160. DrawLine(old_x+16,old_y+5,159,old_y+5,A_REVERSE);
  161. fire--;
  162. }
  163. }
  164. }
  165. FontSetSys(F_8x10);
  166. draw_str(50,45,"GAME OVER !");
  167. ngetchx();
  168. return score;
  169. }
  170. void high_scores(HSC_ITEM hsc_table[])
  171. {
  172. int i;
  173. draw_border();
  174. FontSetSys(F_8x10);
  175. draw_str(12,10,">> HIGH SCORES <<");
  176. for(i=0;i<=4;i++)
  177. printf_xy(12,30+12*i,"%d. %-8s%6ld",i+1,hsc_table[i].name,
  178. hsc_table[i].score);
  179. ngetchx();
  180. }
  181. void input_str(char *str,int x,int y,int maxlen)
  182. {
  183. int i=0,key=0;
  184. while(key!=13)
  185. {
  186. str[i]='_'; str[i+1]=' '; str[i+2]=0;
  187. draw_str(x,y,str);
  188. key=ngetchx();
  189. if(key>=' '&&key<='~'&&i<maxlen) str[i++]=key;
  190. if(key==257&&i) i--;
  191. }
  192. str[i]=0;
  193. }
  194. void update_hsc(HSC_ITEM hsc_table[],unsigned long score)
  195. {
  196. int i;
  197. for(i=4;(hsc_table[i-1].score<score)&&i;i--)
  198. memcpy(&hsc_table[i],&hsc_table[i-1],sizeof(HSC_ITEM));
  199. hsc_table[i].score=score;
  200. ClrScr();
  201. FontSetSys(F_8x10);
  202. draw_str(35,10,"WELL DONE !!!");
  203. FontSetSys(F_6x8);
  204. draw_str(17,30,"You have achieved one");
  205. draw_str(27,40,"of the best scores!");
  206. draw_str(30,60,"Enter your name");
  207. draw_str(20,70,"(max. 8 characters):");
  208. input_str(hsc_table[i].name,50,84,8);
  209. high_scores(hsc_table);
  210. }
  211. void _main(void) // Main program
  212. {
  213. static HSC_ITEM hsc_table[5]={{"PPanther",15000},{"DDuck",13000},
  214. {"MMouse",10000},{"Popeye",8000},{"BBunny",5000}};
  215. static char land[]="1",speed[]="4";
  216. int key=0;
  217. unsigned long score;
  218. pokeIO(0x600017,0xFA); // Force timer to work faster
  219. while(key!=264)
  220. {
  221. if(key!='3'&&key!='4') draw_border();
  222. OSFreeTimer(6);
  223. OSRegisterTimer(6,6-(speed[0]-'0'));
  224. FontSetSys(F_8x10);
  225. draw_str(16,10,"CaveBlaster V1.0 ");
  226. FontSetSys(F_4x6);
  227. draw_str(10,70,"KEYS: Arrows: move, 2nd: fire, ESC: exit");
  228. draw_str(30,79,"(C) 2000 by Zeljko Juric");
  229. draw_str(8,88,"Example of arcade written in C language");
  230. FontSetSys(F_6x8);
  231. draw_str(18,27,"1. Play the game");
  232. draw_str(18,36,"2. View high scores");
  233. draw_str(18,45,"3. Select landscape");
  234. draw_str(18,54,"4. Select speed");
  235. draw_str(137,45,land);
  236. draw_str(137,54,speed);
  237. do
  238. {
  239. switch(key=ngetchx())
  240. {
  241. case '1':
  242. randomize(1000*(land[0]-'1'));
  243. if((score=game(speed[0]-'1'))>hsc_table[4].score)
  244. update_hsc(hsc_table,score);
  245. break;
  246. case '2':
  247. high_scores(hsc_table);
  248. break;
  249. case '3':
  250. if(land[0]++=='9') land[0]='1';
  251. break;
  252. case '4':
  253. if(speed[0]++=='5') speed[0]='1';
  254. break;
  255. case 264:
  256. break;
  257. default:
  258. key = 0;
  259. }
  260. } while(!key);
  261. }
  262. pokeIO(0x600017,0xB2); // Restore normal timer speed
  263. }
  264. // If you have any comments, suggestions, questions or bug reports, mail me at:
  265. // zjuric@utic.net.ba
  266. // Zeljko Juric
  267. // Sarajevo
  268. // Bosnia & Herzegovina