/*

InvaderCraft von J.Hertel
(C) CW-Publikationen

Hauptprogramm  "invadercraft.c"


Kompilieren und Linken mit Aztec C Version 3.20a.

Im Include-Directory muessen sich die Header-Files "invadercraft1.h" und
"invadercraft2.h" befinden!

Aufruf:  cc invadercraft -a
         as invadercraft

Linken:  ln invadercraft.o lader.o menu.o action.o con.o -lc
Wenn Sound-Files vorhanden und Sound eingeschaltet (s.u.):
         ln invadercraft.o lader.o menu.o action.o con.o sound.o -lc
*/


/* Falls digitalisierte Klaenge verfuegbar, Kommentarzeichen um #define-
Statement entfernen! */
/* schon geschehen */

#define SOUND_ON


/* Falls spezieller Zeichensatz ("fonts:ic/8e + fonts:ic.font") verfuegbar,
Kommentarzeichen um #define-Statement entfernen! */
/* schon geschehen */

#define DISKFONT_ON


#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <hardware/dmabits.h>
#include <hardware/custom.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <devices/audio.h>

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

#include <invadercraft1.h>
#include <invadercraft2.h>

int _Dorg();

extern struct IOAudio *ioa[];
extern struct format sdata[];
extern int demo;
extern struct liste slots[MAXVERSIONS][SLOTS];
extern long Read(),Write();
extern APTR AllocMem(),OpenLibrary();

struct IntuitionBase *IntuitionBase;
struct Library *DiskfontBase;
struct GfxBase *GfxBase;
struct RastPort rp,rp2,rphi;
struct BitMap bmhi,bm,bm2,inb,schb,misb,expb,bunb,dummyb,mistreb,
mutb,bunkerbuff[2],ab1,bssb,bsib,iff;
struct View v,*old;
struct ViewPort vp,vphi;
struct RasInfo ri,ri2,rihi;
struct ColorMap *cm,*cmhi,*GetColorMap();
#ifdef DISKFONT_ON
struct TextAttr textattr={(STRPTR)"ic.font",8,FS_NORMAL,FPF_DISKFONT};
#endif !DISKFONT_ON
#ifndef DISKFONT_ON
struct TextAttr textattr={(STRPTR)"topaz.font",10,FS_NORMAL,FPF_ROMFONT};
#endif !DISKFONT_ON
struct TextFont *font,*OpenDiskFont(),*OpenFont();
struct Custom *custom=0xDFF000;
struct CIA *ciaa=0xBFE001;
struct FileHandle *fh,*Open();
struct Screen *screen,*OpenScreen();
struct NewScreen newscreen={0,0,320,0,4};
struct NewWindow newwindow={0,0,320,256,0,0,0,BACKDROP|BORDERLESS};
struct Window *window,*OpenWindow();
struct Lock *lock;
struct FileInfoBlock *fib;

long REV[2]={0,33};
long YA[]={187L,243L};
long YA1[]={186L,242};

int titelbildtiefe,kick,trainer;

UWORD *colorp,color[40],dunkelcolors[32],dummycolors[32],titelcolors[32];

UWORD colorhi[HIAC]={ 0x000,0xddd,0xf80,0x08f };

UWORD color1 [AC] ={ 0x000,0x579,0x5ae,0x53a,
                     0xcb6,0xddf,0xfff,0x666,
                     0x000,0xfff,0x888,0xa60,
                     0xb00,0x841,0x045,0x080 };

UWORD color2 [AC] ={ 0x000,0x579,0x5ae,0x53a,
                     0xcb6,0xddf,0xfff,0x666,
                     0x000,0x883,0x0af,0xa60,
                     0xb00,0x841,0x045,0x080 };

UWORD color3 [40] ={ 0x000,0x579,0x5ae,0x53a,
                     0xcb6,0xddf,0xfff,0x666 };


main(argc,argv)
int argc;
char *argv[];

/* Programm-Anfang
CLI-Parameter dekodieren, Libraries eroeffnen, Bilder und Sounds laden,
Speicherplatz reservieren (in Form von Bitmaps), Dual-Playfield-View
einschalten und Sprung ins Hauptmenu */

