home *** CD-ROM | disk | FTP | other *** search
- /* This is Yet Another Boing, "YaBoing." A (game) program for the Amiga.
-
- By Ali T. Ozer (Ali@score.stanford.edu), Sep 21, 1986
-
- This game owes a lot to Leo L. Schwab's "Oing!," where little sprite
- versions of the famous "Boing!" demo ball bounced around your screen...
- This program demonstrates some hardware sprite stuff, collisions, colors,
- etc...
-
- Try to get the red balls with your mouse (+1) while avoiding the
- green ones (-1). Your score is displayed after 100 red balls have been
- thrown to the screen and the game restarts.
-
- The game can be interrupted at any point by just deactivating the
- window. The sprites disappear, and you can do whatever you want. To con-
- tinue, simply click in the YaBoing window, and voila, you're back in your
- game where you left it. YaBoing is a great game to have running in the
- background as you compile or do other time consuming things. Note
- that YaBoing does not start automatically --- You have to click
- on the window to get it running... This allows you to start it up from
- your startup sequence, for example!
-
- The game sets its priority to -1, so it should not steal many CPU cycles
- from other processes. It also uses only 10K memory + whatever your
- stack size is. Thus you can afford to have it in the background and
- come back to it from time to time. Of course, if your other processes
- grap the cpu, then YaBoing will suffer. But, hey, it just makes the game
- more random! You can set the priority yourself by specifying the
- priority (-128..+127) as the argument to the "yaboing" command.
-
- I compiled YaBoing! with Manx 3.20a, without the +l option. Haven't
- tried it with Lattice.
-
- -Ali Ozer
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <intuition/intuition.h>
- #include <graphics/sprite.h>
- #include <hardware/custom.h>
-
- /* The ball image... Note that in YaBoing the balls do not rotate as */
- /* nicely as in Boing! or Oing!. The rotation is just obtained by rotating */
- /* the 3 colors available for sprites, and that doesn't provide for very */
- /* smooth movement... */
-
- UWORD ballimage[] = {
- 0x0660, 0x0780,
- 0x1FF8, 0x1960,
- 0x399C, 0x2778,
- 0x6666, 0x1DDE,
- 0x4E72, 0x3DCE,
- 0xDE7B, 0x39E7,
- 0x39E7, 0xE79C,
- 0x79E7, 0xE79E,
- 0x79E7, 0xE79E,
- 0x39E7, 0xE79C,
- 0xDE7B, 0x39E7,
- 0x4E72, 0x3DCE,
- 0x6666, 0x1DDE,
- 0x399C, 0x2778,
- 0x1FF8, 0x1960,
- 0x0660, 0x0780
- };
-
- #define DEFPRIORITY -1
-
- /* Pointer to base of custom registers. Note that you're supposed to */
- /* be able to simply do "extern struct Custom custom" too... */
-
- struct Custom *cstm = 0xdff000;
-
- /* Collision bits in register CLXDAT. The three bits below correspond */
- /* to collisions between sprite 0 (the mouse) and sprites 2, 4, and 6, */
- /* respectively. */
-
- UWORD colmask[3] = {0x0200, 0x0400, 0x0800};
-
- /* The number of "red/white" sprites that get thrown to the screen */
- /* during the game. This is effectively the max score you can get. */
-
- #define MAXSPRITES 100
-
- /* Various sprite info. Note that in the sides we let the sprite */
- /* disappear completely before it's considered out of bounds while */
- /* at top of the screen we detect as soon as we reach the top line of the */
- /* screen (so we can "bounce" the ball back). */
-
- #define SPRHEIGHT 16
- #define XMAX 640
- #define YMAX 200
- #define XMIN -16
- #define YMIN 0
-
- /* Sprite modes. */
-
- #define SPRITEINACTIVE 0
- #define SPRITEACTIVE 1
- #define SPRITEHIT 2
-
- void *OpenLibrary(), *OpenWindow(), *AllocMem(), *ViewPortAddress();
- long GetSprite(), VBeamPos();
-
- /* The window. Note that the window is really not good for much, except */
- /* for showing the score on its title bar and letting the user activate/ */
- /* deactivate the window (to stop/continue the game). */
-
- struct NewWindow newwindow = {
- 400, 15, 200, 10, -1, -1,
- CLOSEWINDOW | ACTIVEWINDOW | INACTIVEWINDOW,
- WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG | ACTIVEWINDOW | INACTIVEWINDOW,
- NULL, NULL,
- (UBYTE *) "YaBoing!",
- NULL, NULL, 0, 0, 0, 0,
- WBENCHSCREEN
- };
-
- /* The score, sent to the title bar of the window... */
-
- UBYTE scorestr[11];
-
- /* Number of sprites. Of course it's rather silly having a constant for */
- /* this, as parts of the program depend on the fact that there are */
- /* 3 sprites, corresponding to hardware sprites 2, 4, and 6... Oh well! */
-
- #define NUMSPR 3
-
- struct Window *win;
- struct ViewPort *vp;
-
- /* The info we have about a sprite. */
- /* vx, vy are velocity, ax, ay are acceleration, px, py are */
- /* position, mode is current status (sprite is moving, dead, etc), */
- /* and code is a value dependant on the value of mode (how long */
- /* it's been dead, moving, etc...). */
-
- struct sprrec {
- struct SimpleSprite actspr;
- int vx, vy, ax, ay, px, py, mode, code;
- } spr[NUMSPR];
-
- /* For modding by 3, we do a table lookup. (Idea taken from Leo */
- /* Schwab's idx[] in "Oing!"). */
-
- int mod3[] = {0, 1, 2, 0, 1, 2};
-
- /* Coloroffset and rotatecount determine where in the rotation we are */
- /* and how many cycles are left before we rotate. Score is pretty */
- /* obvious, and sprcnt is the number of red/white sprites sent to the */
- /* screen... */
-
- int coloroffset, rotatecount, score, sprcnt;
-
- /* ROTATECOUNT determines the number of cycles between a single */
- /* rotation of the ball (not a full rotation!) */
-
- #define ROTATECOUNT 10
-
- /* 3 second (150 tick) delay between games */
-
- #define NEWGAMEDELAY 150L
-
- /* When the user deactivates the window, the sprites are deactivated */
- /* and the games stops until user activates the window again. */
-
- int spritesactive;
-
- void *GfxBase, *IntuitionBase;
-
- /* Pointer to the base of the CHIP memory obtained for the sprites... */
-
- UWORD *sprbuf;
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- register int cnt;
- register struct sprrec *tmpspr;
- int i, dir; /* During sprite creation, direction it enters from */
- UWORD clxdat; /* Value of collision register */
- ULONG msgclass; /* Message class from Intuition message */
- struct IntuiMessage *msg, *GetMsg();
- struct Task *thistask, *FindTask ();
-
- /* First set the priority of this task. */
-
- if (thistask = FindTask (NULL)) {
- if (argc < 2 || (cnt = atoi (argv[1])) < -128 || cnt > 127)
- cnt = DEFPRIORITY;
- SetTaskPri (thistask, (long)cnt);
- }
-
- OpenStuff ();
-
- InitSprites ();
-
- /* Detect collisions between sprite 0 and sprites 2, 4, 6 */
-
- cstm->clxcon = 0xF000;
-
- sprcnt = 0; score = 0;
-
- while (1) {
-
- /* If the game has ended, the simply display the score and wait */
- /* for a message... */
-
- if (sprcnt >= MAXSPRITES) {
- ChgSpriteHeight (0);
- for (cnt = 0; cnt < NUMSPR; cnt++) spr[cnt].mode = SPRITEINACTIVE;
- ShowScore ();
- Delay (NEWGAMEDELAY);
- sprcnt = 0; score = 0;
- }
-
- while (msg = GetMsg (win->UserPort)) {
- msgclass = msg->Class;
- ReplyMsg (msg);
- switch (msgclass) {
- case CLOSEWINDOW: CloseStuff (0);
- case ACTIVEWINDOW:
- if (!spritesactive) ChgSpriteHeight (SPRHEIGHT);
- spritesactive = TRUE;
- break;
- case INACTIVEWINDOW:
- if (spritesactive) ChgSpriteHeight (0);
- spritesactive = FALSE;
- break;
- default: ;
- }
- }
-
- if (!spritesactive) Wait (1L << win->UserPort->mp_SigBit);
-
- else {
-
- for (cnt = 0; cnt < NUMSPR; cnt++) {
-
- tmpspr = &spr[cnt];
-
- switch (tmpspr->mode) {
-
- case SPRITEINACTIVE:
- if (tmpspr->code++ > 0 && sprcnt < MAXSPRITES) {
- if (cnt < 2) sprcnt++; /* One more sprite gone... */
- dir = (RndNum(2) ? 1 : -1);
- tmpspr->mode = SPRITEACTIVE;
- tmpspr->code = 0;
- tmpspr->vx = dir * (10 + RndNum (12) + 6 * (cnt != 0));
- tmpspr->vy = (3 - RndNum(7));
- tmpspr->ax = dir * (RndNum(6) - 2) * RndNum (2);
- tmpspr->ay = (-1 + RndNum(3)) * cnt;
- tmpspr->px = ((dir == 1) ? (XMIN + 1) : (XMAX - 1));
- tmpspr->py = ((tmpspr->vy > 0) ? 10 : 100) + RndNum(91);
- tmpspr->actspr.height = SPRHEIGHT;
- };
- break;
-
- case SPRITEHIT:
- if (--(tmpspr->code) == 0) { /* Sprite now inactive */
- tmpspr->actspr.height = 0;
- tmpspr->mode = SPRITEINACTIVE;
- tmpspr->code = - RndNum(20);
- DoColors ();
- } else
- SetRGB4 (vp, (long)(21 + (cnt << 2) + (tmpspr->code >> 3)),
- 0L, 0L, 0L); /* Black! (as the sprite dies...) */
- break;
-
- case SPRITEACTIVE:
- /* The following two lines depend on the fact that ">>" works */
- /* correctly on signed quantities here. */
- tmpspr->px += (tmpspr->vx >> 2);
- tmpspr->py += (tmpspr->vy >> 3);
- tmpspr->vx += tmpspr->ax;
- tmpspr->vy += tmpspr->ay;
- if (tmpspr->px < XMIN || tmpspr->px > XMAX ||
- tmpspr->py > YMAX) {
- tmpspr->actspr.height = 0;
- tmpspr->mode = SPRITEINACTIVE;
- tmpspr->code = - RndNum(20);
- DoColors ();
- } else if (tmpspr->py < YMIN) {
- tmpspr->py = 0;
- tmpspr->vy = (-tmpspr->vy) * (1 + RndNum(2));
- };
- switch (RndNum(128)) {
- case 0: tmpspr->ax = -(tmpspr->ax * (RndNum(2) + 1));
- case 1: tmpspr->ay = -tmpspr->ay; break;
- case 2: tmpspr->ay++;
- case 3: tmpspr->ax++; break;
- default: ;
- }
- break;
-
- default: ;
-
- }
-
- }
-
- for (cnt = 0; cnt < NUMSPR; cnt++)
- MoveSprite (vp, &(spr[cnt].actspr),
- (long)spr[cnt].px, (long)spr[cnt].py);
-
- clxdat = cstm->clxdat;
-
- for (cnt = 0; cnt < NUMSPR; cnt++)
- if ((clxdat & colmask[cnt]) && (spr[cnt].mode == SPRITEACTIVE)) {
- spr[cnt].mode = SPRITEHIT;
- spr[cnt].code = 24;
- if (cnt == 2) { /* Hit a negative one, set color to gray */
- score -= 1;
- for (i = 0; i < 3; i++)
- SetRGB4(vp, (long)(21 + (cnt << 2) + i), 10L, 10L, 10L);
- } else {
- score += 1;
- for (i = 0; i < 3; i++)
- SetRGB4(vp, (long)(21 + (cnt << 2) + i), 15L, 14L, 0L);
- }
- }
-
- WaitTOF ();
-
- if (--rotatecount < 0) {
- coloroffset = mod3[coloroffset + 1];
- DoColors ();
- rotatecount = ROTATECOUNT;
- }
-
- }
- }
- }
-
-
- ChgSpriteHeight (newheight)
- int newheight;
- {
- register int cnt;
-
- for (cnt = 0; cnt < NUMSPR; cnt++) {
- spr[cnt].actspr.height = newheight;
- ChangeSprite (vp, &(spr[cnt].actspr), spr[cnt].actspr.posctldata);
- }
- }
-
-
- OpenStuff ()
- {
- register int i;
-
- if (!(IntuitionBase = OpenLibrary ("intuition.library", 0)))
- CloseStuff (1);
- if (!(GfxBase = OpenLibrary ("graphics.library", 0)))
- CloseStuff (1);
- if (!(win = OpenWindow (&newwindow)))
- CloseStuff (1);
-
- vp = ViewPortAddress (win);
-
- spritesactive = FALSE;
- coloroffset = 0;
- rotatecount = ROTATECOUNT;
- }
-
- CloseStuff (exitcode)
- int exitcode;
- {
- register int cnt;
-
- for (cnt = 0; cnt < NUMSPR; cnt++)
- if (spr[cnt].actspr.num) FreeSprite ((long) spr[cnt].actspr.num);
- if (sprbuf)
- FreeMem (sprbuf, (long)((SPRHEIGHT * 2 + 2) * NUMSPR));
- if (win) CloseWindow (win);
- if (GfxBase) CloseLibrary (GfxBase);
- if (IntuitionBase) CloseLibrary (IntuitionBase);
- exit (exitcode);
- }
-
-
- /* This routine mostly from Leo Schwab. It obtains the actual hardware */
- /* sprites, and the chip memory to put the sprite images in, and the */
- /* copies the "ballimage" into the sprite area... */
-
- InitSprites ()
- {
- UWORD *cw, *curspr, *ball;
- int cnt, line;
-
- /* We use 3 sprites, 0..2, corresponding to system sprites 2,4,6 */
-
- if (!(sprbuf =
- AllocMem ((long)((SPRHEIGHT * 2 + 4) * NUMSPR * 2), MEMF_CHIP)))
- CloseStuff (1);
-
- cw = sprbuf;
-
- for (cnt = 0; cnt < NUMSPR; cnt++) {
- if (GetSprite (&(spr[cnt].actspr), (long) ((cnt << 1) + 2)) == -1)
- CloseStuff (1);
- spr[cnt].mode = SPRITEINACTIVE;
- spr[cnt].code = -ROTATECOUNT;
- spr[cnt].actspr.height = 0;
- ball = ballimage;
- curspr = cw;
- *cw++ = 0; *cw++ = 0;
- for (line = 0; line < SPRHEIGHT * 2; line++) *cw++ = *ball++;
- *cw++ = 0; *cw++ = 0;
- ChangeSprite (vp, &(spr[cnt].actspr), curspr);
- }
- }
-
- /* DoColors will rotate the colors for the 3 sprites. Rotation consists */
- /* of putting color 2 into 1, 3 into 2, and 1 into 3. The values are */
- /* hardwired below, so we don't actually go in and obtain the values */
- /* from the window... */
-
- DoColors ()
- {
- register int cnt, creg;
-
- for (cnt = 0; cnt < NUMSPR-1; cnt++)
- if (spr[cnt].mode != SPRITEHIT) {
- creg = 21 + (cnt << 2);
- SetRGB4 (vp, (long)(creg + coloroffset), 15L, 0L, 0L);
- SetRGB4 (vp, (long)(creg + mod3[coloroffset+1]), 15L, 1L, 1L);
- SetRGB4 (vp, (long)(creg + mod3[coloroffset+2]), 15L, 14L, 13L);
- }
- if (spr[2].mode != SPRITEHIT) {
- SetRGB4 (vp, (long)(29 + coloroffset), 2L, 12L, 0L);
- SetRGB4 (vp, (long)(29 + mod3[coloroffset+1]), 0L, 11L, 1L);
- SetRGB4 (vp, (long)(29 + mod3[coloroffset+2]), 15L, 14L, 13L);
- }
- }
-
- ShowScore ()
- {
- register UBYTE *loc = &scorestr[7];
-
- strcpy (scorestr, "SCORE: ");
- if (score < 0) {*loc++ = '-'; score = -score;};
- if (score > 99) *loc++ = (score / 100) + '0';
- if (score > 9) *loc++ = (score / 10) % 10 + '0';
- *loc++ = (score % 10) + '0';
- *loc = 0;
- SetWindowTitles (win, scorestr, -1L);
- DisplayBeep (NULL); /* You might want to get rid of this!!! */
- WindowToFront (win);
- }
-
- ULONG seed;
-
- /* Random number generator, translated into C from rnd.s */
- /* provided with Oing! Returns an integer 0..max-1. Don't know how */
- /* well it works, but the game seems random enough. */
-
- RndNum (max)
- UWORD max;
- {
- int result = (int)(seed % max);
- long datevec[3], *DateStamp();
-
- if (seed == 0L) {
- DateStamp (datevec);
- seed = (UWORD) (datevec[1] * datevec[2]);
- } else {
- if (seed > 0x80000000L) seed = ((seed << 1) ^ 0x1D872B41L);
- else seed <<= 1;
- }
-
- return (result);
- }
-
- /* YaBoing, by Ali T. Ozer */
-