  /* Fichier Aswarm.dark.c				*/
/* Module appele par le programme principal	*/
/* pour effectuer un effet defini..appele par	*/
/* loadseg					*/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/execbase.h>
#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuitionbase.h>
#include <intuition/gadgetclass.h>

#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/macros.h>

#include "/includes/struct.h"
#include "/includes/tom_gadget.h"
#include <string.h>
#include <stdlib.h>

char	*name_module="Aswarm.dark";
char	*p_text_info="             ASWarm\n\nBased on a programm from\nMarkus 'Ill' Illenseer\nand Matthias 'tron' Scheler\nAdapted by T.Landspurg\n\nBased on Sun's XSwarm";
extern	struct	GfxBase	*GfxBase;

#define MAX_SPEED     4L
#define MAX_WASPS     10L
#define MAX_BEES      500L
#define MAX_TIGHTNESS 10L

#define DEF_SPEED     4L
#define DEF_WASPS     2L
#define DEF_BEES      25L
#define DEF_TIGHTNESS 5L

#define	ID_SPEED	0
#define	ID_WASPS	1
#define	ID_BEES		2
#define	ID_TIGHTNESS	3
#define ID_CYCLE	4
#define ID_AIM		5

char *SpeedNames[] = /* List of Speed Modes */
 {"Slow Motion","Very Slow","Slow","Normal","Fast","Very Fast",
  "Incredible",NULL};

struct	tom_gadget	my_gadg[]={
	{"_Speed",	CYCLE,  90, 30,   120, 12,DEF_SPEED,1,MAX_SPEED,0,(char *)SpeedNames},
	{"_Wasps",	SLIDER,  90, 50,   120, 10,DEF_WASPS,1,MAX_WASPS,0,0},
	{"_Bees",	SLIDER,  90, 70,   120, 10,DEF_BEES  ,1,MAX_BEES,0,0},
	{"Tig_htness",	SLIDER,  90, 90,   120, 10,DEF_TIGHTNESS,1,MAX_TIGHTNESS,0,0},
	{"Color c_ycling",CHECKBOX,380,50,   10, 10,0,0,0,0},
	{"_Aim mode"	,CHECKBOX,380,70,    10, 10,0,0,0,0},
	{"_Resolution",	SCREEN,	 90,110,120,12,0, 0,0,0,0},
	{0,		END_LISTE,  0,  0,   0, 0, 0,0,0,0,0}};

LONG Index,NumWasps,NumBees,Speed,Cycle,AimMode,Count,Tightness;

#define VOID_INTERRUPT void __interrupt __saveds
#define REGARGS        __regargs
#define VOID_STDARGS   void __stdargs


/*

   Definitions or Swarm Movement

*/

#define BEEACC  3
#define BEEVEL  9
#define WASPACC 5
#define WASPVEL 13
#define BORDER  5

#define FIXED    0

#define BEE_COL_NUM 32

UWORD BeeColors[BEE_COL_NUM] = /* Color Cycling Table */
 {0x000F,0x004F,0x008F,0x00BF,0x00FF,0x00FB,0x00F7,0x00F3,0x00F0,0x04F0,0x08F0,
  0x09F0,0x0AF0,0x0BF0,0x0CF0,0x0DF0,0x0EF0,0x0FF0,0x0FE0,0x0FD0,0x0FC0,0x0FB0,
  0x0F90,0x0F80,0x0F70,0x0F60,0x0F50,0x0F40,0x0F30,0x0F20,0x0F10,0x0F00};

struct NewScreen NewBlankerScreen =
 {0,0,640,256,2,0,1,HIRES,CUSTOMSCREEN,
  NULL,NULL,NULL,NULL};

#define RAND(m) (Random(m)-(m)/2)

UWORD SwarmColors[4] = {0x0000,0x0FFF,0x0000,0x0FFF};
LONG NumWasps,NumBees,Speed,Tightness;
LONG Cycle,AimMode;
LONG ThisTimeOut,TimeUntilBlank;
UWORD	width,height;
struct SwarmStruct /* structure for a swarm, including the wasp */
 {
  WORD ss_Width;   /* Width and */
  WORD ss_Height;  /* Height of the used Screen, probably useful for
                      future versions of ASwarm :) */
  WORD ss_NumWasps;/* total number of the Wasps */
  WORD *ss_WX[4];  /* The Wasps x-Position*/  /* WX[3] is used for Velocity */
  WORD *ss_WY[4];  /* Y-Position */
  WORD *ss_NB;     /* No. of Bees following this Wasp */
  WORD ss_NumBees; /* Total (!) number of Bees */
  WORD ss_BeeAcc;  /* Acceleration of the Bees */
  WORD *ss_X[4];   /* The Bees X-Position */  /* X[3] used for Velocity */
  WORD *ss_Y[4];   /* Y-Position */
  WORD *ss_MW;     /* The aimed Wasp */
 };