{
   int i;

   if(argc==0)
      exit(1L);
   else if(argc==1 || (argc>1 && *argv[1]!='1' && *argv[1]!='2') ||
    (argc>2 && *argv[2]!='t') ) {
      printf("Syntax: %s <version> <trainer>\n",argv[0]);
      printf("<version>: '1' oder '2', fuer Kickstart Version 1.1 oder 1.2\
\n<trainer>: 't', nur angeben, wenn Trainer erwuenscht.\n");
      exit(1L);
   }
   else {
      if(*argv[1]=='2')
         kick=1;
   }
   if(argc>2)
      trainer=1;
   if((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",
    REV[kick]))==0) {
      printf("Falsche Kickstart-Diskette! Version 1.2 wird benoetigt.\n");
      closeall(0);
   }
   if((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L))==0) {
      printf("Eroeffnen von Graphics-Library erfolglos!\n");
      closeall(0);
   }
   /* Window oeffnen und wieder schliessen, um zu testen, ob erweiterte
      vertikale Aufloesung (256 Pixels) wirklich nutzbar ist. Manchmal
      laesst sich unter Kick1.2 kein Window ueber 200 Zeilen ausdehnen. */
   if(kick) {
      newwindow.Type=WBENCHSCREEN;
      if((window=OpenWindow(&newwindow))==0) {
         printf("Fehler im Amiga-Betriebssytem aufgetreten.\n\
Bitte Amiga mit Ctrl-A-A ruecksetzen!\n");
         closeall(0);
      }
      CloseWindow(window);
   }
   titelbildladen();

#ifdef SOUND_ON
   salloc();
   titelsladen();
#endif !SOUND_ON

#ifdef DISKFONT_ON
   if((DiskfontBase = (struct Library *)OpenLibrary("diskfont.library",0L))
    ==0) {
      printf("libs:diskfont.library fehlt!\n");
      closeall(0);
   }
   if((font=OpenDiskFont(&textattr))==0) {
#endif !DISKFONT_ON

#ifndef DISKFONT_ON
   if((font=OpenFont(&textattr))==0) {
#endif !DISKFONT_ON

      printf("Kann den Zeichensatz nicht eroeffnen!\n");
      closeall(0);
   }
   allocmem();
   laden();

#ifdef SOUND_ON
   for(i=0;i<ANZSOUNDS-1;i++)    /* Titelsound nicht mehr laden */
      soundladen(i);
#endif !SOUND_ON

   titelsstop();

   allocbitmap(&bm,3L,XA+2*VX,YA[kick]+2*VY);
   allocbitmap(&bm2,3L,XA+2*VX,YA[kick]+2*VY);
   allocbitmap(&bunkerbuff[0],3L,XA,BKO4);
   allocbitmap(&bunkerbuff[1],3L,XA,BKO4);
   allocbitmap(&dummyb,DUMMYT,DUMMYX,DUMMYY);

   Forbid();

   old=GfxBase->ActiView;
   InitView(&v); InitVPort(&vp); InitVPort(&vphi);

   v.ViewPort=&vphi; vphi.Next=&vp;
   v.DyOffset=old->DyOffset; v.DxOffset=old->DxOffset;
   vphi.ColorMap=cmhi; vphi.RasInfo=&rihi; vphi.DWidth=HIXA;
   vphi.DHeight=HIYA;  vphi.Modes=HIRES;
   vp.ColorMap=cm;  vp.RasInfo=&ri; vp.DWidth=XA; vp.DHeight=YA[kick];
   vp.Modes=DUALPF; vp.DyOffset=BLKLINE+HIYA;
   rihi.BitMap=&bmhi;
   ri.BitMap=&bm;   ri2.BitMap=&bm2;
   ri.RyOffset=VY;  ri2.RyOffset=VY;
   ri.RxOffset=VX;  ri2.RxOffset=VX;
   ri.Next=&ri2;

   InitRastPort(&rphi);
   rphi.BitMap=&bmhi;
   InitRastPort(&rp); InitRastPort(&rp2);
   SetDrMd(&rp,JAM1); SetDrMd(&rp2,JAM1);
   rp.BitMap=&bm; rp2.BitMap=&bm2;

   MakeVPort(&v,&vphi);
   MakeVPort(&v,&vp);
   MrgCop(&v);

   SetRast(&rp,0L); SetRast(&rp2,0L); SetRast(&rphi,0L); SetAPen(&rphi,1L);
   SetBPen(&rphi,0L); SetDrMd(&rphi,JAM2); SetFont(&rphi,font);
   SetFont(&rp,font); SetFont(&rp2,font);
   LoadRGB4(&vp,dunkelcolors,(long)AC);
   LoadRGB4(&vphi,dunkelcolors,(long)HIAC);

   LoadView(&v);
   sync(); sync();
   ON_DISPLAY

   anfang();

   Permit();
   LoadView(old);
   WaitTOF();
   ON_SPRITE
   hisave();
   FreeVPortCopLists(&vp); FreeVPortCopLists(&vphi);
   FreeCprList(v.LOFCprList);
   closeall(0);
}

