#!/bin/awk -f
#
#		trader [files]
#	Loads, orders, navs, fuels, and scuttles trade ships.
#
#
#
#	Reads the following file formats.
#		dump
#		nation
#		report
#		relations
#		ship
#		cargo
#		unit
#		lcargo
#		spy
#		look  
  
function max(x,y) {
  if (x>y) return x;
  return y;
}
function min(x,y) {
  if (x<y) return x;
  return y;
}

function num(str) {
  return substr(str,1,length(str)-1);
}
#
#	Turns a letter into a name.  Tries the first letter, if that
#	isn't a commodity, tries the last letter (useful for ship, unit,
#	and prod outputs)
#
function commstr(str) {
  char=substr(str,1,1);
  if (char == "c") return "civ";
  if (char == "m") return "mil";
  if (char == "u") return "uw";
  if (char == "f") return "food";
  if (char == "s") return "shell";
  if (char == "g") return "gun";
  if (char == "p") return "pet";
  if (char == "i") return "iron";
  if (char == "d") return "dust";
  if (char == "b") return "bar";
  if (char == "o") return "oil";
  if (char == "l") return "lcm";
  if (char == "h") return "hcm";
  if (char == "r") return "rad";

  char=substr(str,length(str),1);
  if (char == "c") return "civ";
  if (char == "m") return "mil";
  if (char == "u") return "uw";
  if (char == "f") return "food";
  if (char == "s") return "shell";
  if (char == "g") return "gun";
  if (char == "p") return "pet";
  if (char == "i") return "iron";
  if (char == "d") return "dust";
  if (char == "b") return "bar";
  if (char == "o") return "oil";
  if (char == "l") return "lcm";
  if (char == "h") return "hcm";
  if (char == "r") return "rad";
  return "";
}

#
#	Truncate starting and ending whitespace from a string
#
function truncwhite(str,  i,j) {
  for (i=1;i<=length(str) && substr(str,i,1) ~ "[ \t\r\n]";i++) ;
  for (j=length(str);j>i && substr(str,j,1) ~ "[ \t\r\n]";j--) ;
  return (substr(str,i,j-i+1));
}


BEGIN {
  SUBSEP=",";
  mode="";
  stat=0;
  
  ships=0;
  shipnamlen=16;
  
# some defaults so I don't have to parse *everything*
  width=192;
  height=96;

  weight["civ"]=1;	packing["civ"]=1;
  weight["mil"]=1;	packing["mil"]=1;
  weight["uw"]=2;	packing["uw"]=1;
  weight["food"]=1;	packing["food"]=10;
  weight["shell"]=1;	packing["shell"]=10;
  weight["gun"]=10;	packing["gun"]=10;
  weight["pet"]=1;	packing["pet"]=10;
  weight["iron"]=1;	packing["iron"]=10;
  weight["dust"]=5;	packing["dust"]=10;
  weight["bar"]=50;	packing["bar"]=5;
  weight["oil"]=1;	packing["oil"]=10;
  weight["lcm"]=1;	packing["lcm"]=10;
  weight["hcm"]=1;	packing["hcm"]=10;
  weight["rad"]=8;	packing["rad"]=10;
}

/^[ \t]+New treasury:[ \t]+[0-9]+/ {
  budget=$NF;
  printf("# budget: %s\n",budget);
}

/.* Nation Report/ {
  if ($1 in number) coun=number[$1];
  country[coun]=$1;
  number[$1]=coun;
  next;
}
/.* eff capital at/ {
  cap[coun] = $5; next;
}
/ The treasury has .* Military reserves/ {
  money[coun]=substr($4,2,length($4)-4);
  reserves[coun]=$7;
}
/Education\.* * .+ * Happiness\.* .+/ {
  edu[coun] = substr($0,20,6);
  hap[coun] = substr($0,50,6);
  next;
}
/Technology\.* *.+ * Research\.*.+/ {
  tech[coun] = substr($0,20,6);
  res[coun] = substr($0,50,6);
  next;
}

/sects  eff civ  mil  shell gun pet  iron dust oil  pln ship unit money/,/^worldwide/ {
  if ($1=="sects") next;
  i=match($0,"[a-zA-Z]");
  name=substr($0,i,10-i);
  for (coun in country) {
    if (name==substr(country[coun],1,9)) break;
  }
  if (!(coun in money) && name==substr(country[coun],1,9)) {
    amt=num($NF);
    if (substr($NF,length($NF),1)=="K") amt *= 1000;
    if (substr($NF,length($NF),1)=="M") amt *= 1000000;
    money[coun] = amt;
  }
}
  
# Satellite ship report
/^ own  shp# ship type                                  sector   eff/ {
  while (getline) {
    if ($2=="ships") break;
    shipname[$2]=truncwhite(substr($0,11,16));
    shipsect[$2]=$(NF-1);
    shipown[$2]=$1;
    shipeff[$2]=substr($NF,1,length($NF)-1);
  }
  next;
}



/^ *.+\(# *[0-9]+\) .+ #[0-9]+ @ .+,.+/ {
  i=index($0,"(#");
  j=index($0,")");
  c=truncwhite(substr($0,i+2,j-i-2));
  name=truncwhite(substr($0,1,i-1));
  country[c]=name;
  number[name]=c;

  i=index($0," #");
  name=truncwhite(substr($0,j+2,i-j-2));
  n=substr($(NF-2),2);
  sect=$NF;
  if (name=="fishing vessel") name="fishing boat 1";
  if (!(n in shipname)) shiporder[ships++]=n;
  shipname[n]=name;
  shipown[n]=c;
  if (!(n in shipeff)) shipeff[n]=100;
  shipsect[n]=sect;
}