/* Ill's strange Macros for easy access to the above structure */

#define BXVel(I)   (SP->ss_X[3][I])
#define BYVel(I)   (SP->ss_Y[3][I])
#define BeeX(P,I)  (SP->ss_X[P][I])
#define BeeY(P,I)  (SP->ss_Y[P][I])
#define MyWasp(I)  (SP->ss_MW[I])

#define WaXVel(I)  (SP->ss_WX[3][I])
#define WaYVel(I)  (SP->ss_WY[3][I])
#define WaspX(P,I) (SP->ss_WX[P][I])
#define WaspY(P,I) (SP->ss_WY[P][I])

/*

   Functions for Creating/Drawing/Removing the Swarms

*/

/* Ill's strange and genius Random Function :-) */

WORD REGARGS Random(WORD Max)

{
 static ULONG Num=0L; /* So the last random-number is still stored ! */
 ULONG Sec,Mic;

 CurrentTime((LONG *)&Sec,(LONG *)&Mic);

 Num*=Sec;
 Num+=Mic;

 while (Num>32767L) Num=Num>>1;

 return (WORD)Num%Max;
}

ULONG SwarmSize(LONG NumWaps,LONG NumBees)

{
 return sizeof(struct SwarmStruct)+sizeof(WORD)*((ULONG)NumWaps*9L+
                                   (ULONG)NumBees*9L);
}

struct SwarmStruct *REGARGS CreateSwarms(struct Screen *SwarmScreen,
                          LONG NumWasps,LONG NumBees,LONG Speed,LONG Tightness)

/* allocate Memory and initialize the Swarm(s) */

{
 LONG Index;
 struct SwarmStruct *SP;
 WORD *Ptr;

 if ((SP=AllocMem(SwarmSize(NumWasps,NumBees),0L))==NULL) return NULL;

 SP->ss_NumWasps=NumWasps;
 SP->ss_NumBees=NumBees;
 SP->ss_Width=SwarmScreen->Width;    /* Will probably be changed in a */
 SP->ss_Height=SwarmScreen->Height;  /* future version of ASwarm */
 SP->ss_BeeAcc=(Tightness*BEEACC/Speed/MAX_SPEED)*(MAX_SPEED/2)+1;

 Ptr=(WORD *)&SP[1];
 for (Index=0L; Index<4L; Index++)
  {
   SP->ss_WX[Index]=Ptr;
   Ptr+=NumWasps;
   SP->ss_WY[Index]=Ptr;
   Ptr+=NumWasps;
   SP->ss_X[Index]=Ptr;
   Ptr+=NumBees;
   SP->ss_Y[Index]=Ptr;
   Ptr+=NumBees;
  }
 SP->ss_NB=Ptr;
 SP->ss_MW=Ptr+NumWasps;

 /* Wasps */
 for (Index=0L; Index<NumWasps; Index++)
  {
   WaspX(1,Index)=WaspX(0,Index)=BORDER+Random(SP->ss_Width-2*BORDER);
   WaspY(1,Index)=WaspY(0,Index)=BORDER+Random(SP->ss_Height-2*BORDER);
   WaXVel(Index)=RAND(WASPACC);
   WaYVel(Index)=RAND(WASPACC);
   SP->ss_NB[Index]=0;
  }

 /* Bees */
 for (Index=0L; Index<SP->ss_NumBees; Index++)
  {
   BeeX(1,Index)=BeeX(0,Index)=BORDER+Random(SP->ss_Width-2*BORDER);
   BeeY(1,Index)=BeeY(0,Index)=BORDER+Random(SP->ss_Height-2*BORDER);
   BXVel(Index)=RAND(SP->ss_BeeAcc);
   BYVel(Index)=RAND(SP->ss_BeeAcc);
   SP->ss_NB[MyWasp(Index)=Index%SP->ss_NumWasps]++;
  }

 return SP;
}

/* move Swarms and redraw it */

void REGARGS DrawSwarms(struct SwarmStruct *SP,LONG AimMode,
                        struct RastPort *WaspRP,struct RastPort *BeeRP)

{
 LONG Index;

 /* Wasps */

