[comp.sources.amiga] YaBoingII

ain@j.cc.purdue.edu (Patrick White) (01/04/88)

Program Name:	YaBoingII  (part 1 of 1)
Submitted By:	Ali Ozer <ali@navajo.stanford.edu>
Summary:	A game -- catch the numbers and operators zipping across
		the screen to "calculate" a score.
Poster Boy:  Pat White  (ain@j.cc.purdue.edu)
Tested.

NOTES:
   Binaries posted to comp.binaries.amiga.
   I reshared it so I could separate the sources and binaries, and so I
could include an alternate makefile.


-- Pat White   (co-moderator comp.sources/binaries.amiga)
UUCP: j.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM   PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906

----------------------------------------

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	YaBoingII.doc
#	makefile
#	Makefile.pat
#	yb2.h
#	yb2.c
#	ybcalc.c
#	ybspr.c
# This archive created: Mon Jan  4 09:59:13 1988
# By:	Patrick White (PUCC Land, USA)
echo shar: extracting YaBoingII.doc '(2319 characters)'
cat << \SHAR_EOF > YaBoingII.doc
YaBoing II, by Ali T. Ozer 
--------------------------------------------------------
USMail: Box 7703, Stanford, CA 94309
ARPA:   Ali@score.stanford.edu
--------------------------------------------------------
YaBoing II is freely distributable and not for sale.
--------------------------------------------------------
This is a second version of the small WorkBench game 
YaBoing!,"Yet Another Boing." Except for the use of
sprites and general silliness, YaBoing II is much
different that YaBoing!.

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 entry.
-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, the operator
 is ignored and nothing happens.
-The "POP" operator pushes the top element off.
-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, you get 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 of the game? To end up with the
highest number on top of the stack at the end of the
game. When the game ends the rest of the stack is 
discarded. The game lasts about 40-45 seconds, and
about five seconds before the end your mouse pointer
changes shape to warn you (so that you can make sure
you have your best number at the top of the stack...).

When the game ends the current score and the best so
far are displayed. To play another game, simply click
the right mouse button. YaBoing II can also be 
deactivated at any time with a right mouse click.
(Left mouse will also work, but then you need to click
on the YaBoing II window itself.)

The high score is (2^32) - 1. Good luck! 
SHAR_EOF
if test 2319 -ne "`wc -c YaBoingII.doc`"
then
echo shar: error transmitting YaBoingII.doc '(should have been 2319 characters)'
fi
echo shar: extracting makefile '(353 characters)'
cat << \SHAR_EOF > makefile
YaBoingII : yb2.o ybspr.o ybcalc.o
            ln -o YaBoingII +Q +cd yb2.o ybspr.o ybcalc.o -lc

yb2.o : yb2.c yb2.pre
        cc -o yb2.o +Iyb2.pre yb2.c

ybcalc.o : ybcalc.c yb2.pre
           cc -o ram:ybcalc.o +Iyb2.pre ybcalc.c

ybspr.o : ybspr.c yb2.pre
          cc -o ram:ybspr.o +Iyb2.pre ybspr.c

yb2.pre : yb2.h
          cc +Hyb2.pre yb2.h
SHAR_EOF
if test 353 -ne "`wc -c makefile`"
then
echo shar: error transmitting makefile '(should have been 353 characters)'
fi
echo shar: extracting Makefile.pat '(411 characters)'
cat << \SHAR_EOF > Makefile.pat
# This is the makefile I used.  It is a little less memory/disk intensive
# and gets the job done just as quick (not to mention it works)
#    Pat White (1/4/88)
#
YaBoingII : yb2.o ybspr.o ybcalc.o
            ln -o YaBoingII +Q +cd yb2.o ybspr.o ybcalc.o -lc

yb2.o : yb2.c
        cc -o yb2.o yb2.c

ybcalc.o : ybcalc.c 
           cc -o ybcalc.o ybcalc.c

ybspr.o : ybspr.c 
          cc -o ybspr.o ybspr.c
SHAR_EOF
if test 411 -ne "`wc -c Makefile.pat`"
then
echo shar: error transmitting Makefile.pat '(should have been 411 characters)'
fi
echo shar: extracting yb2.h '(1825 characters)'
cat << \SHAR_EOF > yb2.h
/* yb2.h (c)1988 Ali T. Ozer
** The header file for YaBoing II.
** Freely distributable
*/

