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