#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>  /* for randomize only? */

int loop,loop2;
unsigned int res;
unsigned char svefile[0x93e0];

unsigned char *uid[0x1c];
unsigned char *u[1024];
unsigned char *city[128];
char *ruler[8];
char *emp[8];
int bucks[8];
char *cityname[256];

char ch,mainquit;
FILE *fp2;

main(argc,argv)
int argc;
char **argv;
{

  ch = 0x00;
  clrscr();
  if (argc != 2) {
     argv[1] = (char *)malloc(20);
     printf("Please enter an input .sve file: ");
     scanf("%s",argv[1]);
  }
  printf("Input file is %s.\n",argv[1]);

  /* read entire file in at once */
  if ((fp2 = fopen(argv[1],"rb")) == NULL) { printf("Cannot open input file.\n"); exit(1); }
  if ((res = fread(svefile,0x93e0,1,fp2)) != 1) { printf("Only got first %x bytes.\n",res); exit(1); }
  fclose(fp2);

  /* try to assign uid pointers to an area in svefile[] */
  printf("Reading unit type information...");
  for (loop=0; loop<0x1c; loop++) {
    uid[loop] = svefile + 0x2308 + 34*loop;
    putch('.');
  }
  printf("\n");

  /* try to assign unit list to an area in svefile[] */
  printf("Reading unit information...");
  for (loop=0; loop<1024; loop++) {
    u[loop] = svefile + 0x26c0 + 12*loop;
    putch('.');
  }

  /* pointers to empire stats */
  printf("Getting ruler info...");
  for (loop=0; loop<8; loop++) {
    ruler[loop] = svefile + 0x10 + 14*loop;
    emp[loop] = svefile + 0x80 + 12*loop;
    bucks[loop] = *(svefile + 0x138 + 2*loop + 1) *0x100 + *(svefile + 0x138 + 2*loop ) ;
    putch('.');
  }

  /* city stuff */
  printf("Getting city info...");
  for (loop=0; loop<256; loop++) {
    cityname[loop] = svefile + 0x6970 + 13*loop;
    putch('.');
  }
  for (loop=0; loop<128; loop++) {
    city[loop] = svefile + 0x1508 + 28*loop;
    putch('.');
  }

  mainquit = 0;
  do {
    clrscr();
    printf("Currently editing %s.  CivCheat main menu.\n",argv[1]);
    printf("  a) Edit military unit type attributes.\n");
    printf("  b) Edit a specific unit's atttributes.\n");
    printf("  c) Edit player stats, money, etc.\n");
    printf("  d) Edit city pop, food, res, works, etc.\n");
    printf("ESC) Quit to play more Civ.\n");
    gotoxy(1,20); printf("Choose your poison : ");
    ch=getche();
    switch (ch) {
      case 'a': edituid(); break;
      case 'b': editu(); break;
      case 'c': editstats(); break;
      case 'd': editcity2(); break;
      case 27: mainquit = 1; break;
    }
  } while (!mainquit);

  /* try to rewrite file. */
  if ((fp2 = fopen(argv[1],"wb")) == NULL) { printf("Cannot open output file.\n"); exit(1); }
  if ((res = fwrite(svefile,0x93e0,1,fp2)) != 1) { printf("Only wrote first %x bytes.\n",res); exit(1); }
  fclose(fp2);
  quitting();
  exit(0);

}

