]> git.pond.sub.org Git - empserver/blobdiff - src/util/fairland.c
Update copyright notice.
[empserver] / src / util / fairland.c
index aed7e333661e7b5ba58d7cc9c23237b8b52703ed..58ad7c563791eff5c005143820c6880aab088864 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                           Ken Stevens, Steve McClure
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -19,9 +19,9 @@
  *
  *  ---
  *
- *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- *  related information and legal notices. It is expected that any future
- *  projects/authors will amend these files as needed.
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
  *
  *  ---
  *
@@ -32,6 +32,8 @@
  *     Steve McClure, 1998
  */
 
+#include <config.h>
+
 /* define ORE 1 to add resources, define ORE 0 if you want to use another
    program to add the resources */
 static int ORE = 1;
@@ -64,24 +66,25 @@ static int quiet = 0;
 /* lower URAN_MIN for more uranium */
 #define URAN_MIN   56
 
-#if defined(aix) || defined(linux) || defined(solaris)
+#if defined(_WIN32)
+#include "../lib/gen/getopt.h"
+#else
 #include <unistd.h>
-#endif /* aix or linux */
+#endif
 
+#include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <fcntl.h>
-#include "var.h"
+#include "file.h"
 #include "misc.h"
-#include "power.h"
 #include "nat.h"
-#include "sect.h"
-#include "gamesdef.h"
-#include "file.h"
-#include "xy.h"
 #include "optlist.h"
+#include "power.h"
 #include "prototypes.h"
+#include "sect.h"
+#include "version.h"
+#include "xy.h"
 
 /* do not change these 4 defines */
 #define LANDMIN                1       /* plate altitude for normal land */
@@ -92,7 +95,8 @@ static int quiet = 0;
 static void qprint(const char * const fmt, ...)
     ATTRIBUTE((format (printf, 1, 2)));
 
-static const char *outfile = "newcap_script";
+#define DEFAULT_OUTFILE_NAME "newcap_script"
+static const char *outfile = DEFAULT_OUTFILE_NAME;
 /* mark the continents with a * so you can tell them
    from the islands 1 = mark, 0 = don't mark. */
 static int AIRPORT_MARKER = 0;
@@ -101,6 +105,8 @@ static int AIRPORT_MARKER = 0;
    1 = don't merge, 0 = merge. */
 static int DISTINCT_ISLANDS = 1;
 
+static char *program_name;
+
 #define XSIZE           ((WORLD_X) / 2)        /* basically world x-y size */
 #define YSIZE           (WORLD_Y)
 #define STABLE_CYCLE 4         /* stability required for perterbed capitals */
@@ -120,16 +126,7 @@ static int DISTINCT_ISLANDS = 1;
 
 #define new_x(newx) (((newx) + WORLD_X) % WORLD_X)
 #define new_y(newy) (((newy) + WORLD_Y) % WORLD_Y)
-#if !defined(_WIN32)
-#define max(a,b) (a>b?a:b)
-#endif
-#ifndef SRANDOM
-#define SRANDOM srandom
-#endif
-#ifndef RANDOM
-#define RANDOM random
-#endif
-#define rnd(x) (RANDOM() % (x))
+#define rnd(x) (random() % (x))
 
 int secs;                      /* number of sectors grown */
 int ctot;                      /* total number of continents and islands grown */
@@ -153,16 +150,18 @@ int **sectc;                      /* which sectors are on the coast? */
 int *vector;                   /* used for measuring distances */
 int *weight;                   /* used for placing mountains */
 int *dsea, *dmoun;             /* the dist to the ocean and mountain */
-int the_file;                  /* the file we write everything to */
+FILE *sect_fptr;                       /* the file we write everything to */
 struct sctstr **sects;
 struct sctstr *sectsbuf;
 int fl_status;                 /* is anything wrong? */
-#define STATUS_NO_ROOM (1)     /* there was no room to grow */
+#define STATUS_NO_ROOM 1       /* there was no room to grow */
 #define NUMTRIES 10            /* keep trying to grow this many times */
 
 const char *numletter =
     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
 
+static void help(char *);
+static void usage(void);
 static void parse_args(int argc, char *argv[]);
 static int allocate_memory(void);
 static void init(void);
