Nroute.c

From Traveller Wiki - Science-Fiction Adventure in the Far future
Jump to navigation Jump to search
 
/* (c) Anthony Jackson (ac_jackson@yahoo.com), 3/27/2000 */
/* permission granted to copy and modify this file for noncommercial
   purposes, as long as this copyright message is preserved.  For other
   uses, contact me.  */
/* Additional work done by Thomas Jones-Low
   * Refactored to output the .wiki files for uploading into the Traveller Wiki
   * Fixed a number of small bugs
   * Added the (not yet working) Quadrant pdf files generation. 
   * Added Zhodani Travel Zones
   * Made stars->neighbors[] an int for > 32K stars. 
   * Added Allegiances names support
   * Moved sector summaries into struct sector
   * Fixed allegiance handling to work with duplicate allegiance codes
*/
/* 
   compile with gcc -O2 nroute.c -o nroute -lc -lm 
   Usage: takes a list of sector files as arguments.  Of those files, the
   first line is the sector name, the second line is the x and y position
   of the sector (separated by a space; cannot be negative), the third
   line must have the numbers 1-7 at each of the following:
   1)   position
   2)   start of UWP
   3)   base code
   4)   trade classifications
   5)   zone (amber, red, etc)
   6)   PBG
   7)   alignment
   All must be present, though they need not be in this order.  The name 
   must be at the start of the line, however, and the position should be
   second.  There may not be comments on the first three lines; beyond
   that any line starting with # is considered a comment.  All sectors on
   the command line will be mapped.
   
   Any line that begins with a '+' is assumed to be an allegiance code line. 
   The + should be followed by a two letter allegiance code, a space, and a 
   short text description of the allegiance code (e.g. name of the polity). 
   Example:
 +Zh Zhodani Consulate
    The name (all of the rest of the text on the line) is output in the 
    allegiance listings in the top_summary.html, top_summary.wiki and the
    sector summaries (html and wiki). In the wiki files, they are created as 
    wiki links. 
    If you have multiple sector files with the same allegiance code, only 
    the text from the first file is used. 
    
    Note on allegiance codes. It is best if they are unique across all of 
    charted space, that is each government is given a unique Allegiance 
    code. However, as long as each duplicates is confined to a single sector, 
    the nroute correctly calculates the statistics for each of the different 
    (but duplicated) allegiance codes. If the same allegiance code is in two 
    sector files, the name given to them in the allegiance code line determines 
    if they are the same or different allegiances. A warning is posted every 
    time a duplicate code is found. If you see a warning posted that looks like 
    it should be the same allegiance, check the spelling and the spaces at the end
    of the name. 
 */
/* - requires the file blankmap.ps in the same directory as you are running
   from.  Don't edit unless you know postscript. 
   - requires ps2pdf which is run as part of the sector generation. 
   - requires a tool that can convert .ppm graphics files to .gif
   - requires a writeable directory named "sec" in the same directory. 
   
   Outputs: 
   allmap.ppm - Graphic of the sector worlds, borders, and trade routes
   map.html   - image map using .gif of above, plus links to the summaries
   summary.html - sector list with summary statistics
   top_summary.html - top level summary, list of used allegiances, summary report
   imperial_summary - summary report for all Imperial worlds. 
   sec/<sector>.html - summary report for the sector. link page for the map.html
   sec/<sector>.ps   - Postscript version of the trade map.
   sec/<sector>.pdf  - PDF version of the trade map.
   sec/<sector>_sec.html - a copy of the input source sec data
   
   The wiki files are generated for support of the Traveller Wiki
   map.wiki - a wiki markup version of the map.html 
   summary.wiki - a wiki markup version of the summary.html
   top_summary.wiki - a wiki markup version of the top_summary.html
   imperial_summary.wiki - a wiki markup version of the imperial_summary.html
   sec/<sector>.wiki - a wiki markup version of the sector summary support.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define IMP_ALIGN ('I'*256+'m')
#define NON_ALIGN ('N'*256+'a')
#define CS_ALIGN ('C'*256+'s')
#define BA_ALIGN ('-'*256+'-')
#define MAX_NEIGHBOR 60

#define min(X,Y) ((X) < (Y) ? (X) : (Y))

struct  star    {
        char    line[100], uwp[10];
        char    aligns[6], base, gas;
        int             gwp;    /* in billions */
        int             tpos;
        int             pm;
        int             pop;    /* in millions */
        int             port;
        int             tamt;
        int             marginal;
        int             uwtn,owtn,wtn,in,re,ag,na,trade,x,y,back,jumps,align,align2,zone;
        int             tradelen;
        long    tvol;
        int     neighbors[MAX_NEIGHBOR];
        short     distances[MAX_NEIGHBOR];
        short     weight[MAX_NEIGHBOR];
        int     tsum[MAX_NEIGHBOR];
        } stars[50000];

struct sector {
	char * name;
	char * file;
	int etrade, itrade;
	int sys, pop, gsp, avg, tvol;
    int  summaries[8][20];
    int  weighted[8][20];

} sectors [20][20];
        
struct alliegance {
        int     align;
        int     tcnt,scnt;
        int tpop,spop;
        int tgwp,sgwp;
        char * name;
        struct sector * home;
        struct alliegance *next,*sub;
        } pool[500], *alliegances, *freeq=pool;

void add_alliegance_data( int al, struct sector * sector, int pop, int gwp );
void add_allegiance (int al, char* name, struct sector * sector);

//char *sectors[20][20];
//char *sectorf[20][20];
//int etrade[20][20],itrade[20][20];
int     align[640][800];
int starloc[640][800];
int borders[640][800];
int pass;
int     final;
int tramp;
int current_trade;
int     maxstar;
int tot_summaries[8][20], imp_summaries[8][20];
int tot_weighted[8][20], imp_weighted[8][20];
int tot_trade, tot_volume, tot_pop, tot_prod, imp_itrade, imp_etrade,
        imp_pop, imp_prod, imp_world, imp_volume;
FILE *trade_file,*route_file,*summary_file;

/*      get distance on hex-grid        */
int
get_dist( int x1, int y1, int x2, int y2 ) {
        int     dx, dy;
        y1 = y1 * 2; if( !(x1 % 2) ) y1++;
        y2 = y2 * 2; if( !(x2 % 2) ) y2++;
        dy = y2 - y1; if( dy < 1 ) dy = -dy;
        dx = x2 - x1; if( dx < 1 ) dx = -dx;
        if( dx > dy ) return dx;
        return (dx+dy)/2;
}
/*      as above, but using star numbers rather than positions  */
int
get_sdist( int s1, int s2 ) {
        return get_dist( stars[s1].x, stars[s1].y,stars[s2].x,stars[s2].y);
        }
/*      find all stars within 4 parsecs of a given star */
void
get_neighbors( int starnum ) {
        int             x,y,n,nn=0,dist; //,wtn=stars[starnum].wtn;
        int             xx,yy;

        stars[starnum].neighbors[0] = -1;
        if( stars[starnum].zone == 'R' ||stars[starnum].zone == 'F') return;
        x = stars[starnum].x; y = stars[starnum].y;
        for(xx = x-4;xx<= x+4; xx++)
                for( yy = y - 4; yy <= y+4; yy++ ) {
                if( xx < 0 || xx >= 640 ) continue;
                if( yy < 0 || yy >= 800 ) continue;
                n = starloc[xx][yy];
                if( !n ) continue;
                n--;
                if( n == starnum ) continue;
                if( (dist=get_dist( x, y, xx, yy )) > 4 ) continue;
                if( dist < 1 ) continue;
                if( stars[n].zone == 'R' || stars[n].zone == 'F') continue;
                if( dist == 4 ) dist = 6;
                stars[starnum].distances[nn] = dist;
                stars[starnum].neighbors[nn++] = n;
                if( nn >= MAX_NEIGHBOR-1 ) break;
                }
        stars[starnum].neighbors[nn] = -1;
        }
/*      read a sector file      */
char *mod_name( char *name, char *ext ) {
        static  char    out[100];
        char    *p;
        p = strrchr( name, '/' ); if(!p) p = name;
        sprintf(out,"sec/%s",p);
        if( p = strrchr( out, '.' ) ) *p = 0;
        strcat(out,ext);
        return out;
        }
