home *** CD-ROM | disk | FTP | other *** search
-
- /* 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
-
-
- Changes by Ingemar 1996:
- - Speed limit
- - Keyboard equivalents
- - Modern #includes
- */
-
- /*
- #include <MacTypes.h>
- #include <MemoryMgr.h>
- #include <QuickDraw.h>
- #include <EventMgr.h>
- #include <ToolBoxUtil.h>
- #include <ResourceMgr.h>
- #include <WindowMgr.h>
- #include <MenuMgr.h>
- #include <stdio.h>
- #include <SoundMgr.h>
- #include <SoundDvr.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[10])
-
- 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 unsigned char title[] = { 65,
- ' ',' ',' ',' ',' ',' ',' ',' ',
- 'L','e','f','t',' ',' ','0','0',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- 'M','A','C','_','P','o','n','g',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- 'R','i','g','h','t',' ','0','0',
- ' ',' ',' ',' ',' ',' ',' ',' ',
- '\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;
- }
-
- void blat()
- {
- if (sound_on) {
- if (! SoundDone())
- StopSound();
- StartSound((Ptr) &blat_buf, (long) sizeof(blat_buf), nil);
- }
- }
-
- void bleep()
- {
- if (sound_on) {
- if (! SoundDone())
- StopSound();
- StartSound((Ptr) &bleep_buf, (long) sizeof(bleep_buf), nil);
- }
- }
-
- void display_score()
- {
- static long i;
-
- i = l_paddle.score;
- title[15]=0x30+(i/100);
- title[16]=0x30+((i%100)/10);
- title[17]=0x30+(i%10);
- i = r_paddle.score;
- title[63]=0x30+(i/100);
- title[64]=0x30+((i%100)/10);
- title[65]=0x30+(i%10);
- SetWTitle(gamewindow, title);
- }
-
- /* the ball eats the walls and paddles */
- void 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);
- }
-
- void 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();
- }
- }
-
- void move_right_paddle()
- {
- if (r_paddle.dir == STOPPED)
- FillRect(&r_paddle.r, PAD_PAT);
- else {
- r.left = r_paddle.r.left;
- r.right = r_paddle.r.right;
- switch (r_paddle.dir) {
- case UP:
- r.bottom = r_paddle.r.bottom;
- r_paddle.r.top -= r_paddle.speed;
- r_paddle.r.bottom -= r_paddle.speed;
- r.top = r_paddle.r.bottom;
- break;
- case DOWN:
- r.top = r_paddle.r.top;
- r_paddle.r.top += r_paddle.speed;
- r_paddle.r.bottom += r_paddle.speed;
- r.bottom = r_paddle.r.top;
- break;
- }
- EraseRect(&r);
- FillRect(&r_paddle.r, PAD_PAT);
- }
- }
-
- void move_left_paddle()
- {
- static Point mouseloc;
- register int newtop, newbottom;
-
- GetMouse(&mouseloc);
- if (mouseloc.v != l_paddle.r.top) {
- r.left = l_paddle.r.left;
- r.right = l_paddle.r.right;
- if (mouseloc.v <= winstorage.port.portRect.top) {
- newtop = winstorage.port.portRect.top;
- newbottom = newtop + PADLENGTH;
- }
- else if (mouseloc.v + PADLENGTH >= winstorage.port.portRect.bottom) {
- newbottom = winstorage.port.portRect.bottom;
- newtop = newbottom - PADLENGTH;
- }
- else {
- newtop = mouseloc.v;
- newbottom = newtop + PADLENGTH;
- }
- if (newtop > l_paddle.r.top) {
- r.top = l_paddle.r.top;
- r.bottom = (newtop > l_paddle.r.bottom) ? l_paddle.r.bottom : newtop;
- }
- else if (newtop < l_paddle.r.top) {
- r.bottom = l_paddle.r.bottom;
- r.top = (newbottom < l_paddle.r.top) ? l_paddle.r.top : newbottom;
- }
- l_paddle.r.top = newtop;
- l_paddle.r.bottom = newbottom;
- EraseRect(&r);
- FillRect(&l_paddle.r, PAD_PAT);
- }
- else
- FillRect(&l_paddle.r, PAD_PAT);
- }
-
- /* someone scored a point */
- void kill_ball()
- {
- ball.on = volleys = 0;
- CopyRgn(ball.Rgn, ball.unRgn);
- EraseRgn(ball.Rgn);
- recover_from_collision();
- blat();
- display_score();
- }
-
- /* check for bounces, diRection changes, scoring, etc */
- void check_status()
- {
- static Rect *ball_r;
-
- register ball_top = (**ball.Rgn).rgnBBox.top;
- register ball_bottom = (**ball.Rgn).rgnBBox.bottom;
- register ball_left = (**ball.Rgn).rgnBBox.left;
- register ball_right = (**ball.Rgn).rgnBBox.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.top)
- r_paddle.dir = UP;
- else if (ball_bottom - handicap() > r_paddle.r.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.right ) {
- if (SectRect(ball_r, &l_paddle.r, &r)) {
- volleys++;
- bleep();
- if (ball_top <= l_paddle.r.top + 15)
- ball.dir = UP_RIGHT;
- else if (ball_top > l_paddle.r.top + 15 && ball_bottom < l_paddle.r.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.left) {
- if (SectRect(ball_r, &r_paddle.r, &r)) {
- volleys++;
- bleep();
- if (ball_top <= r_paddle.r.top + 15)
- ball.dir = UP_LEFT;
- else if (ball_top > r_paddle.r.top + 15 && ball_bottom < r_paddle.r.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.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.top) {
- if (ball.dir == DOWN_LEFT)
- ball.dir = UP_LEFT;
- else if (ball.dir == DOWN_RIGHT)
- ball.dir = UP_RIGHT;
- bleep();
- return;
- }
- }
-
- void Init_game()
- {
- l_paddle.score = r_paddle.score = 0;
- ball.speed = BALLSPEED;
- kill_ball();
- }
-
- void serve_ball()
- {
- register i;
-
- OffsetRgn(ball.Rgn, 250 - ((**ball.Rgn).rgnBBox.right),
- 150 - ((**ball.Rgn).rgnBBox.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();
- }
-
- void 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);
- }
-
- void create_walls()
- {
- SetRect(&top_wall,
- winstorage.port.portRect.left + 20,
- winstorage.port.portRect.top + 5,
- winstorage.port.portRect.right - 20,
- winstorage.port.portRect.top + 20);
- FillRect(&top_wall, WALL_PAT);
- SetRect(&bottom_wall,
- winstorage.port.portRect.left + 20,
- winstorage.port.portRect.bottom - 20,
- winstorage.port.portRect.right - 20,
- winstorage.port.portRect.bottom - 5);
- FillRect(&bottom_wall, WALL_PAT);
- }
-
- void create_r_paddle()
- {
- r_paddle.dir = STOPPED;
- r_paddle.speed = PADDLESPEED;
- r_paddle.score = 0;
- SetRect (&r_paddle.r,
- winstorage.port.portRect.right - PADWIDTH - PADINSET,
- winstorage.port.portRect.top + PADINSET,
- winstorage.port.portRect.right - PADWIDTH - PADINSET + PADWIDTH,
- winstorage.port.portRect.top + PADINSET + PADLENGTH);
- FillRect(&r_paddle.r, PAD_PAT);
- }
-
- void create_l_paddle()
- {
- l_paddle.dir = STOPPED;
- l_paddle.speed = PADDLESPEED;
- l_paddle.score = 0;
- SetRect (&l_paddle.r,
- winstorage.port.portRect.left + PADINSET,
- winstorage.port.portRect.top + PADINSET,
- winstorage.port.portRect.left + PADINSET + PADWIDTH,
- winstorage.port.portRect.top + PADINSET + PADLENGTH);
- FillRect(&l_paddle.r, PAD_PAT);
- }
-
- void DoCommand(long menu_selection)
- {
- register int the_item;
- static unsigned 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, "\pPause");
- }
- else {
- paused = 1;
- SetItem(gamemenu[1], 1, "\pContinue");
- }
- 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, "\pSound On");
- }
- else {
- sound_on = 1;
- SetItem(gamemenu[4], 1, "\pSound Off");
- }
- break;
- }
- HiliteMenu(0);
- }
-
- void enable_edit_menu()
- {
- EnableItem(gamemenu[2], 1);
- EnableItem(gamemenu[2], 3);
- EnableItem(gamemenu[2], 4);
- EnableItem(gamemenu[2], 5);
- EnableItem(gamemenu[2], 6);
- }
-
- void disable_edit_menu()
- {
- DisableItem(gamemenu[2], 1);
- DisableItem(gamemenu[2], 3);
- DisableItem(gamemenu[2], 4);
- DisableItem(gamemenu[2], 5);
- DisableItem(gamemenu[2], 6);
- }
-
- void build_menus()
- {
- register int i;
-
- InitMenus();
- gamemenu[0] = NewMenu(appleid, "\p");
- gamemenu[1] = NewMenu(fileid, "\pFile");
- gamemenu[2] = NewMenu(editid, "\pEdit");
- gamemenu[3] = NewMenu(skillid, "\pSkill");
- gamemenu[4] = NewMenu(soundid, "\pSound");
- AddResMenu(gamemenu[0],'DRVR');
- AppendMenu(gamemenu[1],"\pPause/P;Restart/R;Quit/Q");
- AppendMenu(gamemenu[2],"\p(Undo;(-;(Cut;(Copy;(Paste;(Clear");
- AppendMenu(gamemenu[3],"\pBeginner;Novice;Normal;Expert");
- AppendMenu(gamemenu[4],"\pSound Off/S");
- for(i = 0; i < 5; i++)
- InsertMenu(gamemenu[i], 0);
- CheckItem(gamemenu[3], skill_level, 1);
- DrawMenuBar();
- }
-
- void 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;
- }
-
- void play_pong()
- {
- long startTicks;
-
- if ( (! paused) && (l_paddle.score < HIGHSCORE && r_paddle.score < HIGHSCORE))
- {
- startTicks = TickCount();
- if (! ball.on)
- serve_ball();
- check_status();
- move_left_paddle();
- move_right_paddle();
- move_ball();
-
- while (startTicks == TickCount());
- }
- }
-
- /* pretty much straight from SAMP in I.M. */
- void 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 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;
- }
- }
- } // Handle_Events
-
- void 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.right - 4, r.bottom - 4);
- gamewindow = NewWindow(&winstorage, &r, title, 1, 0L, (WindowPtr)-1L, 0, 0L);
- SetPort(gamewindow);
- build_menus();
- ShowCursor();
- create_l_paddle();
- create_r_paddle();
- create_walls();
- create_ball();
- Init_game();
- }
-
- void main()
- {
- setup();
- while (! done) {
- Handle_Events();
- play_pong();
- }
- FlushEvents(everyEvent, 0);
- StopSound();
- ExitToShell();
- }
-