/^.+ \(#[0-9]+\) .+ [0-9]+% efficient .* @ .+,.+/ {
  
  i=1;
  while ($i == "ship(s)?") i++;
  
  i=index($0,"(#");
  j=index($0,")");
  c=truncwhite(substr($0,i+2,j-i-2));
  name=truncwhite(substr($0,1,i-1));
  country[c]=name;
  number[name]=c;
  
  i=match($0,"[0-9]+%");
  sectype=substr($0,j+1,i-j-2);
  
  if (sectype == " sea") sec=".";
  else if (sectype == " mountain") sec="^";
  else if (sectype == " sanctuary") sec="s";
  else if (sectype == " wasteland") sec="/";
  else if (sectype == " wilderness") sec="-";
  else if (sectype == " capital") sec="c";
  else if (sectype == " uranium mine") sec="u";
  else if (sectype == " park") sec="p";
  else if (sectype == " defense plant") sec="d";
  else if (sectype == " shell industry") sec="i";
  else if (sectype == " mine") sec="m";
  else if (sectype == " gold mine") sec="g";
  else if (sectype == " harbor") sec="h";
  else if (sectype == " warehouse") sec="w";
  else if (sectype == " airfield") sec="*";
  else if (sectype == " agribusiness") sec="a";
  else if (sectype == " oil field") sec="o";
  else if (sectype == " light manufacturing") sec="j";
  else if (sectype == " heavy manufacturing") sec="k";
  else if (sectype == " fortress") sec="f";
  else if (sectype == " technical center") sec="t";
  else if (sectype == " research lab") sec="r";
  else if (sectype == " nuclear plant") sec="n";
  else if (sectype == " library/school") sec="l";
  else if (sectype == " highway") sec="+";
  else if (sectype == " radar installation") sec=")";
  else if (sectype == " weather stn (useless)") sec="!";
  else if (sectype == " retirement home (useless)") sec="!";
  else if (sectype == " headquarters") sec="!";
  else if (sectype == " bridge head") sec="#";
  else if (sectype == " bridge span") sec="=";
  else if (sectype == " bank") sec="b";
  else if (sectype == " refinery") sec="%";
  else if (sectype == " enlistment center") sec="e";
  else {
    printf("# Unknown sector type `%s'\n",sectype);
    printf("# %s\n",$0);
    sec="?";
  }

  j=index($0,"%");
  seceff = substr($0,i,j-i);

  for (i=1;i<=NF;i++) if ($i=="with") break;

  while ($i == "with") {
    approx=0;
    i++;
    if ($i == "approx") { i++; approx=4; }
    if ($(i+1)=="civ") {
      secciv = $i + approx;
    } else if ($(i+1)=="mil") {
      secmil = $i + approx;
    } else {
      printf("# Expected either civ or mil.  Got %s\n",$(i+1)) ;
    }
    i += 2;
  }
  
  i++;
  n=split($i,a,",");
  sect=$i;
  val[sect,"x"]=a[1];
  val[sect,"y"]=a[2];
  val[sect,"des"]=sec;
  val[sect,"eff"]=seceff;
  val[sect,"civ"]=secciv;
  val[sect,"mil"]=secmil;
  own[sect]=c;
  oldown[sect]=c;
}

/^SPY Plane report/ {
  getline;
  getline;
  if ($0 != "   sect   type own  eff  civ  mil  shl  gun  iron  pet  food") {
    printf("# SPY plane report error\n");
    next;
  }
  getline;
  do {
    if (match($0,"^firing [0-9]+ flak guns in .*\.\.\.")) {
      val[substr($NF,1,length($NF)-3),"gun"] = $2;
      do { getline; } while (match($0,".* .* \(#[0-9]\) takes [0-9]+\."));
      getline;
    } else if (match($0,"own  lnd# unit type         sector   eff")) {
      getline;
      while (length($0)>0) {
        unitown[$2]=$1;
	uniteff[$2]=num($NF);
	unitsect[$2]=$(NF-1);
	unittype[$2]=truncwhite(substr($0,19,35-19));
        if (!($2 in unitname)) unitorder[units++]=$2;
        getline;
      }
    } else {
      split($1,a,"[ ,]");
      sect=$1;
      val[sect,"x"]=a[1];
      val[sect,"y"]=a[2];
      val[sect,"des"]=$2;
      own[sect]=oldown[sect]=$3;
      val[sect,"eff"]=$4;
      val[sect,"civ"]=$5;
      val[sect,"mil"]=$6;
      val[sect,"shell"]=$7;
      val[sect,"gun"]=$8;
      val[sect,"iron"]=$9;
      val[sect,"pet"]=$10;
      val[sect,"food"]=$11;
      if (val[sect,"mil"]==0 && val[sect,"civ"]==0) val[sect,"mil"]=1;
    }
    getline;
  } while (length($0));
}

/^SPY report/ {
  getline;
  getline;
  if ($0 != "   sect   type own  eff  civ  mil  shl  gun  iron  pet  food") {
    printf("# Spy report error\n");
    next;
  }

  getline;
  while (length($0)>0) {
    if ($1 == "Spies") {
      j=index($0,":");
      sect=substr($0,28,j-28);
      i=index($0,"#");
      name=substr($0,j+3,i-4-j);
      j=index(substr($0,i)," ");
      n=substr($0,i+1,j-2);
      if (!(n in unitname)) unitorder[units++]=n;
      unitname[n]=name;
      unitown[n]=own[sect];
      unitsect[n]=sect;
      i=match($0,"efficiency");
      if (i) {
        j=index(substr($0,i),",");
        uniteff[n]=substr($0,i+11,j-12);
      }
      i=match($0,"tech");
      if (i) {
        j=index(substr($0,i),")");
        unittech[n]=substr($0,i+5,j-6);
      }
    } else if ($1 != "BANG!!") {
      split($1,a,"[ ,]");
      sect=$1;
      val[sect,"x"]=a[1];
      val[sect,"y"]=a[2];
      val[sect,"des"]=$2;
      own[sect]=oldown[sect]=$3;
      val[sect,"eff"]=$4;
      val[sect,"civ"]=$5;
      val[sect,"mil"]=$6;
      val[sect,"shell"]=$7;
      val[sect,"gun"]=$8;
      val[sect,"iron"]=$9;
      val[sect,"pet"]=$10;
      val[sect,"food"]=$11;
      if (val[sect,"mil"]==0 && val[sect,"civ"]==0) val[sect,"mil"]=1;
    }
    getline;
  }
}