void
read_sec(char *name) {
    FILE    *f = fopen(name,"r");
    FILE    *hf;
    int     x,y,sx,sy;
    char    buf[100], *sname;
    char    trade[21],*p;
    int     wtn,gwp,pop;
    int     POS, PORT, POP, TL, BASE, TRADE, ZONE, GAS, ALIGN;
    int     pm;
    int     line = 0;
    int     align1, align2;

    if( !f ) { printf("Unable to open [%s]\n", name); return;}
    hf = fopen(mod_name(name,"_sec.html"),"w");
    /* Get line 1 with the sector name */
    fgets( buf, 99, f ); p = strtok(buf,"\n\r"); sname = strdup(p);
    /* Get line 2 with the sector position */
    fgets( buf, 99, f ); if(sscanf(buf,"%d %d",&sx,&sy)!=2) return;
    /* verify position is valid and not a duplicate */
    if( sx < 0 || sx > 19 || sy < 0 || sy > 19 ) {
            printf("Bad sector %s\n",sname);
            return;
            }
    if( sectors[sx][sy].name ) {
            printf("Duplicate sector %s, already %s\n",sname,sectors[sx][sy].name);
            return;
            }
    sectors[sx][sy].name = sname;
    sectors[sx][sy].file = name;
    //sectorf[sx][sy] = name;
    fprintf(hf,"<html><head><title>%s</title></head>\n"
            "<body><h1>%s</h1><pre>\n",sname,sname);
    fprintf(hf,"%s",buf);
    /* Get line 3 with the position parameter values */
    fgets( buf, 99, f );
    if( (p = strchr( buf, '1' ))) POS=p-buf; else return;
    if( (p = strchr( buf, '2' ))) PORT=p-buf; else return;
    POP = PORT+4; TL = PORT+8;
    if( (p = strchr( buf, '3' ))) BASE=p-buf; else return;
    if( (p = strchr( buf, '4' ))) TRADE=p-buf; else return;
    if( (p = strchr( buf, '5' ))) ZONE=p-buf; else return;
    if( (p = strchr( buf, '6' ))) GAS=p-buf+2; else return;
    if( (p = strchr( buf, '7' ))) ALIGN=p-buf; else return;
    fprintf(hf,"%s",buf);
    line = 3;
    /* Read the rest of the lines */
    while( fgets( buf,99,f)) {
		line ++;

        fprintf(hf,"%s",buf);

        if( *buf == '#' ) continue;     /* comment */
        
        if (*buf == '+')    /* allegiances information */
        {
            align1 = ((int)buf[1])*256 + (int)buf[2];
            align2 = 0;
            p = strtok(buf+4,"\n\r"); 
            add_allegiance (align1, strdup(p), &sectors[sx][sy]);
            /*
            add_alliegance_data(align1, 0, 0);
            for (current = alliegances; current; current = current->next)
                if (current->align == align1) break;
            if (!current->name)
            {
                current->name = strdup(p);
                //if (!current->home) current->home = sectors[sx][sy];
            }
            else
            {
                if (strcmp (current->name, p) != 0)
                    fprintf (stderr, "Duplicate Allegiance in sector %s: %s vs. %s\n", 
                        sectors[sx][sy].name, current->name, buf);   
            }
            current->tcnt=0; / need to reset total count, set by add() */
            continue;
        }
        
        if (strlen (buf) < ALIGN) continue; /* skip the too short lines */

        /* Change uppercase names to initcaps */
        for(p = buf+1;p-buf < POS;p++)
                if(isalpha(p[-1]) && isupper(*p) ) *p = tolower(*p);
        
        /* if name blank, use position as name */
        if( *buf == ' ' ) memcpy( buf, buf+POS, 4 );
        
        /* set null values into buf between name and position */
        buf[POS-1] = 0;
        for(p = buf+POS-2;*p == ' ' && p > buf;p--) *p = 0;
        
        //if( buf[POP] == 'B' ) buf[POP] = 'A';/* remove pop-11 worlds */
        //if( buf[POP] == 'C' ) buf[POP] = 'A';/* remove pop-12 worlds */
        if( buf[POP] >= 'A' ) wtn = 10 + buf[POP]-'A';
        else wtn = buf[POP] - '0';
        pop = wtn; gwp = 0;
        
        switch( buf[GAS-2] ) {
                //case '0': pm = 0; break;
                case '1': pm = 10; break;
                case '2': pm = 13; break;
                case '3': pm = 17; break;
                case '4': pm = 22; break;
                case '5': pm = 28; break;
                case '6': pm = 36; break;
                case '7': pm = 47; break;
                case '8': pm = 60; break;
                case '9': pm = 78; break;
                default: pm = 30; break;
        }
        stars[maxstar].pm = pm;
        if(pop>5) for(gwp=1;pop>6;pop--) gwp *= 10;
        stars[maxstar].pop = gwp * pm / 10;
        pop = wtn;
        if( wtn > 13 || wtn < 0 ) {
                fprintf(stderr,"Bad entry in %s -> %s : %9.9s\n",sectors[sx][sy].name, buf,buf+PORT);
                continue;
                }
        
        switch( buf[TL] ) {
                case 'J': case 'I': gwp = 39000; break;
                case 'G': case 'H': gwp = 24400; break;
                case 'F': gwp = 15000; break;
                case 'E': gwp = 9375; break;
                case 'C': case 'D': gwp = 5860; break;
                case '9': case 'A': case 'B': gwp = 3660; break;
                case '8': gwp = 2290; break; 
                case '7': gwp = 1430; break;
                case '5': case '6': gwp = 895; break;
                case '2': case '3': case '4': gwp = 560; break;
                case '1': gwp = 350; break;
                case '0': gwp = 220; break;
                }
        gwp *= pm;
        for(;pop>10;pop--) gwp *= 10; for(;pop<10;pop++) gwp /= 10;
        stars[maxstar].gwp = gwp;
        if( buf[TL] == '0' ) wtn--;
        if( buf[TL] >= '5' ) wtn++;
        if( buf[TL] >= '9' ) wtn++;
        if( buf[TL] >= 'F' ) wtn++;
        stars[maxstar].uwtn = wtn;
        stars[maxstar].port = buf[PORT];
        switch( buf[PORT] ) {
                case 'A': wtn = (wtn*3 + 13)/4; break;
                case 'B': wtn = (wtn*3 + 11)/4; break;
                case 'C': if( wtn > 9 ) wtn = (wtn+9)/2;
                        else wtn = (3 * wtn + 9)/4; break;
                case 'D': if( wtn > 7 ) wtn = (wtn+7)/2;
                        else wtn = (wtn*3+7)/4; break;
                case 'E': if( wtn > 5 ) wtn = (wtn+5)/2;
                        else wtn = (wtn*3+5)/4; break;
                case 'X': wtn = (wtn-5)/2; if(wtn < 0) wtn = 0; break;
                default: break;
                }
        if( wtn < 0 ) wtn = 0;
        stars[maxstar].owtn = wtn;
        stars[maxstar].wtn = wtn;
        switch(wtn) {
                case 14: stars[maxstar].trade = 10000; break;
                case 13: stars[maxstar].trade = 1000; break;
                case 12: stars[maxstar].trade = 100; break;
                case 11: stars[maxstar].trade = 10; break;
                case 10: stars[maxstar].trade = 1; break;
        }
        strncpy( trade, buf+TRADE, min(21,ZONE-TRADE) ); trade[20] = 0;
        for(p=strtok(trade," ");p;p = strtok(0," ")) {
                if( !strcmp( p, "Ri" ) )
                        stars[maxstar].gwp = stars[maxstar].gwp*16/10;
                if( !strcmp( p, "In" ) )
                        stars[maxstar].gwp = stars[maxstar].gwp*14/10;
                if( !strcmp( p, "Ag" ) )
                        stars[maxstar].gwp = stars[maxstar].gwp*12/10;
                if( !strcmp( p, "Po" ) )
                        stars[maxstar].gwp = stars[maxstar].gwp*8/10;
                if( !strcmp( p, "Ni" ) )
                        stars[maxstar].gwp = stars[maxstar].gwp*8/10;
                if( !strcmp( p, "Ag" ) ) stars[maxstar].ag = 1;
                if( !strcmp( p, "As" ) || !strcmp( p, "Ba" ) ||
                        !strcmp( p, "De" ) || !strcmp( p, "Fl" ) ||
                        !strcmp( p, "Ic" ) || !strcmp( p, "Na" ) ||
                        !strcmp( p, "Va" ) || !strcmp( p, "Wa" ) )
stars[maxstar].na=1;
                if( !strcmp( p, "As" ) || !strcmp( p, "Ba" ) ||
                        !strcmp( p, "De" ) || !strcmp( p, "Na" ) ||
                        !strcmp( p, "Fl" ) || !strcmp( p, "Ic" ) ||
                        !strcmp( p, "Va" ) || !strcmp( p, "Wa" ) ) stars[maxstar].re=1;
                if( !strcmp( p, "In" ) ) stars[maxstar].in = 1;
                }
        if( stars[maxstar].re ) stars[maxstar].gwp = stars[maxstar].gwp*8/10;
        memcpy( stars[maxstar].line, buf, ALIGN+2 );
        memcpy( stars[maxstar].uwp, stars[maxstar].line+PORT, 9 );
        stars[maxstar].tpos = TRADE;
        if( sscanf( buf+POS,"%2d%2d",&x,&y) != 2 ||
                x > 32 || x < 1 || y > 40 || y < 1 ) {
                fprintf(stderr,"Badloc: %d,%d@%d,%d: ln %d:  %s\n",x,y,sx,sy,line,buf);
                }
        x += sx*32;
        y += sy*40;
        stars[maxstar].x = x; stars[maxstar].y = y;
        stars[maxstar].align = ((int)buf[ALIGN])*256 + (int)buf[ALIGN+1];
        strncpy(stars[maxstar].aligns, buf+ALIGN,2); stars[maxstar].aligns[2]=0;
        align[x][y] = stars[maxstar].align;
        if( buf[ALIGN+2] == '/' ) {
                stars[maxstar].align2 = ((int)buf[ALIGN+3])*256 + (int)buf[ALIGN+4];
                strncpy(stars[maxstar].aligns, buf+ALIGN+3,2);
                stars[maxstar].aligns[2]=0;
                /* sub-alignments, for vegan autonomy, solomani sub-groups */
                /* will not create a border, but will have different code */
                }
        stars[maxstar].zone = buf[ZONE];
        stars[maxstar].base = buf[BASE];
        stars[maxstar].gas = buf[GAS];
        maxstar++;
    }
    fclose(f);
    fprintf(hf,"</pre></body></html>\n");
    fclose(hf);
}
int
ga( int al, int old ) {
        if( al == NON_ALIGN ) return old;
        if( al == BA_ALIGN ) return old;
        if( al == CS_ALIGN ) return old;
        if( !old ) return al;
        if( !al ) return old;
        if( al == old ) return al;
        return al;
        }
void
compute_borders(void) {
        /*      first, give every hex an alliegance */
        int             x,y;
        int             unaligned = 0, al=0, shift=0;

        for( shift = 0; shift < 2; shift++ ) {
                unaligned = 0;
                for(x=1;x<639;x++)
                        for(y=1;y<799;y++) {
                                if( align[x][y] ) continue;     /* already set */
                                al = 0;
                                /*      check neighbors.  Always have neighbors of:
                                        X-1, Y; X, Y-1; X, Y+1; X+1, Y;
                                        if even, add X-1, Y+1 and X+1, Y+1;
                                        if odd, add X-1, Y-1 and X+1, Y-1;
                                */
                                al = ga( align[x-1][y], al );
                                al = ga( align[x-1][y+(x%2 ? -1:1)], al );
                                al = ga( align[x+1][y], al );
                                al = ga( align[x+1][y+(x%2 ? -1:1)], al );
                                al = ga( align[x][y-1], al );
                                al = ga( align[x][y+1], al );
                                if( !al ) unaligned++;
                                else borders[x][y] = al;
                        }
                for(x=1;x<639;x++) for(y=1;y<799;y++)
                        if( borders[x][y] ) {
                                align[x][y] = borders[x][y];
                                borders[x][y] = 0;
                        }
        }
        for(x=1;x<639;x++)
                for(y=1;y<799;y++)
                        if( align[x][y] == NON_ALIGN || align[x][y] == BA_ALIGN ) align[x][y] = 0;
        for(x=1;x<639;x++)
                for(y=1;y<799;y++) {
                        al = align[x][y];
                        borders[x][y] = 0;
                        shift = -(x%2);
                        if( align[x-1][y+shift] != al ) borders[x][y] += 1;/*UR*/
                        if( align[x][y-1] != al ) borders[x][y] += 2;/*top*/
                        if( align[x+1][y+shift] != al ) borders[x][y] += 4;/*UL*/
                        /*      the other system is responsible if this is reversed */
                }
        for(x=1;x<639;x++) for(y=1;y<799;y++)
                if( align[x][y] == NON_ALIGN || align[x][y] == BA_ALIGN) align[x][y] = 0;
}