/* Tech Notes: 
** YaBoing II was developed with Manx 3.40b. 
** When linking, you'll get warnings about _wb_parse and _cli_parse being
** redefined. Please ignore these warnings. Also, make sure you link with
** the "+cd" option so that the static sprite images go into CHIP memory.
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/sprite.h>
#include <graphics/gfxbase.h>
#include <hardware/custom.h>
#include <functions.h>

#define true  1
#define false 0

#define COPYRIGHT "YaBoing II (C)1988 Ali T. Ozer  (Ali@score.stanford.edu)"

struct sprrec {
  struct SimpleSprite actualsprite;
  unsigned short *sprmem;    /* Pointer to chip memory reserved for image */
  int vx, vy, ax, ay, px, py, mode, value, type;
  unsigned long lastchange;  /* Time at which sprite last changed */
};

/* For convenience sake --- We usually use spr as sprrec pointer.
*/
#define PX      (spr->px)
#define PY      (spr->py)
#define AX      (spr->ax)
#define AY      (spr->ay)
#define VX      (spr->vx)
#define VY      (spr->vy)
#define VAL     (spr->value)
#define MODE    (spr->mode)
#define TYPE    (spr->type)
#define SPRMEM  (spr->sprmem)
#define CHANGE  (spr->lastchange)

/* Modes */
#define SPRITEALIVE 0
#define SPRITEHIT1  1
#define SPRITEHIT2  2
#define SPRITEDEAD  3

/* Types */
#define NUMSPRITE   1
#define OPSPRITE    2

/* Values */
#define DIGITVALUE  0
#define DIGITVALUES 10
#define OPVALUE     10
#define OPVALUES    7
#define OPADD 10
#define OPPOP 11
#define OPMUL 12
#define OPDIV 13
#define OPSWP 14
#define OPSUB 15
#define OPCHK 16

/* Default values for the YaBoing window.
*/
#define WINDOWX 25
#define WINDOWY 25
#define WINDOWWIDTH  168
#define WINDOWHEIGHT 54

SHAR_EOF
if test 1825 -ne "`wc -c yb2.h`"
then
echo shar: error transmitting yb2.h '(should have been 1825 characters)'
fi
echo shar: extracting yb2.c '(16906 characters)'
cat << \SHAR_EOF > yb2.c
/* 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 */



SHAR_EOF
if test 16906 -ne "`wc -c yb2.c`"
then
echo shar: error transmitting yb2.c '(should have been 16906 characters)'
fi
echo shar: extracting ybcalc.c '(3067 characters)'
cat << \SHAR_EOF > ybcalc.c
/* ybcalc.c (c)1988 Ali T. Ozer
** The "stack calculator" and window stuff for YaBoing II.
** Freely distributable.
*/

#include "yb2.h"

extern struct RastPort *rp;  /* The rastport of the YaBoing window */

#define STACKSIZE 4
unsigned long stack[STACKSIZE];
int sp; /* =0 when empty, =STACKSIZE when full */

long stacklocs[STACKSIZE] = {20L,30L,40L,50L};  /* Locations where we write */

unsigned long bestsofar = 0;

#define STRLEN 13
char str[STRLEN];


EraseStackLoc (s) int s; {WriteString (s, "             ", STRLEN);}


DrawStackLoc (s) int s;  {WriteNum (s, stack[s]);}


WriteNum (s, num)
int s;
unsigned long num;
{
  unsigned long mult = 1000000000;   /* 1 billion */
  int zeros = false, curdigit;
  char *tstr = str;
    
  while (mult) {
    curdigit = (int)((num / mult) % 10);
    if (curdigit || mult == 1) zeros = true;  /* End of leading zeros! */
    if (curdigit || zeros) *tstr++ = curdigit + '0'; else *tstr++ = ' ';
    if (mult == 1000000000 || mult == 1000000 || mult == 1000) {
      if (zeros) *tstr++ = ','; else *tstr++ = ' ';
    };
    mult /= 10;
  } 
  WriteString (s, str);       
}


InitMessage ()
{                  
  WriteString (0, " Click  here ");
  WriteString (1, "to start (and");
  WriteString (2, "stop) playing");
  WriteString (3, "--Good luck--");
}

WriteString (s, tstr)
int s;
char *tstr;
{
  Move (rp, 32L, stacklocs[s]); 
  Text (rp, tstr, (long)STRLEN);
}  

ClearStack ()
{
  int cnt;
  sp = 0;
  for (cnt = 0; cnt < STACKSIZE; cnt++) EraseStackLoc (cnt);
}

ShowScore ()
{
  unsigned long score = (sp ? stack[sp-1] : 0L);
  WriteString (0, "SCORE:       "); WriteNum (1, score);  
  WriteString (2, "PREV BEST:   "); WriteNum (3, bestsofar);
  if (score > bestsofar) bestsofar = score;
}

ProcessHit (spr)
struct sprrec *spr;
{
  int cnt; unsigned long tmp;