/^> BULLETIN/ {
  for (i in attackunit) delete attackunit[i];
  do {
    getline;
    if ($1=="Scouts") {
      j=index($0,":");
      i=index($0,"#");
      name=substr($0,j+2,i-4-j);
      j=index(substr($0,i)," ");
      n=substr($0,i+1,j-2);
      if (!(n in unitname)) unitorder[units++]=n;
      attackunit[n]=1;
      unitname[n]=name;
      i=match($0,"efficiency");
      if (i) {
        j=index(substr($0,i),",");
        uniteff[n]=substr($0,i+11,j-12);
      }
      i=match($0,"tech");
      if (i) {
        j=index(substr($0,i),")");
        unittech[n]=substr($0,i+5,j-6);
      }
    }
  } while ($1 == "Scouts");
}

/^[A-Za-z].+ \(#[0-9]+\) lost [0-9]+ troops taking .+,.+/ {
  sect=$NF;
  i=index($0,"#");
  j=index($0,")");
  c=substr($0,i+1,j-i-1);
  own[sect]=c;
  if (!((sect,"des") in val)) val[sect,"des"]="+";
  for (i in attackunit) {
    unitown[i]=c;
    unitsect[i]=sect;
  }
}

/^Kawhomp! Mine detected by .+ \(#[0-9]+\) in .+,.+!/ {
  sect=substr($NF,1,length($NF)-1);
  mine[sect]=20;
}

/[0-9\-]+,[0-9\-]+ efficiency [0-9]+%, max range [0-9]+/ {
  split($1,a,",");
  x=a[1];
  y=a[2];
  range = $NF;
  for (i=-range;i<=range;i++) {
    getline;
    k=1;
    while (j=index(substr($0,k),"$")) {
      satellite[x-range*2+j+k-2,y+i]=1;
      k=j+1;
    }
  }
}

/^bmap/ {    
  getline;
  header[0]=$0
  getline;
  header[1]=$0;

  colskip = match(header[0],"[0-9\-]");
  if (!colskip) printf("error reading bmap\n") >> "/dev/tty";
  columns = length(header[0])-colskip+1;
  
  left=substr(header[0],colskip,1)*10+substr(header[1],colskip,1);
  right=substr(header[0],length(header[0]),1)*10+substr(header[1],length(header[1]),1);
  left2=substr(header[0],colskip+1,1)*10+substr(header[1],colskip+1,1);
  right2=substr(header[0],length(header[0])-1,1)*10+substr(header[1],length(header[1])-1,1);
  
  if (left2<left) left = -left;
  if (right2>right) right = -right;

  getline;
  while (match($0,"[0-9\-]")<colskip) {
    y=$1;
    x=left;
    for (col=colskip;col<columns;col++) {
      if ( (x+y)/2 == int((x+y)/2) ) {
	des=substr($0,col,1);
	if (des=="?") des="+";
	if (match(des,"[s^cupdimghw\\*aojkftrnl+)!#=b%eX\-]")) {
          bdes[x,y]=des;
	}
      }
      x++;
      if (x>=width/2) x -= width;
    }
    getline;
  }
}

/shp#     ship type  orig x,y       x,y    \$\$/ {
  while (getline) {
    if (index($0,"ships")) break;
    shiporig[$1]=truncwhite(substr($0,23,8));
  }
}

/shp#     ship type       x,y   flt  dest1 pick dest2  pick dist eta/ {  
  while (getline) {
    if (index($0,"ships")) break;
    if ($NF == "path") {
      shipdest1[$1]="sail";
    } else {
      shipdest1[$1]=truncwhite(substr($0,36,7));
      shipeta[$1]=$NF;
      shipdist[$1]=$(NF-1);
    }
  }
}


/.* Diplomatic Relations Report/ {
  i=match($0,"Diplomatic Relations Report");
  name=truncwhite(substr($0,1,i-2));
  getline; getline;
  while (getline) {
    if (! ($1 ~ "[0-9]+\\)")) break;
    relname=truncwhite(substr($0,6,20));
    number[relname]=substr($1,1,length($1)-1);
    country[number[relname]]=relname;
    relation[name,relname]=truncwhite(substr($0,28,10));
    relation[relname,name]=truncwhite(substr($0,39,10));
  }

  next;
}


/ *DUMP SECTOR/ { mode="dump"; stat=1; next; }
/^ *# *name *tech *research *education *status/ { mode="report"; stat=1; next; }
/^shp#     ship type       x,y   fl  eff civ mil  uw  fd pn he xl ln mob fuel tech/ { mode="ship"; stat=1; next; }
/^shp# ship type           x,y   flt  eff  sh gun pet irn dst bar oil lcm hcm rad/ { mode="cargo"; stat=1; next; }
/ *# unit type * x,y * a * eff fort * mu food fuel tech retr rad xl ship/ { mode="unit"; stat=1; next; }
/ *#    type                x,y    w  eff  mu att def tech ran hard   s\/l nuke/ { mode="plane"; stat=1; next; }
/ *lcm hcm avail tech \$/ {mode="ssb"; stat=1; next;}
/ *cargos & capabilities/ {mode="ssc"; stat=1; next; }
/ *def  d  s  y  g  r  d  n  l  l/ {mode="sss"; stat=1; next; }
/ *lcm hcm mil guns shells avail tech  \$/ {mode="slb"; stat=1; next;}
/^ *capabilities$/ {mode="slc"; stat=1; next; }
/ *att def vul  d  s  y  d  g  c  m  m  f  c  u  l/ {mode="sls"; stat=1; next;}
/ *lcm hcm crew avail tech  $/ { mode="spb"; stat=1; next; }
/ *acc load att def ran fuel stlth/ { mode="sps"; stat=1; next; }