int
sortfn( const void *p1, const void *p2 ) {
        const struct star *w1=p1, *w2=p2;
        if( w2->wtn != w1->wtn ) return w2->wtn - w1->wtn;
        if( w2->align != w1->align ) return w2->align - w1->align;
        if( w2->line[0] != w1->line[0] ) return (int)w2->line[0] - (int)w1->line[0];
        return strcmp( w2->line, w1->line );
}
void
sort_stars(void) {
        int             n;
        qsort( stars, maxstar, sizeof( struct star ), sortfn );
        for(n=0;n<maxstar;n++) {
                if( stars[n].x < 0 || stars[n].x >= 640 ) abort();
                if( stars[n].y < 0 || stars[n].y >= 800 ) abort();
                starloc[stars[n].x][stars[n].y] = n+1;
                }
        for(n=0;n<maxstar;n++) get_neighbors(n);
        compute_borders();
}
int sec_x( int world ) {
        return ((stars[world].x-1)/32);
}
int sec_y( int world ) {
        return ((stars[world].y-1)/40);
}
int
add_trade( int from, int to, int amt ) {
        int     n, x=amt;
        stars[from].tamt += amt;
        stars[to].tamt += amt;
        if( from > to ) return add_trade(to,from,amt);
        for(n=0;n<MAX_NEIGHBOR;n++) {
                if( stars[from].neighbors[n] != to ) continue;
                x = amt + stars[from].tsum[n];
                stars[from].tsum[n] = x;
                }
        if( sec_x(from) == sec_x(to) && sec_y(from) == sec_y(to)) return;
        for(n=0;n<MAX_NEIGHBOR;n++) {
                if( stars[to].neighbors[n] != from ) continue;
                x = amt + stars[to].tsum[n];
                stars[to].tsum[n] = x;
                }
        }
void
add_weight( int from, int to, int weight ) {
        int     n, x=weight;
        for(n=0;n<MAX_NEIGHBOR;n++) {
                if( stars[from].neighbors[n] != to ) continue;
                x = weight + stars[from].tsum[n];
                stars[from].weight[n] = x;
                }
        for(n=0;n<MAX_NEIGHBOR;n++) {
                if( stars[to].neighbors[n] != from ) continue;
                x = weight + stars[to].tsum[n];
                stars[to].weight[n] = x;
        }
}

void
draw_lineback( int world, int brightness, int verbose ) {
        int     back;
        stars[world].trade += brightness;
        back = stars[world].back;
        if( back == -1 ) return;
        if( final ) (void)add_trade( world, back, brightness );
        add_weight( world, back, brightness );
        draw_lineback( back, brightness, verbose );
}
int
get_trade( int w1, int w2, int jmp) {
        int             tn, lt, i;
        long    vol;
        tn = (stars[w1].wtn + stars[w2].wtn);
        if( ( stars[w1].ag && stars[w2].na ) ||
                ( stars[w2].ag && stars[w1].na ) ) tn++;
        else if( ( stars[w1].re && stars[w2].in ) ||
                ( stars[w2].re && stars[w1].in ) ) tn++;
        if( stars[w1].align == NON_ALIGN ||
                (stars[w1].align != stars[w2].align &&
                (stars[w1].align*stars[w2].align != IMP_ALIGN*CS_ALIGN))) tn--;
        if( get_sdist(w1,w2) > 1 ) tn--;
        if( jmp > 2 ) tn--;
        if( jmp > 5 ) tn--;
        if( jmp > 9 ) tn--;     /* -4 */
        if( jmp > 19 ) tn--; /* -5 */
        if( jmp > 29 ) tn--; /* -6 */
        if( jmp > 59 ) tn--; /* -7 */
        if( jmp > 99 ) tn--; /* -8 */
        if( jmp > 199 ) tn--; /* -9 */
        if( current_trade == 8 && tramp ) {
                if( tn & 2 ) vol = 3; else vol = 1;
                for(i=1;i < tn; i+= 2 ) vol *= 10;
                stars[w1].tvol += vol;
                stars[w2].tvol += vol;
        }
        if( tn < 16 ) {
                if(!tramp) return tn;
                if( tn == 15 ) stars[w1].marginal += 30;
                if( tn == 14 ) stars[w1].marginal += 10;
                if( tn == 13 ) stars[w1].marginal += 3;
                if( tn == 12 ) stars[w1].marginal ++;
                return tn;
                }
        if( tn/2 != current_trade ) return tn;
        if( !tramp && tn < 18 ) return tn;
        if( tramp && tn > 17 ) return tn;
        if( tn % 2 ) lt = 3; else lt = 1;
        while( tn > 17 ) { tn-= 2; lt *= 10; }
        if( final ) {
                fprintf(route_file,"%s:%d:%d:%s:%s\n",sectors[sec_x(w1)][sec_y(w1)].name,
                        lt,jmp,stars[w1].line,stars[w2].line);
                fprintf(route_file,"%s:%d:%d:%s:%s\n",sectors[sec_x(w2)][sec_y(w2)].name,
                        lt,jmp,stars[w2].line,stars[w1].line);
                tot_trade += lt;
                if( stars[w1].align == IMP_ALIGN || stars[w2].align == IMP_ALIGN )
                        if( stars[w1].align == stars[w2].align ) imp_itrade += lt;
                        else imp_etrade += lt;
                if( sec_x(w1) != sec_x(w2) || sec_y(w1) != sec_y(w2) ) {
                        sectors[sec_x(w1)][sec_y(w1)].etrade += lt/2;
                        sectors[sec_x(w2)][sec_y(w2)].etrade += lt/2;
                } else sectors[sec_x(w1)][sec_y(w1)].itrade += lt;
                draw_lineback( w1, lt, 1 );
                }
        else draw_lineback( w1, lt, 0 );
        return tn;
}

int
get_weight( int from, int to ) {
        int             n;
        for(n=0;n<MAX_NEIGHBOR;n++) {
                if( stars[from].neighbors[n] != to ) continue;
                return stars[from].weight[n];
        }
        return 0;
}

int
weight_adj( int x ) {
        if( !x ) return 0;
        if( x >= 10 ) return 5 + weight_adj( x/10 );
        if( x < 5 ) return x;
        if( x < 7 ) return 4;
        if( x < 10 ) return 5;
        return x;
}

int
route_cost( int from, int to, int dist ) {
        int     cost;
        if( dist < 1 ) {
                fprintf(stderr,"bad distance %d: %.15s(%d,%d) to %.15s(%d,%d\n",dist,
                        stars[from].line, stars[from].x,stars[from].y,
                        stars[to].line,stars[to].x,stars[to].y);
                dist = 1;
                }
        switch( dist ) {
                case 1: cost = 30; break;
                case 2: cost = 50; break;
                case 3: cost = 80; break;
                case 6: cost = 150; break;
                }
        if( stars[from].align != stars[to].align ) cost += 25;
        if( stars[from].port > 'C' ) cost += 25;
        if( stars[from].port > 'D' ) cost += 25;
        if( get_weight(from,to) ) cost -= cost/5;
        if( stars[from].wtn >= current_trade ) cost -= cost/5;
        return cost;
}

void
get_paths( int source, int world, int jumps ) {
        int             next, nn, tl=15,weight, dist, ljump;
        tl = stars[world].tradelen;
        if( world > source ) get_trade( world, source, stars[world].jumps );
                /* treat jumps through low-grade ports as extra-long */
        ljump = stars[world].jumps;
        if( world != source && stars[world].port > 'C' ) ljump++;
        if( !tramp && world != source && stars[world].port > 'D' ) ljump++;
        for(nn=0;nn < MAX_NEIGHBOR;nn++) {
                next = stars[world].neighbors[nn];
                if( next == -1 ) break;
                dist = stars[world].distances[nn];
                if( tramp && dist > 2 && stars[world].tsum[nn] < 10 ) continue;
/*              if( stars[next].jumps < ljump+dist ) continue;*/
                weight = route_cost( world, next, dist ) + tl;
                if( stars[next].tradelen <= weight ) continue;
                stars[next].jumps = ljump+dist;
                stars[next].back = world;
                stars[next].tradelen = weight;
                }
        }

void
get_trade_to( int world ) {
        int             max, jn, n;
        //fprintf(stderr,"%d:get_trade_to %d %.20s\n",current_trade,stars[world].wtn, stars[world].line);
        /*      there's a limit to how far it's useful to show these links      */
/*      if( stars[world].wtn < current_trade ) return;*/
        switch( (stars[world].wtn) - current_trade ) {
                case 0: max = 2; break;
                case 1: max = 9; break;
                case 2: max = 29; break;
                case 3: max = 59; break;
                case 4: max = 99; break;
                default: max = 299; break;
                }
        if( stars[world].wtn < 14 && max > 99 ) max = 99;       /* -5.5 */
        if( stars[world].wtn < 13 && max > 29 ) max = 29;       /* -4.5 */
        if( stars[world].wtn < 12 && max > 19 ) max = 19;       /* -3.5 */
        for(n=0;n<maxstar;n++) {
                stars[n].jumps =  999;
                stars[n].tradelen = 99999;
                }
        stars[world].jumps = 0;
        stars[world].tradelen = 0;
        stars[world].back = -1;
        for(jn = 0;jn <= max; jn++) {
                for(n=0;n < maxstar;n++) {
                        if( stars[n].jumps == jn ) get_paths( world, n, jn );
/*                      if( stars[n].tradelen/50 == jn ) get_paths( world, n, jn );*/
                }
        }
}

char * tradecolor( int n ) {
        if( n >= 10000 ) return "0 0 128";   /* blue */
        if( n >= 1000 ) return "0 96 96";    /* cyan  */
        if( n >= 100 ) return "0 128 0";     /* green */
        if( n >= 10 ) return "128 128 0";               /* yellow */
        return "64 0 0";                                        /* red */
        }

void
show_borders( int sx, int sy, FILE *f ) {
        int             x,y,b;

        for(y=1;y <= 40;y++) {
                for(x = 1;x <= 32;x++) {
                        b = borders[x + sx*32][y+sy*40];
                        if( !b ) continue;
                        if( b & 4 ) fprintf(f,"1 "); else fprintf(f,"0 ");
                        if( b & 2 ) fprintf(f,"1 "); else fprintf(f,"0 ");
                        if( b & 1 ) fprintf(f,"1 "); else fprintf(f,"0 ");
                        fprintf(f,"%d %d border\n", x, y );
                }
        }
}
char *print_comma(int n) {
        static  char    buf[20];
        if(n >= 1000000) sprintf(buf,"%d,%03d,%03d",n/1000000,(n/1000)%1000,n%1000);
        else if( n >= 1000 ) sprintf(buf,"%d,%03d",n/1000,n%1000);
        else sprintf(buf,"%d",n);
        return buf;
        }
int code2num( char code ) {
        if( code < '0' ) return 19;
        if( code <= '9' ) return code - '0';
        if( code < 'A' ) return 19;
        if( code <= 'I' ) return code - 'A' + 10;
        if( code <= 'Z' ) return 18;
        return 0;
}

void
clear_sub_al() {
        int             n;
        for(n = 0;n<500;n++)
                pool[n].scnt = pool[n].spop = pool[n].sgwp = 0;
}