editu()
{
  int num,page,pages,count,loop,point[1024]; /* list of all active units */
  unsigned char dum1,dum2;
  count = 0;
  for (loop = 0; loop<1024; loop++) {
    if (*(u[loop] + 3) != 0xff) point[count++] = loop;
  }
  pages = ((count - 1)/21);
  page = 0;
  do {
    clrscr();
    gotoxy(1,1); printf("Units page %d of %d.",page,pages);
    for (loop=0; loop<20; loop++) {
      gotoxy(1,loop+2);
      num = loop + page*20;
      if (num<count) {
        printf("%4d) %s unit from %s (#%d) is at %d,%d. ",
           num,
           uid[*(u[point[num]]+3)],
           cityname[*(city[*(u[point[num]]+11)]+22)],
           *(u[point[num]]+11),
           *(u[point[num]]+1),
           *(u[point[num]]+2));
        if (*(u[point[num]]+6) == 0xff) {
             switch(*(u[point[num]]+7)) {
                case 0x1d: printf("(Fortified)"); break;
                case 0x18: printf("(Sleeping)"); break;
             }
        } else {
             printf("(Unit is moving to %d,%d)",*(u[point[num]]+6),*(u[point[num]]+7));
        }
        printf("\n");
      }
    }
    gotoxy(1,22); printf("Commands are PgUp, PgDn, E to edit, ESC to quit.");
    ch=getch();
    switch (toupper(ch)) {
      case 27: break;
      case 'E':
         do {
           gotoxy(1,23); printf("Which unit [0-%d] : ",count-1);
           scanf("%d",&num);
         } while ((num<0) || (num>=count));
         if ((num>=(page*20)) && (num<=(page*20+19))) {
            gotoxy(1,num-20*page+2); printf("->"); }
         gotoxy(1,24); printf("X,Y pos [%d,%d] : ",*(u[point[num]]+1),*(u[point[num]]+2));
            /* do i have to read em as integers then convert to char and store
               because scanf has no format command to read in bytes? */
         scanf("%d,%d",&dum1,&dum2);
         *(u[point[num]]+1) = dum1; *(u[point[num]]+2) = dum2;
         gotoxy(40,24); printf("New supporting city [%d] : ",*(u[point[num]]+11));
         scanf("%d",&dum1);
         *(u[point[num]]+11) = dum1;
         clrscr();
         printf("Unit types available.\n");
         for (loop=0; loop<0x1c; loop++) printf("%c) %-17s",loop+96,uid[loop]);
         printf("Unit is currently %s.  New type: ",uid[*(u[point[num]]+3)]); /* these pointers are getting out of hand! */
         do { ch=getch(); } while ((ch < 96) || (ch > 123));
         *(u[point[num]]+3) = ch-96;
       break;
      case 00: ch=getch();
         switch (ch) {
           case 73: page = (page == 0) ? 0 : page-1; break;
           case 81: page = (page == pages) ? pages : page+1; break;
         }
         break;
      }
  } while (ch != 27);
}

edituid()
{
  int loop;
  do {
    clrscr();
    gotoxy(1,1); printf("Format is Unit Name : Attack / Defense / Move / Resources ");
    for (loop=0; loop<0x1c; loop++) {
      gotoxy((loop>=14) ? 40 : 1, (loop>=14) ? loop-12 : loop+2);
      printf("%c) %12s:%2d/%2d/%2d/%3d",loop+96,uid[loop],*(uid[loop]+20),*(uid[loop]+22),
              *(uid[loop]+16),*(uid[loop]+24)*10);
    }
    do {
      loop = -1;
      gotoxy(1,20); printf("Which unit [letter, ESC to quit] : ");
      ch=getche();
      if ((ch >= 96) && (ch <= 123)) loop = ch-96;
    } while ((loop == -1) && (ch != 27));
    if (ch != 27) {
       gotoxy(1,21);
       printf("New Att [%d] : ",*(uid[loop]+20)); scanf("%d",uid[loop]+20);
       printf("New Def [%d] : ",*(uid[loop]+22)); scanf("%d",uid[loop]+22);
       printf("New Mov [%d] : ",*(uid[loop]+16)); scanf("%d",uid[loop]+16);
       printf("New Res [%d] : ",*(uid[loop]+24)); scanf("%d",uid[loop]+24);
    }
  } while (ch != 27);
}

