/********************************************************************** 
 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/
#include <stdio.h>
#include <string.h>
#include <aitools.h>
#include <game.h>
#include <map.h>
#include <unitfunc.h>
#include <citytools.h>
#include <aicity.h>
#include <aiunit.h>
#include <unittools.h> /* for get_defender, amazingly */
#include <gotohand.h> /* warmap has been redeployed */
#include <settlers.h>
#include <cityturn.h>

extern struct move_cost_map warmap;

/********************************************************************** 
... this function should assign a value to choice and want, where 
    want is a value between 1 and 100.
    if choice is A_NONE this advisor doesn't want any tech researched at
    the moment
***********************************************************************/

void military_advisor_choose_tech(struct player *pplayer,
				  struct ai_choice *choice)
{
  choice->choice = A_NONE;
  choice->want   = 0;
  /* this function haven't been implemented yet */
}

int assess_defense_quadratic(struct city *pcity)
{ /* Need positive feedback in m_a_c_b and bodyguard routines. -- Syela */
  int v, def, l;
  int igwall = 0; /* this can be an arg if needed, but seems unneeded */
  def = 0;
  for (l = 0; l * l < pcity->ai.wallvalue * 10; l++) ;
/* wallvalue = 10, l = 10, wallvalue = 40, l = 20, wallvalue = 90, l = 30 */
  unit_list_iterate(map_get_tile(pcity->x, pcity->y)->units, punit)
    v = get_defense_power(punit) * punit->hp *
        (is_sailing_unit(punit) ? 1 : get_unit_type(punit->type)->firepower);
    v /= (is_ground_unit(punit) ? 20 : 30);
    if (!igwall && city_got_citywalls(pcity) && is_ground_unit(punit)) {
      v *= l; v /= 10;
    }
    if (is_military_unit(punit)) def += v;
  unit_list_iterate_end;
  if (def > 1<<12) printf("Very large def in assess_defense_quadratic: %d in %s\n",
    def, pcity->name);
  if (def > 1<<15) def = 1<<15; /* more defense than we know what to do with! */
  return(def * def);
}

int assess_defense_unit(struct city *pcity, struct unit *punit, int igwall)
{ /* one unit only, mostly for findjob; handling boats correctly 980803 -- Syela */
  int v;
  v = get_defense_power(punit) * punit->hp *
      (is_sailing_unit(punit) ? 1 : get_unit_type(punit->type)->firepower);
  v /= (is_ground_unit(punit) ? 20 : 30);
  v *= v;
  if (!igwall && city_got_citywalls(pcity) && is_ground_unit(punit)) {
    v *= pcity->ai.wallvalue; v /= 10;
  }
  if (is_military_unit(punit)) return(v);
  return(0);
}

int assess_defense_backend(struct city *pcity, int igwall)
{ /* Most of the time we don't need/want positive feedback. -- Syela */
  int def;
  def = 0;
  unit_list_iterate(map_get_tile(pcity->x, pcity->y)->units, punit)
    def += assess_defense_unit(pcity, punit, igwall);
  unit_list_iterate_end;
  /* def is an estimate of our total defensive might */
  /* now with regard to the IGWALL nature of the units threatening us -- Syela */
  return(def);
/* unclear whether this should treat settlers/caravans as defense -- Syela */
}

int assess_defense(struct city *pcity)
{
  return(assess_defense_backend(pcity, 0));
}

int assess_defense_igwall(struct city *pcity)
{
  return(assess_defense_backend(pcity, 1));
}

int dangerfunct(int v, int m, int dist)
{
#ifdef OLDCODE
  if (dist * dist < m * 3) { v *= m; v /= 3; } /* knights can't attack more than twice */
  else { v *= m * m; v /= dist * dist; }
  return(v);
#else
  int num, denom;
  num = m * 4; denom = m * 4;
  v *= 2;
  while (dist >= m) {
    v /= 2;
    dist -= m;
  }
  m /= 3;
  while (dist && dist >= m) {
    num *= 4;
    denom *= 5;
    dist -= m;
  }
  while (dist) {
    denom += (denom + m * 2) / (m * 4);
    dist--;
  }
  v = (v*num + (denom>>1)) / denom;
  return(v);
#endif
}