void
show_alliegances( int sect, int wiki, struct alliegance *current, FILE *f ) {
    if (wiki)
    {
        fprintf(f, "{| class=\"wikitable sortable\"\n!Code ||Name||Worlds||Population||GNP\n");
    }
    else
        fprintf(f,"<ul>\n");
    for(;current;current = current->next) {
        if( sect && !current->scnt ) continue;
        if( !sect && current->tcnt < 10 ) continue;
        if( !current->name)
            if (wiki)
                fprintf (f, "|-\n| %c%c || ", current->align/256, current->align%256);
            else
                fprintf(f, "<li>%c%c", current->align/256, current->align%256);
        else
        {
            if (wiki)
                fprintf (f, "|-\n| %c%c || [[%s]]", current->align/256, current->align%256,
                current->name);
            else 
                fprintf(f, "<li>%c%c: %s", current->align/256, current->align%256,
                current->name);
        }
        if (wiki)
        {
            fprintf (f, "|| %d || %s", 
                sect?current->scnt:current->tcnt,
                print_comma(sect?current->spop:current->tpop));
           fprintf (f, "|| %s\n", print_comma(sect?current->sgwp:current->tgwp));
        }     
        else
        {
            fprintf(f, ": %d worlds, %sM pop, ", 
                sect?current->scnt:current->tcnt,
                print_comma(sect?current->spop:current->tpop));
            fprintf(f,"%s BCr gnp\n",print_comma(sect?current->sgwp:current->tgwp));
        }
        if( current->sub ) show_alliegances( sect, wiki, current->sub, f );
    }
    if (wiki)
        fprintf (f, "|}\n");
    else
        fprintf(f,"</ul>\n");
}

void add_allegiance (int al, char* name, struct sector * sector)
{
    struct alliegance * current, *tmp; 
    for(current = alliegances;current;current=current->next) 
    {
        if( current->align > al ) { current=0;break; }
        if( current->align == al ) break;
        if( !current->next || current->next->align > al ) 
        {
            tmp = freeq++;
            tmp->next = current->next;
            current->next = tmp;
            current = tmp;
            current->align = al;
            current->name = name;
            current->home = sector;
            break;
        }
    }
    if( !current ) 
    {
        current=freeq++; 
        current->next = alliegances; 
        alliegances = current; 
        current->align = al;
        current->name = name;
        current->home = sector;
    }

    if (strcmp (current->name, name) != 0)
    {
        fprintf (stderr, "Duplicate Allegiance in sector %s: %s vs. %s: %s\n", 
            (current->home?current->home->name:"(multi-sector)"), current->name, sector->name, name);
        tmp = freeq++;
        tmp->next = current->next;
        current->next = tmp;
        current = tmp;
        current->align = al;
        current->name = name;
        current->home = sector;
    }
    
    if (current->home != sector) current->home = 0;
}

void
add_alliegance_data( int al, struct sector * sector, int pop, int gwp ) 
{
    struct  alliegance      *current, *tmp, *parent;
    for(current = alliegances;current;current=current->next) {
        if( current->align > al ) { current=0;break; }
        if( current->align == al ) break;
        if( !current->next || current->next->align > al ) {
            tmp = freeq++;
            tmp->next = current->next;
            current->next = tmp;
            current = tmp;
            current->align = al;
            current->home = sector;
            break;
        }
    }
    if( !current ) 
    {
        current=freeq++; 
        current->next = alliegances; 
        alliegances = current; 
        current->align = al;
        current->home = sector;
    }
    
    if (current->home && current->home != sector)
    {
        parent = current;
        while (current -> align == al)
        {
            if (current->home && current->home == sector) break;
            if (!current->home) parent = current;
            current = current -> next;
        }
        if (current->align != al) current = parent;
        
    }
    current->tcnt++; current->scnt++;
    current->tpop += pop; current->spop += pop;
    current->tgwp += gwp; current->sgwp += gwp;
#if 0
        if( !al2 ) return;
        parent = current;
        for(current = parent->sub;current;current=current->next) {
                if( current->align > al2 ) { current=0;break; }
                if( current->align == al2 ) break;
                if( !current->next || current->next->align > al2 ) {
                        tmp = freeq++;
                        tmp->next = current->next;
                        current->next = tmp;
                        current = tmp;
                        break;
                        }
                }
        if( !current ) {
                current = freeq++;
                current->next = parent->sub;
                parent->sub = current;
                }
        current->align = al2;
        current->tcnt++; current->scnt++; 
        current->tpop += pop; current->spop += pop;
        current->tgwp += gwp; current->sgwp += gwp;
#endif        
}

void show_quadrants (int sx, int sy) 
{
    char cbuf[200], cp, wtn; 
    FILE *fa, *fb, *fg, *fd, *f;
    int n, nn, x, y, xf, yf, other, ox, oy, maxsize;

    
    if (! sectors[sx][sy].name) return;
    /* Alpha Quadrant*/    
    sprintf (cbuf, "cp blankquadmap.ps %s", mod_name(sectors[sx][sy].file,"A.ps"));
    system (cbuf);
    fa = fopen (mod_name(sectors[sx][sy].file,"A.ps"), "a");
    fprintf (fa, "(%s) namesec\n", sectors[sx][sy].name);
    if(sy > 0 && sectors[sx][sy-1].name) fprintf(fa,"(%s) abovesec\n",sectors[sx][sy-1].name);
    fprintf(fa,"([%s Gamma Quadrant]) belowsec\n", sectors[sx][sy].name);
    if(sx > 0 && sectors[sx-1][sy].name) fprintf(fa,"(%s) leftsec\n",sectors[sx-1][sy].name);
    fprintf(fa,"([%s Beta Quadrant]) rightsec\n",sectors[sx][sy].name);
    fprintf(fa,"/Times-Roman findfont 8 scalefont setfont\n");
   /* Beta Quadrant*/
    sprintf (cbuf, "cp blankquadmap.ps %s", mod_name(sectors[sx][sy].file,"B.ps"));
    system (cbuf);
    fb = fopen (mod_name(sectors[sx][sy].file,"B.ps"), "a");
    fprintf (fb, "(%s) namesec\n", sectors[sx][sy].name);
    if(sy > 0 && sectors[sx][sy-1].name) fprintf(fb,"(%s) abovesec\n",sectors[sx][sy-1].name);
    fprintf(fb,"([%s Delta Quadrant]) belowsec\n", sectors[sx][sy].name);
    fprintf(fb,"([%s Alpha Quadrant]) leftsec\n",sectors[sx][sy].name);
    if (sx < 19 && sectors[sx+1][sy].name) fprintf(fb,"(%s) rightsec\n",sectors[sx+1][sy].name);
    fprintf(fb,"/Times-Roman findfont 8 scalefont setfont\n");
    /* Gamma Quadrant */
    sprintf (cbuf, "cp blankquadmap.ps %s", mod_name(sectors[sx][sy].file,"G.ps"));
    system (cbuf);
    fg = fopen (mod_name(sectors[sx][sy].file,"G.ps"), "a");
    fprintf (fg, "(%s) namesec\n", sectors[sx][sy].name);
    fprintf(fg,"([%s Alpha Quadrant]) abovesec\n",sectors[sx][sy].name);
    if (sy < 19 && sectors[sx][sy+1].name) fprintf(fg,"(%s) belowsec\n", sectors[sx][sy+1].name);
    if (sx > 0 && sectors[sx-1][sy].name) fprintf(fg,"(%s) leftsec\n",sectors[sx-1][sy].name);
    fprintf(fg,"([%s Delta Quadrant]) rightsec\n",sectors[sx][sy].name);
    fprintf(fg,"/Times-Roman findfont 8 scalefont setfont\n");

    /* Delta Quadrant */
    sprintf (cbuf, "cp blankquadmap.ps %s", mod_name(sectors[sx][sy].file,"D.ps"));
    system (cbuf);
    fd = fopen (mod_name(sectors[sx][sy].file,"D.ps"), "a");
    fprintf (fd, "(%s) namesec\n", sectors[sx][sy].name);
    fprintf(fd,"([%s Beta Quadrant]) abovesec\n",sectors[sx][sy].name);
    if (sy < 19 && sectors[sx][sy+1].name) fprintf(fd,"(%s) belowsec\n", sectors[sx][sy+1].name);
    fprintf(fd,"([%s Gamma Quadrant]) leftsec\n",sectors[sx][sy].name);
    if (sx < 19 && sectors[sx+1][sy].name) fprintf(fd,"(%s) rightsec\n",sectors[sx+1][sy].name);
    fprintf(fd,"/Times-Roman findfont 8 scalefont setfont\n");
    /* show_borders (sx, sy, f); */
    for (n = 0; n < maxstar; n++)
    {
        if (sec_x(n) != sx || sec_y(n) != sy) continue;
        if (stars[n].zone == 'A' || stars[n].zone == 'U') /* amber zone */
        {
            xf = 0; yf = 0;
            x = stars[n].x-sx*32;
            y = stars[n].y-sy*40;
            if (x > 16) { x -=16; xf = 1; }
            if (y > 20) { y -=20; yf = 1; }
            if (xf && yf) f = fd;
            if (xf && !yf) f = fb;
            if (!xf && yf) f = fg;
            if (!xf && !yf) f = fa;
            fprintf (f, "%d %d amber\n", x, y);
        }
        if (stars[n].zone == 'R' || stars[n].zone == 'F') /* red zone */
        {
            xf = 0; yf = 0;
            x = stars[n].x-sx*32;
            y = stars[n].y-sy*40;
            if (x > 16) { x -=16; xf = 1; }
            if (y > 20) { y -=20; yf = 1; }
            if (xf && yf) f = fd;
            if (xf && !yf) f = fb;
            if (!xf && yf) f = fg;
            if (!xf && !yf) f = fa;
            fprintf (f, "%d %d redzone\n", x, y);

        }
    }     
    for (maxsize = 10; maxsize <  10000000; maxsize *= 10)
    {
        for (n = 0; n < maxstar; n++)
        {
            if (sec_x(n) != sx || sec_y(n) != sy) continue;
            if (!stars[n].trade) continue;
            for (nn = 0; nn < MAX_NEIGHBOR; nn++)
            {
                if ( (other = stars[n].neighbors[nn]) == -1) break ;
                if ( stars[n].tsum[nn] < maxsize/10) continue;
                if ( stars[n].tsum[nn] >= maxsize) continue;
                xf = 0; yf = 0;
                x = stars[n].x-sx*32;
                y = stars[n].y-sy*40;
                ox = stars[other].x-sx*32;
                oy = stars[other].y-sy*40;
                if (x > 16) { x -=16; ox -=16; xf = 1; }
                if (y > 20) { y -=20; oy -=20; yf = 1; }
                if (xf && yf) f = fd;
                if (xf && !yf) f = fb;
                if (!xf && yf) f = fg;
                if (!xf && !yf) f = fa;
                fprintf(f,"%d %d %d %d %s hexl\n", x, y, ox, oy,tradecolor(stars[n].tsum[nn]));
            }
        }
    }
    for (n = 0; n < maxstar; n++)
    {
        if (sec_x(n) != sx || sec_y(n) != sy) continue;
        wtn = stars[n].owtn;
        if (wtn > 9) wtn += 'A' - 10;
        else if (wtn > 0) wtn += '0';
        else wtn = '0';
        if( strstr( stars[n].line+stars[n].tpos,"Cp" ) ) cp = '+';
        else if( strstr( stars[n].line+stars[n].tpos,"Cx" ) ) cp = '*';
        else cp = ' ';
        xf = 0; yf = 0;
        x = stars[n].x-sx*32;
        y = stars[n].y-sy*40;
        if (x > 16) { x -=16; xf = 1; }
        if (y > 20) { y -=20; yf = 1; }
        if (xf && yf) f = fd;
        if (xf && !yf) f = fb;
        if (!xf && yf) f = fg;
        if (!xf && !yf) f = fa;
            
        fprintf(f,"(%s) (%7.7s-%c) (%2.2s %c%c%c%c) %d %d world\n",
            stars[n].line, stars[n].uwp,stars[n].uwp[8],stars[n].aligns,cp,
            stars[n].base, stars[n].gas,wtn,x,y);
    }
    fputs ("showpage\n", fa);
    fputs ("showpage\n", fb);
    fputs ("showpage\n", fg);
    fputs ("showpage\n", fd);
    fclose(fa); fclose(fb); fclose(fg); fclose(fd);
    sprintf(cbuf,"ps2pdf %s",mod_name(sectors[sx][sy].file,"A.ps"));
    sprintf(cbuf+strlen(cbuf)," %s",mod_name(sectors[sx][sy].file,"A.pdf"));
    system(cbuf);
    sprintf(cbuf,"ps2pdf %s",mod_name(sectors[sx][sy].file,"B.ps"));
    sprintf(cbuf+strlen(cbuf)," %s",mod_name(sectors[sx][sy].file,"B.pdf"));
    system(cbuf);
    sprintf(cbuf,"ps2pdf %s",mod_name(sectors[sx][sy].file,"G.ps"));
    sprintf(cbuf+strlen(cbuf)," %s",mod_name(sectors[sx][sy].file,"G.pdf"));
    system(cbuf);
    sprintf(cbuf,"ps2pdf %s",mod_name(sectors[sx][sy].file,"D.ps"));
    sprintf(cbuf+strlen(cbuf)," %s",mod_name(sectors[sx][sy].file,"D.pdf"));
    system(cbuf);
    
}