 for (Index=0L; Index<SP->ss_NumWasps; Index++)
  {
   WaspX(2,Index)=WaspX(1,Index);
   WaspX(1,Index)=WaspX(0,Index);
   WaspY(2,Index)=WaspY(1,Index);
   WaspY(1,Index)=WaspY(0,Index);

   WaXVel(Index)+=RAND(WASPACC);
   WaYVel(Index)+=RAND(WASPACC);

   if (WaXVel(Index)>WASPVEL) WaXVel(Index)=WASPVEL;
   if (WaXVel(Index)<-WASPVEL) WaXVel(Index)=-WASPVEL;
   if (WaYVel(Index)>WASPVEL) WaYVel(Index)=WASPVEL;
   if (WaYVel(Index)<-WASPVEL) WaYVel(Index)=-WASPVEL;

   WaspX(0,Index)=WaspX(1,Index)+WaXVel(Index);
   WaspY(0,Index)=WaspY(1,Index)+WaYVel(Index);

   /* Bounce check for Wasps */

   if ((WaspX(0,Index)<BORDER)||(WaspX(0,Index)>SP->ss_Width-BORDER-1))
    {
     WaXVel(Index)=-WaXVel(Index);
     if (WaspX(0,Index)<BORDER) WaspX(0,Index)=BORDER;
     else WaspX(0,Index)=SP->ss_Width-BORDER-1;
    }
   if ((WaspY(0,Index)<BORDER)||(WaspY(0,Index)>SP->ss_Height-BORDER-1))
    {
     WaYVel(Index)=-WaYVel(Index);
     if (WaspY(0,Index)<BORDER) WaspY(0,Index)=BORDER;
     else WaspY(0,Index)=SP->ss_Height-BORDER-1;
    }
  }

 /* Bees */

 for (Index=0L; Index<SP->ss_NumBees; Index++)
  {
   WORD DX,DY,ChkIndex;
   LONG Distance,NewDistance;

   BeeX(2,Index)=BeeX(1,Index);
   BeeX(1,Index)=BeeX(0,Index);
   BeeY(2,Index)=BeeY(1,Index);
   BeeY(1,Index)=BeeY(0,Index);

   DX=WaspX(1,MyWasp(Index))-BeeX(1,Index);
   DY=WaspY(1,MyWasp(Index))-BeeY(1,Index);
   Distance=(ABS(DX)+ABS(DY))/2L;
   if (Distance==0L) Distance=1L;

   if (AimMode) /* Look out for the nearest wasp if Aim-Mode is on */
    for (ChkIndex=0; ChkIndex<=SP->ss_NumWasps; ChkIndex++)
     if (ChkIndex!=MyWasp(Index))
      {
       LONG NewDX,NewDY;

       NewDX=WaspX(1,ChkIndex)-BeeX(1,Index);
       NewDY=WaspY(1,ChkIndex)-BeeY(1,Index);
       NewDistance=(ABS(NewDX)+ABS(NewDY))/2L;
       if (NewDistance==0L) NewDistance=1L;
       if (Distance>NewDistance)
        {
         DX=NewDX;
         DY=NewDY;
         Distance=NewDistance;
         SP->ss_NB[MyWasp(Index)]--;
         SP->ss_NB[MyWasp(Index)=ChkIndex]++; /* Mark a nearer Wasp */
        }
      }

   BXVel(Index)+=(DX*SP->ss_BeeAcc)/Distance+RAND(3);
   BYVel(Index)+=(DY*SP->ss_BeeAcc)/Distance+RAND(3);

   if (BXVel(Index)>BEEVEL)  BXVel(Index)=BEEVEL;
   if (BXVel(Index)<-BEEVEL) BXVel(Index)=-BEEVEL;
   if (BYVel(Index)>BEEVEL)  BYVel(Index)=BEEVEL;
   if (BYVel(Index)<-BEEVEL) BYVel(Index)=-BEEVEL;

   BeeX(0,Index)=BeeX(1,Index)+BXVel(Index);
   BeeY(0,Index)=BeeY(1,Index)+BYVel(Index);

  /* Bounce check for Bees */

   if ((BeeX(0,Index)<BORDER)||(BeeX(0,Index)>(SP->ss_Width-BORDER-1)))
    {
     BXVel(Index)=-BXVel(Index);
     BeeX(0,Index)=BeeX(1,Index)+BXVel(Index);
    }
   if ((BeeY(0,Index)<BORDER)||(BeeY(0,Index)>(SP->ss_Height-BORDER-1)))
    {
     BYVel(Index)=-BYVel(Index);
     BeeY(0,Index)=BeeY(1,Index)+BYVel(Index);
    }
  }


 /* Move our insects */