int assess_danger(struct city *pcity)
{
  int i, danger = 0, v, dist, con, m;
  int danger2 = 0; /* linear for walls */
  int danger3 = 0; /* linear for coastal */
  int danger4 = 0; /* linear for SAM */
  int danger5 = 0; /* linear for SDI */
  struct player *aplayer, *pplayer;
  int pikemen = 0;
  int urgency = 0;
  int igwall;
  int badmojo = 0;
  int boatspeed;
  int boatid, boatdist;
  int x = pcity->x, y = pcity->y; /* dummy variables */

  pplayer = &game.players[pcity->owner];
  con = map_get_continent(pcity->x, pcity->y); /* Not using because of boats */

  generate_warmap(pcity, 0); /* generates both land and sea maps */

  pcity->ai.grave_danger = 0;

  unit_list_iterate(map_get_tile(pcity->x, pcity->y)->units, punit)
    if (unit_flag(punit->type, F_PIKEMEN)) pikemen++;
  unit_list_iterate_end;

  for(i=0; i<game.nplayers; i++) {
    if (i != pcity->owner) {
      aplayer = &game.players[i];
      boatspeed = (get_invention(aplayer, A_NAVIGATION) == TECH_KNOWN ? 12 : 6);
      boatid = find_boat(aplayer, &x, &y, 0);
      if (boatid) boatdist = warmap.seacost[x][y];
      else boatdist = -1;
/* should I treat empty enemy cities as danger? */
      unit_list_iterate(aplayer->units, punit)
        igwall = 0;
        v = get_unit_type(punit->type)->attack_strength * 10;
        if (punit->veteran) v *= 1.5;
        if (unit_flag(punit->type, F_SUBMARINE)) v = 0;
        if (is_sailing_unit(punit) && !is_terrain_near_tile(pcity->x, pcity->y, T_OCEAN)) v = 0;
/* get_attack_power will be wrong if moves_left == 1 || == 2 */
        v *= punit->hp * get_unit_type(punit->type)->firepower;
        if (unit_ignores_citywalls(punit) || 
            (!is_heli_unit(punit) && !is_ground_unit(punit))) igwall++;
        if (city_got_building(pcity, B_COASTAL) && is_sailing_unit(punit)) v >>= 1;
        if (city_got_building(pcity, B_SAM) && is_air_unit(punit)) v >>= 1;

        if (is_tiles_adjacent(punit->x, punit->y, pcity->x, pcity->y)) dist = 3;
        else if (is_sailing_unit(punit)) dist = warmap.seacost[punit->x][punit->y];
        else if (!is_ground_unit(punit))
          dist = real_map_distance(punit->x, punit->y, pcity->x, pcity->y) * 3;
        else if (unit_flag(punit->type, F_IGTER))
          dist = real_map_distance(punit->x, punit->y, pcity->x, pcity->y);
        else dist = warmap.cost[punit->x][punit->y];
          
        m = get_unit_type(punit->type)->move_rate;
/* if dist = 9, a chariot is 1.5 turns away.  NOT 2 turns away. */
/* Samarkand bug should be obsoleted by re-ordering of events */
        if (dist < 3) dist = 3;
        if ((is_ground_unit(punit) && v) ||
           (get_transporter_capacity(punit) &&
            !unit_flag(punit->type, F_SUBMARINE) &&
            !unit_flag(punit->type, F_CARRIER))) {
          if (dist <= m * 3) urgency++;
          if (dist <= m) pcity->ai.grave_danger++;
/* NOTE: This should actually implement grave_danger, which is supposed
to be a feedback-sensitive formula for immediate danger.  I'm having
second thoughts about the best implementation, and therefore this
will have to wait until after 1.7.0.  I don't want to do anything I'm
not totally sure about and can't thoroughly test in the hours before
the release.  The AI is in fact vulnerable to gang-attacks, but I'm
content to let it remain that way for now. -- Syela 980805 */
        }

        if (is_ground_unit(punit) && boatid &&
            find_beachhead(punit, pcity->x, pcity->y, &x, &y)) {
/* this bug is so obvious I can't believe it wasn't discovered sooner. -- Syela */
          y = warmap.seacost[punit->x][punit->y];
          if (y >= 6 * THRESHOLD)
            y = real_map_distance(pcity->x, pcity->y, punit->x, punit->y) * 3;
          x = MAX(y, boatdist) * m / boatspeed;
          if (dist > x) dist = x;
          if (dist < 3) dist = 3;
        }

        v /= 30; /* rescaling factor to stop the overflow nonsense */

        if (unit_flag(punit->type, F_HORSE)) {
          if (pikemen) v >>= 1;
          else if (get_invention(pplayer, A_FEUDALISM) != TECH_KNOWN)
            pplayer->ai.tech_want[A_FEUDALISM] += v * m / (dist<<1);
        }

        v *= v;

        if (!igwall) danger2 += v * m / dist;
        else if (is_sailing_unit(punit)) danger3 += v * m / dist;
        else if (is_air_unit(punit) && punit->type != U_NUCLEAR) danger4 += v * m / dist;
        if (unit_flag(punit->type, F_MISSILE)) danger5 += v * m / MAX(m, dist);
        if (punit->type != U_NUCLEAR) { /* only SDI helps against NUCLEAR */
          v = dangerfunct(v, m, dist);
          danger += v;
          if (igwall) badmojo += v;
        }

/* if (v > 1000 || (v > 100 && !city_got_citywalls(pcity)))
printf("%s sees %d danger from %s at (%d, %d) [%d]\n", pcity->name, v,
unit_types[punit->type].name, punit->x, punit->y, dist);  */
      unit_list_iterate_end;
    }
  } /* end for */

  if (!badmojo) pcity->ai.wallvalue = 90;
  else pcity->ai.wallvalue = (danger * 9 - badmojo * 8) * 10 / (danger);
/* afraid *100 would create integer overflow, but *10 surely won't */

  if (danger < 0 || danger > 1<<24) /* I hope never to see this! */
    printf("Dangerous danger (%d) in %s.  Beware of overflow.\n", danger, pcity->name);
  if (danger2 < 0 || danger2 > 1<<24) /* I hope never to see this! */
    printf("Dangerous danger2 (%d) in %s.  Beware of overflow.\n", danger2, pcity->name);
  if (danger3 < 0 || danger3 > 1<<24) /* I hope never to see this! */
    printf("Dangerous danger3 (%d) in %s.  Beware of overflow.\n", danger3, pcity->name);
  if (danger4 < 0 || danger4 > 1<<24) /* I hope never to see this! */
    printf("Dangerous danger4 (%d) in %s.  Beware of overflow.\n", danger4, pcity->name);
  if (danger5 < 0 || danger5 > 1<<24) /* I hope never to see this! */
    printf("Dangerous danger5 (%d) in %s.  Beware of overflow.\n", danger5, pcity->name);
  if (pcity->ai.grave_danger) urgency += 10; /* really, REALLY urgent to defend */
  pcity->ai.danger = danger;
  if (pcity->ai.building_want[B_CITY] > 0 && danger2) {
    i = assess_defense(pcity);
    if (!i) pcity->ai.building_want[B_CITY] = 100 + urgency;
    else if (danger2 > i + (i>>1)) pcity->ai.building_want[B_CITY] = 200 + urgency;
    else pcity->ai.building_want[B_CITY] += danger2 * 100 / i;
  }
/* My first attempt to allow ng_wa >= 200 led to stupidity in cities with
no defenders and danger = 0 but danger > 0.  Capping ng_wa at 100 + urgency
led to a failure to buy walls as required.  This is the latest attempt,
which seems to work acceptably. -- Syela */
  if (pcity->ai.building_want[B_COASTAL] > 0 && danger3) {
    i = assess_defense_igwall(pcity);
    if (!i) pcity->ai.building_want[B_COASTAL] = 100 + urgency;
    else if (danger3 > i + (i>>1)) pcity->ai.building_want[B_COASTAL] = 200 + urgency;
    else pcity->ai.building_want[B_COASTAL] += danger3 * 100 / i;
  }
/* COASTAL and SAM are TOTALLY UNTESTED and could be VERY WRONG -- Syela */
/* update 980803; COASTAL seems to work; still don't know about SAM. -- Syela */
  if (pcity->ai.building_want[B_SAM] > 0 && danger4) {
    i = assess_defense_igwall(pcity);
    if (!i) pcity->ai.building_want[B_SAM] = 100 + urgency;
    else if (danger4 > i + (i>>1)) pcity->ai.building_want[B_SAM] = 200 + urgency;
    else pcity->ai.building_want[B_SAM] += danger4 * 100 / i;
  }
  if (pcity->ai.building_want[B_SDI] > 0 && danger5) {
    i = assess_defense_igwall(pcity);
    if (!i) pcity->ai.building_want[B_SDI] = 100 + urgency;
    else if (danger5 > i + (i>>1)) pcity->ai.building_want[B_SDI] = 200 + urgency;
    else pcity->ai.building_want[B_SDI] += danger5 * 100 / i;
  }
  pcity->ai.urgency = urgency; /* need to cache this for bodyguards now -- Syela */
  return(urgency);
}