void show_sector_summary_wiki (int sx, int sy)
{
    FILE    *f;
    int nn;
    
    f = fopen(mod_name(sectors[sx][sy].file,".wiki"),"w");
    fprintf (f, "==%s==\n", sectors[sx][sy].name);
    fprintf (f, "{|\n|Systems||%d\n", sectors[sx][sy].sys);
    fprintf (f, "|-\n|Population||%s million\n", print_comma(sectors[sx][sy].pop));
    fprintf (f, "|-\n|Gross Sector Product||%s billion\n", print_comma(sectors[sx][sy].gsp));
    fprintf (f, "|-\n|Per Capita GSP||Cr %s\n", print_comma(sectors[sx][sy].avg));
    fprintf (f, "|-\n|Trade Volume||%s billion\n", print_comma(sectors[sx][sy].tvol/10));
    fprintf (f, "|-\n|Internal Trade||%s billion\n", print_comma(sectors[sx][sy].itrade/10));
    fprintf (f, "|-\n|external Trade||%s billion\n", print_comma(sectors[sx][sy].etrade/10));
    fprintf (f, "|}\n\n");
    
    fprintf (f, "==Allegiance Information==\n");
    show_alliegances (1, 1, alliegances, f);

    fprintf (f, "==Summary Report==\n");
    fprintf (f, "{|\n!Component ");
	for (nn=0; nn <= 9; nn++) fprintf (f, "||%d", nn);
	for (nn=0; nn < 8; nn++) fprintf (f, "||%c", nn + 'A');
	fprintf (f, "||I-Z\n");

    fprintf (f, "|-\n|Port Code\n");    
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n", sectors[sx][sy].summaries[0][nn]);
    fprintf (f, "|-\n|Size\n");    
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n",sectors[sx][sy].summaries[1][nn]);
    fprintf (f, "|-\n|Atmosphere\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n",sectors[sx][sy].summaries[2][nn]);
    fprintf (f, "|-\n|Water\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n",sectors[sx][sy].summaries[3][nn]);    
    fprintf (f, "|-\n|Population\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n",sectors[sx][sy].summaries[4][nn]);
    fprintf (f, "|-\n|Government\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n",sectors[sx][sy].summaries[5][nn]);
    fprintf (f, "|-\n|Law Level\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n",sectors[sx][sy].summaries[6][nn]);
    fprintf (f, "|-\n|Tech Level\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d\n",sectors[sx][sy].summaries[7][nn]);
    fprintf (f, "|-\n|colspan=20 align=center|Percent by Population\n");
    fprintf (f, "|-\n|Port Code\n");    
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[0][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|-\n|Size\n");    
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[1][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|-\n|Atmosphere\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[2][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|-\n|Water\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[3][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|-\n|Population\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[4][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|-\n|Government\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[5][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|-\n|Law Level\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[6][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|-\n|Tech Level\n");
    for(nn=0;nn<19;nn++) fprintf(f,"|%d%%\n",sectors[sx][sy].weighted[7][nn]/(sectors[sx][sy].pop/100));
    fprintf (f, "|}\n");
    fclose (f);    
}


void show_sector_summary (int sx, int sy)
{
    FILE    *f;
    char *fn;
    int nn;
            
    fn = strrchr(sectors[sx][sy].file,'/'); 
    if( !fn )fn = sectors[sx][sy].file; else fn++;
    
    f = fopen(mod_name(sectors[sx][sy].file,".html"),"w");
    fprintf(f,"<html><head><title>%s</title></head>\n",sectors[sx][sy].name);
    fprintf(f,"<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
            "<h1><center>%s</center></h1>\n",sectors[sx][sy].name);
    fprintf(f,"<table>\n");
    fprintf(f,"<tr><td>Systems</td><td>%d</td></tr>\n",sectors[sx][sy].sys);
    fprintf(f,"<tr><td>Population</td><td>%s million</td></tr>\n",
            print_comma(sectors[sx][sy].pop));
    fprintf(f,"<tr><td>Gross Sector Product</td><td>%s billion</td></tr>\n",
            print_comma(sectors[sx][sy].gsp));
    if(sectors[sx][sy].pop > 100000) sectors[sx][sy].avg = sectors[sx][sy].gsp/(sectors[sx][sy].pop/1000);
    else if(sectors[sx][sy].pop) sectors[sx][sy].avg = sectors[sx][sy].gsp*1000/sectors[sx][sy].pop;
    else sectors[sx][sy].avg = 0;
    if(sectors[sx][sy].pop < 100) sectors[sx][sy].pop = 100;
    fprintf(f,"<tr><td>Per Capita GSP</td><td>Cr %s</td></tr>\n",
            print_comma(sectors[sx][sy].avg));
    fprintf(f,"<tr><td>Trade Volume</td><td>%s billion</td></tr>\n",
            print_comma(sectors[sx][sy].tvol/10));
    fprintf(f,"<tr><td>Internal Trade</td><td>%s billion</td></tr>\n",
            print_comma(sectors[sx][sy].itrade/10));
    fprintf(f,"<tr><td>External Trade</td><td>%s billion</td></tr>\n",
            print_comma(sectors[sx][sy].etrade/10));
    fprintf(f,"</table>\n");
    fprintf(f,"<p>Alliegance Information\n");
    show_alliegances( 1, 0, alliegances, f );
    fprintf(f,"<p>Sector Data File is <a href=%s>here</a>\n",mod_name(fn,"_sec.html"));
    fprintf(f,"<p>PDF map of sector is <a href=%s>here</a>\n",
            mod_name(fn,".pdf"));
    fprintf(f,"<p>Sector Notes are <a href=%s>here</a>\n",
            mod_name(fn,"_worlds.html"));
    fprintf(f,"<p>Summary Report:\n<table>\n<tr><td>Component</td>");
    for(nn=0;nn<=9;nn++) fprintf(f,"<td width=4%%>%d</td>",nn);
    for(nn=0;nn<8;nn++) fprintf(f,"<td width=4%%>%c</td>",nn+'A');
    fprintf(f,"<td width=4%%>I-Z</td>\n");
    fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[0][nn]);
    fprintf(f,"</tr><tr><td>SIZE</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[1][nn]);
    fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[2][nn]);
    fprintf(f,"</tr><tr><td>WATER</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[3][nn]);
    fprintf(f,"</tr><tr><td>POPULATION</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[4][nn]);
    fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[5][nn]);
    fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[6][nn]);
    fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d</td>",sectors[sx][sy].summaries[7][nn]);
    fprintf(f,"</tr><tr><td colspan=20 align=center>Percent by Population</td>\n");
    fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[0][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr><tr><td>SIZE</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[1][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[2][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr><tr><td>WATER</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[3][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr><tr><td>POPULATION</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[4][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[5][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[6][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
    for(nn=0;nn<19;nn++) fprintf(f,"<td>%d%%</td>",sectors[sx][sy].weighted[7][nn]/(sectors[sx][sy].pop/100));
    fprintf(f,"</tr></table>\n");
    fclose(f);
}

void
show_sector( int sx, int sy ) {
        FILE    *f;
        int     n, nn, other, is_bold=1;
        char    wtn, wtc, cp, x, y, cbuf[200];
//        int             tvol=0,pop=0,gsp=0,sys=0,avg=0, 
		int 	maxsize=0;
        //int             summaries[8][20];
        //int             weighted[8][20];
        if( !sectors[sx][sy].name ) return;
		sectors[sx][sy].tvol=0;sectors[sx][sy].pop=0;sectors[sx][sy].sys=0;
		sectors[sx][sy].avg=0;
        //memset(summaries,0,sizeof(summaries));
        //memset(weighted,0,sizeof(weighted));
        clear_sub_al();
        sprintf(cbuf,"cp basemap.ps %s",mod_name(sectors[sx][sy].file,".ps"));
        system(cbuf);
        f = fopen(mod_name( sectors[sx][sy].file,".ps"),"a" );
        fprintf(f,"(%s) namesec\n",sectors[sx][sy].name);
        if(sy > 0 && sectors[sx][sy-1].name) fprintf(f,"(%s) abovesec\n",sectors[sx][sy-1].name);
        if(sy < 19 && sectors[sx][sy+1].name) fprintf(f,"(%s) belowsec\n",sectors[sx][sy+1].name);
        if(sx > 0 && sectors[sx-1][sy].name) fprintf(f,"(%s) leftsec\n",sectors[sx-1][sy].name);
        if(sx < 19 && sectors[sx+1][sy].name) fprintf(f,"(%s) rightsec\n",sectors[sx+1][sy].name);
        fprintf(f,"/Times-Roman findfont 4 scalefont setfont\n");
        show_borders( sx, sy, f );
        for(n=0;n<maxstar;n++) {
                if( sec_x(n) != sx || sec_y(n) != sy ) continue;
                sectors[sx][sy].sys++;
                if( stars[n].zone == 'A' || stars[n].zone=='U') fprintf(f,"%d %d amber\n",
                        stars[n].x-sx*32,stars[n].y-sy*40);
                if( stars[n].zone == 'R' || stars[n].zone =='F') fprintf(f,"%d %d redzone\n",
                        stars[n].x-sx*32,stars[n].y-sy*40);
                sectors[sx][sy].pop += stars[n].pop;
                add_alliegance_data( stars[n].align, &sectors[sx][sy], stars[n].pop, stars[n].gwp );
                tot_pop += stars[n].pop;
                tot_prod += stars[n].gwp;
                if( stars[n].align == IMP_ALIGN ) {
                        imp_world++;
                        imp_pop += stars[n].pop;
                        imp_prod += stars[n].gwp;
                        }
                if( stars[n].pop > 100000 ) fprintf(stderr,"bad pop %s=%d\n",
                        stars[n].line,stars[n].pop);
                sectors[sx][sy].gsp += stars[n].gwp;
                if( !stars[n].trade ) continue;
                fprintf(trade_file,"%s:%s:(null):0:%d.%02d\n",
                        sectors[sec_x(n)][sec_y(n)].name,
                        stars[n].line,stars[n].tamt+stars[n].marginal/100,
                        stars[n].marginal % 100);
                }
        for(maxsize=10;maxsize < 10000000; maxsize *= 10)
                for(n=0;n<maxstar;n++) {
                        if( sec_x(n) != sx || sec_y(n) != sy ) continue;
                        if( !stars[n].trade ) continue;
                        for(nn=0;nn<MAX_NEIGHBOR;nn++) {
                                if( (other=stars[n].neighbors[nn]) == -1 ) break;
                                if( stars[n].tsum[nn] < maxsize/10 ) continue;
                                if( stars[n].tsum[nn] >= maxsize ) continue;
                                if( sec_x(other) == sx && sec_y(other)==sy )
                                        sectors[sx][sy].tvol += stars[n].tsum[nn];
                                else sectors[sx][sy].tvol += stars[n].tsum[nn]/2;
                                fprintf(f,"%d %d %d %d %s hexl\n",
                                        stars[n].x-sx*32,stars[n].y-sy*40,
                                        stars[other].x-sx*32,stars[other].y-sy*40,
                                        tradecolor(stars[n].tsum[nn]));
                                if( n < other ) {
                                tot_volume += stars[n].tsum[nn];
                                if(stars[n].align == IMP_ALIGN||stars[other].align == IMP_ALIGN)
                                        imp_volume += stars[n].tsum[nn];

                                fprintf(trade_file,"%s:%s:%s:%d:%d\n",sectors[sec_x(n)][sec_y(n)].name,
                                        stars[n].line,stars[other].line,stars[n].distances[nn],
                                        stars[n].tsum[nn]);
                                fprintf(trade_file,"%s:%s:%s:%d:%d\n",
                                        sectors[sec_x(other)][sec_y(other)].name,stars[other].line,
                                        stars[n].line, stars[n].distances[nn],stars[n].tsum[nn]);
                                }
                        }
                }
        for(n=0;n<maxstar;n++) {
                if( sec_x(n) != sx || sec_y(n) != sy ) continue;
                for(nn=0;nn<7;nn++) {
                        sectors[sx][sy].summaries[nn][code2num(stars[n].uwp[nn])]++;
                        sectors[sx][sy].weighted[nn][code2num(stars[n].uwp[nn])] += stars[n].pop;
                        tot_summaries[nn][code2num(stars[n].uwp[nn])]++;
                        tot_weighted[nn][code2num(stars[n].uwp[nn])] += stars[n].pop;
                        if( stars[n].align == IMP_ALIGN ) {
                                imp_weighted[nn][code2num(stars[n].uwp[nn])] += stars[n].pop;
                                imp_summaries[nn][code2num(stars[n].uwp[nn])]++;
                                }
                        }
                sectors[sx][sy].summaries[7][code2num(stars[n].uwp[8])]++;
                sectors[sx][sy].weighted[7][code2num(stars[n].uwp[8])] += stars[n].pop;
                tot_summaries[7][code2num(stars[n].uwp[8])]++;
                tot_weighted[7][code2num(stars[n].uwp[8])] += stars[n].pop;
                if( stars[n].align == IMP_ALIGN ) {
                        imp_summaries[7][code2num(stars[n].uwp[8])]++;
                        imp_weighted[7][code2num(stars[n].uwp[8])] += stars[n].pop;
                        }
                wtn = stars[n].owtn;
                if( wtn > 9 ) wtn += 'A' - 10;
                else if( wtn > 0 ) wtn += '0';
                else wtn = '0';
                wtc = 0;
                while( stars[n].tvol > 9 ) {
                        stars[n].tvol /= 10;
                        wtc++;
                        }
                if( wtc > 9 ) wtc += 'A' - 10;
                else if( wtc > 0 ) wtc += '0';
                else wtc = '0';
                x = stars[n].x - sx * 32;
                y = stars[n].y - sy * 40;
                if( stars[n].align == NON_ALIGN || stars[n].align == BA_ALIGN) {
                        if( is_bold ) fputs("gsave 0.3 setgray\n",f);
                        is_bold = 0;
                } else {
                        if( !is_bold ) fputs("grestore\n",f);
                        is_bold = 1;
                }
                if( strstr( stars[n].line+stars[n].tpos,"Cp" ) ) cp = '+';
                else if( strstr( stars[n].line+stars[n].tpos,"Cx" ) ) cp = '*';
                else cp = ' ';
                fprintf(f,"(%s) (%7.7s-%c) (%2.2s %c%c%c%c%c) %d %d world\n",
                        stars[n].line, stars[n].uwp,stars[n].uwp[8],stars[n].aligns,cp,
                                stars[n].base, stars[n].gas,wtn,wtc,x,y);
        }
        if( !is_bold ) fputs("grestore\n",f);
        fputs("showpage\n",f);
        fclose(f);
        sprintf(cbuf,"ps2pdf %s",mod_name(sectors[sx][sy].file,".ps"));
        sprintf(cbuf+strlen(cbuf)," %s",mod_name(sectors[sx][sy].file,".pdf"));
        system(cbuf);
    show_sector_summary(sx, sy);
    show_sector_summary_wiki(sx, sy);
}
unsigned char bitmap[1280][1600][3];
void
draw_tl(int x1, int y1, int x2, int y2, int brightness ) {
        int             dx, dy, x, y, dist, r, n;
        y1 = y1 * 2 - (x1 & 1); x1 = x1 * 2 - 1;
        y2 = y2 * 2 - (x2 & 1); x2 = x2 * 2 - 1;
        dx = x1 - x2; dy = y1 - y2;
        if( dx * dx > dy * dy ) dist = (dx > 0) ? dx : -dx;
        else dist = (dy > 0) ? dy : -dy;
        if( dist < 1 ) return;
        brightness /= dist+1;
        brightness *= 60;
        //printf("draw_tl: %d,%d to %d,%d, b=%d\n",x1,y1,x2,y2,brightness);
        for(r = 0;r <= dist;r++) {
                x = x2 + r * dx / dist;
                y = y2 + r * dy / dist;
                if( x < 0 || y < 0 ) continue;
                n = bitmap[x][y][2];
                n = n * n + brightness; if( n > 65000 ) n = 65000;
                n = (int) sqrt( (double)n );
                bitmap[x][y][2] = n;
                }
        }

void write_map_wiki()
{
	int x, y, minx=20, miny=20, maxx=0, maxy=0;
    FILE    *h = fopen("map.wiki","w");

    for(x = 0;x < 20;x++) for(y=0;y<20;y++) {
            if( !sectors[x][y].name ) continue;
            if( x < minx ) minx = x; if( x >= maxx ) maxx = x+1;
            if( y < miny ) miny = y; if( y >= maxy ) maxy = y+1;
            }
	fprintf( h, "==Map of Charted Space==\n");
	fprintf( h, "<imagemap>\nImage:allmap.gif | Charted Space map");
    for( x = minx; x < maxx; x++ ) for(y = miny; y < maxy; y++) {
        if( !sectors[x][y].name ) continue;
        fprintf(h,
			"\nrect %d %d %d %d [[%s Sector|%s]]",
			(x-minx)*64,(y-miny)*80,(x-minx)*64+63,(y-miny)*80+79,
			sectors[x][y].name, sectors[x][y].name);
    }

	fprintf( h, "\n</imagemap>\n");
	fprintf( h, "===Key===\n");
	fprintf( h, "<ul>\n");
	fprintf( h, "<li><font color=#00A000>Green</font> Dots: star systems.\n");
	fprintf( h, "<li><font color=#A00000>Red</font> Lines: borders.\n");
	fprintf( h, "<li><font color=#0000C0>Bright Blue</font> Grid: sector borders.\n");
	fprintf( h, "<li><font color=#000080>Dim Blue</font> Grid: subsector borders.\n");
	fprintf( h, "<li><font color=#000080>Blue</font> Lines: trade mains, brighter is bigger.\n");
	fprintf( h, "</ul>\n");
	fclose(h);
}
void write_map()
{
	int x, y, minx=20, miny=20, maxx=0, maxy=0;
    FILE    *h = fopen("map.html","w");

    for(x = 0;x < 20;x++) for(y=0;y<20;y++) {
            if( !sectors[x][y].name ) continue;
            if( x < minx ) minx = x; if( x >= maxx ) maxx = x+1;
            if( y < miny ) miny = y; if( y >= maxy ) maxy = y+1;
            }

    fprintf(h,
            "<html><head><title>Map of Traveller Charted Space</title></head>\n"
            "<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
            "<h1><center>Map of Traveller Charted Space</center></h1>\n"
            "<p>Related Links</p><ul>\n"
            "<li><a href=summary.html>Toplevel Summary</a> of known space.\n"
            "<li><a href=top_summary.html>Statistical Summary</a> of charted space.\n"
            "<li><a href=imperial_summary.html>Statistical Summary</a> of imperial space.\n"
            "<li><a href=notes.html>Notes</a> on these files.\n"
            "</ul>\n"
            "<p>Key:\n<ul>\n"
            "<li><font color=#00A000>Green</font> Dots: star systems.\n"
            "<li><font color=#A00000>Red</font> Lines: borders.\n"
            "<li><font color=#0000C0>Bright Blue</font> Grid: sector borders.\n"
            "<li><font color=#000080>Dim Blue</font> Grid: subsector borders.\n"
            "<li><font color=#000080>Blue</font> Lines: trade mains, brighter is bigger.\n"
            "<p><img src=allmap.gif usemap=#map0>"
            "<map name=map0>\n");
    for( x = minx; x < maxx; x++ ) for(y = miny; y < maxy; y++) {
            if( !sectors[x][y].file ) continue;
            fprintf(h,
                    "<area shape=rect alt=\"%s\" coords=%d,%d,%d,%d href=\"%s\">\n",
                    sectors[x][y].name,(x-minx)*64,(y-miny)*80,(x-minx)*64+63,(y-miny)*80+79,
                    mod_name(sectors[x][y].file,".html"));
            }
    fprintf(h,"</map></body></html>\n"); 
	fclose(h);
}

void
show_all() {
	FILE    *f = fopen("allmap.ppm","w");
    int     n, x, y, b, nn, minx=20, miny=20, maxx=0, maxy=0;

	write_map();
	write_map_wiki();
    for(x = 0;x < 20;x++) for(y=0;y<20;y++) {
            if( !sectors[x][y].name ) continue;
            if( x < minx ) minx = x; if( x >= maxx ) maxx = x+1;
            if( y < miny ) miny = y; if( y >= maxy ) maxy = y+1;
            }
    minx *= 64; maxx *= 64; miny *= 80; maxy *= 80;
	/* Draw blue sector/subsector borders */
        for( x = minx; x <= maxx;x++) {
                for(y = miny;y <= maxy;y++) {
                        if( x % 64 == 0 || y % 80 == 0 ) bitmap[x][y][2] = 192;
                        else if( x % 16 == 0 || y % 20 == 0 ) bitmap[x][y][2] = 128;
                        }
                }
	/* draw red allegiance borders */
        for(x = minx/2+1; x <= maxx/2; x++ )
                for(y = miny/2+1; y <= maxy/2; y++ ) {
                        b = borders[x][y];
                        if(b & 1) bitmap[2*x-2][2*y-(x&1)][0] =
                                bitmap[2*x-2][2*y-(x&1)-1][0] = 160;
                        if(b & 2) bitmap[2*x-1][2*y-(x&1)-1][0] = 160;
                        if(b & 4) bitmap[2*x][2*y-(x&1)][0] =
                                bitmap[2*x][2*y-(x&1)-1][0] = 160;
                        }
	/* Draw green stars plus blue trade routes */
    for(n=0;n<maxstar;n++) {
                int             other;
        x = stars[n].x * 2-1;
        y = stars[n].y * 2 - (stars[n].x & 1);
                if( x < minx || x > maxx ) {
                        fprintf(stderr,"badx:%d, minx%d,maxx%d\n",x,minx,maxx);
                        continue;
                        }
                if( y < miny || y > maxy ) {
                        fprintf(stderr,"bady:%d, miny%d,maxy%d\n",y,miny,maxy);
                        continue;
                        }
                bitmap[x][y][1] = 160;
                for(nn=0;nn<MAX_NEIGHBOR;nn++) {
                        if(stars[n].tsum[nn]>=100) {
                                other = stars[n].neighbors[nn];
                                if( n < other ) draw_tl( stars[n].x, stars[n].y,
                                        stars[other].x, stars[other].y,
                                        stars[n].tsum[nn]);
                                }
                        }
                }
	/* Output the bitmap data to the allmap.ppm file */
        fprintf(f,"P6\n#creator=cmap\n%d %d\n255\n", 1+maxx-minx, 1+maxy-miny );
        for(y = miny;y <= maxy;y++)
                for( x = minx; x <= maxx;x++)
                        fprintf(f,"%c%c%c",bitmap[x][y][0],bitmap[x][y][1],
                                (bitmap[x][y][2] & 0xF0));
        fclose(f);
}

void write_summary_wiki()
{
	int sx, sy;

	summary_file = fopen ("summary.wiki","w");
	fprintf (summary_file, "==Economic Summary==\n");
	fprintf (summary_file, "===Statistical Analysis===\n");
	fprintf (summary_file, "Ppoulations are in millions, economy and trade in billions.\n");
	fprintf (summary_file, "{| class=\"wikitable sortable\"\n!Sector!!X,Y!!Worlds !!Pop!!Economy !!Per Capita!!Trade Volume!! Int. Trade !! Ext. Trade\n");
    for(sy=0;sy<=19;sy++) for(sx=0;sx<=19;sx++) {
		if (!sectors[sx][sy].name) continue;
		fprintf(summary_file, "|-\n|[[%s Sector|%s]]", sectors[sx][sy].name, sectors[sx][sy].name);
		fprintf(summary_file, "|| %d,%d", sx-9,sy-5);
		fprintf(summary_file, "\n|align=\"right\"|%d", sectors[sx][sy].sys);
		fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(sectors[sx][sy].pop));
		fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(sectors[sx][sy].gsp));
        fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(sectors[sx][sy].avg));
        fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(sectors[sx][sy].tvol/10));
		fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(sectors[sx][sy].itrade/10));
		fprintf(summary_file, "\n|align=\"right\"|%s\n", print_comma(sectors[sx][sy].etrade/10));
	}
	fprintf(summary_file, "|-\n|Imperial Total|| ");
	fprintf(summary_file, "\n|align=\"right\"|%d", imp_world);
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(imp_pop));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(imp_prod));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(imp_prod/(imp_pop/1000+1)));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(imp_volume/10));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(imp_itrade/10));
	fprintf(summary_file, "\n|align=\"right\"|%s\n", print_comma(imp_etrade/10));

	fprintf(summary_file, "|-\n|Global Total|| ");
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(maxstar));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(tot_pop));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(tot_prod));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(tot_prod/(tot_pop/1000+1)));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(tot_volume/10));
	fprintf(summary_file, "\n|align=\"right\"|%s", print_comma(tot_trade/10));
	fprintf(summary_file, "\n|align=\"right\"|0\n|}\n");
    fclose(summary_file);	
}

