1 /*
2 * D E A T H S T A R - Microbee version
3 *
4 * How to build:
5 * zcc +cpm -lmicrobee -create-app -DSOUND -DGRAPHICS -O3 -odstar dstar.c
6 *
7 * Crap text only variant:
8 * zcc +cpm -lmicrobee -create-app -DSOUND -O3 -odstar dstar.c
9 *
10 *
11 * *****
12 *
13 * Ported to the Ti82/83/83+ (rest will follow) by Henk Poley
14 * Extended with different sprite sizes and sound by Stefano Bodrato
15 *
16 * * * * * * *
17 *
18 * dstar.c
19 *
20 * DStar Z88 - C Demo
21 * Original TI game By A Von Dollen
22 * Converted to Z88 By D Morris
23 * Keys: Q,A,O,P,SPACE,H,G
24 *
25 * * * * * * *
26 *
27 * dstarz88 is a conversion of a TI86 game I found with
28 * source on www.ticalc.org.
29 *
30 * The original program was written by Andrew Von Dollen who
31 * in turn based it on a HP game by Joe W.
32 *
33 * The aim of the game is to collect all the clear bubbles by
34 * running over them. You control either the dark bubble or
35 * the solid box. The dark bubble is used to collect the clear
36 * bubbles, and the solid box is used as a sort of movable wall.
37 *
38 * Both objects carry on moving until they hit something else
39 * (except for the dark bubble in the case of clear bubbles).
40 *
41 * * * * * * *
42 *
43 * The keys are defined in #define statements, and default thus:
44 *
45 * Up: Q
46 * Down: A
47 * Left: O
48 * Right: P
49 * Quit: G
50 * Retry: H
51 * Switch: [SPACE]
52 *
53 * Switch changes between the dark bubble and the solid box.
54 *
55 *
56 * On the TI Calculators the keyboard mapping is:
57 *
58 * up,down,left,right - move ball/box
59 * [Enter] - toggle ball/box
60 * 7 - Quit
61 * 9 - Restart level
62 * +,- - CHEAT....
63 *
64 * * * * * * *
65 *
66 * This is the first game ever produced with the Small C compiler -
67 * it was written as a statement saying that it is possible to
68 * write something easily, quickly and efficiently using the
69 * compiler. Hopefully it will be an encouragement for others to
70 * do likewise!
71 *
72
73 * * * * * * *
74 *
75 * Enough twaddle, enjoy the game and study the source!
76 *
77 * d. <djm@jb.man.ac.uk> 1/12/98
78 *
79 * * * * * * *
80
81 */
82
83 #include <stdio.h>
84 #include <games.h>
85 #include <stdlib.h>
86 #include <graphics.h>
87 #include <string.h>
88
89 #include <sound.h>
90
91
92 #include "dstar.h"
93
main()94 void main()
95 {
96 int i;
97
98 /* Load user defined graphics (reversed) onto character set */
99
100 #ifdef GRAPHICS
101
102 for (i=0; i<128*16; i++)
103 udg[i]=sprites[i]^0xff;
104 #asm
105 ;ld a,$80
106 ;out ($1c),a
107
108 ; jr vdini
109
110 ;.vdutab ; 64*16
111 ; defb 107,64,81,55,18,9,16,17,$48,$0F,$2F,$0F,0,0,0,0
112
113 ;.vdutab ; 40x24
114 ; defb $35,40,$2D,$24,$1b,$05,$19,$1a,$48,$0a,$2a,$0a,$20,0,0,0
115
116 ;.vdutab ; 80x24
117 ; defb $6b,80,$58,$37,$1b,$05,$18,$1a,$48,$0a,$2a,$0a,$20,0,0,0
118
119 .vdutab ; 80x24 / 80x25 - Peter Broughton
120 ; defb $6b,$50,$5b,$37,$1b,$05,$19,$1a,$48,$0a,$2a,$0a,$20,0,0,0
121 ; defb $6b,$50,$59,$37,$1b,$05,$19,$1b,$48,$0a,$2a,$0a,$20,0,0,0
122
123
124 ;.vdini
125
126
127 ; LD HL,vdutab
128 ; LD C,0
129 ; LD B,16
130 ;.vdloop
131 ; LD A,C
132 ; OUT ($0C),A
133 ; LD A,(HL)
134 ; OUT ($0D),A
135 ; INC HL
136 ; INC C
137 ; DJNZ vdloop
138
139 ; LD HL,vdutab+16
140 ; LD B,16
141 ;.vdloop
142 ; LD A,B
143 ; DEC A
144 ; OUT ($0C),A
145 ; LD A,(HL)
146 ; OUT ($0D),A
147 ; DEC HL
148 ; DJNZ vdloop
149
150 #endasm
151
152 #endif
153
154 SetupLevel(); /* Display the first level */
155
156 /* Loop keyhandler till you finished the game */
157 while (CheckNotFinished())
158 Gamekeys();
159 }
160
161
Gamekeys(void)162 void Gamekeys(void)
163 {
164 char *charptr;
165
166 /* Set up a pointer to the variable we want to change
167 * (either the box or the ball) */
168 charptr = PieceIsBall ? &BoxOffset : &BallOffset;
169
170 switch(getk())
171 {
172 case K_DOWN:
173 MovePiece(charptr,0,+1);
174 break;
175 case K_UP:
176 MovePiece(charptr,0,-1);
177 break;
178 case K_RIGHT:
179 MovePiece(charptr,+1,0);
180 break;
181 case K_LEFT:
182 MovePiece(charptr,-1,0);
183 break;
184 case K_SWITCH:
185 PieceIsBall^=1; /* Toggle ball/box */
186 #ifdef SOUND
187 bit_fx4 (5);
188 #endif
189 while (getk() == K_SWITCH) {}
190 break;
191 case K_EXIT:
192 #ifdef GRAPHICS
193 #asm
194 xor a
195 out ($1c),a
196 #endasm
197 #endif
198 exit(0);
199 case K_NEXTLEV: /* Okay this IS cheating... */
200 if(++Level==MAXLEVEL)
201 { --Level; break; }
202 SetupLevel();
203 break;
204 case K_PREVLEV:
205 if(--Level==-1)
206 { ++Level; break; }
207 /* fall thrue */
208 case K_CLEAR:
209 #ifdef SOUND
210 bit_fx4 (3);
211 #endif
212 SetupLevel();
213 }
214 }
215
216
217 /* The level is stored 'compressed', taking up 38 bytes a time.
218 * byte 0 - position of ball
219 * byte 1 - position of box
220 * 2-37 - Level data
221 *
222 * Level data is stored as two bits per block, so we have to shift our
223 * picked up byte round to get it.
224 */
SetupLevel(void)225 void SetupLevel(void)
226 {
227 int x;
228 char *ptr,*ptr2;
229
230 /* Fresh level, so start with the ball */
231 PieceIsBall = FALSE;
232
233 ptr2 = Board; /* We copy to the Board */
234 ptr = levels + (Level * 38); /* from the Level data */
235
236 /* First two bytes are the ball and the box position */
237 BallOffset = *ptr++;
238 BoxOffset = *ptr++;
239
240 /* Decompress Level into the Board */
241 for (x=0; x!=36; x++)
242 {
243 *ptr2++=((*ptr)>>6)&3;
244 *ptr2++=((*ptr)>>4)&3;
245 *ptr2++=((*ptr)>>2)&3;
246 *ptr2++=( *ptr) &3;
247 ptr++;
248 }
249
250 /* Put the ball and box into their Board position */
251 *(Board+BallOffset) = BALL;
252 *(Board+BoxOffset) = BOX;
253
254 DrawBoard(); /* Display the clean Board */
255
256 #ifdef SOUND
257 bit_fx4 (1);
258 #endif
259 }
260
261
DrawBoard(void)262 void DrawBoard(void)
263 {
264 int x,y;
265 char *ptr;
266
267 ptr = Board;
268
269 /* clear the screen */
270 //printf("%c",12);
271
272 for (y=0 ; y!=9 ; y++)
273 {
274 for (x=0 ; x!=16 ; x++)
275 {
276 // putsprite(spr_or,(x*spritesize),(y*spritesize),sprites + (spritemem * (*ptr++)));
277 putpic (x,y,(*ptr++));
278 }
279 }
280 }
281
282
283
284 /* Check if a Level is (not) finished:
285 * There are 144 squares in each Level
286 *
287 * Note the use of != instead of < or <=
288 * - this is faster to execute on the Z80!
289 */
CheckNotFinished(void)290 char CheckNotFinished(void)
291 {
292 char *ptr;
293 int i;
294
295 ptr = Board;
296 for(i=1 ; i!=144 ; i++)
297 {
298 if(*ptr++ == BUBB) return(TRUE); /* Are there any bubbles? */
299 }
300 if(++Level == MAXLEVEL) return(FALSE); /* All levels done? */
301
302 SetupLevel(); /* If not => Next Level! */
303 return(TRUE); /* And keep scanning keys */
304 }
305
306
307 /* Check to see if we're running into anything:
308 * - The box stops for everything (exept empty space [= 0])
309 * - The ball stops for everything exept a bubble
310 */
TestNextPosIsStop(char nextpos)311 char TestNextPosIsStop(char nextpos)
312 {
313 if(!PieceIsBall)
314 if (nextpos==BUBB) return(FALSE);
315 return(nextpos);
316 }
317
318
MovePiece(char * ptr,char plusx,char plusy)319 void MovePiece(char *ptr, char plusx, char plusy)
320 {
321 char *locn;
322 char temp,temp2;
323 int x,y;
324
325 temp = PieceIsBall + 3;
326 temp2 = (plusx + (plusy * 16));
327
328 while(1) /* loop */
329 {
330
331 locn = *(ptr) + Board;
332 if(TestNextPosIsStop(*(locn+temp2))) return; /* till edge */
333 /*
334 y = (*(ptr) / 16);
335 x = (*(ptr) - (y * 16)) * spritesize;
336 y *= spritesize;
337 */ y = (*(ptr) / 16); x = (*(ptr) - (y * 16));
338 if(*(locn+temp2)==BUBB)
339 {
340 //putsprite(spr_xor,x+(plusx*spritesize),y+(plusy*spritesize),sprites + (spritemem * BUBB));
341 putpic (x+plusx,y+plusy,BUBB);
342
343 #ifdef SOUND
344 bit_fx2 (5);
345 #endif
346 }
347
348 *(locn+temp2) = *locn;
349 *locn = 0;
350
351 /* remove old */
352 //putsprite(spr_xor,x,y,sprites + (spritemem * temp));
353 putpic (x,y,0);
354
355 /* put new */
356 //putsprite(spr_xor,x+(plusx*spritesize),y+(plusy*spritesize),sprites + (spritemem * temp));
357 putpic (x+plusx,y+plusy,temp);
358
359 #ifdef SOUND
360 //bit_fx2 (6);
361 bit_fx4 (2);
362 #endif
363
364 (*ptr) += temp2;
365 }
366 }
367
368 // Sorcerer Exidy text resolution is 64x25
putpic(int x,int y,int picture)369 void putpic(int x, int y, int picture) {
370 #ifdef GRAPHICS
371 switch (picture) {
372
373 case 0:
374 display[y*160+x*5]=128;
375 display[y*160+x*5+1]=128;
376 display[y*160+x*5+2]=128;
377 display[y*160+x*5+3]=128;
378 display[y*160+x*5+4]=128;
379 display[y*160+80+x*5]=128;
380 display[y*160+80+x*5+1]=128;
381 display[y*160+80+x*5+2]=128;
382 display[y*160+80+x*5+3]=128;
383 display[y*160+80+x*5+4]=128;
384 break;
385
386 // brick
387 case 1:
388 display[y*160+x*5]=129;
389 display[y*160+x*5+1]=130;
390 display[y*160+x*5+2]=131;
391 display[y*160+x*5+3]=132;
392 display[y*160+x*5+4]=133;
393 display[y*160+80+x*5]=134;
394 display[y*160+80+x*5+1]=135;
395 display[y*160+80+x*5+2]=136;
396 display[y*160+80+x*5+3]=137;
397 display[y*160+80+x*5+4]=138;
398 break;
399
400 // bubble
401 case 2:
402 display[y*160+x*5]=139;
403 display[y*160+x*5+1]=140;
404 display[y*160+x*5+2]=141;
405 display[y*160+x*5+3]=142;
406 display[y*160+x*5+4]=143;
407 display[y*160+80+x*5]=144;
408 display[y*160+80+x*5+1]=145;
409 display[y*160+80+x*5+2]=146;
410 display[y*160+80+x*5+3]=147;
411 display[y*160+80+x*5+4]=148;
412 break;
413
414 // ball
415 case 3:
416 display[y*160+x*5]=149;
417 display[y*160+x*5+1]=150;
418 display[y*160+x*5+2]=151;
419 display[y*160+x*5+3]=152;
420 display[y*160+x*5+4]=153;
421 display[y*160+80+x*5]=154;
422 display[y*160+80+x*5+1]=155;
423 display[y*160+80+x*5+2]=156;
424 display[y*160+80+x*5+3]=157;
425 display[y*160+80+x*5+4]=158;
426 break;
427
428 // blocker
429 case 4:
430 display[y*160+x*5]=159;
431 display[y*160+x*5+1]=160;
432 display[y*160+x*5+2]=161;
433 display[y*160+x*5+3]=162;
434 display[y*160+x*5+4]=163;
435 display[y*160+80+x*5]=164;
436 display[y*160+80+x*5+1]=165;
437 display[y*160+80+x*5+2]=166;
438 display[y*160+80+x*5+3]=167;
439 display[y*160+80+x*5+4]=168;
440 break;
441 }
442
443 #else
444 switch (picture) {
445
446 case 0:
447 display[y*160+x*5]=' ';
448 display[y*160+x*5+1]=' ';
449 display[y*160+x*5+2]=' ';
450 display[y*160+x*5+3]=' ';
451 display[y*160+x*5+4]=' ';
452 display[y*160+80+x*5]=' ';
453 display[y*160+80+x*5+1]=' ';
454 display[y*160+80+x*5+2]=' ';
455 display[y*160+80+x*5+3]=' ';
456 display[y*160+80+x*5+4]=' ';
457 break;
458
459 // brick
460 case 1:
461 display[y*160+x*5]=131;
462 display[y*160+x*5+1]=131;
463 display[y*160+x*5+2]=131;
464 display[y*160+x*5+3]=131;
465 display[y*160+x*5+4]=131;
466 display[y*160+80+x*5]=131;
467 display[y*160+80+x*5+1]=131;
468 display[y*160+80+x*5+2]=131;
469 display[y*160+80+x*5+3]=131;
470 display[y*160+80+x*5+4]=131;
471 break;
472
473 // bubble
474 case 2:
475 display[y*160+x*5]=' ';
476 display[y*160+x*5+1]='_';
477 display[y*160+x*5+2]='-';
478 display[y*160+x*5+3]='_';
479 display[y*160+x*5+4]=' ';
480 display[y*160+80+x*5]=' ';
481 display[y*160+80+x*5+1]=' ';
482 display[y*160+80+x*5+2]=126;
483 display[y*160+80+x*5+3]=' ';
484 display[y*160+80+x*5+4]=' ';
485 break;
486
487 // ball
488 case 3:
489 display[y*160+x*5]=' ';
490 display[y*160+x*5+1]=127;
491 display[y*160+x*5+2]=127;
492 display[y*160+x*5+3]=127;
493 display[y*160+x*5+4]=' ';
494 display[y*160+80+x*5]=' ';
495 display[y*160+80+x*5+1]=127;
496 display[y*160+80+x*5+2]=127;
497 display[y*160+80+x*5+3]=127;
498 display[y*160+80+x*5+4]=' ';
499 break;
500
501 // blocker
502 case 4:
503 display[y*160+x*5]=10;
504 display[y*160+x*5+1]=10;
505 display[y*160+x*5+2]=10;
506 display[y*160+x*5+3]=10;
507 display[y*160+x*5+4]=10;
508 display[y*160+80+x*5]=10;
509 display[y*160+80+x*5+1]=10;
510 display[y*160+80+x*5+2]=10;
511 display[y*160+80+x*5+3]=10;
512 display[y*160+80+x*5+4]=10;
513 break;
514
515 }
516 #endif
517 }
518
519