int unit_desirability(int i, int def)
{
  int cur, a, d;   
  cur = get_unit_type(i)->hp;
  if (unit_types[i].move_type != SEA_MOVING || !def)
    cur *= get_unit_type(i)->firepower;
  if (def) cur *= 3;
  else cur *= get_unit_type(i)->move_rate;
  a = get_unit_type(i)->attack_strength;
  d = get_unit_type(i)->defense_strength;
  if (def) cur *= d;
  else if (d > a) return(0);
  else if (d < 2) cur = (cur * (a + d))>>1;
  else cur *= a; /* wanted to rank Legion > Catapult > Archer */
  if (unit_flag(i, F_IGTER) && !def) cur *= 3;
  if (unit_flag(i, F_PIKEMEN) && def) cur *= 1.5;
  if (unit_types[i].move_type == LAND_MOVING && def) cur *= 1.5;
  return(cur);  
}

void process_defender_want(struct player *pplayer, struct city *pcity, int danger,
                           struct ai_choice *choice)
{
  int i, j, k, l, m, n;
  int best= 0;
  int bestid = 0;
  int walls = city_got_citywalls(pcity);
  int desire[U_LAST]; /* what you get is what you seek */
  int shore = is_terrain_near_tile(pcity->x, pcity->y, T_OCEAN);
  int isdef = has_a_normal_defender(pcity);

