/*

InvaderCraft von J.Hertel
(C) CW-Publikationen

 "menu.c"


Kompilieren mit Aztec C Version 3.20a.

Im Include-Directory muss sich das Header-File "invadercraft1.h" befinden!

Aufruf:  cc menu -a
         as menu

Linken:  siehe invadercraft.c

*/

#include <exec/types.h>
#include <exec/interrupts.h>
#include <graphics/gfx.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/gfxmacros.h>
#include <hardware/intbits.h>
#include <hardware/dmabits.h>
#include <hardware/custom.h>
#include <hardware/cia.h>

/* Vor Compiler-Aufruf unbedingt "invadercraft1.h" in include/ - Directory
kopieren! */

#include <invadercraft1.h>

extern char *versstr[];
extern int _Dorg,player,anzplay,ship[],version,demo,kick;
extern struct Custom *custom;
extern struct CIA *ciaa;
extern struct RastPort rp,rp2;
extern struct ViewPort vp,vphi;
extern struct BitMap bm,bm2,ab1;
extern UWORD colorhi[],color1[],color2[],color3[];
extern long YA[];

long MITTE[]={87,110};
struct Interrupt VertBIntr;
struct liste slots[MAXVERSIONS][SLOTS];

#define ANZSTR1 6          /* Hauptmenu */
char *textstr[ANZSTR1]={
"Choose Version",
"One Player Game",
"Two Player Game",
"Hall of Fame",
"About",
"Exit"
};

#define ANZSTR3 7          /* About */
char *aboutstr[ANZSTR3]={
"InvaderCraft",
"written by",
"J. Hertel",
"Version 2.0",
"Copyright",
"1987 by",
"CW-Publikationen",
};

#define ANZSTERN 35
UBYTE vstern[ANZSTERN];
USHORT xstern[ANZSTERN],ystern[ANZSTERN];

long zufall=523476729;
USHORT rnd;

VertBServer()
/* Interface zwischen C-Code und Interrupt-Handler */
{
#asm
   movem.l d2-d7/a2-a4,-(sp)
   move.l a1,a4
#endasm
   hinter();
#asm
   MOVEQ.L #0,D0
   movem.l (sp)+,d2-d7/a2-a4
#endasm
}

/* Zufallszahlen-Routine, Aufruf: rnd1(), Resultat in rnd */

#asm
   cseg
_rnd1:
   public _rnd1
   movem.l d0-d3,-(sp)
   move.l _zufall,d0
   move.w #7,d3
label:
   move.b d0,d1
   move.b d0,d2
   lsr.b #3,d1
   lsr.b #1,d2
   eor.b d1,d2
   lsr.b #1,d2
   roxr.l #1,d0
   move.l d0,_zufall
   dbra d3,label
   move.w d0,_rnd
   movem.l (sp)+,d0-d3
   rts
   cseg
#endasm

interein()
/* Vertical-Blank-Interrupt einschalten fuer die Bewegung der Sterne im
Hintergrund */
{
   VertBIntr.is_Node.ln_Type=NT_INTERRUPT;
   VertBIntr.is_Node.ln_Pri=-60;
   VertBIntr.is_Node.ln_Name="InvaderCraft!";
   VertBIntr.is_Data=(APTR)((BYTE *)&_Dorg+32766);
   VertBIntr.is_Code=(void (*)())VertBServer;

   AddIntServer(INTB_VERTB,&VertBIntr);
}

interaus()
/* Ausschalten des Vertical-Blank-Interrupts */
{
   RemIntServer(INTB_VERTB,&VertBIntr);
}

hauptmenu()

/* Hauptmenue (Choose Version/One Player Game/Two Player Game/Hall of Fame/
About/Exit) anzeigen, Joystick abfragen und entsprechende Routinen
aufrufen */