void write_summary()
{
	int sx, sy;

	summary_file = fopen("summary.html","w");
	fprintf(summary_file,
	        "<html><head><title>Economic Summary</title></head><body bgcolor=BLACK text=#00FF00>\n"
	        "<h1>Economic Summary</h1><h2>Statistical Analysis</h2>\n"
	        "<p>Populations are in millions, economy and trade in billions.\n"
	        "<table><tr><td>Sector</td><td>X,Y</td><td># Worlds</td>"
	        "<td>Population</td><td>Economy</td><td>Per Capita</td>"
	        "<td>T.Volume</td><td>Int. Trade</td><td>Ext. Trade</td></tr>\n");

    for(sy=0;sy<=19;sy++) for(sx=0;sx<=19;sx++) {
		if (!sectors[sx][sy].name) continue;
        fprintf(summary_file,"<tr><td>%s</td>",sectors[sx][sy].name);
        fprintf(summary_file,"<td>%d,%d</td>",sx-9,sy-5);
        fprintf(summary_file,"<td align=right>%d</td>",sectors[sx][sy].sys);
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(sectors[sx][sy].pop));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(sectors[sx][sy].gsp));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(sectors[sx][sy].avg));
        fprintf(summary_file,"<td align=right>%s</td>",
                print_comma(sectors[sx][sy].tvol/10));
        fprintf(summary_file,"<td align=right>%s</td>",
                print_comma(sectors[sx][sy].itrade/10));
        fprintf(summary_file,"<td align=right>%s</td></tr>\n",
                print_comma(sectors[sx][sy].etrade/10));
	}

    fprintf(summary_file,"<tr><td>Imperial Total</td>");
        fprintf(summary_file,"<td>0,0</td>");
        fprintf(summary_file,"<td align=right>%d</td>",imp_world);
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_pop));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_prod));
        fprintf(summary_file,"<td align=right>%s</td>",
                print_comma(imp_prod/(imp_pop/1000+1)));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_volume/10));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(imp_itrade/10));
        fprintf(summary_file,"<td align=right>%s</td></tr>\n",
                print_comma(imp_etrade/10));
    fprintf(summary_file,"<tr><td>Global Total</td>");
        fprintf(summary_file,"<td>0,0</td>");
        fprintf(summary_file,"<td align=right>%d</td>",maxstar);
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_pop));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_prod));
        fprintf(summary_file,"<td align=right>%s</td>",
                print_comma(tot_prod/(tot_pop/1000+1)));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_volume/10));
        fprintf(summary_file,"<td align=right>%s</td>",print_comma(tot_trade/10));
        fprintf(summary_file,"<td align=right>0</td></tr>\n");
        fprintf(summary_file,"</table></html>");
        fclose(summary_file);

}

