home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel
/
CAROUSEL.cdr
/
mactosh
/
code
/
shar_max.sit
< prev
next >
Wrap
Text File
|
1988-06-20
|
24KB
|
972 lines
18-Jun-88 14:35:41-MDT,24983;000000000000
Return-Path: <u-lchoqu%sunset@cs.utah.edu>
Received: from cs.utah.edu by SIMTEL20.ARPA with TCP; Sat, 18 Jun 88 14:35:12 MDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA22408; Sat, 18 Jun 88 14:35:09 MDT
Received: by sunset.utah.edu (5.54/utah-2.0-leaf)
id AA24685; Sat, 18 Jun 88 14:35:04 MDT
Date: Sat, 18 Jun 88 14:35:04 MDT
From: u-lchoqu%sunset@cs.utah.edu (Lee Choquette)
Message-Id: <8806182035.AA24685@sunset.utah.edu>
To: rthum@simtel20.arpa
Subject: Maxwell.shar
#! /bin/sh
#
# This is a shell archive. Save this into a file, edit it
# and delete all lines above this comment. Then give this
# file to sh by executing the command "sh file". The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# 2 README
# 1 ball.h
# 10 damain.c
# 5 movebits.c
# 5 phys.c
#
echo 'Extracting README'
if test -f README; then echo 'shar: will not overwrite README'; else
sed 's/^X//' << '________This_Is_The_END________' > README
XThis is the Maxwell desk accessory. It is written in version 2.? of
XMegamax C. This is public domain.
X
XTo compile this, stick it on your Mac, and compile all the .c files.
XLink the resulting objects, with damain.o being first. Make sure to
Xtell the linker that you are makeing a DRVR, not CODE.
X
XNote that these files were edited with tabstops set every four.
X
XHere is a suggestion for decreasing the turnaround time
Xif you are going to make changes to this:
X
X 1. Modify some random program that supports DAs to open
X a resource file named TESTDA before it puts up the Apple
X menu. The editor demo program from Megamax is a good
X choice. Just change the place where it tries to open
X "clock" to open "TESTDA" instead.
X
X 2. Have the linker put the DA in TESTDA. Be sure to use
X the same resource ID each time, or things might get
X confused.
X
X 3. Add an "Edit DA" item to the FILE menu.
X
X 4. The code for the "Edit DA" menu item should be something
X like this:
X
X char *argv[] = {
X "file1.c", "file2.c", "file3.c", 0
X }; /* or whatever your source files are called */
X
X edit_da() {
X execv( "editor", argv );
X }
X You might need to use the form "volume:name" for your file
X names, or to get the editor, depending on how you set things
X up.
X
XThis changes the test cycle from
X
X editor -> compiler -> linker -> resource editor -> finder -> editor
X
Xto
X
X editor -> compiler -> linker -> program -> editor
X
Xwhich can be faster.
X
X Tim Smith
________This_Is_The_END________
if test `wc -l < README` -ne 49; then
echo 'shar: README was damaged during transit'
echo ' (should have been 49 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting ball.h'
if test -f ball.h; then echo 'shar: will not overwrite ball.h'; else
sed 's/^X//' << '________This_Is_The_END________' > ball.h
Xtypedef struct particle {
X long x,y; /* location */
X long vx, vy; /* velocity */
X int pict; /* which picture this ball is */
X} ball;
X
X#define GRAD 6 /* radius for drawing (quickdraw units) */
X#define CRAD 28 /* radius for collision (box units) */
X#define SDIM (2*GRAD) /* diameter on screen */
X
X#define SLOW 225 /* max v squared for slow ball */
________This_Is_The_END________
if test `wc -l < ball.h` -ne 11; then
echo 'shar: ball.h was damaged during transit'
echo ' (should have been 11 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting damain.c'
if test -f damain.c; then echo 'shar: will not overwrite damain.c'; else
sed 's/^X//' << '________This_Is_The_END________' > damain.c
X/*
X * Maxwell: particles in box, with gate in middle. Inspired by the
X * demo by the same name for the Teletype DMD 5620 terminal.
X */
X
X#include <acc.h>
X#include <desk.h>
X#include <qd.h>
X#include <qdvars.h>
X#include <event.h>
X#include <res.h>
X#include <misc.h>
X#include <mem.h>
X#include <menu.h>
X#include <te.h>
X#include <font.h>
X#include <file.h>
X#include <win.h>
X#include <control.h>
X#include <device.h>
X#include "ball.h"
X
X#define NULL 0
X
XACC( 0x2400, 2, 0xfffb, 0, 7, "Maxwell" )
X
X#define MAXBALLS 20 /* must be even */
X
Xball Balls[ MAXBALLS ];
Xint nBalls;
Xint GateState;
XControlHandle help;
X
Xint wide = 300; /* initial size of box */
Xint tall = 255;
X
Xaccopen( dctl, pb )
X dctlentry *dctl;
X paramblockrec *pb;
X{
X WindowPeek mywindow;
X Rect bound; int i;
X
X if ( dctl->dCtlWindow == NULL )
X {
X GrafPtr saveport;
X
X GetPort( &saveport );
X SetRect( &bound, 100, 40, 130 + wide, 80 + tall );
X mywindow = NewWindow( 0L, &bound, "Maxwell", -1,
X DocumentProc, -1L, -1, 0L );
X mywindow->windowKind = dctl->dCtlRefNum;
X dctl->dCtlWindow = mywindow;
X initmove();
X SetPort( mywindow );
X helpControl( mywindow );
X InitRandom( TickCount() );
X SetupUniverse();
X SetPort( saveport );
X }
X return 0;
X}
X
Xaccclose( dctl, pb )
X dctlentry *dctl;
X paramblockrec *pb;
X{
X DisposeWindow( dctl->dCtlWindow );
X dctl->dCtlWindow = NULL;
X return 0;
X}
X
Xaccctl( dctl, pb )
X dctlentry *dctl;
X paramblockrec *pb;
X{
X WindowPtr mywindow;
X int code;
X EventRecord *erp;
X int infront, inmine;
X
X code = pb->paramunion.CntrlParam.CSCode;
X mywindow = dctl->dCtlWindow;
X
X SetPort( mywindow );
X
X infront = mywindow == FrontWindow();
X
X switch ( code ) {
Xcase accRun:
X step( mywindow, infront );
X break;
Xcase accEvent:
X erp = (EventRecord *)(pb->paramunion.CntrlParam.csParam.eventaddr);
X switch ( erp->what ) {
X case activateEvt:
X case updateEvt:
X setgate(0);
X redraw( mywindow );
X HiliteControl( help, infront ? 0 : 255 );
X break;
X case mouseDown:
X /*
X * Only mouse down events we care about are in the grow
X * icon and in the help button. I tried FindWindow(),
X * but it refused to distinguish between the grow icon
X * and the rest of the content region, so instead, I
X * will just do it directly with co-ordinates.
X */
X if ( infront ) {
X GlobalToLocal( &erp->where );
X /*
X * check grow icon...
X */
X if ( 15+wide < erp->where.a.h
X && erp->where.a.h < 30+wide
X && 25+tall < erp->where.a.v &&
X erp->where.a.v < 40+tall
X ) {
X LocalToGlobal( &erp->where );
X resize( mywindow, &erp->where );
X } else
X /*
X * see if there is any reason to check the help button...
X */
X if ( erp->where.a.v <= 25 )
X /*
X * yup, there is...
X */
X checkhelp( erp, mywindow );
X }
X break;
X }
X break;
X }
X}
X
Xaccprime() {}
Xaccstatus() {}
X
X/*
X * step() moves all the balls
X */
Xstatic int nslow;
X
Xstep(wp, infront)
X GrafPtr wp;
X{
X register int i,j;
X
X nslow = 0;
X sortballs();
X for ( i = 0; i < nBalls; i++ ) {
X for ( j = i+1; j < nBalls; j++ )
X if ( bbump( Balls+i, Balls+j ) )
X break;
X wbump( Balls+i );
X if ( infront )
X setgate( Button() );
X }
X /*
X * If we just draw the balls in order on the screen it will look
X * bad, since we have them sorted by x.
X */
X for ( i = 0; i < 10; i++ )
X for ( j = i; j < nBalls; j += 10 )
X MoveBall( Balls + j, wp );
X
X if ( nslow < nBalls/3 )
X walls( -1 );
X else
X if ( nslow >= (nBalls/3)<<1 )
X walls( 1 );
X else
X walls( 0 );
X}
X
XMoveBall( pA, wp )
X register ball *pA;
X GrafPtr wp;
X{
X Rect R;
X register long v2;
X ball before;
X
X before = *pA; /* save old ball */
X mball( pA ); /* compute new ball */
X
X v2 = pA->vx * pA->vx + pA->vy * pA->vy;
X
X if ( v2 <= SLOW ) nslow++;
X
X pA->pict = (v2 <= SLOW ? 0 : 1);
X
X Draw( wp, &before, pA );
X
X return;
X}
X
X
X/*
X * redraw() is called to deal with update events in our window
X */
Xredraw( wp )
X GrafPtr wp;
X{
X Rect bound; int i;
X
X BeginUpdate( wp );
X SetRect( &bound, 0, 0, wide+30, tall+40 );
X EraseRect( &bound ); /* clear whole window */
X SetRect( &bound, 15, 25, 15+wide, 25+tall );
X FrameRect( &bound ); /* draw outer border */
X SetRect( &bound, 13+wide/2, 25, 17+wide/2, 25+tall );
X InvertRect( &bound ); /* draw barrier */
X SetRect( &bound, 13+wide/2, 24+tall/3, 17+wide/2, 26+(tall+tall)/3 );
X InvertRect( &bound ); /* remove gate + 1 pixel */
X Toggle();
X GateState = 0; /* gate is closed */
X DrawControls( wp );
X
X /*
X * Now draw the balls. This only works for an even number of balls,
X * since Draw() wants two balls.
X */
X for ( i = 0; i < nBalls; i+=2 )
X Draw( wp, Balls + i, Balls + i + 1 );
X
X EndUpdate( wp );
X
X /*
X * now do the grow icon
X */
X SetRect( &bound, wide+15, tall+25, wide+30, tall+40 );
X ClipRect( &bound );
X DrawGrowIcon( wp );
X SetRect( &bound, 0, 0, 31415, 27182 );
X ClipRect( &bound );
X}
X
X/*
X * Draw() draws two balls in the window. It is used both to draw the
X * initial balls, with the two balls being different balls, and to
X * draw a ball that has moved. In the latter case, the two balls are
X * the same ball, once at the old position and once at the new postion.
X * This works since drawing is done in xor mode.
X */
XDraw( wp, pA, pB )
X GrafPtr wp;
X register ball *pA, *pB;
X{
X register long ax, ay, bx, by;
X
X ax = pA->x >> 2;
X ay = pA->y >> 2;
X
X bx = pB->x >> 2;
X by = pB->y >> 2;
X
X movebits( wp, bx-GRAD+15, by-GRAD+25, ax-GRAD+15,
X ay-GRAD+25, (long)pB->pict, (long)pA->pict );
X}
X
X/*
X * set gate to a given state. bs != 0 means make sure the gate is
X * open, and bs == 0 means make sure it is closed.
X */
Xsetgate( bs ) {
X if ( !!bs != GateState ) {
X GateState = !!bs;
X Toggle();
X }
X}
X
X/*
X * Change the state of the gate on the screen
X */
XToggle() {
X Rect bound;
X
X SetRect( &bound, 13+wide/2, 25+tall/3, 17+wide/2, 25+(tall+tall)/3 );
X InvertRect( &bound );
X}
X
XInitRandom( seed )
X long seed;
X{
X asm {
X move.l (A5), A0
X move.l seed(A6), 0xff82(A0)
X }
X}
X
X/*
X * Generate a random integer in [low,high]. If "contract" is not zero,
X * it skews the distribution to favor numbers nearer the center of
X * the interval
X */
Xrani(low,high,contract)
X int low, high;
X{
X register long r;
X register int range;
X
X r = (Random()>>1) + 16384;
X if ( !contract )
X return r * (high-low) / 32768L + low;
X
X range = (high - low) >> 1;
X
X r = r * range;
X r /= 32768;
X r *= Random();
X range = r / 32768;
X
X return ( (low + high) >> 1 ) + range;
X}
X
X/*
X * Set up balls.
X */
XSetupUniverse() {
X int i; long nb;
X
X PenNormal();
X PenMode( patXor );
X
X nb = (long)tall * (long)wide; nb >>= 13; nb <<= 1;
X nBalls = nb + 4;
X if ( nBalls > MAXBALLS )
X nBalls = MAXBALLS;
X
X for ( i = 0; i < nBalls; i++ ) {
X register long a,b;
X
X Balls[i].x = rani(CRAD, (wide<<2)-CRAD, 0);
X Balls[i].y = rani(CRAD, (tall<<2)-CRAD, 0);
X Balls[i].vx = a = rani(-40, 40, 1);
X Balls[i].vy = b = rani(-40, 40, 1);
X if ( a*a + b*b <= SLOW )
X Balls[i].pict = 0;
X else
X Balls[i].pict = 1;
X }
X}
X
X/*
X * resize the window
X */
Xresize( wp, mp )
X WindowPtr wp;
X Point *mp;
X{
X Rect sizerect; long result;
X
X SetRect( &sizerect, 150, 80, 2500, 402 );
X result = GrowWindow( wp, mp, &sizerect );
X if ( !result )
X return;
X tall = result >> 16; tall &= 0xffff;
X wide = result & 0xffff;
X
X wide -= 29; wide -= wide % 2;
X tall -= 38; tall -= tall % 3;
X
X DisposeControl( help );
X
X SizeWindow( wp, wide + 30, tall + 40, 0 );
X
X helpControl( wp );
X
X SetRect( &sizerect, 0, 0, wide + 30, tall + 40 );
X InvalRect( &sizerect );
X
X SetupUniverse();
X redraw( wp );
X}
X
X/*
X * Sort balls by x co-ordinate. The first time this is called, it has
X * to do a lot of work, but on subsequent calls, the balls will for the
X * most part be already in order. We shall use a bubble sort, since
X * it is very fast for an already sorted list.
X */
Xsortballs() {
X register int i, j, flag;
X
X flag = 1;
X for ( i = 0; i < (nBalls - 1) && flag; i++ )
X for ( flag = 0, j = nBalls-1; j > i; --j )
X if ( Balls[j-1].x > Balls[j].x ) {
X ball temp;
X flag = 1;
X temp = Balls[j-1]; Balls[j-1] = Balls[j];
X Balls[j] = temp;
X }
X}
X
X/*
X * repond to a click in the help button
X */
Xshowhelp() {
X Rect bound;
X WindowPtr wp;
X char *h1, *h2, *h3, *h4;
X char helptext[1024];
X
X SetRect( &bound, 91, 68, 421, 303 );
X wp = NewWindow( 0L, &bound, "A", -1, DBoxProc, -1L, 0, 0L );
X SetPort( wp );
X
X TextMode( srcXor );
X TextSize( 9 );
X
X SetRect( &bound, 10, 10, 320, 225 );
X
X h1 = "\
XMaxwell V2.1 from Mithral Engineering\r\r\
XWhenever the Maxwell window is in front, holding down the\
X mouse button opens the gate so that balls may go from one\
X side to the other.\r\r";
X h2 = "\
XTry to get all the fast balls ( the black ones ) in the right\
X half of the window, and all the slow ones in the left.\r\r\
XDue to roundoff errors, at each collision there is a slight";
X h3 = "\
X net decrease in the total energy of the balls. To balance\
X this, the right wall will become 'hot' if less than one third\
X of the balls are fast balls. When a slow ball hits the hot right";
X h4 = "\
X wall, it will become a very fast ball. When more than one third\
X of the balls are fast, the right wall will cool off.\r\r\
XThis program and its source code are in the public domain";
X
X strcpy( helptext, h1 );
X strcat( helptext, h2 );
X strcat( helptext, h3 );
X strcat( helptext, h4 );
X
X TextBox( helptext, (long)strlen( helptext ), &bound, teJustLeft );
X
X while ( !Button() )
X ;
X FlushEvents( mDownMask, 0 );
X DisposeWindow( wp );
X}
X
X/*
X * put up the help button
X */
XhelpControl( wp )
X WindowPtr wp;
X{
X Rect bound;
X
X SetRect( &bound, (wide>>1)-7, 4 , (wide>>1)+37, 22 );
X
X help = NewControl( wp, &bound, "Info...", -1,0,0,0, PushButProc, 0L );
X}
X
X/*
X * find out if the user wants help
X */
Xcheckhelp( erp, win )
X EventRecord * erp;
X WindowPtr win;
X{
X int part;
X ControlHandle ch;
X
X part = FindControl( &erp->where, win, &ch );
X
X if ( part != inButton || ch != help )
X return;
X
X part = TrackControl( ch, &erp->where, 0L );
X
X if ( part == inButton )
X showhelp();
X}
________This_Is_The_END________
if test `wc -l < damain.c` -ne 480; then
echo 'shar: damain.c was damaged during transit'
echo ' (should have been 480 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting movebits.c'
if test -f movebits.c; then echo 'shar: will not overwrite movebits.c'; else
sed 's/^X//' << '________This_Is_The_END________' > movebits.c
X/*
X * move or draw ball on screen
X */
X
X#include <qd.h>
X#include <qdvars.h>
X#include "ball.h"
X
X/*
X * There are three off-screen bitmaps. The first two hold the images of
X * a slow ball and a fast ball. The third is used for combining the
X * before and after pictures so that a screen update of a moving ball
X * whose new postion overlaps its old position can be done in one
X * screen operation. This is intended to reduce flicker, by cutting
X * number of copybits calls to the screen from two to one per slow
X * moving ball. However, it increases the total number of copybits
X * calls, which makes things run slower.
X *
X * The use of this third bitmap is enabled by defining SMOOTH. It will
X * run ~25% slower with SMOOTH defined.
X */
X
Xchar sbits[ 2*(SDIM)*((SDIM+15)/16) ]; /* slow bits */
Xchar fbits[ 2*(SDIM)*((SDIM+15)/16) ]; /* fast bits */
X#ifdef SMOOTH
Xchar dbits[ 2*(2*SDIM)*((2*SDIM+15)/16) ]; /* combined bits */
X#endif
X
XBitMap sm, fm /* bitmaps for slow and fast bits */
X#ifdef SMOOTH
X ,dm /* and combined bits */
X#endif
X;
X
X/*
X * movebits() draws two balls. The first is in the square with corner
X * at Sx, Sy, and side SDIM. The second is at Dx and Dy, and has the
X * same size. Which drawing to use for each is determined by op and np.
X */
Xmovebits( win, Sx, Sy, Dx, Dy, op, np )
X GrafPtr win;
X long Sx, Sy, Dx, Dy, op, np;
X{
X register int sx, sy, dx, dy;
X int tx,ty;
X int rt, rl;
X Rect S,D;
X
X /*
X * The pointers to the bits in the bitmaps may have changed if we
X * have been moved on the heap since we were initialized, so we shall
X * fix them.
X */
X sm.baseAddr = sbits;
X fm.baseAddr = fbits;
X#ifdef SMOOTH
X dm.baseAddr = dbits;
X#endif
X
X sx = Sx; sy = Sy; dx = Dx; dy = Dy; /* convert to integers */
X tx = dx - sx; /* relative x positions */
X ty = dy - sy; /* relative y positions */
X
X
X#define pict(v) ((v) == 0 ? &sm : &fm )
X
X SetPort( win );
X
X/*
X * If the balls do not overlap, or if SMOOTH is not defined, then we
X * simply want to erase the first ball and draw the second.
X */
X#ifdef SMOOTH
X /*
X * If the balls can't possibly overlap, then just draw them directly
X * on the screen
X */
X if ( tx < -GRAD || tx > GRAD || ty < -GRAD || ty > GRAD ) {
X#endif
X SetRect( &S, 0, 0, SDIM, SDIM );
X SetRect( &D, sx, sy, sx + SDIM, sy + SDIM );
X CopyBits( pict(op), &win->portBits, &S, &D, srcXor, 0L );
X SetRect( &D, dx, dy, dx + SDIM, dy + SDIM );
X CopyBits( pict(np), &win->portBits, &S, &D, srcXor, 0L );
X return;
X#ifdef SMOOTH
X }
X
X /*
X * The balls are close enough that we may combine their updates into
X * one CopyBits to the screen.
X */
X
X /*
X * The rest of this is a pain to explain without a diagram,
X * so figure it out for yourself!
X */
X if ( ty > 0 )
X if ( tx > 0 ) { rt = 0; rl = 0; }
X else { rt = 0; rl = SDIM; }
X else
X if ( tx > 0 ) { rt = SDIM; rl = 0; }
X else { rt = SDIM; rl = SDIM; }
X
X SetRect( &D, 0, 0, 2*SDIM, 2*SDIM );
X CopyBits( &dm, &dm, &D, &D, srcXor, 0L );
X SetRect( &S, 0, 0, SDIM, SDIM );
X SetRect( &D, rl, rt, rl+SDIM, rt+SDIM );
X CopyBits( pict(op), &dm, &S, &D, srcCopy, 0L );
X SetRect( &D, rl + tx, rt + ty, rl + tx + SDIM, rt + ty + SDIM );
X CopyBits( pict(np), &dm, &S, &D, srcXor, 0L );
X SetRect( &S, 0, 0, SDIM*2, SDIM*2 );
X SetRect( &D, sx - rl, sy - rt, sx - rl + 2*SDIM, sy - rt + 2*SDIM );
X CopyBits( &dm, &win->portBits, &S, &D, srcXor, 0L );
X#endif
X}
X
X/*
X * Initialize the bitmaps
X */
Xinitmove() {
X Rect S,D;
X GrafPort port;
X
X /*
X * get a grafport to do our thing in
X */
X OpenPort( &port );
X PenNormal();
X
X /*
X * bitmap for slow bits...
X */
X sm.baseAddr = sbits;
X sm.rowBytes = 2*((SDIM+15)/16);
X sm.bounds.a.top = 0;
X sm.bounds.a.bottom = 2*SDIM;
X sm.bounds.a.left = 0;
X sm.bounds.a.right = 2*SDIM;
X
X /*
X * bitmap for fast bits...
X */
X fm.baseAddr = fbits;
X fm.rowBytes = 2*((SDIM+15)/16);
X fm.bounds.a.top = 0;
X fm.bounds.a.bottom = 2*SDIM;
X fm.bounds.a.left = 0;
X fm.bounds.a.right = 2*SDIM;
X
X SetPortBits( &sm ); /* prepare to draw slow ball */
X
X SetRect( &S, 0, 0, SDIM, SDIM );
X FrameOval( &S );
X MoveTo( 3, 7 ); LineTo( 4, 8 ); /* ...risking the taste-police */
X LineTo( 7, 8 ); LineTo( 8, 7 );
X MoveTo( 4, 4 ); LineTo( 4, 4 );
X MoveTo( 7, 4 ); LineTo( 7, 4 );
X
X SetPortBits( &fm ); /* prepare to draw fast ball */
X InvertOval( &S );
X
X#ifdef SMOOTH
X /*
X * bitmap for combined drawings...
X */
X dm.baseAddr = dbits;
X dm.rowBytes = 2*((SDIM+SDIM+15)/16);
X dm.bounds.a.top = 0;
X dm.bounds.a.bottom = 2*SDIM;
X dm.bounds.a.left = 0;
X dm.bounds.a.right = 2*SDIM;
X#endif
X}
________This_Is_The_END________
if test `wc -l < movebits.c` -ne 174; then
echo 'shar: movebits.c was damaged during transit'
echo ' (should have been 174 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting phys.c'
if test -f phys.c; then echo 'shar: will not overwrite phys.c'; else
sed 's/^X//' << '________This_Is_The_END________' > phys.c
X/*
X * do collisions and movement
X */
X
X#include "ball.h"
X
Xextern wide, tall; /* the size of the box we are in */
Xextern GateState; /* != 0 iff gate is open */
X
X#define TWO(X) ((X)+(X))
X#define THREE(X) (TWO(X)+(X))
X
X/*
X * bbump() deals with a possible collision between two specific balls.
X * The first ball will not be to the right of the second ball. Returns
X * one if the second ball is far enough to the right so that no balls
X * farther right could collide with the first ball, else returns zero
X */
Xbbump( pA, pB )
X register ball *pA, *pB;
X{
X register long k;
X long tAvx, tAvy;
X register long tBx, tBy;
X long tBvx, tBvy;
X long WIDE, TALL;
X
X WIDE = wide<<2; /* scale from window to physical co-ords */
X TALL = tall<<2;
X
X /*
X * Deal with the barrier and the gate
X */
X if ( TWO(pA->x) <= WIDE && TWO(pB->x) >= WIDE )
X /* gate closed means no collision */
X if ( ! GateState )
X return 0;
X else
X /* if either ball is below gate, no collision */
X if ( THREE(pA->y) < TALL || THREE(pB->y) < TALL )
X return 0;
X else
X /* if either ball is above gate, no collision */
X if ( THREE(pA->y) > TWO(TALL) || THREE(pB->y) > TWO(TALL) )
X return 0;
X
X /* shift to A's co-ordinate system */
X tBx = pB->x - pA->x;
X tBy = pB->y - pA->y;
X tBvx = pB->vx - pA->vx; tAvx = 0;
X tBvy = pB->vy - pA->vy; tAvy = 0;
X
X /*
X * see if the balls are close enough to have collided
X */
X if ( tBx > TWO(CRAD) )
X return 1;
X if ( tBx * tBx + tBy * tBy > (CRAD*CRAD<<2) )
X return 0;
X
X k = tBx * tBvx + tBy * tBvy;
X
X /*
X * make sure they are going towards each other
X */
X if ( k > -1 )
X return 0;
X
X k = ( tBy * tBvx - tBx * tBvy ) / k;
X
X tAvx = ( tBvx - k * tBvy ) / ( 1 + k*k );
X tAvy = ( k * tBvx + tBvy ) / ( 1 + k*k );
X
X tBvx = k * tAvy;
X tBvy = -k * tAvx;
X
X pB->vx = pA->vx + tBvx;
X pB->vy = pA->vy + tBvy;
X pA->vx += tAvx;
X pA->vy += tAvy;
X
X return 0;
X}
X
X/*
X * Because the calculations above use longs instead of floats, we have a
X * lot of round off error. This seems to manifest itself by causing the
X * balls to slow down over time. We use the walls to correct this.
X *
X * If "we" is greater than zero, we are attempting to add energy to the
X * system. We do this by looking for slow balls bouncing off the right
X * wall. When we find such a ball, we give it a swift kick towards the
X * left.
X *
X * If "we" is less than zero, then we are trying to remove energt from
X * the system for some reason. In this case, the outer walls become
X * slightly sticky, with the ball slowing down by abs(we) perpendicular
X * to the wall.
X *
X * This stuff is done in wbump().
X *
X */
X
Xstatic int we = 0; /* wall energy factor */
X
Xwalls( i ) {
X we = i;
X}
X
X/*
X * wump() checks for collisions between a ball walls or the gate
X */
Xwbump( pA )
X register ball *pA;
X{
X register long WIDE, TALL;
X
X WIDE = wide<<2; TALL = tall<<2;
X
X if ( (pA->x <= CRAD && pA->vx < 0)
X || (pA->x >= WIDE-CRAD && pA->vx > 0) ) {
X pA->vx = -pA->vx;
X if ( we > 0 ) {
X if ( pA->vx < 0 && pA->pict == 0 && pA->x >= WIDE-CRAD)
X pA->vx -= 30; /* swift kick */
X } else {
X if ( pA->vx > 0 )
X pA->vx += we;
X else
X pA->vx -= we;
X }
X }
X if ( (pA->y <= CRAD && pA->vy < 0)
X || (pA->y >= TALL-CRAD && pA->vy > 0) ) {
X pA->vy = -pA->vy;
X if ( we < 0 ) {
X if ( pA->vy > 0 )
X pA->vy += we;
X else
X pA->vy -= we;
X }
X
X }
X
X /*
X * if the ball is on the same level as the gate, and the gate is open,
X * there is nothing for the ball to hit on the barrier
X */
X if ( TALL < THREE(pA->y) && THREE(pA->y) < TWO(TALL) && GateState )
X return;
X
X WIDE >>= 1; /* location of the barrier */
X
X /*
X * see if the ball hits the barrier
X */
X if ( pA->x <= WIDE && pA->vx > 0 ) {
X if ( pA->x + CRAD >= WIDE || pA->x + pA->vx > WIDE )
X pA->vx = -pA->vx;
X } else
X if ( pA->x >= WIDE && pA->vx < 0 )
X if ( pA->x - CRAD <= WIDE || pA->x + pA->vx < WIDE )
X pA->vx = -pA->vx;
X}
X
Xmball( pA )
X ball *pA;
X{
X register long vx, vy;
X pA->x += vx = pA->vx;
X pA->y += vy = pA->vy;
X
X /*
X * check for stalled balls, and offer them a chance to get going again
X */
X if ( vx == 0 && vy == 0 ) {
X if ( Random() > 0 )
X pA->vx = Random() > 0 ? 1 : -1;
X if ( Random() > 0 )
X pA->vy = Random() > 0 ? 1 : -1;
X }
X}
________This_Is_The_END________
if test `wc -l < phys.c` -ne 182; then
echo 'shar: phys.c was damaged during transit'
echo ' (should have been 182 bytes)'
fi
fi ; : end of overwriting check
exit 0