home *** CD-ROM | disk | FTP | other *** search
- 18-Jun-88 14:52:30-MDT,16523;000000000001
- Return-Path: <u-lchoqu%sunset@cs.utah.edu>
- Received: from cs.utah.edu by SIMTEL20.ARPA with TCP; Sat, 18 Jun 88 14:52:07 MDT
- Received: by cs.utah.edu (5.54/utah-2.0-cs)
- id AA22823; Sat, 18 Jun 88 14:52:05 MDT
- Received: by sunset.utah.edu (5.54/utah-2.0-leaf)
- id AA24896; Sat, 18 Jun 88 14:52:01 MDT
- Date: Sat, 18 Jun 88 14:52:01 MDT
- From: u-lchoqu%sunset@cs.utah.edu (Lee Choquette)
- Message-Id: <8806182052.AA24896@sunset.utah.edu>
- To: rthum@simtel20.arpa
- Subject: pong.c
-
- /* pong.c
- The classic game of pong in Megamax C for the Mac.
- Thanks to MacTutor (Vol 1, No. 5 April 1985 page 39) for
- animation techniques. If you are reading this and don't
- subscribe to MacTutor, consider it. No resource file is
- needed. This program, source and object, is in the
- public domain and not for sale.
-
- Author : David L. O'Connor, 370 Eden St. Buffalo, N.Y.
- 14220. (716) 828-0898. CIS - 70265,1172
- Date : July, 1985 Version 2
- */
-
- #include <mem.h>
- #include <qd.h>
- #include <qdvars.h>
- #include <event.h>
- #include <toolbox.h>
- #include <res.h>
- #include <win.h>
- #include <menu.h>
- #include <stdio.h>
- #include <sound.h>
-
- /* the game directions */
- #define STOPPED 0
- #define UP 1
- #define DOWN 2
- #define LEFT 3
- #define RIGHT 4
- #define UP_LEFT 5
- #define UP_RIGHT 6
- #define DOWN_LEFT 7
- #define DOWN_RIGHT 8
-
- /* paddle + ball dimensions */
- #define PADWIDTH 10
- #define PADLENGTH 45
- #define PADINSET 10
- #define BALLWIDTH 9
- #define BALLLENGTH 9
-
- #define BALLSPEED 7
- #define PADDLESPEED 9
- #define HIGHSCORE 21
-
- /* the menu ids */
- #define appleid 128
- #define fileid 129
- #define editid 130
- #define skillid 131
- #define soundid 132
-
- /* from the MAC's standard pattern list */
- #define PAD_PAT ((*pat_handle)->pat_list[6])
- #define WALL_PAT ((*pat_handle)->pat_list[4])
-
- typedef struct{
- int pat_cnt;
- pattern pat_list[38];
- } sys_patterns;
-
- typedef struct {
- rect r;
- int dir;
- int speed;
- int score;
- } paddle;
-
- typedef struct {
- rgnhandle rgn;
- rgnhandle oldrgn;
- rgnhandle unrgn;
- int dir;
- int speed;
- int on;
- } target;
-
- typedef struct {
- int mode;
- tone triplet[1];
- } bleep_tag;
-
- typedef struct {
- int mode;
- tone triplet[2];
- } blat_tag;
-
- static bleep_tag bleep_buf;
- static blat_tag blat_buf;
- static paddle l_paddle, r_paddle;
- static target ball;
- static sys_patterns **pat_handle;
- static windowptr gamewindow, which_window;
- static windowrecord winstorage;
- static rect r, dragrect, top_wall, bottom_wall;
- static eventrecord gameevent;
- static menuhandle gamemenu[5];
- static char menutitle[1];
- static int skill_level, done, paused, last_won, volleys, sound_on;
- static char title[] = {
- ' ',' ',' ',' ',' ',' ',' ',' ',
- 'L','e','f','t',' ',' ','0','0',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- 'M','A','C','_','P','o','n','g',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- 'R','i','g','h','t',' ','0','0',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- '\0'};
-
- main()
- {
- setup();
- while (! done){
- handle_events();
- play_pong();
- }
- flushevents(everyevent, 0);
- stopsound();
- exittoshell();
- }
-
- setup()
- {
- done = 0;
- skill_level = 2;
- sound_on = 1;
- last_won = RIGHT;
- initgraf(&theport);
- initfonts();
- initwindows();
- teinit();
- initdialogs(0);
- initcursor();
- initsounds();
- pat_handle = (sys_patterns**) getresource("PAT#", 0);
- flushevents(everyevent, 0);
- setrect(&r, 4, 40, 508, 338);
- setrect(&dragrect, 4, 24, r.a.right - 4, r.a.bottom - 4);
- gamewindow = newwindow(&winstorage, &r, title, 1, rdocproc, -1L, 0, 0L);
- setport(gamewindow);
- build_menus();
- showcursor();
- create_l_paddle();
- create_r_paddle();
- create_walls();
- create_ball();
- init_game();
- }
-
- /* pretty much straight from SAMP in I.M. */
- handle_events()
- {
- systemtask();
- if (getnextevent(everyevent, &gameevent)){
- switch (gameevent.what){
- case mousedown :
- switch (findwindow(&gameevent.where, &which_window)){
- case inmenubar :
- docommand(menuselect(&gameevent.where));
- break;
- case insyswindow :
- systemclick(&gameevent, which_window);
- break;
- case indrag :
- dragwindow(which_window, &gameevent.where, &dragrect);
- break;
- case incontent :
- if (which_window != frontwindow())
- selectwindow(which_window);
- break;
- }
- break;
- case activateevt :
- if (bitand(gameevent.modifiers, windowact))
- disable_edit_menu();
- else
- enable_edit_menu();
- break;
- case updateevt :
- setport(gamewindow);
- beginupdate(gamewindow);
- fillrect(&l_paddle.r, PAD_PAT);
- fillrect(&r_paddle.r, PAD_PAT);
- fillrect(&top_wall, WALL_PAT);
- fillrect(&bottom_wall, WALL_PAT);
- if (ball.on)
- paintrgn(ball.rgn);
- endupdate(gamewindow);
- break;
- }
- }
- }
-
- play_pong()
- {
- if ( (! paused) && (l_paddle.score < HIGHSCORE && r_paddle.score < HIGHSCORE)){
- if (! ball.on)
- serve_ball();
- check_status();
- move_left_paddle();
- move_right_paddle();
- move_ball();
- }
- }
-
- initsounds(){
- bleep_buf.mode = swmode;
- bleep_buf.triplet[0].count = 1000;
- bleep_buf.triplet[0].amplitude = 255;
- bleep_buf.triplet[0].duration = 5;
- blat_buf.mode = swmode;
- blat_buf.triplet[0].count = 1000;
- blat_buf.triplet[0].amplitude = 255;
- blat_buf.triplet[0].duration = 5;
- blat_buf.triplet[1].count = 3000;
- blat_buf.triplet[1].amplitude = 255;
- blat_buf.triplet[1].duration = 10;
- }
-
- build_menus()
- {
- register int i;
-
- initmenus();
- menutitle[0] = applesymbol;
- gamemenu[0] = newmenu(appleid, menutitle);
- gamemenu[1] = newmenu(fileid, "File");
- gamemenu[2] = newmenu(editid, "Edit");
- gamemenu[3] = newmenu(skillid, "Skill");
- gamemenu[4] = newmenu(soundid, "Sound");
- addresmenu(gamemenu[0],"DRVR");
- appendmenu(gamemenu[1],"Pause;Restart;Quit");
- appendmenu(gamemenu[2],"(Undo;(-;(Cut;(Copy;(Paste;(Clear");
- appendmenu(gamemenu[3],"Beginner;Novice;Normal;Expert");
- appendmenu(gamemenu[4],"Sound Off");
- for(i = 0; i < 5; i++)
- insertmenu(gamemenu[i], 0);
- checkitem(gamemenu[3], skill_level, 1);
- drawmenubar();
- }
-
- disable_edit_menu()
- {
- disableitem(gamemenu[2], 1);
- disableitem(gamemenu[2], 3);
- disableitem(gamemenu[2], 4);
- disableitem(gamemenu[2], 5);
- disableitem(gamemenu[2], 6);
- }
-
- enable_edit_menu()
- {
- enableitem(gamemenu[2], 1);
- enableitem(gamemenu[2], 3);
- enableitem(gamemenu[2], 4);
- enableitem(gamemenu[2], 5);
- enableitem(gamemenu[2], 6);
- }
-
- docommand(menu_selection)
- long menu_selection;
- {
- register int the_item;
- static char name[256];
-
- the_item = loword(menu_selection);
- switch (hiword(menu_selection)){
- case appleid :
- getitem(gamemenu[0], the_item, name);
- opendeskacc(name);
- setport(gamewindow);
- break;
- case editid:
- systemedit(the_item - 1);
- break;
- case fileid:
- switch (the_item){
- case 1 :
- if (paused){
- paused = 0;
- setitem(gamemenu[1], 1, "Pause");
- }
- else{
- paused = 1;
- setitem(gamemenu[1], 1, "Continue");
- }
- break;
- case 2:
- init_game();
- break;
- case 3 :
- done = 1;
- break;
- }
- break;
- case skillid :
- checkitem(gamemenu[3], skill_level, 0);
- skill_level = the_item;
- checkitem(gamemenu[3], skill_level, 1);
- break;
- case soundid:
- if (sound_on){
- sound_on = 0;
- setitem(gamemenu[4], 1, "Sound On");
- }
- else{
- sound_on = 1;
- setitem(gamemenu[4], 1, "Sound Off");
- }
- break;
- }
- hilitemenu(0);
- }
-
- create_l_paddle()
- {
- l_paddle.dir = STOPPED;
- l_paddle.speed = PADDLESPEED;
- l_paddle.score = 0;
- setrect (&l_paddle.r,
- winstorage.port.portrect.a.left + PADINSET,
- winstorage.port.portrect.a.top + PADINSET,
- winstorage.port.portrect.a.left + PADINSET + PADWIDTH,
- winstorage.port.portrect.a.top + PADINSET + PADLENGTH);
- fillrect(&l_paddle.r, PAD_PAT);
- }
-
- create_r_paddle()
- {
- r_paddle.dir = STOPPED;
- r_paddle.speed = PADDLESPEED;
- r_paddle.score = 0;
- setrect (&r_paddle.r,
- winstorage.port.portrect.a.right - PADWIDTH - PADINSET,
- winstorage.port.portrect.a.top + PADINSET,
- winstorage.port.portrect.a.right - PADWIDTH - PADINSET + PADWIDTH,
- winstorage.port.portrect.a.top + PADINSET + PADLENGTH);
- fillrect(r_paddle.r, PAD_PAT);
- }
-
- create_walls()
- {
- setrect(&top_wall,
- winstorage.port.portrect.a.left + 20,
- winstorage.port.portrect.a.top + 5,
- winstorage.port.portrect.a.right - 20,
- winstorage.port.portrect.a.top + 20);
- fillrect(&top_wall, WALL_PAT);
- setrect(&bottom_wall,
- winstorage.port.portrect.a.left + 20,
- winstorage.port.portrect.a.bottom - 20,
- winstorage.port.portrect.a.right - 20,
- winstorage.port.portrect.a.bottom - 5);
- fillrect(&bottom_wall, WALL_PAT);
- }
-
- create_ball()
- {
- ball.rgn = newrgn();
- ball.oldrgn = newrgn();
- ball.unrgn = newrgn();
- ball.dir = LEFT;
- ball.speed = BALLSPEED;
- setrect (&r, 250, 150, 250 + BALLWIDTH, 150 + BALLLENGTH);
- openrgn();
- frameoval(&r);
- closergn(ball.rgn);
- }
-
- serve_ball()
- {
- register i;
-
- offsetrgn(ball.rgn, 250 - ((**ball.rgn).rgnbbox.a.right),
- 150 - ((**ball.rgn).rgnbbox.a.top) );
- for (i = 0; i < 250; i++){
- check_status();
- move_right_paddle();
- move_left_paddle();
- move_ball();
- }
- ball.dir = (last_won == RIGHT) ? LEFT : RIGHT;
- ball.speed = BALLSPEED;
- ball.on = 1;
- paintrgn(ball.rgn);
- bleep();
- }
-
- /* someone scored a point */
- kill_ball()
- {
- ball.on = volleys = 0;
- copyrgn(ball.rgn, ball.unrgn);
- erasergn(ball.rgn);
- recover_from_collision();
- blat();
- display_score();
- }
-
- init_game()
- {
- l_paddle.score = r_paddle.score = 0;
- ball.speed = BALLSPEED;
- kill_ball();
- }
-
- /* check for bounces, direction changes, scoring, etc */
- check_status()
- {
- static rect *ball_r;
-
- register ball_top = (**ball.rgn).rgnbbox.a.top;
- register ball_bottom = (**ball.rgn).rgnbbox.a.bottom;
- register ball_left = (**ball.rgn).rgnbbox.a.left;
- register ball_right = (**ball.rgn).rgnbbox.a.right;
-
- ball_r = &((**ball.rgn).rgnbbox);
-
- /* make it a little harder as time goes by */
- if (volleys > 35)
- ball.speed = BALLSPEED + 6;
- else if (volleys > 30)
- ball.speed = BALLSPEED + 5;
- else if (volleys > 25)
- ball.speed = BALLSPEED + 4;
- else if (volleys > 20)
- ball.speed = BALLSPEED + 3;
- else if (volleys > 15)
- ball.speed = BALLSPEED + 2;
- else if (volleys > 10)
- ball.speed = BALLSPEED + 1;
-
- r_paddle.speed = ball.speed + 2;
-
- /* the right paddle tries to track the ball */
- if ( (ball_right > 250) &&
- (ball.dir == UP_RIGHT || ball.dir == DOWN_RIGHT ||
- ball.dir == RIGHT) ){
- if (ball_top + handicap() < r_paddle.r.a.top)
- r_paddle.dir = UP;
- else if (ball_bottom - handicap() > r_paddle.r.a.bottom)
- r_paddle.dir = DOWN;
- else
- r_paddle.dir = STOPPED;
- }
- else
- r_paddle.dir = STOPPED;
-
- /* the ball and the left boundry */
- if (ball_left < l_paddle.r.a.right ){
- if (sectrect(ball_r, &l_paddle.r, &r)){
- volleys++;
- bleep();
- if (ball_top <= l_paddle.r.a.top + 15)
- ball.dir = UP_RIGHT;
- else if (ball_top > l_paddle.r.a.top + 15 && ball_bottom < l_paddle.r.a.top + 30)
- ball.dir = RIGHT;
- else
- ball.dir = DOWN_RIGHT;
- }
- else{
- last_won = RIGHT;
- r_paddle.score++;
- kill_ball();
- }
- return;
- }
-
- /* the ball and the right boundry */
- if (ball_right > r_paddle.r.a.left){
- if (sectrect(ball_r, &r_paddle.r, &r)){
- volleys++;
- bleep();
- if (ball_top <= r_paddle.r.a.top + 15)
- ball.dir = UP_LEFT;
- else if (ball_top > r_paddle.r.a.top + 15 && ball_bottom < r_paddle.r.a.top + 30)
- ball.dir = LEFT;
- else
- ball.dir = DOWN_LEFT;
- }
- else{
- last_won = LEFT;
- l_paddle.score++;
- kill_ball();
- }
- return;
- }
-
- /* the ball and the top wall */
- if (ball_top < top_wall.a.bottom){
- if (ball.dir == UP_LEFT)
- ball.dir = DOWN_LEFT;
- else if (ball.dir == UP_RIGHT)
- ball.dir = DOWN_RIGHT;
- bleep();
- return;
- }
-
- /* the ball and the bottom wall */
- if (ball_bottom > bottom_wall.a.top){
- if (ball.dir == DOWN_LEFT)
- ball.dir = UP_LEFT;
- else if (ball.dir == DOWN_RIGHT)
- ball.dir = UP_RIGHT;
- bleep();
- return;
- }
- }
-
- /* the ball eats the walls and paddles */
- recover_from_collision()
- {
- register rect *rp = &((**ball.unrgn).rgnbbox);
-
- if (sectrect(rp, &top_wall, &r))
- fillrect(&r, WALL_PAT);
- else if (sectrect(rp, &bottom_wall, &r))
- fillrect(&r, WALL_PAT);
- if (sectrect(rp, &l_paddle.r, &r))
- fillrect(&r, PAD_PAT);
- else if (sectrect(rp, &r_paddle.r, &r))
- fillrect(&r, PAD_PAT);
- }
-
- move_left_paddle()
- {
- static point mouseloc;
- register int newtop, newbottom;
-
- getmouse(&mouseloc);
- if (mouseloc.a.v != l_paddle.r.a.top){
- r.a.left = l_paddle.r.a.left;
- r.a.right = l_paddle.r.a.right;
- if (mouseloc.a.v <= winstorage.port.portrect.a.top){
- newtop = winstorage.port.portrect.a.top;
- newbottom = newtop + PADLENGTH;
- }
- else if (mouseloc.a.v + PADLENGTH >= winstorage.port.portrect.a.bottom){
- newbottom = winstorage.port.portrect.a.bottom;
- newtop = newbottom - PADLENGTH;
- }
- else{
- newtop = mouseloc.a.v;
- newbottom = newtop + PADLENGTH;
- }
- if (newtop > l_paddle.r.a.top){
- r.a.top = l_paddle.r.a.top;
- r.a.bottom = (newtop > l_paddle.r.a.bottom) ? l_paddle.r.a.bottom : newtop;
- }
- else if (newtop < l_paddle.r.a.top){
- r.a.bottom = l_paddle.r.a.bottom;
- r.a.top = (newbottom < l_paddle.r.a.top) ? l_paddle.r.a.top : newbottom;
- }
- l_paddle.r.a.top = newtop;
- l_paddle.r.a.bottom = newbottom;
- eraserect(&r);
- fillrect(&l_paddle.r, PAD_PAT);
- }
- else
- fillrect(&l_paddle.r, PAD_PAT);
- }
-
- move_right_paddle()
- {
- if (r_paddle.dir == STOPPED)
- fillrect(&r_paddle.r, PAD_PAT);
- else{
- r.a.left = r_paddle.r.a.left;
- r.a.right = r_paddle.r.a.right;
- switch (r_paddle.dir){
- case UP:
- r.a.bottom = r_paddle.r.a.bottom;
- r_paddle.r.a.top -= r_paddle.speed;
- r_paddle.r.a.bottom -= r_paddle.speed;
- r.a.top = r_paddle.r.a.bottom;
- break;
- case DOWN:
- r.a.top = r_paddle.r.a.top;
- r_paddle.r.a.top += r_paddle.speed;
- r_paddle.r.a.bottom += r_paddle.speed;
- r.a.bottom = r_paddle.r.a.top;
- break;
- }
- eraserect(&r);
- fillrect(&r_paddle.r, PAD_PAT);
- }
- }
-
- move_ball()
- {
- if (ball.on){
- copyrgn(ball.rgn, ball.oldrgn);
- switch (ball.dir){
- case LEFT:
- offsetrgn(ball.rgn, -ball.speed, 0);
- break;
- case RIGHT:
- offsetrgn(ball.rgn, ball.speed, 0);
- break;
- case UP_LEFT:
- offsetrgn(ball.rgn, -ball.speed, -ball.speed);
- break;
- case UP_RIGHT:
- offsetrgn(ball.rgn, ball.speed, -ball.speed);
- break;
- case DOWN_LEFT:
- offsetrgn(ball.rgn, -ball.speed, ball.speed);
- break;
- case DOWN_RIGHT:
- offsetrgn(ball.rgn, ball.speed, ball.speed);
- break;
- }
- unionrgn(ball.rgn, ball.oldrgn, ball.unrgn);
- diffrgn(ball.unrgn, ball.rgn, ball.unrgn);
- erasergn(ball.unrgn);
- paintrgn(ball.rgn);
- recover_from_collision();
- }
- }
-
- display_score()
- {
- static long i;
-
- if (l_paddle.score < 10){
- title[14] = '0';
- i = l_paddle.score;
- numtostring(i, (title + 15));
- }
- else{
- i = l_paddle.score;
- numtostring(i, (title + 14));
- }
- if (r_paddle.score < 10){
- title[62] = '0';
- i = r_paddle.score;
- numtostring(i, (title + 63));
- }
- else{
- i = r_paddle.score;
- numtostring(i, (title + 62));
- }
- /* numtostring inserts a '\0' we don't need */
- *(title + 16) = *(title + 64) = ' ';
- setwtitle(gamewindow, title);
- }
-
- bleep()
- {
- if (sound_on){
- if (! sounddone())
- stopsound();
- startsound((ptr) &bleep_buf, (long) sizeof(bleep_buf), (ptr) 0);
- }
- }
-
- blat()
- {
- if (sound_on){
- if (! sounddone())
- stopsound();
- startsound((ptr) &blat_buf, (long) sizeof(blat_buf), (ptr) 0);
- }
- }
-
- /* Every so often, let the Mac's paddle fail to track the ball until
- the ball has passed it by a certain amount.
- This is the heart of a satisfying game. */
- int handicap()
- {
- register mac_skill;
-
- switch(skill_level){
- case 1 :
- mac_skill = 2;
- break;
- case 2 :
- mac_skill = 8;
- break;
- case 3 :
- mac_skill = 27;
- break;
- case 4 :
- mac_skill = 64;
- break;
- default :
- mac_skill = 2;
- break;
- }
- return ((random() % mac_skill) == 0) ? 5 : 0;
- }
-