  if (TYPE == NUMSPRITE || VAL == OPCHK) {
    if (VAL == OPCHK) VAL = 10 + 2 * Rnd(11);
    if (sp == STACKSIZE) {
      for (cnt = 0; cnt < STACKSIZE-1; cnt++) stack[cnt] = stack[cnt+1];
      stack[STACKSIZE-1] = VAL;
      for (cnt = 0; cnt < STACKSIZE; cnt++) DrawStackLoc (cnt);
    } else {
      stack[sp] = (unsigned long)VAL;
      DrawStackLoc (sp++);
    };
    return;
  };

  /* Must be an OPSPRITE, an operator */
  
  if (VAL == OPPOP) {if (sp) EraseStackLoc (--sp);
  } else {
    if (sp < 2) return;
    switch (VAL) {
      case OPADD: stack[sp-2] += stack[sp-1]; break;
      case OPMUL: stack[sp-2] *= stack[sp-1]; break;
      case OPSUB: if (stack[sp-1] > stack[sp-2]) stack[sp-2] = 0;
                  else stack[sp-2] -= stack[sp-1]; 
                  break;
      case OPDIV: if (stack[sp-1] == 0) {ClearStack (); return;};
                  stack[sp-2] /= stack[sp-1]; break;
      case OPSWP: tmp = stack[sp-2]; 
                  stack[sp-2] = stack[sp-1];
                  stack[sp-1] = tmp;
		  DrawStackLoc (sp-2);
		  DrawStackLoc (sp-1);
                  return;
                  break;
      default: return;
    };
    DrawStackLoc (sp-2);
    EraseStackLoc (--sp);
  }
}

 
    
   
    
  
    
      
SHAR_EOF
if test 3067 -ne "`wc -c ybcalc.c`"
then
echo shar: error transmitting ybcalc.c '(should have been 3067 characters)'
fi
echo shar: extracting ybspr.c '(4665 characters)'
cat << \SHAR_EOF > ybspr.c
/* ybspr.c (c)1988 Ali T. Ozer
** Sprite stuff for YaBoing II
** Freely distributable.
*/

#include "yb2.h"

#define IMAGEHEIGHT 20