titelsstop()

/* Titelbild und Titelsound sanft ausblenden, Speicher zurueckgeben,
Screen schliessen  */

{
   int i,j;
   UWORD zcol;

   for(j=0;j<16;j++) {
      sync();

#ifdef SOUND_ON
      soundvol(16,60-j*4,3);
      soundvol(16,60-j*4,4);
#endif !SOUND_ON

      sync();
      for(i=0; i < 1<<titelbildtiefe ;i++) {
         zcol=*((UWORD *)screen->ViewPort.ColorMap->ColorTable+i);
         if(zcol&0xf00)
            zcol-=0x100;
         if(zcol&0x0f0)
            zcol-=0x010;
         if(zcol&0x00f)
            zcol-=0x001;
         SetRGB4(&screen->ViewPort,(long)i,(long)zcol/256,(long)(zcol/16)%16,
          (long)zcol%16);
      }
   }

#ifdef SOUND_ON
   if(sdata[16].name) {
      ioa[3]->ioa_Request.io_Command=CMD_FLUSH;
      ioa[3]->ioa_Request.io_Flags=IOF_QUICK;
      ioa[4]->ioa_Request.io_Command=CMD_FLUSH;
      ioa[4]->ioa_Request.io_Flags=IOF_QUICK;
      BeginIO(ioa[3]);
      BeginIO(ioa[4]);
      Delay(30L);
      FreeMem(sdata[16].buffer,sdata[16].len);   sdata[16].buffer=0;
   }
#endif !SOUND_ON

   CloseScreen(screen);   screen=0;
   OFF_DISPLAY
}

soundvol(which,vol,channel)
int which,vol,channel;

/* Lautstaerke eines gerade ertoenenden Klangs veraendern
   which   = Soundfilenummer 0...ANZSOUNDS-1
   vol     = Lautstaerke      0...64
   channel = Kanalnummer      1...4  */

{
#ifdef SOUND_ON
   if(sdata[which].name) {
      ioa[channel]->ioa_Request.io_Command=ADCMD_PERVOL;
      ioa[channel]->ioa_Request.io_Flags=IOF_QUICK;
      ioa[channel]->ioa_Period=(UWORD)((int)sdata[which].period);
      ioa[channel]->ioa_Volume=vol;
      BeginIO(ioa[channel]);
   }
#endif !SOUND_ON
   ;
}

sound(which,deltaf,channel)
int which,deltaf,channel;

/* Bestimmten Sound abspielen
   which   = Soundfilenummer  0...ANZSOUNDS-1
   deltaf =  Abweichung von
             vordef. Period
                              je nach Period
   channel = Kanalnummer      1...4         */

{
#ifdef SOUND_ON
   if(sdata[which].name && demo==0) {
      ioa[channel]->ioa_Request.io_Command=CMD_FLUSH;
      ioa[channel]->ioa_Request.io_Flags=IOF_QUICK;
      BeginIO(ioa[channel]);
      ioa[channel]->ioa_Request.io_Command=CMD_WRITE;
      ioa[channel]->ioa_Request.io_Flags=ADIOF_PERVOL|IOF_QUICK;
      ioa[channel]->ioa_Data=sdata[which].buffer;
      if((int)sdata[which].period+deltaf<90)
         ioa[channel]->ioa_Period=90;
      else
         ioa[channel]->ioa_Period=(UWORD)((int)sdata[which].period+deltaf);
      ioa[channel]->ioa_Cycles=sdata[which].cycles;
      ioa[channel]->ioa_Length=sdata[which].len;
      ioa[channel]->ioa_Volume=sdata[which].volume;
      BeginIO(ioa[channel]);
   }
#endif !SOUND_ON
   ;
}

laden()

