/*
 * Module: BB.Worms2.c
 *
 * Aktion: Bunte Würmer, die über den Bildschirm kriechen.
 *
 * Version:
 *   1.1  (28.01.95) Portierung nach BlitzBlank
 *   1.0             Originalimplementation für SuperDark
 *
 * Autor:
 *   Dirk Farin
 *   Kapellenweg 15
 *   72070 Tübingen
 *   Germany
 *
 *   EMail: farindk@trick.informatik.uni-stuttgart.de
 *
 * Copyright:
 *   Dieses Programm ist Freeware, es darf nur
 *   unentgeltlich und unverändert kopiert werden.
 */

#define __USE_SYSBASE 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <dos.h>
#include <dos/dos.h>
#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <blitzblank_pragmas.h>
#include <BlitzBlank.h>

#include <time.h>
#include <proto/dos.h>

struct Library *BlitzBlankBase;
char *VersionString="$VER: BB.Worms2 1.1 (28.01.95)";

#define TXTBASE 470

#define TXT_INFO      0
#define TXT_NWORMS    1
#define TXT_LENGTH    2
#define TXT_CRAZYNESS 3
#define TXT_SPEED     4

char *text[]={"\33c\33uWorms2\33n\n\nVersion 1.1\n\nCopyright 1995\nby\nDirk Farin",
              "_number of worms",
              "worm _length",
              "c_razyness",
              "sp_eed"
             };

struct BB_Object object[]={ {&object[1],BB_VGroup,0,0,0,NULL,NULL},
                            {&object[2],BB_Slider,1,50,20,NULL,NULL},
                            {&object[3],BB_Slider,10,200,50,NULL,NULL},
                            {&object[4],BB_Slider,3,30,20,NULL,NULL},
                            {&object[5],BB_Slider,1,6,4,NULL,NULL},
                            {NULL      ,BB_VGroup_End,0,0,0,NULL,NULL} };

struct BB_Message message;

struct BB_Screeninfo *screeninfo;
struct RastPort *rp;
struct ViewPort *vp;


long   scr_width;
long   scr_height;
USHORT scr_colors;
int    scr_depth;


static ULONG  nWorms=20;
static ULONG  MaxWormLength=50;
static ULONG  MaxTurn=20;
static ULONG  Speed=4;
static double forward_step =1.0;



struct Worm
{
  short  head;
  short  angle;

  double cx,cy; // current head-position

  short  *x,*y;
};

static struct Worm* worms = NULL;

static double sintab[90];

void InitSin(void)
{
    double w=0;
    int i;

    for (i=0;i<90;i++)
    {
        w+=PI/180;
        sintab[i]=sin(w);
    }
}

double GetSin(short angle)
{
    if (angle< 90) return  sintab[angle];
    if (angle<180) return  sintab[179-angle];
    if (angle<270) return -sintab[angle-180];
                   return -sintab[359-angle];
}

double GetCos(short angle)
{
    angle+=90;
    if (angle>=360) angle-=360;

    return GetSin(angle);
}

void StepWorms(void)
{
    struct Worm* worm;
    int          n;
    int          last;
    double       newx,newy;


    for ( n=0 ; n<nWorms ; n++ )
    {
        worm=&worms[n];

        last = worm->head+1;
        if (last==MaxWormLength) last=0;


        /* --- remove last point --- */

        SetAPen(rp,0);
        WritePixel(rp,worm->x[last],worm->y[last]);


        /* --- add a new point at the head --- */

        /* move head */

        newx = worm->cx + GetCos(worm->angle)*forward_step;
        newy = worm->cy + GetSin(worm->angle)*forward_step;

        worm->angle += (rand()%(2*MaxTurn))-MaxTurn;


        /* check for overflow */

        if      (newx <  0         ) newx += scr_width;
        else if (newx >= scr_width ) newx -= scr_width;

        if      (newy <  0         ) newy += scr_height;
        else if (newy >= scr_height) newy -= scr_height;

        if      (worm->angle >= 360) worm->angle-=360;
        else if (worm->angle <  0  ) worm->angle+=360;


        /* store values */

        worm->cx = newx;
        worm->cy = newy;
        worm->x[last] = newx;
        worm->y[last] = newy;

        worm->head=last;


        /* draw pixel */

        SetAPen(rp,(n%(scr_colors-1))+1);
        WritePixel(rp,(int)newx,(int)newy);
    }
}

