/* Storm Library */

#include <exec/memory.h>
#include <exec/execbase.h>
#include <graphics/gfxbase.h>
#include <intuition/intuitionbase.h>
#include <libraries/iffparse.h>
#include <utility/tagitem.h>

#include <clib/macros.h>

#define __USE_SYSBASE 42

#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>

#include <BTD.h>

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *UtilityBase;

/* #define DEBUG YES */

#ifdef DEBUG 

void KPrintF(char *,...);

#define DEBUG_PRINTF(a,b)  KPrintF(a,b);
#define DEBUG_PRINT(a)     KPrintF(a)
#else
#define DEBUG_PRINTF(a,b)
#define DEBUG_PRINT(a)
#endif

#define DTAG(o) (BTD_Client+(o))

#define RP_Drops DTAG(0)
#define RP_Colors DTAG(1)
#define RP_Mode  DTAG(2)

#define DEF_COLORS 15L
#define MAX_COLORS 255L

#define DEF_DROPS 25L
#define MAX_DROPS 100L

#define DEF_MODES 0L
#define MAX_MODES 1L

#ifndef max
#define max( x, y ) ((x)>(y)?(x):(y))
#endif

char MyBlankerName[] = "storm.btd";
char MyBlankerID[]   = "Storm Blanker V" VERSION "." REVISION " for BTD";

char *Modes[] = {"Stay Dark","Flash and Light",NULL};

struct BTDCycle StormCycleParams[] =
 {
  RP_Mode,"Mode",BTDPT_CYCLE,DEF_MODES,Modes
 };

struct BTDInteger StormIntParams[] =
 {
  RP_Drops,"Drops",BTDPT_INTEGER,DEF_DROPS,1L,MAX_DROPS,TRUE,
  RP_Colors,"Length/Colors",BTDPT_INTEGER,DEF_COLORS,1L,MAX_COLORS,TRUE
 };

struct BTDNode *StormParams[] = 
 {
  &StormIntParams[0].BI_Node,
  &StormIntParams[1].BI_Node,
  &StormCycleParams[0].BC_Node,
  NULL
 };

struct BTDInfo StormInfo =
 {
  BTDI_Revision,MAKE_ID('S','T','O','R'),
  "Stormy Night","See drops falling...","Markus Illenseer 1995",
  StormParams
 };

struct StormStruct
 {
  struct BTDDrawInfo *BTDDrawInfo;
  LONG Colors;
  LONG Drops;
  LONG DropCount;
  LONG Mode;
  LONG RandN,RandF,RandI;
  BYTE Direction;
 };

void __regargs InitRandom(struct StormStruct *RP,ULONG Instance)

{
 ULONG Time[2];

 CurrentTime (&Time[0],&Time[1]);
 RP->RandN=(LONG)Time[0];

 if (Time[1]<1024L) Time[1]|=1;
 else Time[1]>>=10;
 Time[1]^=Instance;

 RP->RandF=4*Time[1]+1;
 RP->RandI=2*Time[1]+1;
}

WORD __regargs Random(struct StormStruct *RP,WORD Max)

{
 RP->RandN=RP->RandF*RP->RandN+RP->RandI;
 if (RP->RandN<0L) RP->RandN=-RP->RandN;

 return (WORD)(RP->RandN%Max);
}


ULONG FindTagData(struct TagItem *TagList,Tag ID,ULONG Default)

{
 while (TagList)
  switch (TagList->ti_Tag)
   {
    case TAG_DONE:
     return Default;
    case TAG_MORE:
     TagList=(struct TagItem *)TagList->ti_Data;
     break;
    default:
     if (TagList->ti_Tag==ID) return TagList->ti_Data;
     else TagList++;
   }
 return Default;
}


LONG MyBlankerLibInit(void)

{
 if (GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37L))
  {
   if (IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37L))
    {
     if (UtilityBase=OpenLibrary("utility.library",37L)) return TRUE;
     CloseLibrary (&IntuitionBase->LibNode);
    }
   CloseLibrary (&GfxBase->LibNode);
  }
 return FALSE;
}

void MyBlankerLibFree(void)

{
 CloseLibrary (UtilityBase);
 CloseLibrary (&IntuitionBase->LibNode);
 CloseLibrary (&GfxBase->LibNode);
}

struct BTDInfo *QueryMyBlanker(void)
{
 return &StormInfo;
}

struct StormStruct *InitMyBlanker(struct TagItem *TagList)

{
 struct StormStruct *RP;
 struct BTDDrawInfo *BTDDrawInfo;
 ULONG *Error,Dummy,Instance,Index,Step;