{
   int i,item=1;

   do {
      player=0; anzplay=1; ship[0]=0; ship[1]=0;
      titrest();
      sync();
      if(item==1||item==2)
         demorot();
      SetRast(&rp2,0L); SetRast(&rp,0L);
      auswahlanz(0,1,ANZSTR1,textstr[0]);
      for(i=1;i<ANZSTR1;i++)
         auswahlanz(i,3,ANZSTR1,textstr[i]);
      interein();
      if(item==2||item==1) {
         sound(15,0,3);
         sound(15,0,4);
         einblenden(color1,1);
      }
      else
         einblenden(color1,0);
      item=0;
      do {
         for(i=0;i<5;i++) {
            sync();
            SetRGB4(&vp,10L,(long)(i%5+5),(long)((i+3)%5+6),
             (long)((i+6)%6+5));
         }
         auswahlanz(item,3,ANZSTR1,textstr[item]);
         if((custom->joy1dat>>1 ^ custom->joy1dat)&1)
            item=(item+1)%6;
         else if((custom->joy1dat>>1 ^ custom->joy1dat)&0x100)
            item=(item+5)%6;
         auswahlanz(item,1,ANZSTR1,textstr[item]);

      } while(ciaa->ciapra&0x80);
      while ((ciaa->ciapra&0x80)==0) ;

      if(item==1||item==2) {     /* One/Two Player Game  */
         ausblenden(1);
         interaus();
         spiel(item-1);
      }
      else if(item==3) {         /* Hall of Fame */
         ausblenden(0);
         interaus();
         showhi();
         while(ciaa->ciapra&0x80);
         while ((ciaa->ciapra&0x80)==0) ;
         ausblenden(0);
         interaus();
      }
      else if(item==0)
         otherversion();         /* Choose Version */
      else if(item==4) {
         ausblenden(0);          /* About */
         about1();
         einblenden(color3,0);
         while(ciaa->ciapra&0x80);
         while ((ciaa->ciapra&0x80)==0);
         ausblenden(0);
         about();
         einblenden(color1,0);
         while(ciaa->ciapra&0x80);
         while ((ciaa->ciapra&0x80)==0);
         ausblenden(0);
         interaus();
      }
      else {
         ausblenden(1);          /* Exit */
         interaus();
      }
   } while(item!=5);
}

otherversion()

/* Menue zur Auswahl der verschiedenen Versionen anzeigen und gewuenschte
Version einschalten */

{
   int i;

   ausblenden(0);
   SetRast(&rp2,0L);
   auswahlanz(version,1,MAXVERSIONS,versstr[version]);
   for(i=0;i<MAXVERSIONS;i++) {
      if(i!=version)
         auswahlanz(i,3,MAXVERSIONS,versstr[i]);
   }
   einblenden(color1,0);
   do {
      for(i=0;i<5;i++) {
         sync();
         SetRGB4(&vp,10L,(long)(i%5+5),(long)((i+3)%5+6),(long)((i+6)%6+5));
      }
      auswahlanz(version,3,MAXVERSIONS,versstr[version]);
      if((custom->joy1dat>>1 ^ custom->joy1dat)&1)
         version=(version+1)%MAXVERSIONS;
      else if((custom->joy1dat>>1 ^ custom->joy1dat)&0x100)
         version=(version+MAXVERSIONS-1)%MAXVERSIONS;
      auswahlanz(version,1,MAXVERSIONS,versstr[version]);

   } while(ciaa->ciapra&0x80);
   while ((ciaa->ciapra&0x80)==0);
   ausblenden(0);
   interaus();
}

demorot()

/* Demo-Modus - Computer spielt nun Invadercraft bis Joystick-Knopf (oder
ausnahmsweise linke Maustaste) betaetigt wird */

{
   int demozeiger=0,flg=1;

   SetRast(&rp,0L); SetRast(&rp2,0L);
   sound(15,0,3);
   sound(15,0,4);
   demo=1;
   for(;;demozeiger=(demozeiger+1)%4) {
     /* Auswahl aller Hauptmenuepunkte */
      switch(demozeiger) {
         case 0:
            ausblenden(0);
            interein();
            about1();
            einblenden(color3,flg);
            if(sleep()) {
               ausblenden(1);
               interaus();
               goto enddemo1;
            }
            flg=0;
         break;
         case 1:
            ausblenden(0);
            about();
            einblenden(color1,0);
            if(sleep()) {
               ausblenden(1);
               interaus();
               goto enddemo1;
            }
         break;
         case 2:
            ausblenden(0);
            interaus();
            showhi();
            if(sleep()) {
               ausblenden(1);
               interaus();
               goto enddemo1;
            }
            ausblenden(0);
            interaus();
         break;
         case 3:
            SetRast(&rp,0L); SetRast(&rp2,0L);
            SetAPen(&rp,0L); SetAPen(&rp2,0L);
            if(spiel(0))
               goto enddemo;
            SetRast(&rp,0L);
         break;
      }
   }

enddemo:
   ausblenden(1);
enddemo1:
   demo=0;
}

sleep()

/* Joystick und linke Maustaste abfragen; wenn gedrueckt, dann sleep()==1 */

{
   int i;

   for(i=0;i<300;i++) {
      sync();
      if((ciaa->ciapra&0x80)==0) {
         while ((ciaa->ciapra&0x80)==0);
         return(1);
      }
      if((ciaa->ciapra&0x40)==0) {
         while ((ciaa->ciapra&0x40)==0);
         return(1);
      }
   }
   return(0);
}

about()

/* Copyright-Hinweis und Name des Programmierers zeigen */

{
   int i,j;

   SetRast(&rp2,0L);
   for(i=0;i<ANZSTR3;i++) {
      auswahlanz(i,1,ANZSTR3,aboutstr[i]);
   }
}