void write_imperial_summary_wiki()
{
	FILE * f;
	int n; 

	f = fopen ("imperial_summary.wiki", "w");
	fprintf (f, "==Imperial Summary==\n");
	fprintf (f, "{|\n");
	fprintf (f, "|Systems || %d\n", imp_world);
	fprintf (f, "|-\n|Population || %s million\n", print_comma(imp_pop));
	fprintf (f, "|-\n|Gross Imperial Product || %s billion\n", print_comma(imp_prod));
	fprintf (f, "|-\n|Per Capita GSP || Cr %s\n", print_comma(imp_prod/(imp_pop/1000+1)));
	fprintf (f, "|-\n|Internal Trade || %s billion\n", print_comma(imp_itrade/10));
	fprintf (f, "|-\n|External Trade || %s billion\n", print_comma(imp_etrade/10));
	fprintf (f, "|}\n");
	fprintf (f, "===Summary Report===\n");
	fprintf (f, "{|\n!Component ");
	for (n=0; n <= 9; n++) fprintf (f, "||%d", n);
	for (n=0; n < 8; n++) fprintf (f, "||%c", n + 'A');
	fprintf (f, "||I-Z\n");
	fprintf (f, "|-\n|Port Code");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[0][n]);
	fprintf (f, "\n|-\n|Size");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[1][n]);
	fprintf (f, "\n|-\n|Atmosphere");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[2][n]);
	fprintf (f, "\n|-\n|Water");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[3][n]);
	fprintf (f, "\n|-\n|Population");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[4][n]);
	fprintf (f, "\n|-\n|Government");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[5][n]);
	fprintf (f, "\n|-\n|Law level");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[6][n]);
	fprintf (f, "\n|-\n|Tech level");
	for (n=0; n < 19; n++) fprintf (f, "||%d", imp_summaries[7][n]);
	fprintf (f, "\n|-\n|colspan=\"20\" align=\"center\" | Percent by Population\n");
	fprintf (f, "|-\n|Port Code");
	for(n=0;n<19;n++) fprintf(f,"||%d%%",imp_weighted[0][n]/(imp_pop/100+1));
	fprintf (f, "\n|-\n|Size");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", imp_weighted[1][n]/(imp_pop/100+1));
	fprintf (f, "\n|-\n|Atmosphere");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", imp_weighted[2][n]/(imp_pop/100+1));
	fprintf (f, "\n|-\n|Water");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", imp_weighted[3][n]/(imp_pop/100+1));
	fprintf (f, "\n|-\n|Population");		
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", imp_weighted[4][n]/(imp_pop/100+1));
	fprintf (f, "\n|-\n|Government");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", imp_weighted[5][n]/(imp_pop/100+1));
	fprintf (f, "\n|-\n|Law level");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", imp_weighted[6][n]/(imp_pop/100+1));
	fprintf (f, "\n|-\n|Tech level");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", imp_weighted[7][n]/(imp_pop/100+1));
	fprintf (f, "\n|}");
	fclose (f);
	
}
void write_imperial_summary ()
{
    FILE * f;
	int n; 

	f = fopen("imperial_summary.html","w");
	fprintf(f,"<html><head><title>Imperial Summary</title></head>\n");
	fprintf(f,"<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
	        "<h1><center>Imperial Summary</center></h1>\n");
	fprintf(f,"<table>\n");
	fprintf(f,"<tr><td>Systems</td><td>%d</td></tr>\n",imp_world);
	fprintf(f,"<tr><td>Population</td><td>%s million</td></tr>\n",
	        print_comma(imp_pop));
	fprintf(f,"<tr><td>Gross Imperial Product</td><td>%s billion</td></tr>\n",
	        print_comma(imp_prod));
	fprintf(f,"<tr><td>Per Capita GSP</td><td>Cr %s</td></tr>\n",
	        print_comma(imp_prod/(imp_pop/1000+1)));
	fprintf(f,"<tr><td>Internal Trade</td><td>%s billion</td></tr>\n",
	        print_comma(imp_itrade/10));
	fprintf(f,"<tr><td>External Trade</td><td>%s billion</td></tr>\n",
	        print_comma(imp_etrade/10));
	fprintf(f,"</table></body></html>\n");
	fprintf(f,"<p>Summary Report:\n<table>\n<tr><td>Component</td>");
	for(n=0;n<=9;n++) fprintf(f,"<td width=4%%>%d</td>",n);
	for(n=0;n<8;n++) fprintf(f,"<td width=4%%>%c</td>",n+'A');
	fprintf(f,"<td width=4%%>I-Z</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[0][n]);
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[1][n]);
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[2][n]);
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[3][n]);
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[4][n]);
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[5][n]);
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[6][n]);
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",imp_summaries[7][n]);
	fprintf(f,"</tr><tr><td colspan=20 align=center>Percent by Population</td>\n");
	fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
	for(n=0;n<19;n++)
	        fprintf(f,"<td>%d%%</td>",imp_weighted[0][n]/(imp_pop/100+1));
	fprintf(f,"</tr><tr><td>SIZE</td>\n");
	for(n=0;n<19;n++)
	        fprintf(f,"<td>%d%%</td>",imp_weighted[1][n]/(imp_pop/100+1));
	fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
	for(n=0;n<19;n++)
	        fprintf(f,"<td>%d%%</td>",imp_weighted[2][n]/(imp_pop/100+1));
	fprintf(f,"</tr><tr><td>WATER</td>\n");
	for(n=0;n<19;n++)
	        fprintf(f,"<td>%d%%</td>",imp_weighted[3][n]/(imp_pop/100+1));
	fprintf(f,"</tr><tr><td>POPULATION</td>\n");
	for(n=0;n<19;n++)
	        fprintf(f,"<td>%d%%</td>",imp_weighted[4][n]/(imp_pop/100+1));
	fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
	for(n=0;n<19;n++)
	        fprintf(f,"<td>%d%%</td>",imp_weighted[5][n]/(imp_pop/100+1));
	fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
	for(n=0;n<19;n++)
	        fprintf(f,"<td>%d%%</td>",imp_weighted[6][n]/(imp_pop/100+1));
	fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
	for(n=0;n<19;n++) fprintf(f,"<td>%d%%</td>",
	        imp_weighted[7][n]/(imp_pop/100+1));
	fprintf(f,"</tr></table>\n");
	fclose(f);

}

