#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/sprite.h>

#define REV      0L
#define FRAMES      6
#define SPRHEIGHT   16
#define WORDSPERSPR   (2 * SPRHEIGHT + 4)
#define MAXX      (640-32)
#define MAXY      (200-16)
#define MAGIC1      33
#define MAGIC2      21
#define ever      (;;)

extern UWORD   ballmask[], ball0[];
extern void   *OpenLibrary(), *OpenWindow(), *AllocMem(), *GetMsg(),
      *ViewPortAddress();
extern long   GetSprite(), VBeamPos();


struct NewWindow windef = {
   0, 15, 300, 10,
   -1, -1,
   CLOSEWINDOW,
   WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG | ACTIVATE,
   NULL, NULL,
   (UBYTE *) "One moment....",
   NULL, NULL, 0, 0, 0, 0,
   WBENCHSCREEN
};
/*   Facendo in questo modo e' piu' veloce che  (i+offset) % 6  */
UBYTE      idx[] = { 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4 };

struct SimpleSprite   spr[FRAMES];
struct Window   *win;
struct ViewPort   *vp;
UWORD      *sprbuf;
UWORD      *sprites[FRAMES];
int      vx[FRAMES], vy[FRAMES];
void      *GfxBase, *IntuitionBase;


main ()
{
   int i, offset = 0, flag = 0;
   void *msg;

   openstuff ();
   setupsprites ();
   rnd ((short) -VBeamPos());

   for (i=0; i<FRAMES; i++) {
      if (GetSprite (&spr[i], (long) i+2) < 0)
         die ("Sprite allocation failed.");
      spr[i].x = 640 / 2;
      spr[i].y = 10;
      spr[i].height = SPRHEIGHT;
      ChangeSprite (vp, &spr[i], sprites[i]);
   }

   SetWindowTitles (win, "  \253\253<< Boing! >>\273\273  ", "Boing!");
   for ever {
      WaitTOF ();
      if (msg = GetMsg (win -> UserPort)) {
         ReplyMsg (msg);
         closestuff ();
         return;
      }
      for (i=0; i<FRAMES; i++) {
         spr[i].x += vx[i];
         if (spr[i].x > MAXX) {
            spr[i].x = (spr[i].x & 0x8000) ? 0 : MAXX;
            vx[i] = -vx[i];
         }

         if ((spr[i].y += (vy[i] >> 2)) > MAXY) {
            spr[i].y = MAXY;
            vx[i] = rnd (MAGIC2) - MAGIC2 / 2;
            vy[i] = -rnd (MAGIC1) - 5;
         }
         vy[i]++;   /*  Gravity  */
      }

      for (i=0; i<FRAMES; i++) 
         ChangeSprite (vp, &spr[i], sprites[idx[i+offset]]);

      if (flag = !flag)
         offset = (offset + 1) % 6;
   }
}

openstuff ()
{
   register int i;

   if (!(IntuitionBase = OpenLibrary ("intuition.library", REV)))
      die ("Intuition open failed.");

   if (!(GfxBase = OpenLibrary ("graphics.library", REV)))
      die ("Art shop closed.");

   if (!(win = OpenWindow (&windef)))
      die ("Window painted shut.");
   vp = ViewPortAddress (win);

   for (i=20; i<32; i += 4) {
      SetRGB4 (vp, i+1L, 15L, 0L, 0L);
      SetRGB4 (vp, i+3L, 15L, 14L, 13L);
   }
}

closestuff ()
{
   register int i;

   for (i=0; i<FRAMES; i++)
      if (spr[i].num)
         FreeSprite ((long) spr[i].num);

   if (sprbuf)
      FreeMem (sprbuf, 2L * WORDSPERSPR * FRAMES);
   if (win)
      CloseWindow (win);
   if (GfxBase)
      CloseLibrary (GfxBase);
   if (IntuitionBase)
      CloseLibrary (IntuitionBase);
}

die (str)
char *str;
{
   if (win) {
      SetWindowTitles (win, str, -1L);
      WaitPort (win -> UserPort);
   } else
      puts (str);
   closestuff ();
   exit (100);
}

setupsprites ()
{
   UWORD *cw;   /* posizione corrente nel buffer dell'immagine sprite*/
   UWORD *maskp;
   UWORD *ballp;
   int frame, scan;

   if (!(sprbuf = AllocMem (2L * WORDSPERSPR * FRAMES, MEMF_CHIP)))
      die ("Can't allocate sprite buffer.");

   cw = sprbuf;   /* posizione corrente in cima al buffer */
   ballp = ball0;

   for (frame=0; frame<FRAMES; frame++) {
      maskp = ballmask;
      sprites[frame] = cw;
      *cw++ = 0;
      *cw++ = 0;

      for (scan=0; scan<SPRHEIGHT; scan++) {
         *cw++ = *maskp++;
         *cw++ = *ballp++;
      }
      *cw++ = 0;
      *cw++ = 0;
   }
}
