1 /* pong, Copyright (c) 2003 Jeremy English <jenglish@myself.com>
4 * Modified by Brian Sawicki <sawicki@imsa.edu> to fix a small bug.
5 * Before this fix after a certain point the paddles would be too
6 * small for the program to effectively hit the ball. The score would
7 * then skyrocket as the paddles missed most every time. Added a max
8 * so that once a paddle gets 10 the entire game restarts. Special
9 * thanks to Scott Zager for some help on this.
11 * Modified by Trevor Blackwell <tlb@tlb.org> to use analogtv.[ch] display.
12 * Also added gradual acceleration of the ball, shrinking of paddles, and
15 * Permission to use, copy, modify, distribute, and sell this software and its
16 * documentation for any purpose is hereby granted without fee, provided that
17 * the above copyright notice appear in all copies and that both that
18 * copyright notice and this permission notice appear in supporting
19 * documentation. No representations are made about the suitability of this
20 * software for any purpose. It is provided "as is" without express or
25 * TLB sez: I haven't actually seen a pong game since I was about 9. Can
26 * someone who has one make this look more realistic? Issues:
28 * - the font for scores is wrong. For example '0' was square.
29 * - was there some kind of screen display when someone won?
30 * - did the ball move smoothly, or was the X or Y position quantized?
32 * It could also use better player logic: moving the paddle even when the ball
33 * is going away, and making mistakes instead of just not keeping up with the
36 * There is some info at http://www.mameworld.net/discrete/Atari/Atari.htm#Pong
38 * It says that the original Pong game did not have a microprocessor, or even a
39 * custom integrated circuit. It was all discrete logic.
43 #include "screenhack.h"
45 /* #define OUTPUT_POS */
47 typedef struct _paddle {
57 typedef struct _ball {
69 static int paddle_rate;
72 static analogtv_input *inp;
73 static analogtv_reception reception;
75 static int paddle_ntsc[4];
76 static int field_ntsc[4];
77 static int ball_ntsc[4];
78 static int score_ntsc[4];
79 static int net_ntsc[4];
81 analogtv_font score_font;
84 PONG_W = ANALOGTV_VIS_LEN,
85 PONG_H = ANALOGTV_VISLINES,
92 if ( (ball.y <= PONG_TMARG) ||
93 (ball.y+ball.h >= PONG_H) )
100 /* Starts a Whole New Game*/
110 paddle_rate = m_unit-1;
114 l_paddle.h = PONG_H/4;
115 r_paddle.h = PONG_H/4;
131 paddle_rate = m_unit-1;
133 if (l_paddle.h > 10) l_paddle.h= l_paddle.h*19/20;
134 if (r_paddle.h > 10) r_paddle.h= r_paddle.h*19/20;
140 if ( ball.x + ball.w >= r_paddle.x &&
141 bx > 0 ) /*we are traveling to the right*/
143 if ((ball.y + ball.h > r_paddle.y) &&
144 (ball.y < r_paddle.y + r_paddle.h))
155 if (r_paddle.score >=10)
162 if (ball.x <= l_paddle.x + l_paddle.w &&
163 bx < 0 ) /*we are traveling to the left*/
165 if ( ball.y + ball.h > l_paddle.y &&
166 ball.y < l_paddle.y + l_paddle.h)
177 if (l_paddle.score >= 10)
186 init_pong (Display *dpy, Window window)
188 tv=analogtv_allocate(dpy, window);
189 analogtv_set_defaults(tv, "");
190 tv->event_handler = screenhack_handle_event;
192 analogtv_make_font(dpy, window, &score_font,
195 /* If you think we haven't learned anything since the early 70s,
196 look at this font for a while */
197 analogtv_font_set_char(&score_font, '0',
204 analogtv_font_set_char(&score_font, '1',
211 analogtv_font_set_char(&score_font, '2',
218 analogtv_font_set_char(&score_font, '3',
225 analogtv_font_set_char(&score_font, '4',
232 analogtv_font_set_char(&score_font, '5',
239 analogtv_font_set_char(&score_font, '6',
246 analogtv_font_set_char(&score_font, '7',
253 analogtv_font_set_char(&score_font, '8',
260 analogtv_font_set_char(&score_font, '9',
268 score_font.y_mult *= 2;
269 score_font.x_mult *= 2;
272 printf("screen(%d,%d,%d,%d)\n",0,0,PONG_W,PONG_H);
275 inp=analogtv_input_allocate();
276 analogtv_setup_sync(inp, 0, 0);
278 reception.input = inp;
279 reception.level = 2.0;
283 reception.multipath = frand(1.0);
286 reception.multipath=0.0;
295 l_paddle.h = PONG_H/4;
299 r_paddle.x = PONG_W - 8 - r_paddle.w;
307 m_unit = get_integer_resource ("speed", "Integer");
311 analogtv_lcp_to_ntsc(ANALOGTV_BLACK_LEVEL, 0.0, 0.0, field_ntsc);
312 analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, ball_ntsc);
313 analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, paddle_ntsc);
314 analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, score_ntsc);
315 analogtv_lcp_to_ntsc(100.0, 0.0, 0.0, net_ntsc);
317 analogtv_draw_solid(inp,
318 ANALOGTV_VIS_START, ANALOGTV_VIS_END,
319 ANALOGTV_TOP, ANALOGTV_BOT,
328 targ = ball.y + by * (r_paddle.x-ball.x) / bx;
331 targ = ball.y - by * (ball.x - l_paddle.x - l_paddle.w) / bx;
336 if (targ > PONG_H) targ=PONG_H;
337 if (targ < 0) targ=0;
339 if (targ < p->y && !p->lock)
343 else if (targ > (p->y + p->h) && !p->lock)
349 int move=targ - (p->y + p->h/2);
350 if (move>paddle_rate) move=paddle_rate;
351 if (move<-paddle_rate) move=-paddle_rate;
358 p_hit_top_bottom(Paddle *p)
360 if(p->y <= PONG_TMARG)
364 if((p->y + p->h) >= PONG_H)
366 p->y = PONG_H - p->h;
371 XFillRectangle (dpy, window, gc, p->x, p->y, p->w, p->h);
374 XClearArea(dpy,window, p->x, p->y + p->h,
375 p->w, (old_v + p->h) - (p->y + p->h), 0);
377 else if (old_v < p->y)
379 XClearArea(dpy,window, p->x, old_v, p->w, p->y - old_v, 0);
383 paint_paddle(analogtv_input *inp, Paddle *p)
385 analogtv_draw_solid(inp,
386 ANALOGTV_VIS_START + p->x, ANALOGTV_VIS_START + p->x + p->w,
387 ANALOGTV_TOP, ANALOGTV_BOT,
390 analogtv_draw_solid(inp,
391 ANALOGTV_VIS_START + p->x, ANALOGTV_VIS_START + p->x + p->w,
392 ANALOGTV_TOP + p->y, ANALOGTV_TOP + p->y + p->h,
397 XClearArea(dpy,window, old_ballx, old_bally, ball.d, ball.d, 0);
398 XFillRectangle (dpy, window, gc, ball.x, ball.y, ball.d, ball.d);
399 XFillRectangle (dpy, window, gc, xgwa.width / 2, 0, ball.d, xgwa.height);
403 erase_ball(analogtv_input *inp)
405 analogtv_draw_solid(inp,
406 ANALOGTV_VIS_START + ball.x, ANALOGTV_VIS_START + ball.x + ball.w,
407 ANALOGTV_TOP + ball.y, ANALOGTV_TOP + ball.y + ball.h,
412 paint_ball(analogtv_input *inp)
414 analogtv_draw_solid(inp,
415 ANALOGTV_VIS_START + ball.x, ANALOGTV_VIS_START + ball.x + ball.w,
416 ANALOGTV_TOP + ball.y, ANALOGTV_TOP + ball.y + ball.h,
421 paint_score(analogtv_input *inp)
425 analogtv_draw_solid(inp,
426 ANALOGTV_VIS_START, ANALOGTV_VIS_END,
427 ANALOGTV_TOP, ANALOGTV_TOP + 10+ score_font.char_h * score_font.y_mult,
430 sprintf(buf, "%d",r_paddle.score%256);
431 analogtv_draw_string(inp, &score_font, buf,
432 ANALOGTV_VIS_START + 130, ANALOGTV_TOP + 8,
435 sprintf(buf, "%d",l_paddle.score%256);
436 analogtv_draw_string(inp, &score_font, buf,
437 ANALOGTV_VIS_END - 200, ANALOGTV_TOP + 8,
443 paint_net(analogtv_input *inp)
447 x=(ANALOGTV_VIS_START + ANALOGTV_VIS_END)/2;
449 for (y=ANALOGTV_TOP; y<ANALOGTV_BOT; y+=6) {
450 analogtv_draw_solid(inp, x-2, x+2, y, y+3,
452 analogtv_draw_solid(inp, x-2, x+2, y+3, y+6,
466 if ((random()%40)==0) {
467 if (bx>0) bx++; else bx--;
479 p_hit_top_bottom(&r_paddle);
480 p_hit_top_bottom(&l_paddle);
486 printf("(%d,%d,%d,%d)\n",ball.x,ball.y,ball.w,ball.h);
494 paint_paddle(inp, &r_paddle);
495 paint_paddle(inp, &l_paddle);
497 if (1) paint_ball(inp);
499 analogtv_handle_events(tv);
501 analogtv_init_signal(tv, 0.04);
502 analogtv_reception_update(&reception);
503 analogtv_add_signal(tv, &reception);
508 char *progclass = "pong";
510 char *defaults [] = {
511 ".background: black",
512 ".foreground: white",
519 XrmOptionDescRec options [] = {
520 { "-percent", ".percent", XrmoptionSepArg, 0 },
521 { "-speed", ".speed", XrmoptionSepArg, 0 },
527 screenhack (Display *dpy, Window window)
529 init_pong (dpy, window);