void write_top_summary_wiki()
{
	FILE * f; 
	int n;

	f = fopen ("top_summary.wiki", "w");
	fprintf (f, "==Top level Summary==\n");
	fprintf (f, "{|\n");
	fprintf (f, "|Systems || %d\n", maxstar);
	fprintf (f, "|-\n|Population || %s million\n", print_comma(tot_pop));
	fprintf (f, "|-\n|Gross Total Product || %s billion\n", print_comma (tot_prod));
	fprintf (f, "|-\n|Per Capita GSP || Cr %s\n", print_comma(tot_prod/(tot_pop/1000+1)));
	fprintf (f, "|-\n|Trade || %s billion\n", print_comma(tot_trade/10));
	fprintf (f, "\n|}\n");
	fprintf (f, "===[[Allegiance Code|Allegiance Information]]===\n");
	show_alliegances( 0, 1, alliegances, f);
	fprintf (f, "===Summary Report===\n");
	fprintf (f, "{|\n!Component ");
	for (n=0; n <= 9; n++) fprintf (f, "||%d", n);
	for (n=0; n < 8; n++) fprintf (f, "||%c", n + 'A');
	fprintf (f, "||I-Z\n");
	fprintf (f, "|-\n|Port Code");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[0][n]);
	fprintf (f, "\n|-\n|Size");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[1][n]);
	fprintf (f, "\n|-\n|Atmosphere");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[2][n]);
	fprintf (f, "\n|-\n|Water");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[3][n]);
	fprintf (f, "\n|-\n|Population");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[4][n]);
	fprintf (f, "\n|-\n|Government");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[5][n]);
	fprintf (f, "\n|-\n|Law level");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[6][n]);
	fprintf (f, "\n|-\n|Tech level");
	for (n=0; n < 19; n++) fprintf (f, "||%d", tot_summaries[7][n]);
	fprintf (f, "\n|-\n|colspan=\"20\" align=\"center\" | Percent by Population\n");
	fprintf (f, "|-\n|Port Code");
	for(n=0;n<19;n++) fprintf(f,"||%d%%",tot_weighted[0][n]/(tot_pop/100+1));
	fprintf (f, "\n|-\n|Size");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", tot_weighted[1][n]/(tot_pop/100+1));
	fprintf (f, "\n|-\n|Atmosphere");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", tot_weighted[2][n]/(tot_pop/100+1));
	fprintf (f, "\n|-\n|Water");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", tot_weighted[3][n]/(tot_pop/100+1));
	fprintf (f, "\n|-\n|Population");		
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", tot_weighted[4][n]/(tot_pop/100+1));
	fprintf (f, "\n|-\n|Government");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", tot_weighted[5][n]/(tot_pop/100+1));
	fprintf (f, "\n|-\n|Law level");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", tot_weighted[6][n]/(tot_pop/100+1));
	fprintf (f, "\n|-\n|Tech level");
	for (n=0; n < 19; n++) fprintf (f, "||%d%%", tot_weighted[7][n]/(tot_pop/100+1));
	fprintf (f, "\n|}");
	fclose (f);
}

void write_top_summary()
{
	FILE * f;
	int n; 

    f = fopen("top_summary.html","w");
    fprintf(f,"<html><head><title>Toplevel Summary</title></head>\n");
    fprintf(f,"<body bgcolor=BLACK text=#00FF00 link=#FF0000>\n"
            "<h1><center>Toplevel Summary</center></h1>\n");
    fprintf(f,"<table>\n");
    fprintf(f,"<tr><td>Systems</td><td>%d</td></tr>\n",maxstar);
    fprintf(f,"<tr><td>Population</td><td>%s million</td></tr>\n",
            print_comma(tot_pop));
    fprintf(f,"<tr><td>Gross Total Product</td><td>%s billion</td></tr>\n",
            print_comma(tot_prod));
    fprintf(f,"<tr><td>Per Capita GSP</td><td>Cr %s</td></tr>\n",
            print_comma(tot_prod/(tot_pop/1000+1)));
    fprintf(f,"<tr><td>Trade</td><td>%s billion</td></tr>\n",
            print_comma(tot_trade/10));
    fprintf(f,"</table>\n");
    fprintf(f,"<p>Alliegance Information\n");
    show_alliegances( 0, 0, alliegances, f );
    fprintf(f,"<p>Summary Report:\n<table>\n<tr><td>Component</td>");
    for(n=0;n<=9;n++) fprintf(f,"<td width=4%%>%d</td>",n);
    for(n=0;n<8;n++) fprintf(f,"<td width=4%%>%c</td>",n+'A');
    fprintf(f,"<td width=4%%>I-Z</td>\n");
    fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[0][n]);
    fprintf(f,"</tr><tr><td>SIZE</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[1][n]);
    fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[2][n]);
    fprintf(f,"</tr><tr><td>WATER</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[3][n]);
    fprintf(f,"</tr><tr><td>POPULATION</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[4][n]);
    fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[5][n]);
    fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[6][n]);
    fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d</td>",tot_summaries[7][n]);
    fprintf(f,"</tr><tr><td colspan=20 align=center>Percent by Population</td>\n");
    fprintf(f,"</tr><tr><td>PORT CODE</td>\n");
    for(n=0;n<19;n++)
            fprintf(f,"<td>%d%%</td>",tot_weighted[0][n]/(tot_pop/100 + 1));
    fprintf(f,"</tr><tr><td>SIZE</td>\n");
    for(n=0;n<19;n++)
            fprintf(f,"<td>%d%%</td>",tot_weighted[1][n]/(tot_pop/100 + 1));
    fprintf(f,"</tr><tr><td>ATMOSPHERE</td>\n");
    for(n=0;n<19;n++)
            fprintf(f,"<td>%d%%</td>",tot_weighted[2][n]/(tot_pop/100+ 1));
    fprintf(f,"</tr><tr><td>WATER</td>\n");
    for(n=0;n<19;n++)
            fprintf(f,"<td>%d%%</td>",tot_weighted[3][n]/(tot_pop/100+ 1));
    fprintf(f,"</tr><tr><td>POPULATION</td>\n");
    for(n=0;n<19;n++)
            fprintf(f,"<td>%d%%</td>",tot_weighted[4][n]/(tot_pop/100+ 1));
    fprintf(f,"</tr><tr><td>GOVERNMENT</td>\n");
    for(n=0;n<19;n++)
            fprintf(f,"<td>%d%%</td>",tot_weighted[5][n]/(tot_pop/100+ 1));
    fprintf(f,"</tr><tr><td>LAW LEVEL</td>\n");
    for(n=0;n<19;n++)
            fprintf(f,"<td>%d%%</td>",tot_weighted[6][n]/(tot_pop/100+ 1));
    fprintf(f,"</tr><tr><td>TECH LEVEL</td>\n");
    for(n=0;n<19;n++) fprintf(f,"<td>%d%%</td>",
            tot_weighted[7][n]/(tot_pop/100+ 1));
    fprintf(f,"</tr></table>\n");
    fclose(f);
}

int
main(int argc, char **argv) {
        int             y,x,n;

        for(n=1;n<argc;n++) read_sec(argv[n]);
        sort_stars();
        fprintf(stderr,"stars sorted.\n");
#if 0
        pass++;
        for(n=0;n<maxstar;n++) {
                if( stars[n].wtn < 9 ) break;
                get_trade_to( n );
                }
        pass++;
        for(;n>=0;n--) get_trade_to(n);
#endif
        trade_file = fopen("TRADE","w");
        route_file = fopen("ROUTES","w");
        final=1;
        pass++;
        for( current_trade = 15; current_trade > 8; current_trade-- ) {
                for(n=0;n<maxstar;n++) {
                        if( (stars[n].wtn) < (current_trade) ) break;
                        get_trade_to( n );
                        }
                }
        tramp = 1;
        for(n=0;n<maxstar;n++) {
                if( (stars[n].wtn) < (current_trade) ) break;
                get_trade_to( n );
                }
	fprintf (stderr, "trade routes computed\n");
        show_all();
/*      show_sector(0,0);*/

    for(y=0;y<=19;y++) for(x=0;x<=19;x++) {show_sector(x,y); /*show_quadrants(x,y);*/ }

	write_summary();
	write_imperial_summary();
	write_top_summary();
	write_summary_wiki();
	write_imperial_summary_wiki();
	write_top_summary_wiki();
    return 0;
}