  memset(desire, 0, sizeof(desire));
  for (i = U_WARRIORS; i <= U_BATTLESHIP; i++) {
    m = unit_types[i].move_type;
    if ((m == LAND_MOVING || m == SEA_MOVING)) {
      k = pplayer->ai.tech_turns[unit_types[i].tech_requirement];
      j = unit_desirability(i, 1);
      if (!isdef && unit_flag(i, F_FIELDUNIT)) j = 0;
      j /= 15; /* good enough, no rounding errors */
      j *= j;
      if (can_build_unit(pcity, i)) {
        if (walls && m == LAND_MOVING) { j *= pcity->ai.wallvalue; j /= 10; }
        if (j > best || (j == best && get_unit_type(i)->build_cost <=
                               get_unit_type(bestid)->build_cost)) {
          best = j;
          bestid = i;
        }
      } else if (k > 0 && (shore || m == LAND_MOVING) &&
                unit_types[i].tech_requirement != A_LAST) {
        if (m == LAND_MOVING) { j *= pcity->ai.wallvalue; j /= 10; }
        l = k * (k + pplayer->research.researchpoints) * game.techlevel /
         (game.year > 0 ? 2 : 4); /* cost (shield equiv) of gaining these techs */
        l /= city_list_size(&pplayer->cities);
/* Katvrr advises that with danger high, l should be weighted more heavily */
        desire[i] = j * danger / (unit_types[i].build_cost + l);
      }
    }
  }
  if (!walls && unit_types[bestid].move_type == LAND_MOVING) {
    best *= pcity->ai.wallvalue;
    best /= 10;
  } /* was getting four-figure desire for battleships otherwise. -- Syela */
/* Phalanx would be 16 * danger / 20.  Pikemen would be 36 * danger / (20 + l) */
/* multiply by unit_types[bestid].build_cost / best */
  for (i = U_WARRIORS; i <= U_BATTLESHIP; i++) {
    if (desire[i]) {
      j = unit_types[i].tech_requirement;
      n = desire[i] * unit_types[bestid].build_cost / best;
      pplayer->ai.tech_want[j] += n; /* not the totally idiotic
      pplayer->ai.tech_want[j] += n * pplayer->ai.tech_turns[j];  I amaze myself. -- Syela */
/*      printf("%s wants %s for defense with desire %d <%d>\n",
pcity->name, advances[j].name, n, desire[i]); */
    }
  }
  choice->choice = bestid;
  choice->want = danger;
  choice->type = 3;
  return;
}

