1 /*
2  * Ported to the Ti82/83/83+ (rest will follow) by Henk Poley
3  * Extended with different sprite sizes and sound by Stefano Bodrato
4  *
5  * * * * * * *
6  *
7  *      dstar.c
8  *
9  *		DStar Z88 - C Demo
10  *		Original TI game By A Von Dollen
11  *		Converted to Z88 By D Morris
12  *		Keys: Q,A,O,P,SPACE,H,G
13  *
14  * * * * * * *
15  *
16  *      dstarz88 is a conversion of a TI86 game I found with
17  *      source on www.ticalc.org.
18  *
19  *      The original program was written by Andrew Von Dollen who
20  *      in turn based it on a HP game by Joe W.
21  *
22  *      The aim of the game is to collect all the clear bubbles by
23  *      running over them. You control either the dark bubble or
24  *      the solid box. The dark bubble is used to collect the clear
25  *      bubbles, and the solid box is used as a sort of movable wall.
26  *
27  *      Both objects carry on moving until they hit something else
28  *      (except for the dark bubble in the case of clear bubbles).
29  *
30  * * * * * * *
31  *
32  *      The keys are defined in #define statements, and default thus:
33  *
34  *      Up:     Q
35  *      Down:   A
36  *      Left:   O
37  *      Right:  P
38  *      Quit:   G
39  *      Retry:  H
40  *      Switch: [SPACE]
41  *
42  *      Switch changes between the dark bubble and the solid box.
43  *
44  *
45  *      On the TI Calculators the keyboard mapping is:
46  *
47  *      up,down,left,right - move ball/box
48  *      [Enter]            - toggle ball/box
49  *      7                  - Quit
50  *      9                  - Restart level
51  *      +,-                - CHEAT....
52  *
53  * * * * * * *
54  *
55  *      This is the first game ever produced with the Small C compiler -
56  *      it was written as a statement saying that it is possible to
57  *      write something easily, quickly and efficiently using the
58  *      compiler. Hopefully it will be an encouragement for others to
59  *      do likewise!
60  *
61  * * * * * * *
62  *
63  *      Compile examples :
64  *
65  *      To get a TI82 version of the game (optionally you could add sound):
66  *      zcc +ti82 -create-app dstar.c
67  *
68  *      To get a TI85 version of the game (optionally you could add sound):
69  *      zcc +ti85 -Dspritesize=7 -create-app dstar.c
70  *
71  *      To get a Spectrum 16K version of the game:
72  *      zcc +zx -Dspritesize=16 -DSOUND -create-app -zorg=24300 dstar.c
73  *
74  *      To get a TS2068 HRG version of the game:
75  *      zcc +ts2068 -startup=2 -Dspritesize=21 -DSOUND -create-app dstar.c
76  *
77  *      To get a VZ200 version:
78  *      zcc +vz -Dspritesize=7 -DSOUND -odztar.vz dstar.c
79  *
80  *      TIKI1-100
81  *      zcc +cpm -subtype=tiki100 -o dstar.com -Dspritesize=28 dstar.c
82  *
83  *      MSXDOS:
84  *      zcc +msx -Dspritesize=16 -DSOUND -startup=2 dstar.c
85  *
86  *      MSX:
87  *      zcc +msx -Dspritesize=16 -DSOUND -create-app dstar.c
88  *
89  *      MULTI 8:
90  *      zcc +multi8 -Dspritesize=21 -create-app dstar.c
91  *
92  *      NEC PC-8801:
93  *      zcc +pc88 -lgfxpc88 -create-app -DSOUND -Dspritesize=10 dstar.c
94  *      zcc +pc88 -lgfxpc88hr200 -create-app -lm -Dspritemem=102 -DSOUND dstar.c
95  *
96  *      Robotron KC:
97  *      zcc +z9001 -Dspritesize=20 -DSOUND -lgfx9001krt -create-app dstar.c
98  *      zcc +kc -Dspritesize=20 -create-app dstar.c
99  *
100  *      Sharp PC-G850:
101  *      zcc +g800 -clib=g850 -Dspritesize=5 -create-app -DSOUND dstar.c
102  *
103  *      SPC-1000:
104  *      zcc +spc1000 -Dspritesize=16 -create-app dstar.c
105  *
106  *      Commodore 128:
107  *      zcc +c128 -lgfx128hr -create-app -lm -Dspritesize=21 dstar.c
108  *
109  *      ZX81, various HRG flavours (see also the specific target version):
110  *      zcc +zx81 -O3 -clib=mt  -create-app -Dspritesize=15 dstar.c
111  *      zcc +zx81 -O3 -clib=g007  -create-app -Dspritesize=16 dstar.c
112  *      zcc +zx81 -O3 -clib=arx -subtype=arx  -create-app -Dspritesize=16 dstar.c
113  *      zcc +zx81 -O3 -clib=wrx -subtype=wrx  -create-app -Dspritesize=16 dstar.c
114  *
115  *      To get an 80 pixel graphics version of the game (Mattel Aquarius, TRS80, etc):
116  *      zcc +aquarius -Dspritesize=5 -create-app dstar.c
117  *
118  *      Even smaller version of the game:
119  *      zcc +gal -Dspritesize=4 -create-app dstar.c
120  *
121  *      (in the above examples the sprite size can be set to 4,5,6,7,8 or 16
122  *      and sound can optionally be added with some target)
123  *
124  * * * * * * *
125  *
126  *      Enough twaddle, enjoy the game and study the source!
127  *
128  *      d. <djm@jb.man.ac.uk> 1/12/98
129  *
130  * * * * * * *
131  */
132 
133 #include <stdio.h>
134 #include <games.h>
135 #include <stdlib.h>
136 #include <graphics.h>
137 
138 #ifdef SOUND
139 #include <sound.h>
140 #endif
141 #ifdef SOUNDB
142 #include <sound.h>
143 #endif
144 
145 
146 /* #define spritesize 4   -->  minimalistic, 64x36 pixels  */
147 /* #define spritesize 5   -->  very low resolutions, 80x45 pixels  */
148 /* #define spritesize 6   -->  TI mode, 96x54  */
149 /* #define spritesize 7   -->  TI85/86, VZ200  */
150 /* #define spritesize 8   -->  128x72 pixels   */
151 /* #define spritesize 10  -->  160x90 pixels   */
152 /* #define spritesize 14  -->  Medium screen mode 224x126  */
153 /* #define spritesize 16  -->  Big screen mode 256x144  */
154 /* #define spritesize 20  -->  Wide screen mode 320x160 */
155 /* #define spritesize 21  -->  Wide screen mode 512x192 */
156 /* #define spritemem  102  -->  640x200 */
157 /* #define spritesize 28  -->  Extra wide screen mode 1024x256 */
158 
159 
160 /* Single sprite memory usage, including bytes for its size */
161 #if (spritesize == 10)
162   #define spritemem 22
163 #endif
164 #if (spritesize == 14)
165   #define spritemem 30
166 #endif
167 #if (spritesize == 15)|(spritesize == 16)
168   #define spritemem 34
169 #endif
170 #if (spritesize == 20)
171   #define spritemem 62
172   #define xsize 20
173 #endif
174 #if (spritemem == 102)	// 640x200
175   #define spritesize 20
176   #define xsize 40
177 #endif
178 #if (spritesize == 21)
179   #define spritemem 90
180   #define xsize 32
181 #endif
182 #if (spritesize == 28)
183   #define spritemem 226
184   #define xsize 64
185 #endif
186 
187 #ifndef spritemem
188   #define spritemem (spritesize+2)
189 #endif
190 
191 #ifndef spritesize
192 #define spritesize 6
193 #endif
194 
195 
196 #include "dstar.h"
197 
198 
199 #ifdef __TIKI100__
200 #include "tiki100.h"
201 #endif
202 
203 
main()204 void main()
205 {
206 	Level = (STARTLEV-1);
207 	SetupLevel(); /* Display the first level */
208 
209 	/* Loop keyhandler till you finished the game */
210 	while (CheckNotFinished())
211 	  Gamekeys();
212 }
213 
214 
Gamekeys(void)215 void Gamekeys(void)
216 {
217 	char *charptr;
218 
219     /* Set up a pointer to the variable we want to change
220      * (either the box or the ball) */
221 	charptr = PieceIsBall ? &BoxOffset : &BallOffset;
222 
223 	switch(getk())
224 	{
225 		case K_DOWN:
226 		  MovePiece(charptr,0,+1);
227 		  break;
228 		case K_UP:
229 		  MovePiece(charptr,0,-1);
230 		  break;
231 		case K_RIGHT:
232 		  MovePiece(charptr,+1,0);
233 		  break;
234 		case K_LEFT:
235 		  MovePiece(charptr,-1,0);
236 		  break;
237 		case K_SWITCH:
238 		  PieceIsBall^=1;   /* Toggle ball/box */
239 		  #ifdef SOUND
240 		    bit_fx4 (5);
241 		  #endif
242 		  #ifdef SOUNDB
243 			bit_fx6 (6);
244 		  #endif
245 		  while (getk() == K_SWITCH) {}
246 		  break;
247 		case K_EXIT:
248 		  #ifdef SOUNDB
249 		  bit_fx6 (4);
250 		  #endif
251 		  exit(0);
252 		case K_NEXTLEV:    /* Okay this IS cheating... */
253 		  if(++Level==MAXLEVEL)
254 		  { --Level; break; }
255 		  SetupLevel();
256 		  break;
257 		case K_PREVLEV:
258 		  if(--Level==-1)
259 		  { ++Level; break; }
260 		  /* fall thrue */
261 		case K_CLEAR:
262 		  #ifdef SOUND
263 		    bit_fx4 (3);
264 		  #endif
265 		  #ifdef SOUNDB
266 			bit_fx6 (1);
267 		  #endif
268 		  SetupLevel();
269 	}
270 }
271 
272 
273 /* The level is stored 'compressed', taking up 38 bytes a time.
274  *      byte 0 - position of ball
275  *      byte 1 - position of box
276  *      2-37   - Level data
277  *
278  * Level data is stored as two bits per block, so we have to shift our
279  * picked up byte round to get it.
280  */
SetupLevel(void)281 void SetupLevel(void)
282 {
283 	int x;
284 	char *ptr,*ptr2;
285 
286 	/* Fresh level, so start with the ball */
287 	PieceIsBall = FALSE;
288 
289 	ptr2 = Board;                 /* We copy to the Board */
290 	ptr  = levels + (Level * 38); /*  from the Level data */
291 
292     /* First two bytes are the ball and the box position */
293 	BallOffset = *ptr++;
294 	BoxOffset  = *ptr++;
295 
296     /* Decompress Level into the Board */
297 	for (x=0; x!=36; x++)
298 	{
299 		*ptr2++=((*ptr)>>6)&3;
300 		*ptr2++=((*ptr)>>4)&3;
301 		*ptr2++=((*ptr)>>2)&3;
302 		*ptr2++=( *ptr)    &3;
303 		ptr++;
304 	}
305 
306     /* Put the ball and box into their Board position */
307 	*(Board+BallOffset) = BALL;
308 	*(Board+BoxOffset)  = BOX;
309 
310 	DrawBoard(); /* Display the clean Board */
311 
312 #ifdef SOUND
313 	bit_fx4 (1);
314 #endif
315 #ifdef SOUNDB
316 	bit_fx6 (0);
317 #endif
318 }
319 
320 
DrawBoard(void)321 void DrawBoard(void)
322 {
323 	int x,y;
324 	char *ptr;
325 
326 	ptr = Board;
327 
328 #ifdef __TIKI100__
329 	gr_defmod(1);
330 #endif
331 
332 	clg(); /* clear the screen */
333 
334 	for (y=0 ; y!=9 ; y++)
335 	{
336 		for (x=0 ; x!=16 ; x++)
337 		{
338 #ifdef xsize
339 			putsprite(spr_or,(x*xsize),(y*spritesize),sprites + (spritemem * (*ptr++)));
340 #else
341 			putsprite(spr_or,(x*spritesize),(y*spritesize),sprites + (spritemem * (*ptr++)));
342 #endif
343 		}
344 	}
345 }
346 
347 
348 
349 /* Check if a Level is (not) finished:
350  * There are 144 squares in each Level
351  *
352  * Note the use of != instead of < or <=
353  *  - this is faster to execute on the Z80!
354  */
CheckNotFinished(void)355 char CheckNotFinished(void)
356 {
357 	char *ptr;
358 	int i;
359 
360 	ptr = Board;
361 	for(i=1 ; i!=144 ; i++)
362 	{
363 		if(*ptr++ == BUBB) return(TRUE);   /* Are there any bubbles? */
364 	}
365 	if(++Level == MAXLEVEL) return(FALSE); /* All levels done?       */
366 
367 	SetupLevel();                          /* If not => Next Level!  */
368 	return(TRUE);                          /* And keep scanning keys */
369 }
370 
371 
372 /* Check to see if we're running into anything:
373  *  - The box stops for everything (exept empty space [= 0])
374  *  - The ball stops for everything exept a bubble
375  */
TestNextPosIsStop(char nextpos)376 char TestNextPosIsStop(char nextpos)
377 {
378 	if(!PieceIsBall)
379 	  if (nextpos==BUBB) return(FALSE);
380 	return(nextpos);
381 }
382 
383 
MovePiece(char * ptr,char plusx,char plusy)384 void MovePiece(char *ptr, char plusx, char plusy)
385 {
386 	char *locn;
387 	char temp,temp2;
388 	int x,y;
389 
390 	temp  = PieceIsBall + 3;
391 	temp2 = (plusx + (plusy * 16));
392 
393 	while(1) /* loop */
394 	{
395 
396 		locn = *(ptr) + Board;
397 		if(TestNextPosIsStop(*(locn+temp2))) return; /* till edge */
398 
399 		y = (*(ptr) / 16);
400 #ifdef xsize
401 		x = (*(ptr) - (y * 16)) * xsize;
402 #else
403 		x = (*(ptr) - (y * 16)) * spritesize;
404 #endif
405 		y *= spritesize;
406 
407 		if(*(locn+temp2)==BUBB)
408 		{
409 #ifdef xsize
410 			putsprite(spr_xor,x+(plusx*xsize),y+(plusy*spritesize),sprites + (spritemem * BUBB));
411 #else
412 			putsprite(spr_xor,x+(plusx*spritesize),y+(plusy*spritesize),sprites + (spritemem * BUBB));
413 #endif
414 
415 			#ifdef SOUND
416 			bit_fx2 (5);
417 			#endif
418 			#ifdef SOUNDB
419 			bit_fx6 (3);
420 			#endif
421 		}
422 
423 		*(locn+temp2) = *locn;
424 		*locn = 0;
425 
426  		/* remove old */
427 		putsprite(spr_xor,x,y,sprites + (spritemem * temp));
428 		/* put new */
429 #ifdef xsize
430 		putsprite(spr_xor,x+(plusx*xsize),y+(plusy*spritesize),sprites + (spritemem * temp));
431 #else
432 		putsprite(spr_xor,x+(plusx*spritesize),y+(plusy*spritesize),sprites + (spritemem * temp));
433 #endif
434 
435 		#ifdef SOUND
436 		bit_fx2 (2);
437 		#endif
438 		#ifdef SOUNDB
439 		bit_fx6 (7);
440 		#endif
441 
442 		(*ptr) += temp2;
443 	}
444 }
445