/* ******************************************************************

Programma .... Friends.c
Versione ..... 1.0I, Giugno 1989
Autore ....... Michael Warner
Scopo ........ Effetto grafico di animazione sul puntatore mouse
Software ..... Lattice C V5.02 od Aztec C V3.6a
Hardware ..... Amiga 512K + Kickstart V1.2/V1.3
Sintassi ..... Friends velocitą casualitą (solo da CLI, opzionali)
Note ......... Traduzione ed adattamento x EAD di Luigi Callegari

****************************************************************** */

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

#ifdef LATTICE           /* Inclusioni per Lattice C V4/5 */
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <string.h>
#include <stdlib.h>
#else
#include <functions.h>   /* Inclusione per Aztec C */
#endif

/* Alcune definizioni di costanti di comodo */

#define AllocChip(dime) AllocMem((LONG)dime,(MEMF_CHIP|MEMF_CLEAR))
#define DataBytes       (height*2+4)*2
#define prec 8

/* Strutture e variabili globali */

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct NewWindow newwin =
{ 0, 30, 160, 10, -1, -1,
  CLOSEWINDOW, WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH | 
  SMART_REFRESH,  NULL, NULL, (UBYTE *)" Friends!  ", NULL, NULL,
  0, 0, 0, 0, WBENCHSCREEN };

struct IntuiMessage *msg;
struct Window *win;
struct Screen *wb;            /* schermo workbench */
struct ViewPort *vp;          /* viewport dello screen */
USHORT *clrs;                 /* tabella colori della viewport */
struct SimpleSprite ss[8];    /* usa 1 a 7 */
struct SimpleSprite *ptr;     /* copia del puntatore */
SHORT height;                 /* altezza puntatre */
SHORT which[8]                /* sprite in uso */
  = { 0,0,0,0,0,0,0,0 };	
LONG px[8],py[8];             /* posizioni sprites */
LONG rate = 100;              /* fattore di scala per movimento */
LONG rnd = 100;               /* fattore casualitą */

LONG fixmult( a, b)             /* Moltiplicazione fissa */
LONG a,b;
{
 return( a >> (prec/2) * b >> (prec/2) );
}

LONG tofix(a)        /* Conversione short in n. fisso */
SHORT a;
{
 return( ( (long) a ) << ( prec / 2 ) );
}

SHORT toint(a)       /* Converione n.fisso in short */
LONG a;
{
 return( (short)(a >> (prec/2)) );
}

void init()    /* Inizializzazione sprites */
{
  register SHORT i, any;
  
  IntuitionBase = (struct IntuitionBase *) \
                                  OpenLibrary("intuition.library",33L);
  GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",33L);
  wb = IntuitionBase -> ActiveWindow -> WScreen;
  vp = &wb -> ViewPort;
  clrs = (USHORT *)(vp -> ColorMap -> ColorTable);/* base tabella colori */
  ptr = *GfxBase -> SimpleSprites;                /* puntatore a ptr */
  height = ptr -> height;                         /* altezza puntatore */

  any = FALSE;
  for (i=1; i<8; i++) /* Inizializza sprites */
  {
    if (any |= which[i] = ~GetSprite(&ss[i],(long)i))
    {
      ss[i].height = height;
      
      if (!(ss[i].posctldata = AllocChip(DataBytes)))
         _exit(0);

      movmem((char *)ptr->posctldata, (char *)ss[i].posctldata, DataBytes);
      
      ss[i].posctldata[1] = ss[i].posctldata[0] = 0;
      ss[i].posctldata[DataBytes/2-2] = ss[i].posctldata[DataBytes/2-1] \
                                      = 0xffff;
      
      px[i] = tofix(ss[i].x = (short)RangeRand(640L)); /* Posizione */
      py[i] = tofix(ss[i].y = (short)RangeRand(200L));
    }
  }
  if ( !any ) _exit(0);

  for ( i=1 ; i<=3; i++) /* Fissa sprites allo stesso colore */
    movmem((char *)&clrs[16],(char *)&clrs[16+i*4],4*2);
  LoadRGB4( vp, clrs, 32L );
  if ( ! (win= OpenWindow( &newwin ) )) _exit(0L); /* Apre finestra */
}

void move()        /* muove tutti gli amici del mouse */
{
  static LONG vx[8] = { 0,0,0,0,0,0,0,0 };
  static LONG vy[8] = { 0,0,0,0,0,0,0,0 };
  LONG ax,ay;           /* (punto fisso) accelerazione x ed y */
  LONG mx,my;           /* punto fisso (x,y) mouse */
  register SHORT i;

  mx = tofix( wb -> MouseX ); my = tofix( wb -> MouseY );
  for ( i = 1 ; i < 8; i++ )
  {
    if (which[ i ] )
    {
      ax = (mx-px[i]) - 2*vx[i] + tofix((short)(RangeRand(3*rnd)-3*rnd/2));
      ay = (my-py[i]) - 2*vy[i] + tofix((short)(RangeRand(rnd)-rnd/2));
      vx[i] += ax/rate;
      vy[i] += ay/rate;
      px[i] += vx[i]; py[i] += vy[i]; /* Posizione */
      if (toint(px[i])<0)   { px[i]=-px[i]; vx[i]=-vx[i]; }
      if (toint(px[i])>639) { px[i]=tofix(639*2)-px[i]; vx[i]=-vx[i]; }
      if (toint(py[i])<0)   { py[i]=-py[i]; vy[i]=-vy[i]; }
      if (toint(py[i])>199) { py[i]=tofix(199*2)-py[i]; vy[i]=-vy[i]; }
      MoveSprite(vp,&ss[i],
                 (long)toint(px[i]),
                 (long)toint(py[i]));
    }
  }
}

void main( argc, argv)
int argc; char *argv[];
{
  register SHORT i;

  if (argv[1]) /* legge velocitą se specificata */
  {
    rate = atol(argv[1]);
    if (argv[2]) rnd  = atol( argv[2] ); /* Ricava casualitą */
  }
  
  init();
  while ( ! ( msg=(struct IntuiMessage *) GetMsg (win->UserPort)))
  {
    WaitTOF();
    move();
  }
  ReplyMsg((struct Message *)msg);

  for (i = 1; i < 8; i++)
  {
    if (which[i]) /* Libera memoria allocata da AllocMem() */
    {
      FreeSprite((long)i);
      if (ss[i].posctldata)
        FreeMem(ss[i].posctldata,(long)DataBytes);
    }
  }
  CloseWindow( win );
  CloseLibrary((struct Library *)GfxBase);
  CloseLibrary((struct Library *)IntuitionBase);
}