{
  if (mode=="dump") {
    if (stat==1) {
      for (i=1;i<=NF;i++) header[i]=$i;
      nheader=NF;
      stat=2;
      break;
    }
    
    if (NF != nheader) {
      stat=0;
    }
    
    if (stat==2) {
      dump[coun]++;
      for (i=1;i<=nheader;i++) temp[header[i]] = $i;
      sect = temp["x"] "," temp["y"];
      for (i=1;i<=nheader;i++) val[sect,header[i]] = $i;
      
      if (val[sect,"*"]=="*") oldown[sect]=0;
      else if ("own" in temp) oldown[sect]=val[sect,"own"];
      else oldown[sect]=coun;
      if ("own" in temp) own[sect]=val[sect,"own"];
      else own[sect]=coun;
    }
  } else if (mode=="ssb") {
    if (stat==1 && NF > 5) {
      name=truncwhite(substr($0,1,shipnamlen));
      shipcost[name]=substr($NF,2);
      shiptech[name]=$(NF-1);
      shipavail[name]=$(NF-2);
      shiplcm[name]=$(NF-3);
      shiphcm[name]=$(NF-4);
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="sss") {
    if (stat==1 && NF > 11) {
      name=truncwhite(substr($0,1,shipnamlen));
      nf=split(substr($0,21),a,"[ \t/]*");
      shipdef[name]=a[2];
      shipspd[name]=a[3];
      shipvis[name]=a[4];
      shipspy[name]=a[5];
      shiprng[name]=a[6];
      shipfir[name]=a[7];
      shiplnd[name]=a[8];
      shippln[name]=a[9];
      shiphel[name]=a[10];
      shipxpl[name]=a[11];
      shipfc[name]=a[12];

      shipfu[name]=a[13];
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="ssc") {
    if (stat==1 && NF > 3) {
      name=truncwhite(substr($0,1,shipnamlen));
      nf=split(substr($0,21),a,"[ \t/]*");
      for (i=2;i<=nf;i++) {
	if (a[i] ~ "[0-9]+[cmufsgpidbolhr]") {
	  shipcargo[name,commstr(a[i])] = num(a[i]);
	} else {
	  capability[name] = capability[name] " " a[i] " ";
	}
      }
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="sls") {
    if (stat==1 && NF > 11) {
      name=truncwhite(substr($0,1,shipnamlen));
      nf=split(substr($0,24),a,"[ \t/]*");
      unitatt[name]=a[2];
      unitdef[name]=a[3];
      unitvul[name]=a[4];
      unitspd[name]=a[5];
      unitvis[name]=a[6];
      unitspy[name]=a[7];
      unitrad[name]=a[8];
      unitfrg[name]=a[9];
      unitacc[name]=a[10];
      unitdam[name]=a[11];
      unitamm[name]=a[12];
      unitaaf[name]=a[13];
      unitfc[name]=a[14];
      unitfu[name]=a[15];
      unitxpl[name]=a[16];
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="slc" || mode=="spc") {
    if (stat==1 && length($0)>26) {
      name=truncwhite(substr($0,1,20));
      nf=split(substr($0,22),a,"[ \t/]*");
      for (i=2;i<=nf;i++) {
	if (a[i] ~ "[0-9]+[cmufsgpidbolhr]") {
	  unitcargo[name,commstr(a[i])] = num(a[i]);
	} else {
	  capability[name] = capability[name] " " a[i] " ";
	}
      }
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="ship") {
    if (stat==1) {
      ships=0;
      for (i in shiporder) delete shiporder[i];
      stat=2;
    }
    if (stat==2 && NF > 2) {
      name=truncwhite(substr($0,6,shipnamlen));
      shiporder[ships++]=$1;
      shipname[$1]=name;
      shipown[$1]=coun;
      shiptech[$1]=$NF;
      shipfuel[$1]=$(NF-1);
      shipmob[$1]=$(NF-2);
      shiplnd[$1]=$(NF-3);
      shipxlnd[$1]=$(NF-4);
      shiphel[$1]=$(NF-5);
      shippln[$1]=$(NF-6);
      shipcargo[$1,"food"]=$(NF-7);
      shipcargo[$1,"uw"]=$(NF-8);
      shipcargo[$1,"mil"]=$(NF-9);
      shipcargo[$1,"civ"]=$(NF-10);
      shipeff[$1]=num($(NF-11));
      shipfleet[$1]=substr($0,33,1);
      shipsect[$1]=truncwhite(substr($0,22,9));
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="cargo") {
    if (stat==1) {
      ships=0;
      for (i in shiporder) delete shiporder[i];
      stat=2;
    }
    if (stat==2 && NF > 10) {
      name=truncwhite(substr($0,6,shipnamlen));
      shiporder[ships++]=$1;
      shipname[$1]=name;
      shipown[$1]=coun;
      shipcargo[$1,"rad"]=$NF;
      shipcargo[$1,"hcm"]=$(NF-1);
      shipcargo[$1,"lcm"]=$(NF-2);
      shipcargo[$1,"oil"]=$(NF-3);
      shipcargo[$1,"bar"]=$(NF-4);
      shipcargo[$1,"dust"]=$(NF-5);
      shipcargo[$1,"iron"]=$(NF-6);
      shipcargo[$1,"pet"]=$(NF-7);
      shipcargo[$1,"gun"]=$(NF-8);
      shipcargo[$1,"shell"]=$(NF-9);
      shipeff[$1]=num($(NF-10));
      shipfleet[$1]=substr($0,31,1);
      shipsect[$1]=truncwhite(substr($0,22,9));
      next;
    }
  } else if (mode=="unit") {
    if (stat==1) {
      units=0;
      for (i in unitorder) delete unitorder[i];
      stat=2;
    }
    if (stat==2 && NF > 2) {
      name=truncwhite(substr($0,6,shipnamlen));
      unitorder[units++]=$1;
      unitname[$1]=name;
      unitown[$1]=coun;
      unitsect[$1]=truncwhite(substr($0,25,9));
      unitarmy[$1]=substr($0,34,1);
      uniteff[$1]=substr($0,36,3);
      unitfort[$1]=substr($0,41,4);
      unitmob[$1]=substr($0,46,3);
      unitcargo[$1,"food"]=substr($0,50,4);
      unitfuel[$1]=substr($0,55,4);
      unittech[$1]=substr($0,60,4);
      unitretr[$1]=substr($0,65,3);
      unitrad[$1]=substr($0,70,3);
      unitxpl[$1]=substr($0,74,2);
      unitship[$1]=substr($0,77,4);
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="plane") {
    if (stat==1) {
      planes=0;
      for (i in planeorder) delete planeorder[i];
      stat=2;
    }
    if (stat==2 && NF > 2) {
      name=truncwhite(substr($0,6,20));
      planeorder[planes++]=$1;
      planename[$1]=name;
#      planename[$1]=$2;	
      planeown[$1]=coun;
      planesect[$1]=truncwhite(substr($0,25,9));
      planewing[$1]=substr($0,36,1);
      planeeff[$1]=substr($0,38,3);
      planemob[$1]=substr($0,43,3);
      planeatt[$1]=substr($0,47,3);
      planedef[$1]=substr($0,51,3);
      planetech[$1]=substr($0,55,4);
      planeran[$1]=substr($0,60,3);
      planehard[$1]=substr($0,64,4);
      next;
    } else {
      mode="";
      stat=0;
      next;
    }
  } else if (mode=="lcargo") {
    if (stat==1) {
      units=0;
      for (i in unitorder) delete unitorder[i];
      stat=2;
    }
    if (stat==2 && NF > 2) {
      name=truncwhite(substr($0,6,shipnamlen));
      unitorder[units++]=$1;
      unitname[$1]=name;
      unitown[$1]=coun;
      unitsect[$1]=truncwhite(substr($0,25,9));
      unitarmy[$1]=substr($0,34,1);
      uniteff[$1]=substr($0,36,3);
      unitcargo[$1,"rad"]=num($NF);
      unitcargo[$1,"hcm"]=num($(NF-1));
      unitcargo[$1,"lcm"]=num($(NF-2));
      unitcargo[$1,"oil"]=num($(NF-3));
      unitcargo[$1,"bar"]=num($(NF-4));
      unitcargo[$1,"dust"]=num($(NF-5));
      unitcargo[$1,"iron"]=num($(NF-6));
      unitcargo[$1,"pet"]=num($(NF-7));
      unitcargo[$1,"gun"]=num($(NF-8));
      unitcargo[$1,"shell"]=num($(NF-9));
      next;
    }
  } else if (mode=="report") {
    if (NF>5) {
      name=truncwhite(substr($0,8,14));
      if (!($1 in country)) {
	country[$1]=name;
	number[name]=$1;
      }
      if (coun in tech) {
	if (!($1 in maxtech)) maxtech[$1]=9999;
	rel=truncwhite(substr($0,23,10));
	if (rel=="similar") {
	  maxtech[$1]=min(maxtech[$1],min(tech[coun]*2+1,tech[coun]+50));
	  mintech[$1]=max(mintech[$1],max((tech[coun]-1)/2,tech[coun]-50));
	} else if (rel=="backward") {
	  maxtech[$1]=min(maxtech[$1],max((tech[coun]-1)/2,tech[coun]-50));
	  mintech[$1]=max(mintech[$1],min((tech[coun]-9)/10,tech[coun]-300));
	} else if (rel=="advanced") {
	  maxtech[$1]=min(maxtech[$1],min(tech[coun]*10+9,tech[coun]+300));
	  mintech[$1]=max(mintech[$1],min(tech[coun]*2+1,tech[coun]+50));
	} else if (rel=="primitive") {
	  maxtech[$1]=min(maxtech[$1],max((tech[coun]-9)/10,tech[coun]-300));
	} else if (rel=="superior") {
	  mintech[$1]=max(mintech[$1],min(tech[coun]*10+9,tech[coun]+300));
	}
      }
      if (coun in res) {
	if (!($1 in maxres)) maxres[$1]=9999;
	rel=truncwhite(substr($0,35,10));
	if (rel=="similar") {
	  maxres[$1]=min(maxres[$1],min(res[coun]*2+1,res[coun]+50));
	  minres[$1]=max(minres[$1],max((res[coun]-1)/2,res[coun]-50));
	} else if (rel=="backward") {
	  maxres[$1]=min(maxres[$1],max((res[coun]-1)/2,res[coun]-50));
	  minres[$1]=max(minres[$1],min((res[coun]-9)/10,res[coun]-300));
	} else if (rel=="advanced") {
	  maxres[$1]=min(maxres[$1],min(res[coun]*10+9,res[coun]+300));
	  minres[$1]=max(minres[$1],min(res[coun]*2+1,res[coun]+50));
	} else if (rel=="primitive") {
	  maxres[$1]=min(maxres[$1],max((res[coun]-9)/10,res[coun]-300));
	} else if (rel=="superior") {
	  minres[$1]=max(minres[$1],min(res[coun]*10+9,res[coun]+300));
	}
      }
      if (coun in edu) {
	if (!($1 in maxedu)) maxedu[$1]=9999;
	rel=truncwhite(substr($0,47,10));
	if (rel=="similar") {
	  maxedu[$1]=min(maxedu[$1],min(edu[coun]*2+1,edu[coun]+50));
	  minedu[$1]=max(minedu[$1],max((edu[coun]-1)/2,edu[coun]-50));
	} else if (rel=="backward") {
	  maxedu[$1]=min(maxedu[$1],max((edu[coun]-1)/2,edu[coun]-50));
	  minedu[$1]=max(minedu[$1],min((edu[coun]-9)/10,edu[coun]-300));
	} else if (rel=="advanced") {
	  maxedu[$1]=min(maxedu[$1],min(edu[coun]*10+9,edu[coun]+300));
	  minedu[$1]=max(minedu[$1],min(edu[coun]*2+1,edu[coun]+50));
	} else if (rel=="primitive") {
	  maxedu[$1]=min(maxedu[$1],max((edu[coun]-9)/10,edu[coun]-300));
	} else if (rel=="superior") {
	  minedu[$1]=max(minedu[$1],min(edu[coun]*10+9,edu[coun]+300));
	}
      }
      next;
    } else mode="";
  } else {
    mode="";
    stat=0;
    next;
  }
  
}



# calculate hexes between two sectors
function distance(from,to, a,b,deltax,deltay)
{
  split(from,a,",");
  split(to,b,",");

  deltax=b[1]-a[1];
  if (deltax<0) deltax = -deltax;
  if (deltax>width/2) deltax=width-deltax;
  deltay=b[2]-a[2];
  if (deltay<0) deltay = -deltay;
  if (deltay>height/2) deltay=height-deltay;

  if (deltax>deltay) return ((deltax-deltay)/2+deltay);
  return (deltay);
}

function navigable(sect)
{
  if (!(sect in bdes) || bdes[sect]=="") return 1;
  if (bdes[sect]=="=") {
    if (!((sect,"eff") in val) || val[sect,"eff"]>59) {
      if (own[sect]==coun) return 1;
      if (relation[country[own[sect]],country[coun]]=="Allied") return 1;
    }
    return 0;
  }
  if (bdes[sect]=="h") {
    if (!((sect,"eff") in val) || val[sect,"eff"]>1) {
      if (own[sect]==coun) return 1;
      if (relation[country[own[sect]],country[coun]]=="Allied") return 1;
    }
  }
  return 0;
}

function normsect(x,y)
{
  if (x>=width/2) x -= width;
  if (y>=height/2) y -= height;
  if (x<-width/2) x += width;
  if (y<-height/2) y += height;
  return x "," y ;
}

# build navigation paths
function navbuild(path,navlen, sect,added,x,y,tmp)
{
  if (navlen=="") {
    for (sect in path) if (path[sect]>navlen) navlen=path[sect];
  }

  added=0;
  for (sect in path) if (path[sect]==navlen) {
    split(sect,a,",");
    x=a[1];
    y=a[2];

    tmp= normsect(x+2,y);
    if (!(tmp in path) && navigable(tmp)) { path[tmp]=navlen+1; added++; }
    tmp=normsect(x-2,y);
    if (!(tmp in path) && navigable(tmp)) { path[tmp]=navlen+1; added++; }
    tmp= normsect(x+1,y+1);
    if (!(tmp in path) && navigable(tmp)) { path[tmp]=navlen+1; added++; }
    tmp= normsect(x+1,y-1);
    if (!(tmp in path) && navigable(tmp)) { path[tmp]=navlen+1; added++; }
    tmp= normsect(x-1,y+1);
    if (!(tmp in path) && navigable(tmp)) { path[tmp]=navlen+1; added++; }
    tmp= normsect(x-1,y-1);
    if (!(tmp in path) && navigable(tmp)) { path[tmp]=navlen+1; added++; }
  }

  return added;
}

# returns navigation path.  Optionally pass path array from buildcost.
function navpath(from,to, path,pathlen,x,y,a,b)
{
#  printf("navpath(%s,%s) ",from,to);
  pathlen=0;
  path[to]=0;
  for (sect in path) delete path[sect];
  path[to]=0;
  while ( navbuild(path,pathlen) && !(from in path)) pathlen++;
  if (to in path) {
    sect=from;
    nav="";
    for (i=pathlen;i>=0;i--) {
#      printf(" %s(%s) {",sect,path[sect]);
      split(sect,a,",");
      for (newsect in path) if (path[newsect]==i) {
#	printf(" %s(%s)",newsect,path[newsect]);
	split(newsect,b,",");
	x=b[1]-a[1];
	if (x>2) x -= width;
	if (x<-2) x += width;
	y=b[2]-a[2];
	if (y>2) y -= height;
	if (y<-2) y += height;
	if (x==2 && y==0) { nav=nav "j"; break; }
	else if (x==1 && y==1) { nav=nav "n"; break; }
	else if (x==-1 && y==1) { nav=nav "b"; break; }
	else if (x==-2 && y==0) { nav=nav "g"; break; }
	else if (x==-1 && y==-1) { nav=nav "y"; break; }
	else if (x==1 && y==-1) { nav=nav "u"; break; }
      }
#      printf("}\n");
      if (path[newsect]==i) {
	sect=newsect;
      } else {
	printf("# error from=%s to=%s nav=%s sect=%s pathlen=%s i=%s newsect=%s x=%s y=%s\n",
	       from,to,nav,sect,pathlen,i,newsect,x,y);
	exit 0;
	return "";
      }
    }
  }
  return nav;
}


END {
  for (n in shipname) {
    speed=shipspd[shipname[n]];
    shiprange[n]=int(0.9999 + shipmob[n]*((speed+speed*(50+shiptech[n])/(200+shiptech[n]))*shipeff[n]/100)/480);
  }

  for (sect in own) {
    if (val[sect,"des"]=="h") {
      if (relation[country[own[sect]],country[coun]]=="Allied") {
	allyharbor[sect]=own[sect];
      } else if (own[sect]==coun) {
	harbor[sect]=own[sect];
      }
    }
  }

  for (n in shipname) {
    if (index(capability[shipname[n]],"oiler")) {
      if (shipcargo[n,"oil"]>0 || shipcargo[n,"pet"]>10) {
	oiler[n]=shipsect[n];
      } else {
	printf("# %s #%d in need of fuel at %s\n",shipname[n],n,shipsect[n]);
      }
    }
  }
  

  for (n in shiporig) {
    if (shipcargo[n,"civ"]==0 || shipcargo[n,"food"]==0 || shipfuel[n]<10 || !(n in shipdest1) || shipeta[n]<2) {
      printf("# %s (#%d) at %s needs:",shipname[n],n,shipsect[n]);
      if (shipcargo[n,"civ"]==0) printf(" civs");
      if (shipcargo[n,"food"]==0) printf(" food");
#      if (shipfuel[n]<1.5*shipfu[shipname[n]]*etu/10) printf(" fuel");
      if (shipfuel[n]<10) printf(" fuel");
      if (!(n in shipdest1)) printf(" orders");
      if (shipeta[n]==1) printf(" nav");
      if (shipeff[n]==100 && (n in shipdest1) && shipdest1[n]==shipsect[n]) printf(" scuttled");
      printf("\n");


      if (shipeta[n]==1 && shipeff[n]==100 && (n in shiporig)) {
	printf("nav %d %sh\n\n",n,navpath(shipsect[n],shipdest1[n]));
	scuttle[n]=1;
      }
      
      sect=shipsect[n];
      if (!nofood && shipcargo[n,"food"]==0) {
	if (sect in own) {
	  if (val[sect,"des"]=="h" && own[sect]==coun) {
	    if (val[sect,"food"]>200) {
	      printf("load %d -50 f\n",n);
	      shipcargo[n,"food"]=50;
	      val[sect,"food"] -= 50;
	    }
	  }
	}
      }

      if (shipcargo[n,"civ"]==0 && (nofood || shipcargo[n,"food"]>0)) {
	if (sect in own) {
	  if (val[sect,"des"]=="h" && own[sect]==coun) {
	    if (val[sect,"civ"]>100) {
	      printf("load %d -50 c\n",n);
	      shipcargo[n,"civ"]=50;
	      val[sect,"civ"] -= 50;
	    }
	  }
	}
      }

      if (!(n in shipdest1)) {
	if (shipcargo[n,"civ"]>0 && shipeff[n]==100 && shipmob[n]>0 && shipfuel[n]>0) {
	  best="";
	  for (i in allyharbor) {
	    if (!best || distance(shiporig[n],best) < distance(shiporig[n],i)) {
	      best=i;
	    }
	  }
	  if (best) {
	    printf("fleet T %d\n",n);
	    printf("order %d d %s\n\n",n,best); 
	    printf("nav %d %sh\n\n",n,navpath(shipsect[n],best));
	    shipdest1[n]=best;
	  } else {
	    printf("# unable to find destination for %s #%d\n",shipname[n],n);
	  }
	}
      }
    

# fuel ships in harbor
      if (shipfuel[n]<10) {
	if ((shipsect[n] in harbor) && val[shipsect[n],"oil"]>1) {
	  printf("fuel s %d 50\n",n);
	  shipfuel[n]=min(shipfc[shipname[n]],shipfuel[n]+50);
	}
      }


# fuel ships in sector with oilers
      if (shipfuel[n]<10) {
	for (o in oiler) {
	  if (shipsect[n]==shipsect[o]) break;
	}
	if (shipsect[n]==shipsect[o]) {
	  printf("fuel s %d 50\n%d\n",n,o);
	  shipfuel[n]=min(shipfc[shipname[n]],shipfuel[n]+50);
	  shipcargo[o,"oil"]--;
	  continue;
	}
      }

      
#	fill path[] with sectors-to-go along the path to the destsect
      if (shipfuel[n]<10) {
	for (sect in path) delete path[sect];
	for (sect in fpath) delete fpath[sect];
	path[shipdest1[n]]=0;
	fpath[shipsect[n]]=0;
	pathlen=fpathlen=0;
	while (navbuild(path,pathlen++) && !(shipsect[n] in path)) ;
	while (fpathlen<shiprange[n] && navbuild(fpath,fpathlen++)) ;
	for (sect in path) {
	  if (!(sect in fpath)) delete path[sect];
	  else if (path[sect]+fpath[sect]>pathlen) delete path[sect];
	}
	
	if (shipsect[n] in path) {

	  printf("# look for a harbor along the path\n");
	  fuelsect="";
	  for (sect in harbor) {
	    if ((sect in path) &&
		shiprange[n]>=(path[shipsect[n]]-path[sect])) {
	      fuelsect=sect;
	      break;
	    }
	  }
	  if (!fuelsect) {

	    printf("# look for an oiler along the path\n");
	    for (o in oiler) {
	      if ((shipsect[o] in path) &&
		  shiprange[n]>=(path[shipsect[n]]-path[shipsect[o]])) {
		fuelsect=shipsect[o];
		break;
	      }
	    }
	  }
	  if (fuelsect) {
	    if (fuelsect!=shipsect[n]) {
	      printf("nav %d %sh\n\n",n,navpath(shipsect[n],fuelsect));
	      shipsect[n]=fuelsect;
	      shiprange[n]-=path[n];
	    }
	    printf("fuel s %d 50\n",n);
	    shipfuel[n]=min(shipfc[shipname[n]],shipfuel[n]+50);
	    if (!(fuelsect in harbor)) {
	      printf("%d\n",o);
	      shipcargo[o,"oil"]--;
	    } else {
	      val[fuelsect,"oil"]--;
	    }
	  }
	}
      }
    }
  }


  printf("# send trade ships and oilers to common points\n");
  for (n in shiporig) {
    if (shipfuel[n]<10 && shipfu[shipname[n]]>0) {
      
#	build path[] that ship n can reach (towards destination)
      for (sect in path) delete path[sect];
      for (sect in fpath) delete fpath[sect];
      path[shipdest1[n]]=0;
      fpath[shipsect[n]]=0;
      pathlen=fpathlen=0;
      while (navbuild(path,pathlen++) && !(shipsect[n] in path)) ;
      while (fpathlen<shiprange[n] && navbuild(fpath,fpathlen++)) ;
      for (sect in path) {
	if (!(sect in fpath)) delete path[sect];
	else if (path[sect]+fpath[sect]>pathlen) delete path[sect];
      }


# find an oiler that can reach a point along the path
      fuelsect="";
      for (o in oiler) if (shipcargo[o,"oil"]>0) {
	sect=shipsect[o];
	if (distance(sect,shipsect[n]) <= shiprange[n]+shiprange[o]) {
	  for (i in opath) delete opath[i];
	  opath[sect]=0;
	  opathlen=0;
	  while (opathlen<shiprange[o] && navbuild(opath,opathlen++)) ;
	  for (osect in opath) {
	    if (osect in path) {
	      if (!fuelsect || opath[osect]<opath[fuelsect]) {
		fuelsect=osect;
	      }
	    }
	  }
	  if (fuelsect) {
	    shiprange[o] -= opath[fuelsect];
	    if (shipsect[o]!=fuelsect) {
	      printf("nav %d %sh\n\n",o, navpath(sect,fuelsect));
	      shipsect[o] = fuelsect;
	    }
	    if (shipsect[n]!=fuelsect) {
	      printf("nav %d %sh\n\n",n,navpath(shipsect[n],fuelsect));
	      shipsect[n]=fuelsect;
	      shiprange[n]-=path[fuelsect];
	    }
	    printf("fuel s %d 50\n%d\n",n,o);
	    shipcargo[o,"oil"]--;
	    break;
	  }		
	}
      }
    }
  }

  printf("# send oilers towards thirsty trade ships\n");
  for (n in shiporig) {
    if (shipfuel[n]<10 && shipfu[shipname[n]]>0 && !(n in scuttle)) {
      best="";
      for (o in oiler) if (shiprange[o]>0 && shipcargo[o,"oil"]>0) {
	if (!best || distance(shipsect[o],shipsect[n])-shiprange[o]<distance(shipsect[best],shipsect[n])-shiprange[best]) {
	  best=o;
	}
      }
      if (best) {
	printf("# send tanker #%d towards %s\n",best,shipsect[n]);
	if (shipsect[n]!=shipsect[best]) {
	  printf("# nav %d %sh\n\n",best,
		 navpath(shipsect[best],shipsect[n]));
	} else {
	  printf("fuel %d 50\n%d\n",n,best);
	}
	shiprange[best]=0;
	shipsect[best]="";
      } else {
	printf("# no fuel along ship #%d's path\n",n);
      }
    }
  }

# refuel oilers
  for (n in oiler) {
    printf("# %s #%d at %s\n",shipname[n],n,sect);
    if (shipfuel[n]<10) printf("fuel s %d 50\n%d\n",n,n);
  }

# send empty oilers towards harbors
  for (n in oiler) {
    if (shipcargo[n,"oil"]<20) {
      printf("# %s #%d at %s has %d oil left\n",shipname[n],n,shipsect[n],shipcargo[n,"oil"]);
    }
  }


  for (sect in allyharbor) {
    printf("scuttle ship %s ?\"type=trade ship 2&eff=100\"\ny\n\n",sect);
  }


  if (build) {
    for (n in shipname) {
      bcost=100-shipeff[n];
      lcm = bcost*shiplcm[shipname[n]]/100;
      hcm = bcost*shiphcm[shipname[n]]/100;
      sect=shipsect[n];
      bcost *= (20+shiplcm[shipname[n]]+2*shiphcm[shipname[n]]) / 100;
      if (((sect,"des") in val) && val[sect,"des"]=="h") {
	val[sect,"avail"] -= bcost;
	val[sect,"lcm"] -= lcm;
	val[sect,"hcm"] -= hcm;
      }
    }

    tship="trade ship 2";
    lcm=shiplcm[tship];
    hcm=shiphcm[tship];
    avail=shipavail[tship]+(lcm+2*hcm)*80/100;
    for (sect in harbor) {
      while (val[sect,"avail"]>=shipavail[tship] && val[sect,"hcm"]*5>=hcm && val[sect,"lcm"]*5>=lcm && budget>10000) {

	budget -= shipcost[tship];
	val[sect,"avail"]-=avail;
	val[sect,"lcm"]-=lcm;
	val[sect,"hcm"]-=hcm;
	printf("build ship %s \"%s\" %d\n",sect,tship,tech[coun]);
      }
    }
  }
}