/* IFF-Bilder (fuer Animation der Invaders,Schuesse...) laden, in
die dafuer vorgesehenen Bitmaps kopieren und Highscore-Tabelle laden
bzw., wenn nicht vorhanden, initialisieren. */

{
   int i,j,k;

   getiff("ic.data:lo-res/about",&iff,&color3[8]);
   BltBitMap(&iff,0L,0L,&ab1,0L,0L,ABOUTWIDTH,ABOUTHEIGHT,0xc0L,7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/invader1",&iff,color);
   BltBitMap(&iff,0L,0L,&inb,0L,0L,320L,INY*PHASEN,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/invader2",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&inb,320L,0L,320L,INY*PHASEN,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/invader3",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&inb,640L,0L,320L,INY*PHASEN,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/schuss",&iff,&color[8]);
   BltBitMap(&iff,0L,0L,&schb,0L,0L,SCHWIDTH,SCHHEIGHT*SCHPHASEN,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/missile",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&misb,0L,0L,MISWIDTH,MISHEIGHT*MISPHASEN,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/explosion",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&expb,0L,0L,EXPWIDTH,EXPHEIGHT*EXPPHASEN,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/bunker",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&bunb,0L,0L,BWIDTH,BHEIGHT,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/bunkertreffers",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&bssb,0L,0L,BSSWIDTH,BSSHEIGHT,0xc0L,0x1L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/bunkertrefferi",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&bsib,0L,0L,BSIWIDTH,BSIHEIGHT,0xc0L,0x1L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/missiletreffer",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&mistreb,0L,0L,MTWIDTH,MTHEIGHT,0xc0L,0x7L);
   freebitmap(&iff);
   getiff("ic.data:lo-res/mutterschiff",&iff,dummycolors);
   BltBitMap(&iff,0L,0L,&mutb,0L,0L,MUTWIDTH*MUTANZ,
    MUTHEIGHT*(MUTPHASEN+MUTEXPPHASEN),0xc0L,0x7L);
   freebitmap(&iff);

   for(k=0;k<MAXVERSIONS;k++)
      for(i=0;i<SLOTS;i++)
         for(j=0;j<8;j++)
            slots[k][i].who[j]='-';
   if((fh=Open("ic.data:highscores",MODE_OLDFILE))==0) {
      return();
   }
   if(Read(fh,slots,(long)sizeof(slots))!=sizeof(slots)) {
      printf("Lesefehler in Datei ic.data:highscores (kein Problem!).\n");
      for(k=0;k<MAXVERSIONS;k++)
         for(i=0;i<SLOTS;i++) {
            for(j=0;j<8;j++)
               slots[k][i].who[j]='-';
            slots[k][i].score=0;
         }
   }
   Close(fh); fh=0;
}

hisave()

/* Highscore-Tabelle abspeichern */

{
   if((fh=Open("ic.data:highscores",MODE_NEWFILE))==NULL) {
      printf("Highscores wurden nicht abgespeichert.\n");
      return();
   }
   if(Write(fh,slots,(long)sizeof(slots))!=sizeof(slots)) {
      printf("Schreibfehler in Datei ic.data:highscores !\n");
   }
   Close(fh); fh=0;
   return();
}

allocmem()

/* Bitmaps und Colormaps bereitstellen */

{
   allocbitmap(&bssb,1L,BSSWIDTH,BSSHEIGHT);
   allocbitmap(&bsib,1L,BSIWIDTH,BSIHEIGHT);
   allocbitmap(&inb,INT,INX,INY*PHASEN);
   allocbitmap(&schb,SCHT,SCHWIDTH,SCHHEIGHT*SCHPHASEN);
   allocbitmap(&misb,MIST,MISWIDTH,MISHEIGHT*MISPHASEN);
   allocbitmap(&expb,EXPT,EXPWIDTH,EXPHEIGHT*(EXPPHASEN+1));
   allocbitmap(&bunb,BT,BWIDTH,BHEIGHT);
   allocbitmap(&mistreb,MTT,MTWIDTH,MTHEIGHT);
   allocbitmap(&mutb,MUTT,MUTWIDTH*MUTANZ,MUTHEIGHT*(MUTEXPPHASEN+1+
    MUTPHASEN));
   allocbitmap(&bmhi,HIT,HIXA,HIYA);
   allocbitmap(&ab1,3L,320L,38L);
   if((cm=GetColorMap((long)AC))==0) {
      printf("GetColorMap() erfolglos...\n");
      closeall(1);
   }
   if((cmhi=GetColorMap((long)HIAC))==0) {
      printf("GetColorMap() erfolglos...\n");
      closeall(1);
   }
}

titelbildladen()

/* Titelbild laden; Format: 320x200 oder 320x256 max. 32 Farben */

{
   UWORD zcol;
   int j,i;

   getiff("ic.data:lo-res/titelbild",&iff,titelcolors);
   titelbildtiefe=iff.Depth;
   if( iff.BytesPerRow!=40 || (iff.Rows!=200 && iff.Rows!=256) ) {
      printf("Titelbild hat falsches Format\n");
      closeall(0);
   }
   if(kick)
      newscreen.Height=256;
   else
      newscreen.Height=200;
   newscreen.Depth=titelbildtiefe;
   if((screen=OpenScreen(&newscreen))==0) {
      printf("OpenScreen() erfolglos!\n");
      closeall(0);
   }
   LoadRGB4(&screen->ViewPort,dunkelcolors,1L<<titelbildtiefe);
   SetRast(&screen->RastPort,0L);
   if(kick){
      if(iff.Rows==256)
         BltBitMap(&iff,0L,0L,&screen->BitMap,0L,0L,320L,256L,
          0xc0L,0xffL);
      else
         BltBitMap(&iff,0L,0L,&screen->BitMap,0L,28L,320L,200L,
          0xc0L,0xffL);
   }
   else {
      if(iff.Rows==256)
         BltBitMap(&iff,0L,28L,&screen->BitMap,0L,0L,320L,200L,
          0xc0L,0xffL);
      else
         BltBitMap(&iff,0L,0L,&screen->BitMap,0L,0L,320L,200L,
          0xc0L,0xffL);
   }
   freebitmap(&iff);
   for(j=0;j<15;j++) {
      sync();
      for(i=0; i < 1<<titelbildtiefe ;i++) {
         zcol=*((UWORD *)screen->ViewPort.ColorMap->ColorTable+i);
         if((zcol&0xf00) < (titelcolors[i]&0xf00))
            zcol+=0x100;
         if((zcol&0x0f0) < (titelcolors[i]&0x0f0))
            zcol+=0x010;
         if((zcol&0x00f) < (titelcolors[i]&0x00f))
            zcol+=0x001;
         SetRGB4(&screen->ViewPort,(long)i,(long)zcol/256,
          (long)(zcol/16)%16,(long)zcol%16);
      }
   }
}

closeall(fehler)
int fehler;

/* Alle reservierten Speicherstuecke und Bitmaps freigeben, Fonts,
Libraries,usw. schliessen */

{
   int i;

   ON_DISPLAY
#ifdef SOUND_ON
   frees();
   for(i=0;i<ANZSOUNDS;i++)
      if(sdata[i].buffer)
         FreeMem(sdata[i].buffer,sdata[i].len);
   if(lock)
      UnLock(lock);
   if(fib)
      FreeMem(fib,(long)sizeof(struct FileInfoBlock));
#endif !SOUND_ON
   if(fh)
      Close(fh);
   if(font)
      CloseFont(font);
   if(cmhi)
      FreeColorMap(cmhi);
   if(cm)
      FreeColorMap(cm);
   freebitmap(&iff);           freebitmap(&ab1);     freebitmap(&bmhi);
   freebitmap(&mutb);          freebitmap(&mistreb); freebitmap(&dummyb);
   freebitmap(&bunb);          freebitmap(&expb);    freebitmap(&misb);
   freebitmap(&schb);          freebitmap(&bm);      freebitmap(&bm2);
   freebitmap(&inb);           freebitmap(&bssb);    freebitmap(&bsib);
   freebitmap(&bunkerbuff[1]); freebitmap(&bunkerbuff[0]);
   if(screen)
      CloseScreen(screen);
#ifdef DISKFONT_ON
   if(DiskfontBase)
      CloseLibrary(DiskfontBase);
#endif !DISKFONT_ON
   if(GfxBase)
      CloseLibrary(GfxBase);
   if(IntuitionBase)
      CloseLibrary(IntuitionBase);
   if(fehler)
      printf("Zu wenig Speicherplatz!\n");
   exit(0);
}