void process_attacker_want(struct player *pplayer, struct city *pcity, int b, int n,
                            int vet, int x, int y, int unhap, int movetype, 
                            int bx, int by, int boatspeed)
{ /* I am beginning to wonder whether this should be its own function! -- Syela */
/* n is type of defender, vet is vet status, x,y is location of target */
  int a, c, d, e, i, a0, b0, f;
  int j, k, l, m;
  int shore = is_terrain_near_tile(pcity->x, pcity->y, T_OCEAN);
  struct city *acity = map_get_city(x, y);

  for (i = U_WARRIORS; i <= U_BATTLESHIP; i++) {
    m = unit_types[i].move_type;
    j = unit_types[i].tech_requirement;
    if (j != A_LAST) k = pplayer->ai.tech_turns[j];
    else k = 0; /* stupid -Wall -Werror -- Syela */
    if ((m == LAND_MOVING || (m == SEA_MOVING && shore)) && j != A_LAST && k &&
         unit_types[i].attack_strength && /* otherwise we get SIGFPE's */
         m == movetype) { /* I don't think I want the duplication otherwise -- Syela */
      l = k * (k + pplayer->research.researchpoints) * game.techlevel;
      if (game.year > 0) l >>= 1;
      else l >>= 2; /* cost (shield equiv) of gaining these techs */
      l /= city_list_size(&pplayer->cities);
/* Katvrr advises that with danger high, l should be weighted more heavily */

      a = unit_types[i].attack_strength * (do_make_unit_veteran(pcity, i) ? 15 : 10) *
             unit_types[i].firepower * unit_types[i].hp;
      a /= 30; /* scaling factor to prevent integer overflows */
      if (acity) a += acity->ai.a;
      a *= a;
      /* b is unchanged */

      m = unit_types[i].move_rate;
      if (get_unit_type(i)->flags & F_IGTER) m *= 3; /* not quite right */
      if (unit_types[i].move_type == LAND_MOVING) {
        if (boatspeed) {
          c = (warmap.cost[bx][by] + m - 1) / m + 1 +
                warmap.seacost[x][y] / boatspeed; /* kluge */
        } else c = (warmap.cost[x][y] + m - 1) / m;
      } else if (unit_types[i].move_type == SEA_MOVING)
        c = (warmap.seacost[x][y] + m - 1) / m;
      else c = real_map_distance(pcity->x, pcity->y, x, y) * 3 / m;

      m = get_virtual_defense_power(i, n, x, y);
      m *= unit_types[n].hp * unit_types[n].firepower;
      m /= (vet ? 20 : 30);
      m *= m;
      d = m;

      f = unit_types[i].build_cost;
      if (unit_types[i].move_type != LAND_MOVING && !d) b0 = 0;
      else b0 = (b * a - (f + (acity ? acity->ai.f : 0)) * d) * SHIELD_WEIGHTING / (a + d);
      if (acity && acity->ai.a)
        b0 -= (b * acity->ai.a * acity->ai.a - acity->ai.f * d) *
                              SHIELD_WEIGHTING / (acity->ai.a * acity->ai.a + d);
      if (b0 > 0) {
        b0 -= l * SHIELD_WEIGHTING;
        b0 -= c * (unhap ? SHIELD_WEIGHTING + 2 * TRADE_WEIGHTING : SHIELD_WEIGHTING);
      }
      if (b0 > 0) {
        a0 = amortize(b0, MAX(1, c));
        e = ((a0 * b0) / (MAX(1, b0 - a0))) * 100 / (f * MORT);
      } else e = 0;  
      if (e > 0) {
        pplayer->ai.tech_want[j] += e;
/*      printf("%s wants %s for attack with desire %d\n",
pcity->name, advances[j].name, e); */
      }
    }
  }
}

void kill_something_with(struct player *pplayer, struct city *pcity, 
                         struct unit *myunit, struct ai_choice *choice)
{
  int a, b, c, d, e; /* variables in the attacker-want equation */
  int m, n, vet, dist, v, a0, b0;
  int x, y, unhap = 0;
  struct unit *pdef, *aunit, *ferryboat;
  struct city *acity;
  int f, boatid = 0, harborcity = 0, bx, by;
  int needferry = 0, fstk, boatspeed;

  if (pcity->ai.danger && !assess_defense(pcity)) return;

  if (is_ground_unit(myunit)) boatid = find_boat(pplayer, &bx, &by, 2);
  if (is_ground_unit(myunit) && !myunit->id &&
      is_terrain_near_tile(myunit->x, myunit->y, T_OCEAN))
    harborcity++;

  ferryboat = unit_list_find(&pplayer->units, boatid);
  if (ferryboat) boatspeed = (ferryboat->type == U_TRIREME ? 6 : 12);
  else boatspeed = (get_invention(pplayer, A_NAVIGATION) != TECH_KNOWN ? 6 : 12);

  fstk = find_something_to_kill(pplayer, myunit, &x, &y);