about1()

/* IFF-Brush ("ic.data:about") mit dem Titel des Programms anzeigen */

{
   SetRast(&rp2,0L);
   BltBitMap(&ab1,0L,0L,&bm2,VX,VY+MITTE[kick]-ABOUTHEIGHT/2,ABOUTWIDTH,
    ABOUTHEIGHT,0xc0L,0xffL);
}

hinter()

/* Sterne im Hintergrund bewegen (einfach, da Dual-Playfield) */

{
   int addr1,i;
   long addr;
   BYTE xz;

   OFF_SPRITE
   for(i=0;i<ANZSTERN;i++) {
      if(xstern[i]< VX-1) {
         xstern[i]=XA+VX;
      }
      addr=ystern[i]*bm.BytesPerRow; addr1=xstern[i]>>3;
      if(i&1)
         *(bm.Planes[0]+addr+addr1)=0;
      if(i&2)
         *(bm.Planes[1]+addr+addr1)=0;
      if(i&4)
         *(bm.Planes[2]+addr+addr1)=0;
      xstern[i]-=vstern[i]; addr1=xstern[i]>>3; xz=128>>(xstern[i]&7);

      if(i&1)  /* Einfaerben der Sterne */
         *(bm.Planes[0]+addr+addr1)=xz;
      if(i&2)
         *(bm.Planes[1]+addr+addr1)=xz;
      if(i&4)
         *(bm.Planes[2]+addr+addr1)=xz;

   }
}

sternsetz()

/* Stern-Koordinaten und Geschwindigkeiten festsetzen */

{
   int i;

   for(i=0;i<ANZSTERN;i++) {
       rnd1();
       ystern[i]=(long)YA[kick]*(long)rnd/0x10000L+VY;
       rnd1();
       vstern[i]=10L*(long)rnd/0x10000L+1;
       rnd1();
       xstern[i]=(long)XA*(long)rnd/0x10000L+VX;
   }
}

auswahlanz(i,j,anzstring,string)
int i,j,anzstring;
char *string;

/* Zeile zweifarbigen Textes anzeigen (automatisch zentrierend)
   i           Zeilennummer ( Zeilenhoehe = 20 Pixels )
   j           Farbe (bzw.j+1)
   anzstring   Anzahl an Zeilen insgesamt (fuer Zentrierung)
   string      Zeiger auf auszudruckenden String */

{
   SetAPen(&rp2,(long)j);
   Move(&rp2,XA/2+VX-5L*strlen(string),VY+MITTE[kick]+6L+20L*i-
    anzstring*10L+5L);
   Text(&rp2,string,(long)strlen(string));
   SetAPen(&rp2,(long)j+1L);
   Move(&rp2,XA/2+VX-5L*strlen(string)+1L,VY+MITTE[kick]+6L+20L*i-
    anzstring*10L+5L);
   Text(&rp2,string,(long)strlen(string));
}

showhi()

/* Highscore-Tabelle zeigen */

{
   int i,y;
   char str[6];
   ULONG z;

   SetRast(&rp,0L); SetRast(&rp2,0L);
   for(y=0;y<SLOTS;y++) {
      for(i=0;i<6;i++)
         str[i]=' ';
      z=slots[version][y].score;
      for(i=5;i>=0;i--) {
         str[i]= z % 10 + 48;
         z/=10;
            if(z==0)
               break;
      }
      SetAPen(&rp2,1L);
      Move(&rp2,125L,y*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2,slots[version][y].who,8L);
      Move(&rp2,220L,y*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2,str,6L);

      SetAPen(&rp2,2L);
      Move(&rp2,126L,y*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2,slots[version][y].who,8L);
      Move(&rp2,221L,y*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2,str,6L);

   }
   interein();
   einblenden(color2,0);
}

ausblenden(nichtstill)
int nichtstill;

/* Ausblenden von Grafik und, wenn 'nichtstill' ungleich Null, von Sound
(Soundfile 15) */

{
   int i,j;
   UWORD zcol;

   for(j=0;j<16;j++) {
      sync();
      if(nichtstill) {
         soundvol(15,60-j*4,3);
         soundvol(15,60-j*4,4);
      }
      for(i=0;i<AC;i++) {
         zcol=*((UWORD *)vp.ColorMap->ColorTable+i);
         if(zcol&0xf00)
            zcol-=0x100;
         if(zcol&0x0f0)
            zcol-=0x010;
         if(zcol&0x00f)
            zcol-=0x001;
         SetRGB4(&vp,(long)i,(long)zcol/256,(long)(zcol/16)%16,
          (long)zcol%16);
      }
      for(i=0;i<HIAC;i++) {
         zcol=*((UWORD *)vphi.ColorMap->ColorTable+i);
         if(zcol&0xf00)
            zcol-=0x100;
         if(zcol&0x0f0)
            zcol-=0x010;
         if(zcol&0x00f)
            zcol-=0x001;
         SetRGB4(&vphi,(long)i,(long)zcol/256,(long)(zcol/16)%16,
          (long)zcol%16);
      }
   }
}