 for(Index=0L; Index<SP->ss_NumWasps; Index++)    /* Wasps */
  {
   SetAPen (WaspRP,0);
   Move (WaspRP,WaspX(2,Index),WaspY(2,Index));
   Draw (WaspRP,WaspX(1,Index),WaspY(1,Index));
   SetAPen (WaspRP,1);
   Draw (WaspRP,WaspX(0,Index),WaspY(0,Index));
  }

 for (Index=0L; Index<SP->ss_NumBees; Index++)   /* Bees  */
  {
   SetAPen (BeeRP,0);
   Move (BeeRP,BeeX(2,Index),BeeY(2,Index));
   Draw (BeeRP,BeeX(1,Index),BeeY(1,Index));
   SetAPen (BeeRP,1);
   Draw (BeeRP,BeeX(0,Index),BeeY(0,Index));
  }
}


struct Screen *CreateScreen()

{
 struct Screen *Screen;
 struct	tom_gadget	*pg;

  pg=&my_gadg[6];
  /* With WB2.0 or higher, we use facilities of the intuition lib. */
  /* to open screen (overscan...)			           */
  if(pg->d3<2){
	pg->d3=2;
  }
  if((GfxBase->LibNode.lib_Version>=37)&&(pg->d3!=0)){
	Screen=OpenScreenTags(NULL,
			   SA_Width,(ULONG)pg->d1,
			   SA_Height,(ULONG)pg->d2,
                           SA_Depth,(ULONG)pg->d3,
			   SA_Overscan,(ULONG)pg->value,
                           SA_DisplayID,(ULONG)pg->p_data,
                           SA_Quiet,TRUE,TAG_DONE);
	 width=pg->d1;
	 height=pg->d2;
   }else{
	Screen=OpenScreen(&NewBlankerScreen);
   }
   if(Screen){
	SetRGB4 (&Screen->ViewPort,0,0,0,0);
	SetRast (&Screen->RastPort,0);
   }
   return Screen;
}

/* Put here your own code */
/* But don't remember     */

void	__saveds	dark()
{
	struct Screen *SwarmScreen;
	struct SwarmStruct *Swarms;
	WORD Color,DColor;
	static struct RastPort RastPorts[2];
	static struct BitMap BitMaps[2];

	NumWasps=my_gadg[ID_WASPS].value;
	NumBees=my_gadg[ID_BEES].value;
	Speed=my_gadg[ID_SPEED].value+1;
	Cycle=my_gadg[ID_CYCLE].value;
	AimMode=my_gadg[ID_AIM].value;
	Tightness=my_gadg[ID_TIGHTNESS].value;

 SwarmScreen=CreateScreen();
 if(SwarmScreen!=NULL){
	FreeSprite (0);
	GfxBase->SpriteReserved|=1;
 /* initialize requested Number of Swarms */

 if ((Swarms=CreateSwarms(SwarmScreen,NumWasps,NumBees,Speed,Tightness))!=NULL)
  {
 /* Here we do a little trick:
   We create two RastPorts - one for the Wasp(s), one for the Bees - with one
   BitPlane. So we have only to draw in one BitPlane and are able to do it
   faster. */

 for (Index=0L; Index<2L; Index++)
  {
   InitRastPort (&RastPorts[Index]);
   RastPorts[Index].BitMap=&BitMaps[Index];
   SetDrMd (&RastPorts[Index],JAM1);
   InitBitMap (&BitMaps[Index],1L,SwarmScreen->Width,SwarmScreen->Height);
   BitMaps[Index].Planes[0]=SwarmScreen->BitMap.Planes[Index];
  }

 Color=BEE_COL_NUM-1;
 DColor=Cycle?1:0;
 Count=Speed;

	while(tst_end()==FALSE){
   /* Color Cycling */

   SwarmColors[2]=BeeColors[Color];
   LoadRGB4 (&SwarmScreen->ViewPort,SwarmColors,4);
   Color+=DColor;
   if ((Color==-1)||(Color==BEE_COL_NUM))
    {
     DColor=-DColor;
     Color+=2*DColor;
    }

   /* Synchronisation */

   WaitTOF();
   if (Count<MAX_SPEED)
    {
     Count++;
     continue;
    }
   Count=Speed;

   /* Move the Swarm(s) */

   DrawSwarms (Swarms,AimMode,&RastPorts[0],&RastPorts[1]);
  }
 FreeMem (Swarms,SwarmSize(NumWasps,NumBees));
 }
 CloseScreen(SwarmScreen);
 }
}
void	proc_init()
{
}

void	proc_save()
{
}
void	proc_end()
{
}