@@ -176,9 +175,9 @@ static int write_newcap_script(void);
 static int stable(void);
 static void elevate_land(void);
 static void elevate_sea(void);
-static void translate_continents(void);
 static int map_symbol(int x, int y);
-static void fl_sct_init(coord x, coord y, s_char *ptr);
+static void fl_sct_init(coord, coord, struct sctstr *, time_t timestamp);
+static void set_coastal_flags(void);
 
 static void print_vars(void);
 static void fl_move(int);
@@ -193,54 +192,51 @@ int
 main(int argc, char *argv[])
 {
     int opt;
-    extern int optind;
-    extern char *optarg;
     char *config_file = NULL;
-    char tbuf[512];
     int i = 0;
 
+    program_name = argv[0];
     rnd_seed = time(NULL);
-#if !defined(_WIN32)
-    rnd_seed += getpid();
 
-    while ((opt = getopt(argc, argv, "ae:ioqs:R:")) != EOF) {
+    while ((opt = getopt(argc, argv, "ae:hioqR:s:v")) != EOF) {
        switch (opt) {
        case 'a':
            AIRPORT_MARKER = 1;
            break;
-       case 'i':
-           DISTINCT_ISLANDS = 0;
-           break;
        case 'e':
            config_file = optarg;
            break;
+       case 'i':
+           DISTINCT_ISLANDS = 0;
+           break;
        case 'o':
            ORE = 0;
            break;
        case 'q':
            quiet = 1;
            break;
-       case 's':
-           outfile = optarg;
-           break;
        case 'R':
            rnd_seed = strtoul(optarg, NULL, 10);
            break;
+       case 's':
+           outfile = optarg;
+           break;
+       case 'h':
+           usage();
+           exit(0);
+       case 'v':
+           printf("%s\n\n%s", version, legal);
+           exit(0);
+       default:
+           help(NULL);
+           exit(1);
        }
     }
-#endif
-    SRANDOM(rnd_seed);
-    if (config_file == NULL) {
-       sprintf(tbuf, "%s/econfig", datadir);
-       config_file = tbuf;
-    }
-    emp_config(config_file);
+    srandom(rnd_seed);
+    if (emp_config(config_file))
+       exit(1);
 
-#if !defined(_WIN32)
     parse_args(argc - optind, argv + optind);
-#else
-    parse_args(argc - 1, argv + 1);
-#endif
     if (allocate_memory() == -1)
        exit(-1);
     print_vars();
@@ -311,29 +307,48 @@ my_sqrt(int n)
   PARSE COMMAND LINE ARGUMENTS
 ****************************************************************************/
 
+static void
+help(char *complaint)
+{
+    if (complaint)
+       fprintf(stderr, "%s: %s\n", program_name, complaint);
+    fprintf(stderr, "Try -h for help.\n");
+}
+
+static void
+usage(void)
+{
+    printf("Usage: %s [OPTION]... NC SC [NI] [IS] [SP] [PM] [DI] [ID]\n"
+          "  -a              airport marker for continents\n"
+          "  -e CONFIG-FILE  configuration file\n"
+          "                  (default %s)\n"
+          "  -h              display this help and exit\n"
+          "  -i              islands may merge\n"
+          "  -o              don't set resources\n"
+          "  -q              quiet\n"
+          "  -R SEED         seed for random number generator\n"
+          "  -s SCRIPT       name of script to create (default %s)\n"
+          "  NC              number of continents\n"
+          "  SC              continent size\n"
+          "  NI              number of islands (default NC)\n"
+          "  IS              average island size (default SC/2)\n"
+          "  SP              spike percentage: 0 = round, 100 = snake (default %d)\n"
+          "  PM              percentage of land that is mountain (default %d)\n"
+          "  DI              minimum distance between continents (default %d)\n"
+          "  ID              minimum distance from islands to continents (default %d)\n",
+          program_name, dflt_econfig, DEFAULT_OUTFILE_NAME,
+          DEFAULT_SPIKE, DEFAULT_MOUNTAIN, DEFAULT_CONTDIST, DEFAULT_ISLDIST);
+}
+
 static void
 parse_args(int argc, char *argv[])
 {
-    if (argc < 2 || argc > 8) {
-       puts("fairland syntax:\n");
-       puts("fairland [-e config] [-aiqo] [-s script] [-R seed] <nc> <sc> [<ni>] [<is>] [<sp>] [<pm>] [<di>] [<id>]");
-       puts("-q = quiet, -o = no ore produced");
-       puts("-a = Airport marker for continents, -i = islands not distinct");
-       puts("-R = seed to use for random, -e = read config file");
-       printf("-s = name of script (default %s)\n",
-              outfile);
-       puts("nc = number of continents [MANDATORY]");
-       puts("sc = continent size [MANDATORY]");
-       puts("ni = number of islands (default = nc)");
-       puts("is = average size of islands (default = sc/2)");
-       printf("sp = spike percentage: 0 = round, 100 = snake (default = %d)\n",
-              DEFAULT_SPIKE);
-       printf("pm = the percentage of land that is mountain (default = %d)\n",
-              DEFAULT_MOUNTAIN);
-       printf("di = the minimum distance between continents (default = %d)\n",
-              DEFAULT_CONTDIST);
-       printf("id = minimum distance from islands to continents (default = %d)\n",
-              DEFAULT_ISLDIST);
+    if (argc < 2) {
+       help("missing arguments");
+       exit(1);
+    }
+    if (argc > 8) {
+       help("too many arguments");
        exit(1);
     }
     nc = atoi(argv[0]);
@@ -418,50 +433,46 @@ static int
 allocate_memory(void)
 {
     int i;
+    char *fname;
 
-#if !defined(_WIN32)
-    the_file =
-       open(empfile[EF_SECTOR].file, O_RDWR | O_CREAT | O_TRUNC, 0660);
-#else
-    the_file =
-       open(empfile[EF_SECTOR].file,
-            O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0660);
-#endif
-    if (the_file < 0) {
-       perror(empfile[EF_SECTOR].file);
+    fname = malloc(strlen(gamedir) + 1 + strlen(empfile[EF_SECTOR].file) + 1);
+    sprintf(fname, "%s/%s", gamedir, empfile[EF_SECTOR].file);
+    sect_fptr = fopen(fname, "wb");
+    if (sect_fptr == NULL) {
+       perror(fname);
        return -1;
     }
-    sectsbuf =
-       (struct sctstr *)calloc((YSIZE * XSIZE), sizeof(struct sctstr));
-    sects = (struct sctstr **)calloc(YSIZE, sizeof(struct sctstr *));
+    free(fname);
+    sectsbuf = calloc((YSIZE * XSIZE), sizeof(struct sctstr));
+    sects = calloc(YSIZE, sizeof(struct sctstr *));
     for (i = 0; i < YSIZE; i++)
        sects[i] = &sectsbuf[XSIZE * i];
-    capx = (int *)calloc(nc, sizeof(int));
-    capy = (int *)calloc(nc, sizeof(int));
-    vector = (int *)calloc(WORLD_X + WORLD_Y, sizeof(int));
-    mc = (int *)calloc(STABLE_CYCLE, sizeof(int));
-    own = (int **)calloc(WORLD_X, sizeof(int *));
-    elev = (int **)calloc(WORLD_X, sizeof(int *));
+    capx = calloc(nc, sizeof(int));
+    capy = calloc(nc, sizeof(int));
+    vector = calloc(WORLD_X + WORLD_Y, sizeof(int));
+    mc = calloc(STABLE_CYCLE, sizeof(int));
+    own = calloc(WORLD_X, sizeof(int *));
+    elev = calloc(WORLD_X, sizeof(int *));
     for (i = 0; i < WORLD_X; ++i) {
-       own[i] = (int *)calloc(WORLD_Y, sizeof(int));
-       elev[i] = (int *)calloc(WORLD_Y, sizeof(int));
+       own[i] = calloc(WORLD_Y, sizeof(int));
+       elev[i] = calloc(WORLD_Y, sizeof(int));
     }
-    sectx = (int **)calloc(nc + ni, sizeof(int *));
-    secty = (int **)calloc(nc + ni, sizeof(int *));
-    sectc = (int **)calloc(nc + ni, sizeof(int *));
-    isecs = (int *)calloc(nc + ni, sizeof(int));
-    weight = (int *)calloc(max(sc, is * 2), sizeof(int));
-    dsea = (int *)calloc(max(sc, is * 2), sizeof(int));
-    dmoun = (int *)calloc(max(sc, is * 2), sizeof(int));
+    sectx = calloc(nc + ni, sizeof(int *));
+    secty = calloc(nc + ni, sizeof(int *));
+    sectc = calloc(nc + ni, sizeof(int *));
+    isecs = calloc(nc + ni, sizeof(int));
+    weight = calloc(MAX(sc, is * 2), sizeof(int));
+    dsea = calloc(MAX(sc, is * 2), sizeof(int));
+    dmoun = calloc(MAX(sc, is * 2), sizeof(int));
     for (i = 0; i < nc; ++i) {
-       sectx[i] = (int *)calloc(sc, sizeof(int));
-       secty[i] = (int *)calloc(sc, sizeof(int));
-       sectc[i] = (int *)calloc(sc, sizeof(int));
+       sectx[i] = calloc(sc, sizeof(int));
+       secty[i] = calloc(sc, sizeof(int));
+       sectc[i] = calloc(sc, sizeof(int));
     }
     for (i = nc; i < nc + ni; ++i) {
-       sectx[i] = (int *)calloc(is * 2, sizeof(int));
-       secty[i] = (int *)calloc(is * 2, sizeof(int));
-       sectc[i] = (int *)calloc(is * 2, sizeof(int));
+       sectx[i] = calloc(is * 2, sizeof(int));
+       secty[i] = calloc(is * 2, sizeof(int));
+       sectc[i] = calloc(is * 2, sizeof(int));
     }
 
     return 0;
@@ -767,6 +778,9 @@ grow_continents(void)
            grow_one_sector(c);
        }
     }
+    for (c = 0; c < nc; ++c)
+       find_coast(c);
+
     if (fl_status)
        qprint("Only managed to grow %d out of %d sectors.\n", secs, sc);
     ctot = nc;
@@ -794,7 +808,7 @@ place_island(int c, int *xp, int *yp)
        for (*yp = sy; *xp != sx || *yp != sy; *xp += 2) {
            if (*xp >= WORLD_X) {
                *yp = new_y(*yp + 1);
-               *xp = (*yp) % 2;
+               *xp = *yp % 2;
                if (*xp == sx && *yp == sy)
                    break;
            }
@@ -822,6 +836,7 @@ grow_islands(void)
            ++secs;
            find_coast(c);
        } while (secs < isiz && grow_one_sector(c));
+       find_coast(c);
        qprint(" %d(%d)", c - nc + 1, secs);
        isecs[c] = secs;
        ctot = c;
@@ -1068,14 +1083,15 @@ add_resources(struct sctstr *sct)
 static void
 write_sects(void)
 {
-    register struct sctstr *sct;
+    struct sctstr *sct;
     int c, x, y, total;
+    time_t current_time = time(NULL);
 
     /*  sct = &sects[0][0]; */
     sct = sectsbuf;
     for (y = 0; y < YSIZE; y++) {
        for (x = 0; x < XSIZE; x++, sct++) {
-           fl_sct_init(x * 2 + (y & 01), y, (s_char *)sct);
+           fl_sct_init(x * 2 + (y & 1), y, sct, current_time);
            total = elev[sct->sct_x][y];
            if (total < LANDMIN) {
                sct->sct_type = SCT_WATER;
@@ -1098,6 +1114,7 @@ write_sects(void)
            sects[capy[c]][capx[c] / 2 + capy[c] % 2].sct_type = SCT_AIRPT;
            sects[capy[c]][capx[c] / 2 + capy[c] % 2].sct_newtype = SCT_AIRPT;
        }
+    set_coastal_flags();
 }
 
 /****************************************************************************
@@ -1108,16 +1125,16 @@ write_file(void)
 {
     int n;
 
-    /*  if ((n = write(the_file, sects, sizeof(sects))) < 0) { */
-    if ((n = write(the_file, sectsbuf, YSIZE * XSIZE * sizeof(struct sctstr))) < 0) {
+    n = fwrite(sectsbuf, sizeof(struct sctstr), YSIZE * XSIZE, sect_fptr);
+    if (n <= 0) {
        perror(empfile[EF_SECTOR].file);
        return -1;
     }
-    if (n != (int)(YSIZE * XSIZE * sizeof(struct sctstr))) {
+    if (n != YSIZE * XSIZE) {
        printf("%s:partial write\n", empfile[EF_SECTOR].file);
        return -1;
     }
-    close(the_file);
+    fclose(sect_fptr);
     return 0;
 }
 
@@ -1128,8 +1145,6 @@ static void
 output(void)
 {
     int i, j;
-    if (opt_BLITZ)
-       translate_continents();
     if (quiet == 0) {
        for (i = 0; i < WORLD_Y; ++i) {
            puts("");
@@ -1148,55 +1163,6 @@ output(void)
        printf("\n\nEach continent is marked by a \"*\" on the map (to distinguish them from\nthe islands).  You can redesignate these airfields to wilderness sectors\none at a time, each time you add a new country to the game.\n");
 }
 
-/* Reorder the continents from top left to bottom right */
-static void
-translate_continents(void)
-{
-    int i, j, n = 0, k, gotit, c;
-    int *trans, *trans_cont, *oldcapx, *oldcapy;
-
-    trans = (int *)calloc(nc, sizeof(int));
-    trans_cont = (int *)calloc(nc, sizeof(int));
-    oldcapx = (int *)calloc(nc, sizeof(int));
-    oldcapy = (int *)calloc(nc, sizeof(int));
-
-    for (i = 0; i < WORLD_Y; ++i) {
-       for (j = i % 2; j < WORLD_X; j += 2) {
-           if (own[j][i] > -1 && own[j][i] < nc) {
-               gotit = 0;
-               for (k = 0; k < n; ++k) {
-                   if (trans[k] == own[j][i])
-                       gotit = 1;
-               }
-               if (!gotit) {
-                   if (n > nc) {
-                       printf("fairland: BUG in translate continents!  mail stevens@math.utoronto.ca\n");
-                       exit(2);
-                   }
-                   trans[n] = own[j][i];
-                   trans_cont[own[j][i]] = n;
-                   ++n;
-               }
-           }
-       }
-    }
-    for (i = 0; i < WORLD_Y; ++i) {
-       for (j = i % 2; j < WORLD_X; j += 2) {
-           if (own[j][i] > -1 && own[j][i] < nc) {
-               own[j][i] = trans_cont[own[j][i]];
-           }
-       }
-    }
-    for (c = 0; c < nc; ++c) {
-       oldcapx[c] = capx[c];
-       oldcapy[c] = capy[c];
-    }
-    for (c = 0; c < nc; ++c) {
-       capx[c] = oldcapx[trans[c]];
-       capy[c] = oldcapy[trans[c]];
-    }
-}
-
 static int
 map_symbol(int x, int y)
 {
@@ -1253,10 +1219,8 @@ qprint(const char * const fmt, ...)
 }
 
 static void
-fl_sct_init(coord x, coord y, s_char *ptr)
+fl_sct_init(coord x, coord y, struct sctstr *sp, time_t timestamp)
 {
-    struct sctstr *sp = (struct sctstr *)ptr;
-
     sp->ef_type = EF_SECTOR;
     sp->sct_x = x;
     sp->sct_y = y;
@@ -1265,4 +1229,20 @@ fl_sct_init(coord x, coord y, s_char *ptr)
     sp->sct_road = 0;
     sp->sct_rail = 0;
     sp->sct_defense = 0;
+    sp->sct_timestamp = timestamp;
+    sp->sct_coastal = 1;
+}
+
+static void
+set_coastal_flags(void)
+{
+    int i, j;
+
+    qprint("setting coastal flags...\n");
+    for (i = 0; i < nc; ++i)
+       for (j = 0; j < sc; j++)
+           sects[secty[i][j]][sectx[i][j] / 2].sct_coastal = sectc[i][j];
+    for (i = nc; i < nc + ni; ++i)
+       for (j = 0; j < isecs[i]; j++)
+           sects[secty[i][j]][sectx[i][j] / 2].sct_coastal = sectc[i][j];
 }