  acity = map_get_city(x, y);
  if (!acity) aunit = get_defender(pplayer, myunit, x, y);
  else aunit = 0;
  if (acity && acity->owner == pplayer->player_no) acity = 0;

/* this code block and the analogous block in f_s_t_k should be calls
to the same utility function, but I don't want to break anything right
before the 1.7.0 release so I'm letting this stay ugly. -- Syela */

/* logically we should adjust this for race attack tendencies */
  if ((acity || aunit)) {
    v = myunit->type;
    vet = myunit->veteran;

    a = unit_types[v].attack_strength * (vet ? 15 : 10) *
             unit_types[v].firepower * unit_types[v].hp;
    a /= 30; /* scaling factor to prevent integer overflows */
    if (acity) a += acity->ai.a;
    a *= a;

    if (acity) {
      pdef = get_defender(pplayer, myunit, x, y);

      m = unit_types[v].move_rate;
      if (get_unit_type(v)->flags & F_IGTER) m *= 3; /* not quite right */

      if (is_ground_unit(myunit)) {
        if (!goto_is_sane(pplayer, myunit, acity->x, acity->y, 1)) {
          if (boatid) c = (warmap.cost[bx][by] + m - 1) / m + 1 +
                warmap.seacost[acity->x][acity->y] / boatspeed; /* kluge */
          else c = warmap.seacost[acity->x][acity->y] / boatspeed + 1;
/*printf("%s attempting to attack via ferryboat (boatid = %d, c = %d)\n",
unit_types[v].name, boatid, c);*/
        } else c = (warmap.cost[acity->x][acity->y] + m - 1) / m;
      } else if (is_sailing_unit(myunit))
        c = (warmap.seacost[acity->x][acity->y] + m - 1) / m;
      else c = real_map_distance(myunit->x, myunit->y, acity->x, acity->y) * 3 / m;

      n = ai_choose_defender_versus(acity, v);
      m = get_virtual_defense_power(v, n, x, y);
      m *= unit_types[n].hp * unit_types[n].firepower;
      m /= (do_make_unit_veteran(acity, n) ? 20 : 30);
      if (c > 1) {
        d = m * m;
        b = unit_types[n].build_cost + 40;
        vet = do_make_unit_veteran(acity, n);
      } else {
        d = 0;
        b = 40;
        vet = 0;
      }
      if (pdef) {
        n = pdef->type;
        m = get_virtual_defense_power(v, n, x, y);
        m *= unit_types[n].hp * unit_types[n].firepower;
        m /= (pdef->veteran ? 20 : 30);
        if (d < m * m) {
          d = m * m;
          b = unit_types[pdef->type].build_cost + 40; 
          vet = pdef->veteran;
        }
      }
    } /* end dealing with cities */

    else {
      m = 0;
      pdef = aunit; /* we KNOW this is the get_defender -- Syela */

      m = unit_types[pdef->type].build_cost;
      b = m;

      if (is_ground_unit(myunit)) dist = warmap.cost[x][y];
      else if (is_sailing_unit(myunit)) dist = warmap.seacost[x][y];
      else dist = real_map_distance(pcity->x, pcity->y, x, y) * 3;
      dist *= unit_types[pdef->type].move_rate;
      if (unit_flag(pdef->type, F_IGTER)) dist *= 3;
      if (!dist) dist = 1;

      m = unit_types[v].move_rate;
      if (get_unit_type(v)->flags & F_IGTER) m *= 3; /* not quite right */
      c = ((dist + m - 1) / m);

      n = pdef->type;
      m = get_virtual_defense_power(v, n, x, y);
      m *= unit_types[n].hp * unit_types[n].firepower;
      m /= (pdef->veteran ? 20 : 30);
      m *= m;
      d = m;
      vet = pdef->veteran;
    } /* end dealing with units */

    if (get_government(pplayer->player_no) == G_REPUBLIC) {
      unit_list_iterate(pcity->units_supported, punit)
        if (unit_being_aggressive(punit)) {
          unhap++;
        } else if (is_field_unit(punit)) {
          unhap++;
        }
      unit_list_iterate_end;
      if (city_affected_by_wonder(pcity, B_WOMENS) ||
          city_got_building(pcity, B_POLICE)) unhap--;
    } /* handle other governments later */

    if (is_ground_unit(myunit) && !goto_is_sane(pplayer, myunit, x, y, 1) && !boatid)
      needferry = 40; /* cost of ferry */
    f = unit_types[v].build_cost;
    if (unit_types[v].move_type != LAND_MOVING && !d) b0 = 0;
    else if (c > THRESHOLD) b0 = 0;
    else b0 = (b * a - (f + (acity ? acity->ai.f : 0)) * d) * SHIELD_WEIGHTING / (a + d);
    if (acity && acity->ai.a)
      b0 -= (b * acity->ai.a * acity->ai.a - acity->ai.f * d) *
                            SHIELD_WEIGHTING / (acity->ai.a * acity->ai.a + d);
    if (b0 > 0)
      b0 -= c * (unhap ? SHIELD_WEIGHTING + 2 * TRADE_WEIGHTING : SHIELD_WEIGHTING);
    if (b0 > 0) {
      a0 = amortize(b0, MAX(1, c));
      e = ((a0 * b0) / (MAX(1, b0 - a0))) * 100 / ((f + needferry) * MORT);
    } else e = 0;  

    if (goto_is_sane(pplayer, myunit, x, y, 1))
      process_attacker_want(pplayer, pcity, b, n, vet, x, y, unhap,
         unit_types[v].move_type, 0, 0, 0);
    else if (boatid) process_attacker_want(pplayer, pcity, b, n, vet, x, y, unhap,
         unit_types[v].move_type, bx, by, boatspeed);
    else process_attacker_want(pplayer, pcity, b, n, vet, x, y, unhap,
         unit_types[v].move_type, myunit->x, myunit->y, boatspeed);

/*if (acity) {
printf("%s (%d, %d), %s -> %s (%d, %d) [A=%d, B=%d, C=%d, D=%d, E=%d/%d, F=%d]\n", 
pcity->name, pcity->x, pcity->y, unit_types[v].name, acity->name, acity->x, acity->y, a, b, c, d, e, fstk, f);
} else if (aunit) {
printf("%s (%d, %d), %s -> %s (%d, %d) [A=%d, B=%d, C=%d, D=%d, E=%d/%d, F=%d]\n", 
pcity->name, pcity->x, pcity->y, unit_types[v].name, unit_types[pdef->type].name, pdef->x, pdef->y,
a, b, c, d, e, fstk, f);
}*/
    if (e > choice->want) {
      if (get_invention(pplayer, A_GUNPOWDER) == TECH_KNOWN &&
          !city_got_barracks(pcity) && is_ground_unit(myunit)) {
        if (get_invention(pplayer, A_COMBUSTION) == TECH_KNOWN)
          choice->choice = B_BARRACKS3;
        else choice->choice = B_BARRACKS2;
        choice->want = e;
        choice->type = 0;
      } else {
        if (!myunit->id) {
          choice->choice = v;
          choice->type = 2; /* type == 2 identifies attackers */
          choice->want = e;
          if (needferry) ai_choose_ferryboat(pplayer, pcity, choice);
/*printf("%s has chosen attacker, %s\n", pcity->name, unit_types[choice->choice].name);*/
        } else {
          choice->choice = ai_choose_defender(pcity);
/*printf("%s has chosen defender, %s\n", pcity->name, unit_types[choice->choice].name);*/
          choice->type = 1;
          choice->want = e;
        }
        if (is_sailing_unit(myunit) && !city_got_building(pcity, B_PORT)) {
          if (get_invention(pplayer, A_AMPHIBIOUS) == TECH_KNOWN) {
            choice->choice = B_PORT;
            choice->want = e;
            choice->type = 0;
          } else pplayer->ai.tech_want[A_AMPHIBIOUS] += e;
        }
      }
    }
  } 
}