einblenden(table,nichtstill)
UWORD table[];
int nichtstill;

/* Einblenden von Grafik mit Farbtabelle, die durch table[] festgelegt
wird, und, wenn 'nichtstill' ungleich Null, von Sound (Nr.15) */

{
   int i,j;
   UWORD zcol;

   for(j=0;j<16;j++) {
      sync();
      if(nichtstill) {
         soundvol(15,j*4+4,3);
         soundvol(15,j*4+4,4);
      }
      for(i=0;i<AC;i++) {
         zcol=*((UWORD *)vp.ColorMap->ColorTable+i);
         if((zcol&0xf00) < (table[i]&0xf00))
            zcol+=0x100;
         if((zcol&0x0f0) < (table[i]&0x0f0))
            zcol+=0x010;
         if((zcol&0x00f) < (table[i]&0x00f))
            zcol+=0x001;
         SetRGB4(&vp,(long)i,(long)zcol/256,(long)(zcol/16)%16,
          (long)zcol%16);
      }
      for(i=0;i<HIAC;i++) {
         zcol=*((UWORD *)vphi.ColorMap->ColorTable+i);
         if((zcol&0xf00) < (colorhi[i]&0xf00))
            zcol+=0x100;
         if((zcol&0x0f0) < (colorhi[i]&0x0f0))
            zcol+=0x010;
         if((zcol&0x00f) < (colorhi[i]&0x00f))
            zcol+=0x001;
         SetRGB4(&vphi,(long)i,(long)zcol/256,(long)(zcol/16)%16,
          (long)zcol%16);
      }
   }
}

eintrag(wieviel)
ULONG wieviel;

/* Eintragen in die Highscore-Liste (Joystick rechts/links = Cursor steuern,
nach oben/unten = Buchstaben wechseln, Feuerknopf = Beenden) */

{
   int i,j,k;
   char z,c;

   for(i=0;i<SLOTS;i++) {
      if(slots[version][i].score<wieviel)
         break;
   }
   if(i==SLOTS)
      return();
   for(j=SLOTS-1;j>i;j--)
      slots[version][j]=slots[version][j-1];
   slots[version][i].score=wieviel;
   for(j=0;j<8;j++)
      slots[version][i].who[j]=' ';
   showhi();
   z=1; j=0;
   do {
      if((custom->joy1dat>>1 ^ custom->joy1dat)&1)
         z=(z+27)%28;
      else if((custom->joy1dat>>1 ^ custom->joy1dat)&0x100)
         z=(z+1)%28;
      else if(custom->joy1dat & 0x200) {
         if(j) {
            j--; z=slots[version][i].who[j]-'?';
         }
      }
      else if(custom->joy1dat & 2) {
         if(j<7) {
            j++; z=slots[version][i].who[j]-'?';
         }
      }
      if(z<0)
         if(z==' '-'?')
            z=1;
         else
            z=0;
      if(z==1)
         c=' ';
      else if(z==0)
         c='.';
      else
         c=z+'?';
      slots[version][i].who[j]=c;
      for(k=0;k<7;k++) {
         SetAPen(&rp2,(long)2*(k%2));
         Move(&rp2,125L+10L*j,i*10L+MITTE[kick]+VY-SLOTS*5L+2L+6L+3L);
         Draw(&rp2,125L+10L*j+10L,i*10L+MITTE[kick]+VY-SLOTS*5L+2L+6L+3L);
         sync();
      }
      SetDrMd(&rp2,JAM2);
      Move(&rp2,125L+10L*j,i*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2," ",1L);
      Move(&rp2,126L+10L*j,i*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2," ",1L);
      SetDrMd(&rp2,JAM1); SetAPen(&rp2,1L);
      Move(&rp2,125L+10L*j,i*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2,&c,1L);
      SetAPen(&rp2,2L);
      Move(&rp2,126L+10L*j,i*10L+MITTE[kick]+VY-SLOTS*5L+6L+3L);
      Text(&rp2,&c,1L);
   } while(ciaa->ciapra&0x80);
   while ((ciaa->ciapra&0x80)==0) ;
}

sync()

/* Bildschirmzeile abwarten ( VBeamPos() wird an Stelle von WaitTOF() oder
WaitBOVP() verwendet, da diese Forbid() wieder desaktivieren ) */

{
   while(VBeamPos()<240||VBeamPos()>249);
   while(VBeamPos()<250);
}