 if ((BTDDrawInfo=(struct BTDDrawInfo *)
                   FindTagData(TagList,BTD_DrawInfo,NULL))==NULL) return NULL;
 Error=(LONG *)FindTagData(TagList,BTD_Error,(ULONG)&Dummy);
 if ((RP=AllocVec(sizeof(struct StormStruct),MEMF_PUBLIC|MEMF_CLEAR))==NULL)
  {
   *Error=BTDERR_Memory;
   return NULL;
  }

 RP->BTDDrawInfo=BTDDrawInfo;
 Instance=FindTagData(TagList,BTD_Instance,0L);

 InitRandom(RP,Instance);

 RP->Colors=FindTagData(TagList,RP_Colors,DEF_COLORS);
 RP->Drops=FindTagData(TagList,RP_Drops,DEF_DROPS);
 RP->Mode=FindTagData(TagList,RP_Mode,DEF_MODES);
 RP->Direction=Random(RP,2)-1;

 RP->DropCount=0L;

 Step=(128/(RP->Colors));

 for(Index=0; Index<RP->Colors; Index++)
  {
   BTDDrawInfo->BDI_Red[BTDDrawInfo->BDI_Pens[Index]]=64+Step*Index;
   BTDDrawInfo->BDI_Green[BTDDrawInfo->BDI_Pens[Index]]=64+Step*Index;
   BTDDrawInfo->BDI_Blue[BTDDrawInfo->BDI_Pens[Index]]=64+Step*Index;
   BTDDrawInfo->BDI_Changed[BTDDrawInfo->BDI_Pens[Index]]=TRUE;
  }

 return RP;
}

void EndMyBlanker(struct StormStruct *RP)

{
DEBUG_PRINT("Storm: FreeMem\n");
 FreeVec (RP);
}

void AnimMyBlanker(struct StormStruct *RP)

{

  LONG Len,x,y,Index;
  struct RastPort *R;
  struct BTDDrawInfo *BTD;

  BTD=RP->BTDDrawInfo;
  R=BTD->BDI_RPort;

  if(RP->DropCount++ >RP->Drops)
   {
    /* Lightning */

    if(RP->Mode && Random(RP,100)>80)
     {
      SetAPen(R,BTD->BDI_Pens[Random(RP,RP->Colors)]);
      RectFill (R,
              BTD->BDI_Left,
              BTD->BDI_Top,
              BTD->BDI_Left+BTD->BDI_Width-1,
              BTD->BDI_Top+BTD->BDI_Height-1);
     }
    WaitTOF();
    SetAPen(R,BTD_BgPen);
    RectFill (R,
              BTD->BDI_Left,
              BTD->BDI_Top,
              BTD->BDI_Left+BTD->BDI_Width-1,
              BTD->BDI_Top+BTD->BDI_Height-1);
    RP->DropCount=0L;

    if(Random(RP,100)<15) 
     {
      RP->Direction=Random(RP,4);
     }

   }

   Len = Random(RP, (BTD->BDI_Width-1)/18)+(BTD->BDI_Width-1)/35;
   x = Random(RP,(BTD->BDI_Width-1)-2*Len)+Len+BTD->BDI_Left-1;
   y = Random(RP,(BTD->BDI_Height-1)-2*Len)+Len+BTD->BDI_Top-1;

   switch(RP->Direction) {
   case 0: /* links */
   for(Index=0; Index<Len; Index++)
    {
      SetAPen(R,BTD->BDI_Pens[Index%RP->Colors]);
      WritePixel(R,x-Index,y+Index);
    }
   break;
   case 1:
   for(Index=0; Index<Len; Index++)
    {
      SetAPen(R,BTD->BDI_Pens[Index%RP->Colors]);
      WritePixel(R,x+Index,y+Index);
    }
   break;
   case 2:
   for(Index=Len; Index>0; Index--)
    {
      SetAPen(R,BTD->BDI_Pens[Index%RP->Colors]);
      WritePixel(R,x,y+Index);
    }
   break;
   case 3:
   for(Index=Len; Index>0; Index--)
    {
      SetAPen(R,BTD->BDI_Pens[Index%RP->Colors]);
      WritePixel(R,x+Index,y+Index/2);
    }
   break;
   case 4:
   for(Index=0; Index<Len; Index++)
    {
      SetAPen(R,BTD->BDI_Pens[Index%RP->Colors]);
      WritePixel(R,x-Index,y+Index/2);
    }
   }
}

ULONG PenCountMyBlanker(struct TagItem *TagList)

{
 return FindTagData(TagList,RP_Colors,DEF_COLORS);;
}