static char colors[32][3] =
{
     0, 0, 0,   15,15,15,   15, 0, 0,    0,15, 0,
     0, 0,15,   15,15, 0,    0,15,15,   15, 0,15,
    15, 8, 0,    8,15, 0,    0, 8,15,    0,15, 8,
     8, 0,15,   15, 0, 8,    8, 8, 8,    8, 8,15,
     8,15, 8,   15, 8, 8,    8, 0, 0,    0, 8, 0,
     0, 0, 8,    8, 8, 0,    8, 0, 8,    0, 8, 8,
     8, 4, 0,    4, 8, 0,    0, 4, 8,    0, 8, 4,
     4, 0, 8,    8, 0, 4,    4, 8, 4,    8, 4, 4
};

static int cnt=0;

void blank(void)
{
    int i;

    InitSin();
    worms = NULL;


    nWorms        = object[1].set;
    MaxWormLength = object[2].set;
    MaxTurn       = object[3].set;
    Speed         = object[4].set;

    /* ask screen size */

    rp=&screeninfo->bbscreen->RastPort;
    vp=&screeninfo->bbscreen->ViewPort;

    scr_width  = screeninfo->bbscreen->Width;
    scr_height = screeninfo->bbscreen->Height;
    scr_depth  = screeninfo->bbscreen->BitMap.Depth;
    scr_colors = 1<<scr_depth;



    /* initialize worms */

    worms = calloc( sizeof(struct Worm) , nWorms );
    if (!worms) goto cleanexit;


    srand(time(NULL));

    for (i=0;i<nWorms;i++)
    {
        worms[i].x = calloc( sizeof(short) , MaxWormLength );
        worms[i].y = calloc( sizeof(short) , MaxWormLength );

        if ( ( ! worms[i].x ) || ( ! worms[i].y ) ) goto cleanexit;

        worms[i].head = 0;

        worms[i].cx = worms[i].x[0]  =  rand()%scr_width;
        worms[i].cy = worms[i].y[0]  =  rand()%scr_height;
        worms[i].angle               =  rand()%360;
    }


    /* set colors */

    for (i=0;i<scr_colors;i++)
      SetRGB4(vp,i,colors[i][0],colors[i][1],colors[i][2]);


    /* move worms till end */

    ScreenToFront (screeninfo->bbscreen);

    if (!CheckSignal (SIGBREAKF_CTRL_C))
    {
      BBL_ModuleRunning ();

      do
      {
        switch (Speed)
        {
            case 2: StepWorms();
                    break;

            case 3: StepWorms();
                    cnt++;
                    if (cnt&1) StepWorms();
                    break;

            case 4: StepWorms();
                    StepWorms();
                    break;

            case 5: StepWorms();
                    StepWorms();
                    break;

            case 6: StepWorms();
                    StepWorms();
                    break;
        }

        WaitTOF();
      } while (!CheckSignal (SIGBREAKF_CTRL_C));
    }

cleanexit:

    if (worms)
    {
        int i;
        for (i=0;i<nWorms;i++)
        {
            if (worms[i].x) free(worms[i].x);
            if (worms[i].y) free(worms[i].y);
        }

        free(worms);
    }
}

void main(int argc,char **argv)
{
  if (!(BlitzBlankBase=OpenLibrary ("blitzblank.library",BLITZBLANKLIB_VER)))
    exit (0);

  message.flags=BBF_Screenmode|BBF_Colors;
  message.first=&object[0];

  StrToLong (argv[3],(long *) &screeninfo);
  screeninfo->mindepth=0;
  screeninfo->maxdepth=5;

  if (strcmp (argv[1],"BLANK")==0)
  {
    BBL_SendMessage (&message,argv[2]);
    if (screeninfo->bbscreen)
      blank ();
    BBL_BlankDone ();
  }
  else
  {
    message.infotext=BBL_GetString (TXTBASE+TXT_INFO  ,text[TXT_INFO]);
    object[1].label =BBL_GetString (TXTBASE+TXT_NWORMS,text[TXT_NWORMS]);
    object[2].label =BBL_GetString (TXTBASE+TXT_LENGTH,text[TXT_LENGTH]);
    object[3].label =BBL_GetString (TXTBASE+TXT_CRAZYNESS,text[TXT_CRAZYNESS]);
    object[4].label =BBL_GetString (TXTBASE+TXT_SPEED ,text[TXT_SPEED]);

    if (strcmp (argv[1],"CONFIG")==0)
    {
      BBL_SendMessage (&message,argv[2]);
    }
    else
    {
      message.first=NULL;
      BBL_SendMessage (&message,argv[2]);
    }
  }
  CloseLibrary (BlitzBlankBase);
  exit (0);
}


