home *** CD-ROM | disk | FTP | other *** search
- /* yb2.c (c)1988 Ali T. Ozer
- ** main() and tons of other stuff for YaBoing II.
- ** Freely distributable.
- */
-
- /* This is a second version of YaBoing!, "Yet Another Boing." Actually, this
- ** program started off with "I should fix YaBoing! up so that it'll run on
- ** morerows'ed or interlaced screens." But I got carried away --- This program
- ** has almost nothing to do with the original YaBoing! (except that the
- ** goal involves chasing sprites aroung with the mouse pointer).
- **
- ** YaBoing! originally written Sep 1986 and posted Sep 21, 1986.
- ** YaBoing II written Dec 1987.
- */
-
- /* YaBoing II is really a "stack-calculator" simulator where you have to
- ** hunt down the numbers to be input and the operators to be applied.
- **
- ** -The "calculator" has a 4-location stack. The window displays the four
- ** entries, with the bottom of the stack at the top (right under the title
- ** bar).
- ** -Inputs are one-digit only; when you catch a "number" sprite the value (0-9)
- ** is pushed to the stack.
- ** -If the stack overflows, you lose the bottom entries.
- ** -The operators "+", "-", "*", "/", pop the top two entries of the stack and
- ** push the result. If you push X and then Y, the result is X op Y
- ** (and not Y op X). If the stack has less than 2 entries, nothing happens.
- ** -The "POP" operator pushes the top element off the stack.
- ** -The "SWAP" operator swaps the top two elements.
- ** -The "?" is a mystery number greater than 9.
- ** -The stack locations hold 32-bit unsigned numbers. If "+" or "*" causes
- ** overflow, the result is simply truncated.
- ** -If subtraction causes a negative result, then the result is 0.
- ** -If you divide by ZERO, the system GURUs.
- ** -No, no, kidding. If you divide by ZERO the stack is cleared.
- **
- ** So what's the goal? To end up with the highest number on top of the stack
- ** at the end of the game. The game lasts about 40-45 seconds, and about
- ** five seconds before the end your mouse pointer changes shape to warn you.
- **
- ** The high score is (2^32) - 1. Good luck!
- **
- ** -Ali
- */
-
- /* Besides changes in the game-play, there are also some technical
- ** differences between YaBoing! and YaBoing II:
- **
- ** -Sprites are not bound to the WB screen --- when WB is pulled down, the
- ** sprites will remain displayed. On some screens the sprites might get
- ** splattered (depending on your preferences settings).
- ** -The valid sprite movement area is determined by looking at the user's
- ** screen parameters.
- ** -The Amiga timer device is used to time the sprite movement rather than
- ** just a counter. Thus sprites will move around at a somewhat constant rate
- ** (as opposed to slowing down when the load is high), although the movement
- ** might be rather jerky.
- ** -The game is deactivated when the window is made inactive (like in YaBoing!).
- ** to continue the game it's not enough to activate the window --- You need to
- ** click either mouse button anywhere within the window (not on a gadget).
- ** This allows you to depth-arrange and move the window without the sprites in
- ** the way.
- */
-
-
- /****************************************************************************/
-
- #include "yb2.h"
-
- /* The following declarations replace Manx's and save about 900 bytes. Don't
- ** worry about the linker's "multiply defined" complaints...
- */
- _wb_parse () {}
- _cli_parse () {}
-
- /* Collision bits in register CLXDAT. The three bits below correspond
- ** to collisions between sprite 0 (the mouse) and sprites 2, 4, and 6,
- ** respectively.
- */
- #define COL0AND2 0x0200
- #define COL0AND4 0x0400
- #define COL0AND6 0x0800
- #define COL2AND4 0x1000
- #define ALLCOL 0x1e00
-
- unsigned short colmasks[] = {COL0AND2, COL0AND4, COL0AND6};
-
- #define MAXVEL 24 /* Twice max velocity in pixels/move */
-
- /* Number of sprites. There are dependencies on the value of this, for
- ** instance, InitSprites asks for sprites by number, and if this number is
- ** changed, the mapping in InitSprites for yaboing sprite num -> HW sprite
- ** should be fixed also.
- */
- #define NUMSPR 3
- struct sprrec ybspr[NUMSPR];
-
- struct timerequest tr;
- struct Screen *scr; /* WorkBench screen, obtained from the window */
- struct Window *win; /* YaBoing window */
- struct ViewPort *vp; /* WorkBench ViewPort */
- struct RastPort *rp; /* YaBoing window rastport */
- struct Font *font; /* Topaz 8 --- We need 8-point font for text */
- struct GfxBase *GfxBase;
- struct IntuitionBase *IntuitionBase;
-
- int minx, miny, maxx, maxy, halfx, halfy, quartx, quarty; /* Screen params */
- int xshiftfactor, yshiftfactor; /* For conversion from screen to LORES */
- int mousex, mousey; /* Updated everytime through the loop, LORES-coords */
- int spritecount; /* Increments everytime a new sprite is generated. */
- unsigned long lastmove; /* The time at which sprites last moved */
- long oldtaskpri = 0;
- struct Task *me;
-
- #define MAXSPRITES 110 /* The number of sprites generated before game ends */
- #define WARNSPRITE 94 /* The number of sprites after which warning's given */
-
-
- /* Returns a value that increments every 1/16 second...
- */
- unsigned long TimeCount()
- {
- DoIO (&tr);
- return ((tr.tr_time.tv_secs << 4L) + (tr.tr_time.tv_micro / 62500L));
- }
-
-
- main ()
- {
- register int cnt;
- unsigned short clxdat; /* Value of collision register */
- int sleeping = true; /* True if game is inactive */
- struct IntuiMessage *msg; /* The intuition message, from our window port */
-
- /* First set the priority of this task. */
- if (me = FindTask (NULL)) oldtaskpri = SetTaskPri (me, 1L);
-
- OpenStuff ();
- InitRnd (); /* Start up the random number generator */
- InitMessage ();
-
- while (1) {
-
- while (msg = (struct IntuiMessage *)GetMsg (win->UserPort)) {
- switch (msg->Class) {
- case CLOSEWINDOW:
- ReplyMsg (msg);
- CloseStuff (0); /* Never returns */
- case MOUSEBUTTONS:
- if (msg->Code==SELECTDOWN || msg->Code==MENUDOWN)
- if (sleeping) {
- sleeping = false;
- if (spritecount == 0) NewGame ();
- ShowSprites (true);
- } else sleeping = true;
- default:
- ReplyMsg (msg);
- }
- }
-
- if (spritecount > MAXSPRITES) {
-
- SetWarnPointer (win, false);
- DisplayBeep (scr);
- ShowScore ();
- while (msg = (struct IntuiMessage *)GetMsg (win->UserPort))
- ReplyMsg (msg);
- sleeping = true;
- spritecount = 0;
- };
-
- if (sleeping) {
-
- ShowSprites (false);
- Wait (1L << win->UserPort->mp_SigBit);
-
-
- } else {
-
- mousex = LoResMouseX();
- mousey = LoResMouseY();
-
- for (cnt = 0; cnt < NUMSPR; cnt++) ProcessSprite (&ybspr[cnt]);
- lastmove = TimeCount ();
- for (cnt = 0; cnt < NUMSPR; cnt++) LocateSprite (&ybspr[cnt]);
-
- if ((clxdat = custom.clxdat) & ALLCOL) CheckCollisions(clxdat);
- else Delay (2L); /* Don't hog the CPU too much! */
-
- WaitTOF ();
- }
- }
- }
-
- /* Mouse coords in LORES (same kind of values as sprite locations)
- */
- int LoResMouseX () { return ((scr->MouseX + vp->DxOffset) >> xshiftfactor); }
- int LoResMouseY () { return ((scr->MouseY + vp->DyOffset) >> yshiftfactor); }
-
- /* Panic puts up a requester with a single "Sigh..." box. The string
- ** provided in "reason" is printed in the body of the requester.
- ** If user hits "Retry," then Panic returns. Else it exits.
- */
- Panic (reason)
- UBYTE *reason;
- {
- static struct IntuiText negtxt = {0,1,COMPLEMENT,4,4,NULL,(UBYTE *)"Sigh...",NULL};
- static struct IntuiText bodytxt = {0,1,COMPLEMENT,10,6,NULL,NULL,NULL};
-
- bodytxt.IText = reason;
- if (AutoRequest (NULL, &bodytxt, NULL, &negtxt, 0L, 0L, 300L, 54L)) return;
- CloseStuff (5);
- }
-
- CloseStuff (exitcode)
- int exitcode;
- {
- register int cnt;
-
- for (cnt = 0; cnt < NUMSPR; cnt++) ReleaseSprite (&ybspr[cnt]);
-
- if (tr.tr_node.io_Message.mn_Node.ln_Type == NT_MESSAGE) CloseDevice (&tr);
- if (font) CloseFont (font);
- if (win) CloseWindow (win);
- if (GfxBase) CloseLibrary (GfxBase);
- if (IntuitionBase) CloseLibrary (IntuitionBase);
- if (me) SetTaskPri (me, oldtaskpri);
- exit (exitcode);
- }
-
- OpenStuff ()
- {
- unsigned short sprcol; /* Used when setting */
- long creg; /* sprite colors... */
-
- static struct NewWindow ybwindow = {
- WINDOWX, WINDOWY, WINDOWWIDTH, WINDOWHEIGHT, -1, -1,
- CLOSEWINDOW | MOUSEBUTTONS,
- SMART_REFRESH | WINDOWCLOSE | WINDOWDEPTH | ACTIVATE |
- WINDOWDRAG | NOCAREREFRESH | RMBTRAP,
- NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
- };
-
- static struct TextAttr ybfontdesc = {(STRPTR)"topaz.font", 8, 0, 0};
-
- if (((IntuitionBase = (struct IntuitionBase *)
- OpenLibrary ("intuition.library", 0L)) == NULL) ||
- ((GfxBase = (struct GfxBase *)
- OpenLibrary ("graphics.library", 0L)) == NULL) ||
- ((font = OpenFont (&ybfontdesc)) == NULL)) CloseStuff (10); /* ROM? */
-
- if (OpenDevice(TIMERNAME, UNIT_VBLANK, &tr, 0L) != 0) Panic ("No timer");
- tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
- tr.tr_node.io_Command = TR_GETSYSTIME;
-
- if (InitSprites () == false) Panic ("No sprites!");
- if ((win = OpenWindow (&ybwindow)) == NULL) Panic ("No memory");
-
- /* Get the various stuff we want to access often into global variables. */
- scr = win->WScreen;
- vp = (struct ViewPort *)ViewPortAddress (win);
- rp = win->RPort;
-
- sprcol = GetRGB4 (vp->ColorMap, 0L) + 0x0888;
-
- for (creg = 20L; creg < 32L; creg += 2L) {
- SetRGB4 (vp, creg, 0L, 0L, 0L);
- SetRGB4 (vp, creg+1, (long)((sprcol & 0x0f00) >> 8),
- (long)((sprcol & 0x00f0) >> 4),
- (long)(sprcol & 0x000f));
- }
-
- SetAPen (rp, 1L);
- SetBPen (rp, 0L);
- SetFont (rp, font);
- RectFill (rp, 0L, 10L, WINDOWWIDTH-1L, WINDOWHEIGHT-1L);
- SetDrMd (rp, JAM2 | INVERSVID);
- SetWindowTitles (win, "YaBoing II", COPYRIGHT);
-
- if (vp->Modes & HIRES) xshiftfactor = 1; else xshiftfactor = 0;
- if (vp->Modes & LACE) yshiftfactor = 1; else yshiftfactor = 0;
-
- quartx = (halfx = (maxx = vp->DWidth >> xshiftfactor) >> 1) >> 1;
- quarty = (halfy = (maxy = vp->DHeight >> yshiftfactor) >> 1) >> 1;
- minx = -8; miny = -10; maxx += minx; maxy += miny;
- /* Minx, miny, maxx, maxy determine the box in which the sprites roam. */
- }
-
- /* NewGame initializes everything necessary for a new game.
- */
- NewGame ()
- {
- int cnt;
- long creg;
-
- for (cnt = 0; cnt < NUMSPR; cnt++) ybspr[cnt].mode = SPRITEDEAD;
-
- ClearStack ();
- spritecount = 1;
- }
-
-
- /* CheckCollisions is called when a collision is detected. CheckCollisions
- ** checks to see who collided with whom and takes action accordingly...
- */
- CheckCollisions (clxdat)
- unsigned short clxdat; /* Sprite collision register image */
- {
- int cnt;
-
- /* First check collision of the two "number" sprites (sprites 2 and 4) */
- if ((clxdat & COL2AND4) &&
- (ybspr[0].mode==SPRITEALIVE) && (ybspr[1].mode==SPRITEALIVE))
- ybspr[0].mode = ybspr[1].mode = SPRITEHIT1; /* Mark them as collided */
-
- /* Now check collisions between the mouse and the 3 sprites */
- for (cnt = 0; cnt < NUMSPR; cnt++)
- if ((clxdat & colmasks[cnt]) && (ybspr[cnt].mode==SPRITEALIVE)) {
- ybspr[cnt].mode = SPRITEHIT1;
- ProcessHit (&ybspr[cnt]);
- }
- }
-
-
- /* Locate sprite will move a sprite to its new location if it's not dead.
- */
- LocateSprite (spr)
- struct sprrec *spr;
- {
- if (MODE != SPRITEDEAD)
- MoveSprite (NULL, &(spr->actualsprite), (long)PX, (long)PY);
- }
-
- /* The "dissolvemasks" array determines how the sprites disappear when they die.
- */
- #define MAXDISSOLVEMASKS 7
- unsigned short dissolvemasks[MAXDISSOLVEMASKS] = {
- 0xeffb,0xeffb,0xef7b,0xcb6b,0xc94a,0x2108,0x0100
- };
-
- ProcessSprite (spr)
- struct sprrec *spr;
- {
- if (MODE != SPRITEDEAD) AdjustSprite (spr);
-
- switch (MODE) {
- case SPRITEALIVE: ChangeNumValue (spr); break;
- case SPRITEHIT1:
- VAL = AX = AY = 0;
- VX >>= 1; VY >>= 1;
- MODE = SPRITEHIT2; /* Fall through */
- case SPRITEHIT2:
- DissolveSprite (SPRMEM, dissolvemasks[VAL++]);
- if (VAL == MAXDISSOLVEMASKS) MODE = SPRITEDEAD;
- break;
- case SPRITEDEAD:
- ShowSprite (spr, false);
- if (Rnd(5) == 0) EnterSprite (spr);
- break;
- }
- }
-
- /* Given a sprite, this routine increases or decreases its value. For numbers,
- ** new value depends on the distance between the sprite and the mouse. For
- ** operator sprites, the value is incremented regularly.
- */
- ChangeNumValue (spr)
- struct sprrec *spr;
- {
- int origval = VAL;
- unsigned long newtc = TimeCount();
-
- if (newtc > CHANGE) {
- if (TYPE == OPSPRITE) {
- CHANGE = newtc + 14; /* Change OPs every ~.9 seconds */
- if (Rnd(40) == 0) VAL = OPVALUE+OPVALUES-1;
- else if ((++VAL) >= OPVALUE+OPVALUES-1) VAL = OPVALUE;
- } else {
- CHANGE == newtc + 5; /* And numbers 16/5 times a second */
- if ((VAL > Rnd(8)) && (PX-mousex < quartx) && (PX-mousex > -quartx) &&
- (PY-mousey < quarty) && (PY-mousey > -quarty)) VAL--;
- else if (VAL < Rnd(10)) VAL += Rnd(3) - (VAL == DIGITVALUE ? 0 : 1);
- }
- if (origval != VAL) LoadSpriteImage (spr->sprmem, VAL);
- }
- }
-
-
- /* This routine moves a sprite and adjusts its velocity and acceleration.
- ** It also checks to see if the sprite is out of bounds --- If it is, the
- ** sprite is made inactive.
- ** Delta is the change in time in 1/8 sec since last move.
- */
- AdjustSprite (spr)
- struct sprrec *spr;
- {
- int delta = (TimeCount() - lastmove + 1);
- if (delta > 32 || delta < 0) delta = 32;
-
- /* Below we update the sprite positions and change the velocities.
- ** We make sure we remain within the speed limit (MAXVEL).
- */
- PX += (VX >> 1) * delta; /* Important that ">>" works */
- PY += (VY >> 1) * delta; /* OK on signed quantities! */
- VX += AX; if (VX > MAXVEL || VX < -MAXVEL) {AX = 0; VX >>= 1;};
- VY += AY; if (VY > MAXVEL || VY < -MAXVEL) {AY = 0; VY >>= 1;};
-
- if (PX < minx || PX > maxx || PY < miny || PY > maxy) {
- MODE = SPRITEDEAD; ShowSprite (spr, false); /* Out of bounds! Kill it! */
- } else switch (Rnd(150)) { /* Randomly change stuff. */
- case 0: AX += (Rnd(5) - 2); AY += (Rnd(5) - 2); break;
- case 1: VX = (VX > halfx ? -MAXVEL : MAXVEL); AX = AY = 0; break;
- case 2: VX = -VX; break;
- case 3: VY = -VY; break;
- case 4: VX = -VX; AX = -AX; break;
- case 5: VY = -VY; AY = -AY; break;
- default: if (Rnd(7) == 0 && TYPE != OPSPRITE) { /* Move away from mouse */
- if (mousex > PX) AX = -Rnd(4); else AX = Rnd(4);
- if (mousey > PY) AY = -Rnd(4); else AY = Rnd(4);
- }; break;
- };
- }
-
- /* Determines where a sprites comes into the screen from and sets the
- ** various parameters (velocity, acceleration, & position) accordingly...
- */
- EnterSprite (spr)
- struct sprrec *spr;
- {
- int v = Rnd(5)+4;
- int vo = Rnd(5)-2;
- int a = (TYPE == OPSPRITE ? 0 : Rnd(3));
-
- switch (Rnd(4)) {
- case 0: VX=v; AX=a; AY=0; VY=vo; PX=minx+1; PY=Rnd(halfy)+quarty; break;
- case 1: VX=-v; AX=-a; AY=0; VY=vo; PX=maxx-1; PY=Rnd(halfy)+quarty; break;
- case 2: VY=v; AY=a; AX=0; VX=vo; PY=miny+1; PX=Rnd(halfx)+quartx; break;
- case 3: VY=-v; AY=-a; AX=0; VX=vo; PY=maxy-1; PX=Rnd(halfx)+quartx; break;
- }
-
- if (TYPE == NUMSPRITE) VAL = Rnd(DIGITVALUES) + DIGITVALUE;
- else VAL = Rnd(OPVALUES) + OPVALUE;
-
- CHANGE = TimeCount();
-
- LoadSpriteImage (SPRMEM, VAL);
- ShowSprite (spr, true);
- MODE = SPRITEALIVE;
-
- if (++spritecount == WARNSPRITE) SetWarnPointer (win, true);
- }
-
-
- /* ShowSprites disables/enables all sprites. Used when the user deactivates
- ** the YaBoing window.
- */
- ShowSprites (show)
- int show;
- {
- int cnt;
- for (cnt = 0; cnt < NUMSPR; cnt++)
- if (show == false || ybspr[cnt].mode != SPRITEDEAD)
- ShowSprite (&ybspr[cnt], show);
- }
-
-
- /* InitSprites attempts to obtain the sprites we need. If unsuccessful, gives
- ** up in shame.
- */
- int InitSprites ()
- {
- int cnt;
- for (cnt = 0; cnt < NUMSPR; cnt++) {
- ybspr[cnt].actualsprite.height = 0;
- ybspr[cnt].type = (cnt == NUMSPR-1 ? OPSPRITE : NUMSPRITE);
- if (InitSprite(&ybspr[cnt],cnt+cnt+2) == false) return (false);
- };
- return (true);
- }
-
-
- static unsigned long rndseed;
-
- InitRnd ()
- {
- rndseed = TimeCount();
- }
-
-
- /* Returns random integer between 0 and max-1 inclusive.
- */
- int Rnd (max)
- int max;
- {
- long res = (rndseed & 0x00000002L) | (rndseed & 0x00000010L);
- rndseed >>= 1;
- if (res == 0x00000012 || res == 0x00000000) rndseed |= 0x80000000L;
- return (((int)((rndseed & 0x00007fffL) % max)));
- }
-
-
- /* YaBoing The Next Generation, by Ali T. Ozer */
-
-
-
-