1 #include <stdlib.h>
2 #include <sms.h>
3 
4 unsigned char pal1[] = {0x00, 0x01, 0x02, 0x03, 0x10, 0x20, 0x30, 0x2B,
5 				0x14, 0x24, 0x39, 0x0F, 0x00, 0x15, 0x2A, 0x3F};
6 
7 unsigned char pal2[] = {0x00, 0x01, 0x02, 0x03, 0x10, 0x20, 0x30, 0x2B,
8 				0x15, 0x35, 0x1D, 0x3D, 0x00, 0x15, 0x2A, 0x3F};
9 
10 unsigned int bkg_bottom[] = {0x000F, 0x000F, 0x000F, 0x0010, 0x000F, 0x000F, 0x000F, 0x0010,
11                              0x000F, 0x000F, 0x0010, 0x000F, 0x000F, 0x000F, 0x0010, 0x000F,
12                              0x000F, 0x0010, 0x000F, 0x000F, 0x000F, 0x0010, 0x000F, 0x000F,
13                              0x0010, 0x000F, 0x000F, 0x000F, 0x0010, 0x000F, 0x000F, 0x000F,};
14 
15 unsigned int bkg_top1[] = {0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
16                            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
17                            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
18                            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0015,};
19 
20 unsigned int bkg_top2[] = {0x0011, 0x0013, 0x0013, 0x0012, 0x0013, 0x0013, 0x0013, 0x0012,
21                            0x0013, 0x0013, 0x0012, 0x0013, 0x0013, 0x0013, 0x0012, 0x0013,
22                            0x0013, 0x0012, 0x0013, 0x0013, 0x0013, 0x0012, 0x0013, 0x0013,
23                            0x0012, 0x0013, 0x0013, 0x0013, 0x0012, 0x0013, 0x0013, 0x0011,};
24 
25 unsigned int lplayer_icons[] = {0x017, 0x019};
26 unsigned int rplayer_icons[] = {0x018, 0x01A, 0x01B, 0x01C};
27 unsigned int paddle_icons[] = {0x01D, 0x01E, 0x01F};
28 unsigned int spin_icons[] = {0x021, 0x020};
29 
30 extern unsigned char pong_graphics[];
31 
32 typedef struct {
33 	int x;
34 	int y;
35 	int size;
36 	int height;
37 	int controlled_by;
38 	int base_spr;
39 	int base_tile;
40 	int spd_x;
41 	int spd_y;
42 	int top_spd;
43 	int accel;
44 	int friction;
45 } paddle_rec;
46 
47 typedef struct {
48 	int x;
49 	int y;
50 	int base_spr;
51 	int base_tile;
52 	int spd_x;
53 	int spd_y;
54 	int base_spd;
55 	int top_spd;
56 	int spin;
57 	int spin_friction;
58 } ball_rec;
59 
60 typedef struct {
61 	int top;
62 	int bottom;
63 	int left;
64 	int right;
65 	int	score0;
66 	int score1;
67 	int left_player;
68 	int right_player;
69 	int paddle_mode;
70 	int actual_paddle_count;
71 	int spin_on;
72 } playfield_rec;
73 
sig_shr(int number,int shift)74 int sig_shr(int number, int shift) {
75 	if (number < 0) {
76 		return -((-number) >> shift);
77 	} else {
78 		return number >> shift;
79 	}
80 }
81 
wait_joy1_release()82 int wait_joy1_release() {
83 	while (read_joypad1()) {
84 		wait_vblank_noint();
85 	}
86 }
87 
draw_score_digits(int x,int y,int n)88 void draw_score_digits(int x, int y, int n) {
89 	unsigned int buffer[2];
90 	buffer[0] = (n / 10) + 1;
91 	buffer[1] = (n % 10) + 1;
92 	set_bkg_map(buffer, x, y, 2, 1);
93 }
94 
draw_option_panel(int x,int y,playfield_rec * playfield)95 void draw_option_panel(int x, int y, playfield_rec *playfield) {
96 	unsigned int buffer[4];
97 	unsigned int *p;
98 	p = buffer;
99 	*p = lplayer_icons[playfield->left_player];
100 	p++;
101 	*p = rplayer_icons[playfield->right_player];
102 	p++;
103 	*p = paddle_icons[playfield->paddle_mode];
104 	p++;
105 	*p = spin_icons[playfield->spin_on];
106 	set_bkg_map(buffer, x, y, 4, 1);
107 }
108 
draw_score(playfield_rec * playfield)109 void draw_score(playfield_rec *playfield) {
110 	draw_score_digits(4, 0, playfield->score0);
111 	draw_score_digits(26, 0, playfield->score1);
112 	draw_option_panel(14, 0, playfield);
113 }
114 
draw_bkg()115 void draw_bkg() {
116 	set_bkg_map(bkg_top1, 0, 0, 32, 1);
117 	set_bkg_map(bkg_top2, 0, 1, 32, 1);
118 	set_bkg_map(bkg_bottom, 0, 23, 32, 1);
119 }
120 
draw_paddle(paddle_rec * paddle)121 void draw_paddle(paddle_rec *paddle) {
122 	int x = (paddle->x >> 4);
123 	int y = (paddle->y >> 4);
124 	int spr = paddle->base_spr;
125 	int tile = paddle->base_tile;
126 	int i;
127 
128 	set_sprite(spr, x, y, tile);
129 	y += 8; spr++; tile++;
130 	for (i = paddle->size; i; i--, y += 8, spr++) {
131 		set_sprite(spr, x, y, tile);
132 	}
133 	tile++;
134 	set_sprite(spr, x, y, tile);
135 }
136 
draw_paddles(paddle_rec * paddles,int count)137 void draw_paddles(paddle_rec *paddles, int count) {
138 	for (; count; count--, paddles++) {
139 		draw_paddle(paddles);
140 	}
141 }
142 
handle_paddle_joypad(int joy,paddle_rec * paddle)143 void handle_paddle_joypad(int joy, paddle_rec *paddle) {
144 	if (joy & JOY_UP) {
145 		paddle->spd_y -= paddle->accel;
146 	}
147 	if (joy & JOY_DOWN) {
148 		paddle->spd_y += paddle->accel;
149 	}
150 }
151 
handle_paddle_joypad_lr(int joy,paddle_rec * paddle)152 void handle_paddle_joypad_lr(int joy, paddle_rec *paddle) {
153 	if (joy & JOY_LEFT) {
154 		paddle->spd_y -= paddle->accel;
155 	}
156 	if (joy & JOY_RIGHT) {
157 		paddle->spd_y += paddle->accel;
158 	}
159 }
160 
handle_paddle_ai(paddle_rec * paddle,ball_rec * ball)161 void handle_paddle_ai(paddle_rec *paddle, ball_rec *ball) {
162 	int h = paddle->height >> 1;
163 	int	y = paddle->y + h;
164 
165 	if (ball->spd_x < 0) {
166 		return;
167 	}
168 
169 	if (y > ball->y) {
170 		paddle->spd_y -= paddle->accel;
171 	} else if (y < ball->y) {
172 		paddle->spd_y += paddle->accel;
173 	}
174 }
175 
handle_paddle_physics(paddle_rec * paddle,playfield_rec * playfield)176 void handle_paddle_physics(paddle_rec *paddle, playfield_rec *playfield) {
177 	paddle->x += paddle->spd_x;
178 	paddle->y += paddle->spd_y;
179 
180 	if (paddle->spd_y < -paddle->top_spd) {
181 		paddle->spd_y = -paddle->top_spd;
182 	} else if (paddle->spd_y > paddle->top_spd) {
183 		paddle->spd_y = paddle->top_spd;
184 	}
185 
186 /*	if (paddle->x < playfield->left) {
187 		paddle->x = playfield->left;
188 		paddle->spd_x = -paddle->spd_x;
189 	}
190 	if (paddle->x > playfield->right-8) {
191 		paddle->x = playfield->right-8;
192 		paddle->spd_x = -paddle->spd_x;
193 	} */
194 
195 	if (paddle->y < playfield->top) {
196 		paddle->y = playfield->top;
197 		paddle->spd_y = -paddle->spd_y;
198 	}
199 	if (paddle->y > playfield->bottom-paddle->height) {
200 		paddle->y = playfield->bottom-paddle->height;
201 		paddle->spd_y = -paddle->spd_y;
202 	}
203 
204 /*	if (paddle->spd_x > 0) {
205 		if (paddle->spd_x > paddle->friction) {
206 			paddle->spd_x -= paddle->friction;
207 		} else {
208 			paddle->spd_x = 0;
209 		}
210 	} else {
211 		if (paddle->spd_x < -paddle->friction) {
212 			paddle->spd_x += paddle->friction;
213 		} else {
214 			paddle->spd_x = 0;
215 		}
216 	}*/
217 
218 	if (paddle->spd_y > 0) {
219 		if (paddle->spd_y > paddle->friction) {
220 			paddle->spd_y -= paddle->friction;
221 		} else {
222 			paddle->spd_y = 0;
223 		}
224 	} else {
225 		if (paddle->spd_y < -paddle->friction) {
226 			paddle->spd_y += paddle->friction;
227 		} else {
228 			paddle->spd_y = 0;
229 		}
230 	}
231 }
232 
draw_ball(ball_rec * ball)233 void draw_ball(ball_rec *ball) {
234 	int x = (ball->x >> 4);
235 	int y = (ball->y >> 4);
236 	int spr = ball->base_spr;
237 	int tile = ball->base_tile;
238 
239 	set_sprite(spr, x, y, tile);
240 }
241 
deploy_ball(ball_rec * ball)242 void deploy_ball(ball_rec *ball) {
243 	ball->x = 128 << 4;
244 	ball->y = 32 << 4;
245 	ball->base_spr = 12;
246 	ball->base_tile = 14;
247 	if (rand() & 0x01) {
248 		ball->spd_x = 0x18;
249 	} else {
250 		ball->spd_x = -0x18;
251 	}
252 	ball->spd_y = (rand() & 0x3F) - 0x20;
253 	ball->base_spd = 0x20;
254 	ball->top_spd = 0x60;
255 	ball->spin = 0;
256 	ball->spin_friction = 0x01;
257 }
258 
handle_ball_physics(ball_rec * ball,playfield_rec * playfield,paddle_rec paddles[],int paddle_count)259 void handle_ball_physics(ball_rec *ball, playfield_rec *playfield, paddle_rec paddles[], int paddle_count) {
260 	int i;
261 	int collided;
262 	paddle_rec *paddle;
263 
264 	ball->x += ball->spd_x;
265 	ball->y += ball->spd_y;
266 
267 	ball->spd_y -= sig_shr(ball->spin, 3);
268 	if (ball->spin > 0) {
269 		if (ball->spin > ball->spin_friction) {
270 			ball->spin -= ball->spin_friction;
271 		} else {
272 			ball->spin = 0;
273 		}
274 	} else {
275 		if (ball->spin < -ball->spin_friction) {
276 			ball->spin += ball->spin_friction;
277 		} else {
278 			ball->spin = 0;
279 		}
280 	}
281 
282 	if (ball->spd_x < 0) {
283 		if (ball->spd_x < -ball->top_spd) {
284 			ball->spd_x = -ball->top_spd;
285 		}
286 	} else {
287 		if (ball->spd_x > ball->top_spd) {
288 			ball->spd_x = ball->top_spd;
289 		}
290 	}
291 
292 	if (ball->x < playfield->left) {
293 		ball->x = playfield->left;
294 		ball->spd_x = -ball->spd_x;
295 		playfield->score0++;
296 		deploy_ball(ball);
297 		draw_score(playfield);
298 	}
299 	if (ball->x > playfield->right-8) {
300 		ball->x = playfield->right-8;
301 		ball->spd_x = -ball->spd_x;
302 		playfield->score1++;
303 		deploy_ball(ball);
304 		draw_score(playfield);
305 	}
306 
307 	if (ball->spd_y < 0) {
308 		if (ball->spd_y < -ball->top_spd) {
309 			ball->spd_y = -ball->top_spd;
310 		}
311 	} else {
312 		if (ball->spd_y > ball->top_spd) {
313 			ball->spd_y = ball->top_spd;
314 		}
315 	}
316 
317 	if (ball->y < playfield->top) {
318 		ball->y = playfield->top;
319 		ball->spd_y = -ball->spd_y;
320 	}
321 	if (ball->y > playfield->bottom-0x80) {
322 		ball->y = playfield->bottom-0x80;
323 		ball->spd_y = -ball->spd_y;
324 	}
325 
326 	for (i = paddle_count, paddle = paddles; i; i--, paddle++) {
327 		if ((ball->y > paddle->y - 0x80) && (ball->y < paddle->y + paddle->height)) {
328 			collided = 0;
329 			if (ball->spd_x < 0) {
330 				if ((ball->x < paddle->x + 0x80) && (ball->x > paddle->x)) {
331 					ball->x = paddle->x + 0x80;
332 					ball->spd_x = -ball->spd_x;
333 					ball->spd_x += 0x02;
334 					ball->spin = paddle->spd_y/* + sig_shr(paddle->spd_y, 1)*/;
335 					collided = 1;
336 				}
337 			} else {
338 				if ((ball->x < paddle->x) && (ball->x > paddle->x - 0x80)) {
339 					ball->x = paddle->x - 0x80;
340 					ball->spd_x = -ball->spd_x;
341 					ball->spd_x -= 0x02;
342 					ball->spin = paddle->spd_y/* + sig_shr(paddle->spd_y, 1)*/;
343 					collided = 1;
344 				}
345 			}
346 			if (collided) {
347 				if (ball->y < paddle->y) {
348 					ball->spd_y -= 0x60;
349 				} else if (ball->y > paddle->y + paddle->height - 0x80) {
350 					ball->spd_y += 0x60;
351 				}
352 
353 				if (!playfield->spin_on) {
354 					ball->spin = 0;
355 				}
356 			}
357 		}
358 	}
359 }
360 
setup_paddles(paddle_rec * paddles,playfield_rec * playfield)361 void setup_paddles(paddle_rec *paddles, playfield_rec *playfield) {
362 	paddle_rec *paddle;
363 	int x, xinc;
364 	int i;
365 	int half_paddle_count;
366 	int base_spr = 0;
367 	int base_tile = 11;
368 	int paddle_size = 2;
369 	int max_speed = 0x60;
370 	int controlled_by = 0;
371 
372 	playfield->actual_paddle_count = 2;
373 	if (playfield->paddle_mode == 1) {
374 		playfield->actual_paddle_count = 4;
375 	}
376 	if (playfield->left_player == 1) {
377 		playfield->actual_paddle_count <<= 1;
378 	}
379 	half_paddle_count = playfield->actual_paddle_count >> 1;
380 
381 	if (playfield->paddle_mode == 2) {
382 		paddle_size = 3;
383 	}
384 
385 	for (i = 0, paddle = paddles; i != playfield->actual_paddle_count; i++, paddle++) {
386 		paddle->y = 80 << 4;
387 		paddle->size = paddle_size;
388 		paddle->height = (paddle->size + 2) << 7;
389 		paddle->base_spr = base_spr;
390 		paddle->base_tile = base_tile;
391 		paddle->spd_x = 0;
392 		paddle->spd_y = 0;
393 		paddle->top_spd = max_speed;
394 		paddle->accel = 0x0E;
395 		paddle->friction = 0x06;
396 
397 		base_spr += paddle_size+2;
398 	}
399 
400 	xinc = 32;
401 	if (half_paddle_count > 2) {
402 		xinc = 16;
403 	}
404 	xinc <<= 4;
405 
406 	x = 8 << 4;
407 	controlled_by = 0;
408 	for (i = 0, paddle = paddles; i != half_paddle_count; i++, paddle++) {
409 		paddle->x = x;
410 		paddle->controlled_by = controlled_by;
411 
412 		x += xinc;
413 		if (playfield->left_player == 1) {
414 			controlled_by++;
415 		} else {
416 			controlled_by = (controlled_by + 2) & 0x03;
417 		}
418 	}
419 
420 	controlled_by = 4;
421 	switch (playfield->right_player) {
422 		case 0:
423 			controlled_by = 1;
424 		break;
425 
426 		case 1:
427 			max_speed = 0x40;
428 		break;
429 
430 		case 2:
431 			max_speed = 0x80;
432 		break;
433 	}
434 
435 	x = 240 << 4;
436 	for (i = 0; i != half_paddle_count; i++, paddle++) {
437 		paddle->x = x;
438 		paddle->controlled_by = controlled_by;
439 		paddle->top_spd = max_speed;
440 
441 		x -= xinc;
442 		if (playfield->left_player == 0) {
443 			controlled_by = (controlled_by + 2) & 0x03;
444 		}
445 	}
446 }
447 
select_options(paddle_rec * paddles,playfield_rec * playfield)448 void select_options(paddle_rec *paddles, playfield_rec *playfield) {
449 	int done;
450 	int joy1;
451 	int incr, lim;
452 	int col = 0;
453 	int blink = 0;
454 
455 	done = 0;
456 	while(!done) {
457 		joy1 = read_joypad1();
458 		incr = 0;
459 		if (joy1 & (JOY_FIREA | JOY_FIREB)) {
460 			done = 1;
461 		} else if (joy1 & JOY_LEFT) {
462 			col--;
463 		} else if (joy1 & JOY_RIGHT) {
464 			col++;
465 		} else if (joy1 & JOY_UP) {
466 			incr = 1;
467 		} else if (joy1 & JOY_DOWN) {
468 			incr = -1;
469 		}
470 
471 		if (incr != 0) {
472 			switch (col) {
473 				case 0:
474 					playfield->left_player += incr;
475 					playfield->left_player &= 0x01;
476 				break;
477 
478 				case 1:
479 					playfield->right_player += incr;
480 					playfield->right_player &= 0x03;
481 				break;
482 
483 				case 2:
484 					playfield->paddle_mode += incr;
485 					if (playfield->paddle_mode < 0) {
486 						playfield->paddle_mode = 2;
487 					} else if (playfield->paddle_mode > 2) {
488 						playfield->paddle_mode = 0;
489 					}
490 				break;
491 
492 				case 3:
493 					playfield->spin_on += incr;
494 					playfield->spin_on &= 0x01;
495 				break;
496 			}
497 			draw_score(playfield);
498 			setup_paddles(paddles, playfield);
499 			draw_paddles(paddles, playfield->actual_paddle_count);
500 		}
501 
502 		col &= 0x03;
503 
504 		wait_vblank_noint();
505 		if (blink & 0x10) {
506 			set_sprite(63, 0, -16, 1);
507 		} else {
508 			set_sprite(63, (col + 14) << 3, 0, 0x16);
509 		}
510 
511 		if (joy1) {
512 			wait_joy1_release();
513 		}
514 
515 		blink++;
516 	}
517 	set_sprite(63, 0, -16, 1);
518 }
519 
main()520 void main() {
521     int joy1, joy2;
522     int i;
523     playfield_rec playfield;
524     paddle_rec paddles[8], *paddle;
525     ball_rec ball;
526 
527     playfield.top = 16 << 4;
528     playfield.bottom = 184 << 4;
529     playfield.left = 0 << 4;
530     playfield.right = 255 << 4;
531     playfield.score0 = 0;
532     playfield.score1 = 0;
533     playfield.left_player = 0;
534     playfield.right_player = 2;
535     playfield.paddle_mode = 0;
536     playfield.actual_paddle_count = 1;
537     playfield.spin_on = 1;
538 
539     setup_paddles(paddles, &playfield);
540 
541     clear_vram();
542     load_tiles(pong_graphics, 1, 64, 4);
543     load_palette(pal1, 0, 16);
544     load_palette(pal2, 16, 16);
545 
546     for (i = 0; i != 64; i++) {
547         set_sprite(i, 0, -16, 0);
548     }
549 
550     set_vdp_reg(VDP_REG_FLAGS1, VDP_REG_FLAGS1_BIT7 | VDP_REG_FLAGS1_SCREEN);
551 	while (1) {
552 		draw_bkg();
553 		draw_score(&playfield);
554 		draw_paddles(paddles, playfield.actual_paddle_count);
555 
556 		select_options(paddles, &playfield);
557 
558 		deploy_ball(&ball);
559 		for (;;) {
560 /*			joy1 = read_joypad1();
561 			handle_paddle_joypad(joy1, paddle);
562 			handle_paddle_physics(paddle, &playfield);
563 
564 			paddle++;
565 			joy2 = read_joypad2();
566 	//		handle_paddle_joypad(joy2, paddle);
567 			handle_paddle_ai(paddle, &ball);
568 			handle_paddle_physics(paddle, &playfield);*/
569 			joy1 = read_joypad1();
570 			joy2 = read_joypad2();
571 
572 			for (i = 0, paddle = paddles; i != playfield.actual_paddle_count; i++, paddle++) {
573 				switch (paddle->controlled_by) {
574 					case 0:
575 						handle_paddle_joypad(joy1, paddle);
576 					break;
577 
578 					case 1:
579 						handle_paddle_joypad(joy2, paddle);
580 					break;
581 
582 					case 2:
583 						handle_paddle_joypad_lr(joy1, paddle);
584 					break;
585 
586 					case 3:
587 						handle_paddle_joypad_lr(joy2, paddle);
588 					break;
589 
590 					default:
591 						handle_paddle_ai(paddle, &ball);
592 				}
593 			}
594 
595 			handle_ball_physics(&ball, &playfield, paddles, playfield.actual_paddle_count);
596 
597 			for (i = 0, paddle = paddles; i != playfield.actual_paddle_count; i++, paddle++) {
598 				handle_paddle_physics(paddle, &playfield);
599 			}
600 
601 			wait_vblank_noint();
602 			draw_paddles(paddles, playfield.actual_paddle_count);
603 /*			for (i = 0, paddle = paddles; i != playfield.actual_paddle_count; i++, paddle++) {
604 				draw_paddle(paddle);
605 			}*/
606 			draw_ball(&ball);
607 		}
608 	}
609 }
610