/********************************************************************** 
... this function should assign a value to choice and want and type, 
    where want is a value between 1 and 100.
    if want is 0 this advisor doesn't want anything
    type = 1 means unit, type = 0 means building
***********************************************************************/

void military_advisor_choose_build(struct player *pplayer, struct city *pcity,
				    struct ai_choice *choice)
{
  int def, danger, v, urgency, want;
  struct unit *myunit = 0;
  struct tile *ptile = map_get_tile(pcity->x, pcity->y);
  struct unit virtualunit;
  struct city *acity = 0;
  struct unit *aunit = 0;
  choice->choice = 0;
  choice->want   = 0;
  choice->type   = 0;

/* TODO: recognize units that can DEFEND_HOME but are in the field. -- Syela */

  urgency = assess_danger(pcity); /* calling it now, rewriting old wall code */
  def = assess_defense_quadratic(pcity); /* has to be AFTER assess_danger thanks to wallvalue */
/* changing to quadratic to stop AI from building piles of small units -- Syela */
  danger = pcity->ai.danger; /* we now have our warmap and will use it! */
/*printf("Assessed danger for %s = %d, Def = %d\n", pcity->name, danger, def);*/

  if (danger) { /* otherwise might be able to wait a little longer to defend */
/* old version had danger -= def in it, which was necessary before disband/upgrade
code was added and walls got built, but now danger -= def would be very bad -- Syela */
    if (danger >= def) {
      if (!urgency) danger = 100; /* don't waste money otherwise */
      else if (danger >= def * 2) danger = 200 + urgency;
      else { danger *= 100; danger /= def; danger += urgency; }
/* without the += urgency, wasn't buying with danger == def.  Duh. -- Syela */
    } else { danger *= 100; danger /= def; }
    if (pcity->ai.building_want[B_CITY] && def && can_build_improvement(pcity, B_CITY)
        && (danger < 101 || unit_list_size(&ptile->units) > 1 ||
/* walls before a second defender, unless we need it RIGHT NOW */
         (!pcity->ai.grave_danger && /* I'm not sure this is optimal */
         pplayer->economic.gold > (80 - pcity->shield_stock) * 2))) {
/* or we can afford just to buy walls.  Added 980805 -- Syela */
      choice->choice = B_CITY; /* great wall is under domestic */
      choice->want = pcity->ai.building_want[B_CITY]; /* hacked by assess_danger */
      if (!urgency && choice->want > 100) choice->want = 100;
      choice->type = 0;
    } else if (pcity->ai.building_want[B_COASTAL] && def &&
        can_build_improvement(pcity, B_COASTAL) &&
        (danger < 101 || unit_list_size(&ptile->units) > 1)) {
      choice->choice = B_COASTAL; /* great wall is under domestic */
      choice->want = pcity->ai.building_want[B_COASTAL]; /* hacked by assess_danger */
      if (!urgency && choice->want > 100) choice->want = 100;
      choice->type = 0;
    } else if (pcity->ai.building_want[B_SAM] && def &&
        can_build_improvement(pcity, B_SAM) &&
        (danger < 101 || unit_list_size(&ptile->units) > 1)) {
      choice->choice = B_SAM; /* great wall is under domestic */
      choice->want = pcity->ai.building_want[B_SAM]; /* hacked by assess_danger */
      if (!urgency && choice->want > 100) choice->want = 100;
      choice->type = 0;
    } else if (danger > 0 && unit_list_size(&ptile->units) <= urgency) {
      process_defender_want(pplayer, pcity, danger, choice);
      if (!urgency && unit_types[choice->choice].defense_strength == 1) {
        if (city_got_barracks(pcity)) choice->want = MIN(49, danger); /* unlikely */
        else choice->want = MIN(25, danger);
      } else choice->want = danger;
/*    printf("%s wants %s to defend with desire %d.\n", pcity->name,
       get_unit_type(choice->choice)->name, choice->want); */
/*    return; - this is just stupid */
    }
  } /* ok, don't need to defend */