editstats()
{
  int loop;
  do {
    clrscr();
    printf("The following players exist.");
    for (loop=0; loop<8; loop++) {
      gotoxy(1,2+loop);
      printf(" %c) Emporer %s of the %s has %d bucks.",loop+97,ruler[loop],emp[loop],bucks[loop]);
    }
    gotoxy(1,20); printf("Edit which one [letter, ESC to quit] : ");
    ch = getche();
    if (ch != 27) {
       loop = ch-97;
       if ((loop>=0) && (loop<=8)) {
          gotoxy(1,21); printf("New bucks [32767 max] : "); scanf("%d",&bucks[loop]);
          gotoxy(1,22); printf("Change empire name? [Y/N] : ");
          do { ch=toupper(getch()); } while ((ch != 'Y') && (ch != 'N')); putch(ch);
          if (ch == 'Y') { printf("  New name: "); scanf("%s",emp[loop]); }
          gotoxy(1,23); printf("Change emporer name? [Y/N] : ");
          do { ch=toupper(getch()); } while ((ch != 'Y') && (ch != 'N')); putch(ch);
          if (ch == 'Y') { printf("  New name: "); scanf("%s",ruler[loop]); }
       }
    }
  } while (ch != 27);
}

editcity2()
{
  int point[128];  /* pointer to active cities */
  int loop,count,page,pages,num;
  unsigned int dum1,dum2,dum3,dum4;

  count = 0;
  for (loop = 0; loop<128; loop++) {
    if (*(city[loop] + 6) != 0xff) point[count++] = loop;
  }
  pages = ((count - 1)/21);
  page = 0;

  do {
    clrscr();
    gotoxy(1,1); printf("City page %d of %d.",page,pages);
    for (loop=0; loop<20; loop++) {
      gotoxy(1,loop+2);
      num = loop + page*20;
      if (num<count) {
         printf("%4d) %s at (%d,%d) has %d pop, %d food, %d res. Works = %02x%02x%02x%02x.",
           num,
           cityname[*(city[point[num]]+22)],
           *(city[point[num]]+4),
           *(city[point[num]]+5),
           *(city[point[num]]+7),
           *(city[point[num]]+12),
           *(city[point[num]]+14),
           *(city[point[num]]),
           *(city[point[num]]+1),
           *(city[point[num]]+2),
           *(city[point[num]]+3));
      }
    }
    gotoxy(1,22); printf("Commands are PgUp, PgDn, E to edit, ESC to quit.");
    ch=getch();
    switch (toupper(ch)) {
      case 27: break;
      case 'E':
         do {
           gotoxy(1,23); printf("Which city [0-%d] : ",count-1);
           scanf("%d",&num);
         } while ((num<0) || (num>=count));
         if ((num>=(page*20)) && (num<=(page*20+19))) {
            gotoxy(1,num-20*page+2); printf("->"); }
         gotoxy(1,24); printf("New population [%d] : ",*(city[point[num]]+7));
         scanf("%d",city[point[num]]+7);
         gotoxy(27,24); printf("New food [%d] : ",*(city[point[num]]+12));
         scanf("%d",city[point[num]]+12);
         gotoxy(50,24); printf("New res [%d] : ",*(city[point[num]]+14));
         scanf("%d",city[point[num]]+14);
         gotoxy(1,25); printf("New Works Map (4 hex bytes separated by commas please) : ");
         scanf("%x,%x,%x,%x",&dum1,&dum2,&dum3,&dum4);
         *(city[point[num]]) = dum1;
         *(city[point[num]]+1) = dum2;
         *(city[point[num]]+2) = dum3;
         *(city[point[num]]+3) = dum4;
       break;
      case 00: ch=getch();
         switch (ch) {
           case 73: page = (page == 0) ? 0 : page-1; break;
           case 81: page = (page == pages) ? pages : page+1; break;
         }
         break;
      }
  } while (ch != 27);
}

quitting()
{
  char *data;
  clrscr();
  randomize();
  printf("What did you think of this program?\n");
  switch (random(5)) {
     case 0 : data = "Sid Meyer is really smart but Steve Norton is brilliant!"; break;
     case 1 : data = "Ever take a needle, dip it in acid and stick it in your eye? It's like that."; break;
     case 2 : data = "So this is what college students do when they're bored."; break;
     case 3 : data = "Cheat?  Who needs to cheat at Civ?  Its easy!"; break;
     case 4 : data = "grog need tanks. Grog Need Tanks! GROG NEED TANKS!!!"; break;
  }
  do {
    ch=getch(); putch(*data++);
  } while ((*data != 0) && (ch != 27));
  printf("\nBy the way, you can press ESC to bypass the comments.\n");
}