unsigned short sprimages[OPVALUE+OPVALUES][IMAGEHEIGHT] = {
{0x00e0,0x071c,0x0e0e,0x0e0e,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,
 0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x0e0e,0x0e0e,0x071c,0x00e0},
{0x0020,0x00e0,0x0fe0,0x0ce0,0x00e0,0x00e0,0x00e0,0x00e0,0x00e0,0x00e0,
 0x00e0,0x00e0,0x00e0,0x00e0,0x00e0,0x00e0,0x00e0,0x00e0,0x0ffe,0x0ffe},
{0x01e0,0x07fc,0x1c1e,0x1c1f,0x1e0f,0x1e0f,0x0c0f,0x000f,0x001e,0x001e,
 0x003c,0x0070,0x00e0,0x01c1,0x0181,0x0203,0x07ff,0x0fff,0x1ffe,0x1ffe},
{0x01e0,0x07fc,0x0e1e,0x0e1e,0x0e1e,0x0e1e,0x001e,0x003c,0x0078,0x01f8,
 0x001e,0x001f,0x000f,0x000f,0x1c0f,0x1e0f,0x1e1f,0x1c1e,0x0ffc,0x01e0},
{0x0018,0x0038,0x0078,0x0078,0x00b8,0x01b8,0x0338,0x0638,0x0438,0x0838,
 0x1838,0x3038,0x6038,0x7fff,0x0078,0x0078,0x0078,0x0078,0x03ff,0x03ff},
{0x0402,0x07fc,0x07fc,0x07f0,0x07c0,0x0400,0x0400,0x0400,0x07f8,0x041e,
 0x000e,0x000f,0x000f,0x1c0f,0x1c0f,0x1c0f,0x180f,0x0c1e,0x07fc,0x01e0},
{0x0078,0x01fe,0x038e,0x070e,0x0e0e,0x1e00,0x1e00,0x1e00,0x1ef8,0x1f0e,
 0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x0e0f,0x070e,0x03fc,0x00f0},
{0x1fff,0x1fff,0x1ffe,0x1ffe,0x100c,0x3018,0x3030,0x0060,0x0060,0x00c0,
 0x00c0,0x01c0,0x01c0,0x01c0,0x01c0,0x03c0,0x03c0,0x03c0,0x03c0,0x0180},
{0x00f0,0x03fc,0x060e,0x0c06,0x0c06,0x0e06,0x0f8e,0x0fdc,0x07f0,0x03fc,
 0x07fe,0x0e3f,0x1c1f,0x1807,0x1803,0x1803,0x1c07,0x0e06,0x07fc,0x01f0},
{0x01e0,0x07f8,0x0f1c,0x1e0e,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,0x1e0f,
 0x0e1f,0x03ef,0x000f,0x000f,0x000f,0x0e0e,0x0e1e,0x0e3c,0x07f0,0x03e0},
/*** ADD ***/
{0x0000,0x0000,0x0000,0x0000,0x00e0,0x00e0,0x00e0,0x00e0,0x0ffe,0x0ffe,
 0x0ffe,0x00e0,0x00e0,0x00e0,0x00e0,0x0000,0x0000,0x0000,0x0000,0x0000},
/*** POP ***/
{0x0000,0x7e00,0x3300,0x3300,0x3300,0x3e00,0x31c0,0x3360,0x3630,0x7e30,
 0x0630,0x067e,0x0633,0x0373,0x01f3,0x003e,0x0030,0x0030,0x0030,0x0078},
/*** MUL ***/
{0x0000,0x0000,0x0000,0x0000,0x0000,0x030c,0x079e,0x03fc,0x01f8,0x00f0,
 0x01f8,0x03fc,0x079e,0x030c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
/*** DIV ***/
{0x0000,0x0000,0x0000,0x00e0,0x00e0,0x00e0,0x0000,0x0000,0x0ffe,0x0ffe,
 0x0ffe,0x0000,0x0000,0x00e0,0x00e0,0x00e0,0x0000,0x0000,0x0000,0x0000},
/*** SWP ***/
{0x3800,0x6def,0x60c6,0x3cc6,0x06c6,0x06d6,0x66d6,0x66d6,0x3c7c,0x006c,
 0x0c00,0x1e7e,0x3333,0x3333,0x3333,0x3f3e,0x3330,0x3330,0x7eb0,0x0078},
/*** SUB ***/
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0ffe,0x0ffe,
 0x0ffe,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
/*** Question Mark ***/
{0x00e0,0x03f8,0x061c,0x0f1e,0x0f1e,0x0f1e,0x001e,0x003c,0x0070,0x0060,
 0x00c0,0x00c0,0x00c0,0x00c0,0x0000,0x00c0,0x01e0,0x01e0,0x01e0,0x00c0} 
};

/* Assuming we have enough bytes in the sprite area...
** Loads specified image into the memory area provided.
*/
void LoadSpriteImage (sprmem, image)
unsigned short *sprmem;
int image;
{
  register int cnt;
  unsigned short *imem = sprimages[image];  
  sprmem += 2;
  for (cnt = 0; cnt < IMAGEHEIGHT; cnt++) {
    *sprmem++ = *imem << 1;
    *sprmem++ = *imem++;
  }
  *sprmem++ = 0;
  *sprmem++ = 0;
}

/* Applies the given mask to the image.
*/
void DissolveSprite (sprmem, dissolvemask)
unsigned short *sprmem, dissolvemask;
{
  register int cnt;
  sprmem += 2;
  for (cnt = 0; cnt < IMAGEHEIGHT+IMAGEHEIGHT; cnt++) *sprmem++ &= dissolvemask;
}

/* Obtains and initializes the specified sprite.
*/
int InitSprite (spr, sprnum)
struct sprrec *spr;
int sprnum;
{
  if ((GetSprite (&(spr->actualsprite), (long)sprnum) != -1) &&
      ((spr->sprmem = AllocMem ((long)((IMAGEHEIGHT*2+4)*2), MEMF_CHIP | MEMF_CLEAR)) != NULL))
    return (1);
  else return (0);
}

/* Gives the sprite back to the system.
*/
void ReleaseSprite (spr)
struct sprrec *spr;
{
  if (spr->actualsprite.num != -1) FreeSprite ((long)(spr->actualsprite.num));
  if (spr->sprmem != NULL) FreeMem (spr->sprmem, (long)((IMAGEHEIGHT*2+4)*2));
}

/* Makes the sprite visible/invisible...
*/
void ShowSprite (spr, show)
struct sprrec *spr;
int show;
{
  spr->actualsprite.height = (show ? IMAGEHEIGHT : 0);
  ChangeSprite (NULL, &(spr->actualsprite), spr->sprmem);
}


/* The following SHOULD go into CHIP RAM, so link with "+cd"
*/
unsigned short timepointer[] = {
  0x0000,0x0000,
  0x0000,0xffff,0x4800,0xffff,0x634c,0xffff,0x4aae,
  0xffff,0x4aa8,0xffff,0x2a26,0xffff,0x0000,0xffff,
  0x0000,0x0000
};

/* Changes the mouse pointer into the "time" pointer
*/
void SetWarnPointer (win, show)
struct Window *win;
int show;
{
  if (show) SetPointer (win, &timepointer[0], 7L, 16L, -7L, -3L);
  else ClearPointer (win);
}

    
SHAR_EOF
if test 4665 -ne "`wc -c ybspr.c`"
then
echo shar: error transmitting ybspr.c '(should have been 4665 characters)'
fi
#	End of shell archive
exit 0