  memset(&virtualunit, 0, sizeof(struct unit));
/* this memset didn't work because of syntax that
the intrepid David Pfitzner discovered was in error. -- Syela */
  virtualunit.owner = pplayer->player_no;
  virtualunit.x = pcity->x;
  virtualunit.y = pcity->y;
  virtualunit.id = 0;
  v = ai_choose_defender_by_type(pcity, LAND_MOVING);  /* Temporary -- Syela */
  virtualunit.type = v;
  virtualunit.veteran = do_make_unit_veteran(pcity, v);
  virtualunit.hp = unit_types[v].hp;

  if (choice->want < 100) {
    want = look_for_charge(pplayer, &virtualunit, &aunit, &acity);
    if (want > choice->want) {
      choice->want = want;
      choice->choice = v;
      choice->type = 1;
    }
  }

  unit_list_iterate(map_get_tile(pcity->x, pcity->y)->units, punit)
    if ((get_unit_type(punit->type)->attack_strength * 4 >
        get_unit_type(punit->type)->defense_strength * 5) ||
        unit_flag(punit->type, F_FIELDUNIT))
     myunit = punit;
  unit_list_iterate_end;
/* if myunit is non-null, it is an attacker forced to defend */
/* and we will use its attack values, otherwise we will use virtualunit */
  if (myunit) kill_something_with(pplayer, pcity, myunit, choice);
  else {
/*printf("Killing with virtual unit in %s\n", pcity->name);*/
    v = ai_choose_attacker_sailing(pcity);
    if (v > 0) { /* have to put sailing first before we mung the seamap */
      virtualunit.type = v;
      virtualunit.veteran = do_make_unit_veteran(pcity, v);
      virtualunit.hp = unit_types[v].hp;
      kill_something_with(pplayer, pcity, &virtualunit, choice);
    } /* ok.  can now mung seamap for ferryboat code.  Proceed! */
    v = ai_choose_attacker_ground(pcity);
    virtualunit.type = v;
    virtualunit.veteran = do_make_unit_veteran(pcity, v);
    virtualunit.hp = unit_types[v].hp;
    kill_something_with(pplayer, pcity, &virtualunit, choice);
  }
  return;
}

void establish_city_distances(struct player *pplayer, struct city *pcity)
{
  int dist = 0;
  int wondercity;
  int freight;
/* at this moment, our warmap is intact.  we need to do two things: */
/* establish faraway for THIS city, and establish d_t_w_c for ALL cities */

  if (!pcity->is_building_unit && is_wonder(pcity->currently_building))
    wondercity = map_get_continent(pcity->x, pcity->y);
  else wondercity = 0;
  if (get_invention(pplayer, A_CORPORATION) == TECH_KNOWN)
    freight = 6;
  else freight = 3;

  pcity->ai.downtown = 0;
  city_list_iterate(pplayer->cities, othercity)
    dist = warmap.cost[othercity->x][othercity->y];
    if (wondercity && map_get_continent(othercity->x, othercity->y) == wondercity)
      othercity->ai.distance_to_wonder_city = dist;
    dist += freight - 1; dist /= freight;
    pcity->ai.downtown += MAX(0, 5 - dist); /* four three two one fire */
  city_list_iterate_end;
  return;
}
