Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2005:
[Freeciv-Dev] Re: (PR#13524) AI Diplomacy revisited
Home

[Freeciv-Dev] Re: (PR#13524) AI Diplomacy revisited

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] Re: (PR#13524) AI Diplomacy revisited
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Thu, 28 Jul 2005 06:15:33 -0700
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=13524 >

Another version. I fixed the overzealousness for treaties, gave it back
its backbone, fixed a ton of bugs and hopefully made it not want war too
early.

  - Per

Index: ai/advdiplomacy.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdiplomacy.c,v
retrieving revision 1.86
diff -u -r1.86 advdiplomacy.c
--- ai/advdiplomacy.c   26 Jul 2005 16:35:56 -0000      1.86
+++ ai/advdiplomacy.c   28 Jul 2005 13:09:49 -0000
@@ -1,5 +1,5 @@
 /********************************************************************** 
- Freeciv - Copyright (C) 2003 - The Freeciv Team
+ Freeciv - Copyright (C) 2005 - The Freeciv Team
    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)
@@ -43,38 +43,23 @@
 
 #include "aidata.h"
 #include "ailog.h"
+#include "aiunit.h"
 #include "aitools.h"
 #include "advmilitary.h"
 
 #include "advdiplomacy.h"
 
-/*
-
-  "When a lobsterman leaves a trap out in the sea and can't get
-  to it for a while, he will find the remains of many lobsters,
-  but only one survivor. You might think that the survivor of the 
-  lobster-battles would be the biggest lobster, but actually it 
-  will always be the SECOND-SMALLEST. That's because when there 
-  are a bunch of lobsters in the tank, they always gang up on the 
-  biggest one first, until there are only two left, and then the 
-  bigger one wins."
-  (Anecdote by banjo@xxxxxxxxxx)
-
-Although the AIs are not this flawlessly deterministic in choosing their
-enemies (they respect alliances and try to preserve treaties among other
-things), this is the basic premise. Gang up on the biggest threat and
-bring it down. Don't be too afraid to ally up with the others and don't
-worry about our own safety. If everyone think the same way, there'll be
-safety in numbers :-) If not, well, at least it makes a good show.
-
-*/
-
 #define LOG_DIPL LOG_DEBUG
 #define LOG_DIPL2 LOG_DEBUG
 
-/* one hundred thousand */
+/* One hundred thousand. Basically a number of gold that no player is
+ * ever likely to have, but not so big that we get integer overflows. */
 #define BIG_NUMBER 100000
 
+/* This is how much negative AI love we need before we decide to embark
+ * on opportunistic war for spoils. */
+#define WAR_THRESHOLD -(MAX_AI_LOVE / 8)
+
 /* turn this off when we don't want functions to message players */
 static bool diplomacy_verbose = TRUE;
 
@@ -107,8 +92,7 @@
     /* Don't change the operation order here.
      * We do not want integer overflows */
     return -((missing_love * MAX_AI_LOVE) / 1000) * 
-           ((missing_love * MAX_AI_LOVE) / 1000) /
-          50;
+           ((missing_love * MAX_AI_LOVE) / 1000) / 10;
   }
 }
 
@@ -136,7 +120,6 @@
 static int ai_goldequiv_tech(struct player *pplayer, Tech_type_id tech)
 {
   int bulbs, tech_want, worth;
-  struct ai_data *ai = ai_data_get(pplayer);
 
   if (get_invention(pplayer, tech) == TECH_KNOWN) {
     return 0;
@@ -147,9 +130,6 @@
   if (get_invention(pplayer, tech) == TECH_REACHABLE) {
     worth /= 2;
   }
-  DIPLO_LOG(LOG_DEBUG, pplayer, ai, "eval tech %s to %d (bulbs=%d, "
-            "tech_want=%d)", get_tech_name(pplayer, tech), worth, bulbs, 
-            tech_want);
   return worth;
 }
 
@@ -185,14 +165,10 @@
 static bool ai_players_can_agree_on_ceasefire(struct player* player1,
                                               struct player* player2)
 {
-  struct ai_data *ai1 = ai_data_get(player1);
+  struct ai_data *ai = ai_data_get(player1);
 
-  return (ai1->diplomacy.target != player2 && 
-          (player1 == ai1->diplomacy.alliance_leader ||
-           !pplayers_at_war(player2, ai1->diplomacy.alliance_leader)) &&
-         player1->ai.love[player2->player_no] > - (MAX_AI_LOVE * 4 / 10)  &&
-         (ai1->diplomacy.target == NULL || 
-          !pplayers_allied(ai1->diplomacy.target, player2)));
+  return (player1->ai.love[player2->player_no] > - (MAX_AI_LOVE * 4 / 10)
+          && ai->diplomacy.player_intel[player2->player_no].countdown == -1);
 }
 
 /********************************************************************** 
@@ -271,12 +247,11 @@
   assert(pplayer != aplayer);
   
   diplomacy_verbose = verbose;
-
+  ds_after = MAX(ds_after, pplayer->diplstates[aplayer->player_no].type);
   giver = pclause->from;
 
   switch (pclause->type) {
   case CLAUSE_ADVANCE:
-    
     if (give) {
       worth -= compute_tech_sell_price(pplayer, aplayer, pclause->value,
                                        &is_dangerous);
@@ -287,8 +262,9 @@
       worth += compute_tech_sell_price(aplayer, pplayer, pclause->value,
                                        &is_dangerous);
     }
-
-  break;
+    DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "%s clause worth %d",
+              get_tech_name(pplayer, pclause->value), worth);
+    break;
 
   case CLAUSE_ALLIANCE:
   case CLAUSE_PEACE:
@@ -301,18 +277,7 @@
       break;
     }
 
-    /* This guy is at war with our alliance and we're not alliance
-     * leader. */
-    if (pplayer != ai->diplomacy.alliance_leader
-        && pplayers_at_war(aplayer, ai->diplomacy.alliance_leader)) {
-      notify(aplayer, _("*%s (AI)* %s leads our alliance. You must contact "
-             "and make peace with him first."), pplayer->name, 
-             ai->diplomacy.alliance_leader->name);
-      worth = -BIG_NUMBER;
-      break;
-    }
-
-    /* And this guy is allied to one of our enemies. Only accept
+    /* This guy is allied to one of our enemies. Only accept
      * ceasefire. */
     if (adip->is_allied_with_enemy
         && pclause->type != CLAUSE_CEASEFIRE) {
@@ -336,57 +301,41 @@
       }
     }
 
-    /* Let's all hold hands in one happy family! */
-    if (adip->is_allied_with_ally) {
-      worth = 0;
-      break;
-    }
-
-    /* If this lucky fella got a ceasefire or peace with da boss, then
-     * let him live. */
-    if ((pplayer_get_diplstate(aplayer, ai->diplomacy.alliance_leader)->type
-         == DS_CEASEFIRE
-         || pplayer_get_diplstate(aplayer, ai->diplomacy.alliance_leader)->type
-            == DS_PEACE)
-        && pclause->type == CLAUSE_CEASEFIRE) {
-        if (ai->diplomacy.target == aplayer) {
-          /* Damn, we lost our target, too! Stupid boss! */
-          /* FIXME: We shouldn't do this here - the other player may not
-           * accept the whole treaty! */
-          ai->diplomacy.target = NULL;
-          ai->diplomacy.timer = 0;
-          ai->diplomacy.countdown = 0;
-        }
-        worth = 0;
-        break;
-    }
-
-    /* Breaking treaties give us penalties on future diplomacy, so
-     * avoid flip-flopping treaty/war with our chosen enemy. */
-    if (aplayer == ai->diplomacy.target) {
-      worth = -BIG_NUMBER;
-      break;
-    }
-
-    /* Steps of the ladder */
+    /* Steps of the treaty ladder */
     if (pclause->type == CLAUSE_PEACE) {
+      struct player_diplstate *ds = &pplayer->diplstates[aplayer->player_no];
+
       if (!pplayers_non_attack(pplayer, aplayer)) {
         notify(aplayer, _("*%s (AI)* Let us first cease hostilies, %s"),
                pplayer->name, aplayer->name);
         worth = -BIG_NUMBER;
+      } else if (ds->type == DS_CEASEFIRE && ds->turns_left > 2) {
+        notify(aplayer, _("*%s (AI)* I wish to see you keep the current "
+               "ceasefire first, %s"), pplayer->name, aplayer->name);
+        worth = -BIG_NUMBER;
+      } else if (adip->countdown >= 0 && adip->countdown < -1) {
+        worth = -BIG_NUMBER; /* but say nothing */
       } else {
         worth = greed(pplayer->ai.love[aplayer->player_no]
                       - ai->diplomacy.req_love_for_peace);
       }
     } else if (pclause->type == CLAUSE_ALLIANCE) {
       if (!pplayers_in_peace(pplayer, aplayer)) {
-        notify(aplayer, _("*%s (AI)* Let us first make peace, %s"),
-               pplayer->name, aplayer->name);
-        worth = -BIG_NUMBER;
-      } else {
         worth = greed(pplayer->ai.love[aplayer->player_no]
-                      - ai->diplomacy.req_love_for_alliance);
+                      - ai->diplomacy.req_love_for_peace);
       }
+      if (adip->countdown >= 0 || adip->countdown < -1) {
+        worth = -BIG_NUMBER; /* but say nothing */
+      } else {
+        worth += greed(pplayer->ai.love[aplayer->player_no]
+                       - ai->diplomacy.req_love_for_alliance);
+      }
+      if (pplayer->ai.love[aplayer->player_no] < MAX_AI_LOVE / 10) {
+        notify(aplayer, _("*%s (AI)* I simply do not trust you with an "
+               "alliance yet, %s"), pplayer->name, aplayer->name);
+        worth = -BIG_NUMBER;
+      }
+      DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "ally clause worth %d", worth);
     } else {
       if (pplayer->ai.control && aplayer->ai.control &&
          ai_players_can_agree_on_ceasefire(pplayer, aplayer)) {
@@ -396,6 +345,14 @@
                       - ai->diplomacy.req_love_for_ceasefire);
       }
     }
+
+    /* Let's all hold hands in one happy family! */
+    if (adip->is_allied_with_ally) {
+      worth /= 2;
+      break;
+    }
+
+    DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "treaty clause worth %d", worth);
   break;
 
   case CLAUSE_GOLD:
@@ -407,7 +364,7 @@
     break;
 
   case CLAUSE_SEAMAP:
-    if (!give || pplayers_allied(pplayer, aplayer)) {
+    if (!give || ds_after == DS_ALLIANCE) {
       /* Useless to us - we're omniscient! And allies get it for free! */
       worth = 0;
     } else {
@@ -415,31 +372,38 @@
          cities. Reasoning is he has more use of seamap for settling
          new areas the more cities he has already. */
       worth -= 15 * city_list_size(aplayer->cities);
-
+      /* Don't like him? Don't give him! */
+      worth = MIN(pplayer->ai.love[aplayer->player_no] * 7, worth);
       /* Make maps from novice player cheap */
       if (ai_handicap(pplayer, H_DIPLOMACY)) {
         worth /= 2;
       }
     }
+    DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "seamap clause worth %d",
+              worth);
     break;
 
   case CLAUSE_MAP:
-    if (!give || pplayers_allied(pplayer, aplayer)) {
+    if (!give || ds_after == DS_ALLIANCE) {
       /* Useless to us - we're omniscient! And allies get it for free! */
       worth = 0;
     } else {
       /* Very silly algorithm 2: Land map more worth the more cities
          we have, since we expose all of these to the enemy. */
-      worth -= 50 * MAX(city_list_size(pplayer->cities), 3);
+      worth -= 40 * MAX(city_list_size(pplayer->cities), 1);
       /* Inflate numbers if not peace */
       if (!pplayers_in_peace(pplayer, aplayer)) {
-        worth *= 4;
+        worth *= 2;
       }
+      /* Don't like him? Don't give him! */
+      worth = MIN(pplayer->ai.love[aplayer->player_no] * 10, worth);
       /* Make maps from novice player cheap */
       if (ai_handicap(pplayer, H_DIPLOMACY)) {
         worth /= 6;
       }
     }
+    DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "landmap clause worth %d",
+              worth);
     break;
 
   case CLAUSE_CITY: {
@@ -466,13 +430,14 @@
     } else {
       worth = city_gold_worth(offer);
     }
-    DIPLO_LOG(LOG_DEBUG, pplayer, ai, "worth of %s is %d", offer->name, worth);
+    DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "worth of %s is %d", 
+              offer->name, worth);
     break;
   }
 
   case CLAUSE_VISION:
     if (give) {
-      if (pplayers_allied(pplayer, aplayer) || ds_after == DS_ALLIANCE) {
+      if (ds_after == DS_ALLIANCE) {
         if (!shared_vision_is_safe(pplayer, aplayer)) {
           notify(aplayer, _("*%s (AI)* Sorry, sharing vision with you "
                            "is not safe."),
@@ -489,17 +454,25 @@
       worth = 0; /* We are omniscient, so... */
     }
     break;
+
   case CLAUSE_EMBASSY:
     if (give) {
-      if (ds_after == DS_PEACE || ds_after == DS_ALLIANCE) {
+      if (ds_after == DS_ALLIANCE) {
         worth = 0;
+      } else if (ds_after == DS_PEACE) {
+        worth = -5 * game.info.turn;
       } else {
-        worth = -BIG_NUMBER; /* No. */
+        worth = MIN(-50 * game.info.turn
+                    + pplayer->ai.love[aplayer->player_no], 
+                    -5 * game.info.turn);
       }
     } else {
       worth = 0; /* We don't need no stinkin' embassy, do we? */
     }
+    DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "embassy clause worth %d",
+              worth);
     break;
+
   case CLAUSE_LAST:
     break;
   } /* end of switch */
@@ -592,14 +565,17 @@
         notify(aplayer, _("*%s (AI)* Yes, may we forever stand united, %s"),
                pplayer->name, aplayer->name);
       }
+      DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "become allies");
       break;
     case CLAUSE_PEACE:
       notify(aplayer, _("*%s (AI)* Yes, peace in our time!"),
              pplayer->name);
+      DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "sign peace treaty");
       break;
     case CLAUSE_CEASEFIRE:
       notify(aplayer, _("*%s (AI)* Agreed. No more hostilities, %s"),
              pplayer->name, aplayer->name);
+      DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "sign ceasefire");
       break;
     default:
       break;
@@ -638,8 +614,11 @@
     total_balance += balance;
     gift = (gift && (balance >= 0));
     ai_treaty_react(pplayer, aplayer, pclause);
-    if (pclause->type == CLAUSE_ALLIANCE && ai->diplomacy.target == aplayer) {
-      ai->diplomacy.target = NULL; /* Oooops... */
+    if (is_pact_clause(pclause->type)
+        && ai->diplomacy.player_intel[aplayer->player_no].countdown >= 0) {
+      /* Cancel a countdown towards war if we just agreed to peace... */
+      DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "countdown cancelled");
+      ai->diplomacy.player_intel[aplayer->player_no].countdown = -1;
     }
   } clause_list_iterate_end;
 
@@ -651,60 +630,89 @@
 
     i = MIN(i, ai->diplomacy.love_incr * 150) * 10;
     pplayer->ai.love[aplayer->player_no] += i;
-    DIPLO_LOG(LOG_DIPL2, pplayer, ai, "%s's gift to %s increased love by %d",
-            aplayer->name, pplayer->name, i);
+    DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "gift increased love by %d", i);
   }
 }
 
 /********************************************************************** 
-  Calculate our desire to go to war against aplayer.
+  Calculate our desire to go to war against aplayer.  We want to 
+  attack a player that is easy to beat and will yield a nice profit.
+
+  This function is full of hardcoded constants by necessity.  They are
+  not #defines since they are not used anywhere else.
 ***********************************************************************/
-static int ai_war_desire(struct player *pplayer, struct player *aplayer,
+static int ai_war_desire(struct player *pplayer, struct player *target,
                          struct ai_data *ai)
 {
-  int kill_desire;
-  struct player_spaceship *ship = &aplayer->spaceship;
-  struct ai_dip_intel *adip = &ai->diplomacy.player_intel[aplayer->player_no];
+  int want = 0, fear = 0, distance = 0, settlers = 0, cities = 0;
+  struct player_spaceship *ship = &target->spaceship;
 
-  /* Number of cities is a player's base potential. */
-  kill_desire = city_list_size(aplayer->cities);
-
-  /* Count settlers in production for us, indicating our expansionism,
-   * while counting all enemy settlers as (worst case) indicators of
-   * enemy expansionism */
-  city_list_iterate(pplayer->cities, pcity) {
-    if (pcity->production.is_unit 
-        && unit_type_flag(get_unit_type(pcity->production.value),
-                         F_CITIES)) {
-      kill_desire -= 1;
-    }
+  city_list_iterate(target->cities, pcity) {
+    want += 100; /* base city want */
+    want += pcity->size * 20;
+    want += pcity->surplus[O_SHIELD] * 8;
+    want += pcity->surplus[O_TRADE] * 6;
+    fear += get_city_bonus(pcity, EFT_LAND_DEFEND);
+    fear += get_city_bonus(pcity, EFT_SEA_DEFEND);
+    built_impr_iterate(pcity, id) {
+      want += impr_build_shield_cost(id);
+      if (is_great_wonder(id)) {
+        want += impr_build_shield_cost(id) * 2;
+      } else if (is_small_wonder(id)) {
+        want += impr_build_shield_cost(id);
+      }
+    } built_impr_iterate_end;
   } city_list_iterate_end;
-  unit_list_iterate(aplayer->units, punit) { 
+  unit_list_iterate(target->units, punit) {
+    fear += ATTACK_POWER(punit);
+
+    /* Fear enemy expansionism */
     if (unit_flag(punit, F_CITIES)) {
-      kill_desire += 1;
+      want += 100;
     }
   } unit_list_iterate_end;
+  unit_list_iterate(pplayer->units, punit) {
+    fear -= ATTACK_POWER(punit) / 2;
 
-  /* Count big cities as twice the threat */
-  city_list_iterate(aplayer->cities, pcity) {
-    kill_desire += pcity->size > 8 ? 1 : 0;
+    /* Our own expansionism reduces want for war */
+    if (unit_flag(punit, F_CITIES)) {
+      want -= 200;
+      settlers++;
+    }
+  } unit_list_iterate_end;
+  city_list_iterate(pplayer->cities, pcity) {
+    if (pcity->production.is_unit 
+        && unit_type_flag(get_unit_type(pcity->production.value),
+                          F_CITIES)) {
+      want -= 150;
+      settlers++;
+    }
+    cities++;
   } city_list_iterate_end;
 
-  /* Tech lead is worrisome */
-  kill_desire += MAX(get_player_research(aplayer)->techs_researched
-                     - get_player_research(pplayer)->techs_researched, 0);
+  /* Modify by settler/cities ratio to prevent early wars when
+   * we should be expanding. This will eliminate want if we 
+   * produce settlers in all cities (ie full expansion). */
+  want -= abs(want) / MAX(cities - settlers, 1);
+
+  /* Calculate average distances to other player's empire. */
+  distance = player_distance_to_player(pplayer, target);
+  ai->diplomacy.player_intel[target->player_no].distance = distance;
+
+  /* Tech lead is worrisome. FIXME: Only consider 'military' techs. */
+  fear += MAX(get_player_research(target)->techs_researched
+              - get_player_research(target)->techs_researched, 0) * 100;
 
   /* Spacerace loss we will not allow! */
   if (ship->state >= SSHIP_STARTED) {
-    /* add potential */
-    kill_desire += city_list_size(aplayer->cities);
+    want *= 2;
   }
-  if (ai->diplomacy.spacerace_leader == aplayer) {
+  if (ai->diplomacy.spacerace_leader == target) {
     ai->diplomacy.strategy = WIN_CAPITAL;
     return BIG_NUMBER; /* do NOT amortize this number! */
   }
 
-  /* Modify by which treaties we would have to break, and what
+  /* Modify by which treaties we would break to other players, and what
    * excuses we have to do so. FIXME: We only consider immediate
    * allies, but we might trigger a wider chain reaction. */
   players_iterate(eplayer) {
@@ -716,32 +724,39 @@
       continue;
     }
 
-    /* Remember: pplayers_allied() returns true when aplayer == eplayer */
-    if (!cancel_excuse && pplayers_allied(aplayer, eplayer)) {
+    /* Remember: pplayers_allied() returns true when target == eplayer */
+    if (!cancel_excuse && pplayers_allied(target, eplayer)) {
       if (ds == DS_NEUTRAL) {
-        kill_desire -= kill_desire / 10; /* 10% off */
+        want -= abs(want) / 10; /* 10% off */
       } else if (ds == DS_CEASEFIRE) {
-        kill_desire -= kill_desire / 7; /* 15% off */
+        want -= abs(want) / 7; /* 15% off */
       } else if (ds == DS_PEACE) {
-        kill_desire -= kill_desire / 5; /* 20% off */
+        want -= abs(want) / 5; /* 20% off */
       } else if (ds == DS_ALLIANCE) {
-        kill_desire -= kill_desire / 3; /* 33% off here, more later */
+        want -= abs(want) / 3; /* 33% off */
       }
     }
   } players_iterate_end;
 
   /* Modify by love. Increase the divisor to make ai go to war earlier */
-  kill_desire -= MAX(0, kill_desire 
-                        * pplayer->ai.love[aplayer->player_no] 
-                        / (2 * MAX_AI_LOVE));
+  want -= MAX(0, want * pplayer->ai.love[target->player_no] 
+                 / (2 * MAX_AI_LOVE));
 
   /* Make novice AI more peaceful with human players */
-  if (ai_handicap(pplayer, H_DIPLOMACY) && !aplayer->ai.control) {
-    kill_desire = kill_desire / 2 - 5;
+  if (ai_handicap(pplayer, H_DIPLOMACY) && !target->ai.control) {
+    want /= 2;
   }
 
   /* Amortize by distance */
-  return amortize(kill_desire, adip->distance);
+  want = amortize(want, distance);
+
+  if (pplayers_allied(pplayer, target)) {
+    want /= 4;
+  }
+
+  DIPLO_LOG(LOG_DEBUG, pplayer, target, "War want %d, war fear %d",
+            want, fear);
+  return (want - fear);
 }
 
 /********************************************************************** 
@@ -777,8 +792,7 @@
 {
   int war_desire[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
   int best_desire = 0;
-  struct player *target = NULL;
-  int mult;
+  struct player *best_target = NULL;
 
   memset(war_desire, 0, sizeof(war_desire));
 
@@ -787,86 +801,94 @@
     return; /* duh */
   }
 
+  /* Calculate our desires, and find desired war target */
+  players_iterate(aplayer) {
+    /* We don't hate ourselves, those we don't know or team members. */
+    if (aplayer == pplayer
+        || !aplayer->is_alive
+        || NEVER_MET(pplayer, aplayer)
+        || players_on_same_team(pplayer, aplayer)) {
+      continue;
+    }
+    war_desire[aplayer->player_no] = ai_war_desire(pplayer, aplayer, ai);
+    if (war_desire[aplayer->player_no] > best_desire) {
+      best_desire = war_desire[aplayer->player_no];
+      best_target = aplayer;
+    }
+  } players_iterate_end;
+
   /* Time to make love. If we've been wronged, hold off that love
    * for a while. Also, cool our head each turn with love_coeff. */
   players_iterate(aplayer) {
     int a = aplayer->player_no;
     struct ai_dip_intel *adip = &ai->diplomacy.player_intel[a];
+    int amount = 0;
 
     if (pplayer == aplayer || !aplayer->is_alive) {
       continue;
     }
-    pplayer->ai.love[aplayer->player_no] -= 
-                         pplayer->diplstates[a].has_reason_to_cancel;
     if ((pplayers_non_attack(pplayer, aplayer) 
          || pplayers_allied(pplayer, aplayer))
         && pplayer->diplstates[a].has_reason_to_cancel == 0
+        && adip->countdown == -1
         && !adip->is_allied_with_enemy
         && !adip->at_war_with_ally
-        && aplayer != ai->diplomacy.target
+        && aplayer != best_target
         && adip->ally_patience >= 0) {
-      pplayer->ai.love[aplayer->player_no] += ai->diplomacy.love_incr;
-      DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Increased love for %s (now %d)",
-                aplayer->name, pplayer->ai.love[aplayer->player_no]);
-    } else if (pplayer->diplstates[aplayer->player_no].type == DS_WAR) {
-      pplayer->ai.love[aplayer->player_no] -= ai->diplomacy.love_incr;
-      if (ai->diplomacy.target != aplayer && 
-          pplayer->ai.love[aplayer->player_no] < 0) {
-        /* Give him a better chance for a cease fire */
-        pplayer->ai.love[aplayer->player_no] += (MAX_AI_LOVE) * 3 / 100;
-      }
-      DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Reduced love for %s (now %d) ",
-                aplayer->name, pplayer->ai.love[aplayer->player_no]);
+      amount += ai->diplomacy.love_incr / 2;
+      if (pplayers_allied(pplayer, aplayer)) {
+        amount += ai->diplomacy.love_incr / 3;
+      }
+      /* Increase love by each enemy he is at war with */
+      players_iterate(eplayer) {
+        if (WAR(eplayer, aplayer) && WAR(pplayer, eplayer)) {
+          amount += ai->diplomacy.love_incr / 4;
+        }
+      } players_iterate_end;
+      pplayer->ai.love[aplayer->player_no] += amount;
+      DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "Increased love by %d", amount);
+    } else if (WAR(pplayer, aplayer)) {
+      amount -= ai->diplomacy.love_incr / 2;
+      pplayer->ai.love[aplayer->player_no] += amount;
+      DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "%d love lost to war", amount);
     } else if (pplayer->diplstates[a].has_reason_to_cancel != 0) {
       /* Provoked in time of peace */
       if (pplayer->ai.love[aplayer->player_no] > 0) {
-        DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Provoked by %s! Love halved "
-                  "(was %d)", aplayer->name,
-                  pplayer->ai.love[aplayer->player_no]);
-        pplayer->ai.love[aplayer->player_no] /= 2;
+        amount -= pplayer->ai.love[aplayer->player_no] / 2;
       }
-      pplayer->ai.love[aplayer->player_no] -= ai->diplomacy.love_incr;
+      amount -= ai->diplomacy.love_incr * 6;
+      pplayer->ai.love[aplayer->player_no] += amount;
+      DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "Provoked! %d love lost!",
+                amount);
     }
-    
-    /* Reduce love by number of units in our territory.
+    if (pplayer->ai.love[aplayer->player_no] > MAX_AI_LOVE * 8 / 10
+        && !pplayers_allied(pplayer, aplayer)) {
+      int amount = ai->diplomacy.love_incr / 3;
+
+      /* Upper levels of AI trust and love is reserved for allies. */
+      pplayer->ai.love[aplayer->player_no] -= amount;
+      DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "%d love lost from excess",
+                amount);
+    }
+    amount = 0;
+
+    /* Reduce love due to units in our territory.
      * AI is so naive, that we have to count it even if players are allied */
-    mult = 
-      pplayers_at_war(pplayer, aplayer) || adip->is_allied_with_enemy ?
-      2 : 1;
-    
-    pplayer->ai.love[aplayer->player_no] -=
-      MIN(player_in_territory(pplayer, aplayer) * (MAX_AI_LOVE / 100),
-          pplayers_allied(aplayer, pplayer) ? 
-           ai->diplomacy.love_incr - 1 : (MAX_AI_LOVE / 2)) * mult;
- 
+    amount -= MIN(player_in_territory(pplayer, aplayer) * (MAX_AI_LOVE / 200),
+                  ai->diplomacy.love_incr 
+                  * ((adip->is_allied_with_enemy != NULL) + 1));
+    pplayer->ai.love[aplayer->player_no] += amount;
+    if (amount != 0) {
+      DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "%d love lost due to units inside 
"
+                "our borders", amount);
+    }
+
     /* Increase the love if aplayer has got a building that makes 
      * us love him more. Typically it's Eiffel Tower */
     pplayer->ai.love[aplayer->player_no] +=
       get_player_bonus(aplayer, EFT_GAIN_AI_LOVE) * MAX_AI_LOVE / 1000;
-         
-    /* Massage our numbers to keep love and its opposite on the ground. 
-     * Gravitate towards zero. */
-    pplayer->ai.love[aplayer->player_no] -= 
-       (pplayer->ai.love[aplayer->player_no] * ai->diplomacy.love_coeff / 100);
-       
-    /* ai love should always be in range [-MAX_AI_LOVE..MAX_AI_LOVE] */
-    pplayer->ai.love[aplayer->player_no] = 
-      MAX(-MAX_AI_LOVE,
-          MIN(MAX_AI_LOVE, pplayer->ai.love[aplayer->player_no]));
   } players_iterate_end;
 
-  /* Stop war against a dead player */
-  if (ai->diplomacy.target && !ai->diplomacy.target->is_alive) {
-    DIPLO_LOG(LOG_DIPL2, pplayer, ai, "Target player %s is dead! Victory!",
-              ai->diplomacy.target->name);
-    ai->diplomacy.timer = 0;
-    ai->diplomacy.countdown = 0;
-    ai->diplomacy.target = NULL;
-    if (ai->diplomacy.strategy == WIN_CAPITAL) {
-      ai->diplomacy.strategy = WIN_OPEN;
-    }
-  }
-
   /* Can we win by space race? */
   if (ai->diplomacy.spacerace_leader == pplayer) {
     freelog(LOG_DIPL2, "%s going for space race victory!", pplayer->name);
@@ -877,90 +899,26 @@
     }
   }
 
-  if (ai->diplomacy.countdown > 0) {
-    ai->diplomacy.countdown--;
-  }
-
-  /* Ensure that we don't prematurely end an ongoing war */
-  if (ai->diplomacy.timer-- > 0) {
-    return;
-  }
-
-  /* Calculate average distances to other players' empires. */
   players_iterate(aplayer) {
-    ai->diplomacy.player_intel[aplayer->player_no].distance = 
-          player_distance_to_player(pplayer, aplayer);
-  } players_iterate_end;
+    int *love = &pplayer->ai.love[aplayer->player_no];
 
-  /* Calculate our desires, and find desired war target */
-  players_iterate(aplayer) {
-    enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;
-    struct ai_dip_intel *adip = 
&ai->diplomacy.player_intel[aplayer->player_no];
-
-    /* We don't hate ourselves, those we don't know or team members
-     * Defer judgement on alliance members we're not (yet) allied to
-     * to the alliance leader. Always respect ceasefires the boss has signed. 
-     */
-    if (aplayer == pplayer
-        || !aplayer->is_alive
-        || ds == DS_NO_CONTACT
-        || players_on_same_team(pplayer, aplayer)
-        || (pplayer != ai->diplomacy.alliance_leader && 
-           aplayer != ai->diplomacy.alliance_leader &&
-            adip->is_allied_with_ally)
-        || (pplayer_get_diplstate(aplayer, ai->diplomacy.alliance_leader)->type
-            == DS_CEASEFIRE)) {
-      continue;
-    }
-    war_desire[aplayer->player_no] = ai_war_desire(pplayer, aplayer, ai);
+    if (aplayer == best_target && best_desire > 0) {
+      int reduction = MIN(best_desire, MAX_AI_LOVE / 20);
 
-    /* We don't want war if we can win through the space race. */
-    if (ai->diplomacy.strategy == WIN_SPACE && !adip->at_war_with_ally) {
-      continue;    
+      *love -= reduction;
+      DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "Wants war, reducing "
+                "love by %d ", reduction);
     }
 
-    /* Strongly prefer players we are at war with already. */
-    if (!pplayers_at_war(pplayer, aplayer)) {
-      war_desire[aplayer->player_no] /= 2;
-    }
-    
-    DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Against %s we have war desire "
-              "%d ", aplayer->name, war_desire[aplayer->player_no]);
+    /* Massage our numbers to keep love and its opposite on the ground.
+     * Gravitate towards zero. */
+    *love -= *love * (ai->diplomacy.love_coeff / 100);
 
-    /* Find best target */
-    if (war_desire[aplayer->player_no] > best_desire) {
-      target = aplayer;
-      best_desire = war_desire[aplayer->player_no];
-    }
+    /* ai love should always be in range [-MAX_AI_LOVE..MAX_AI_LOVE] */
+    *love = MAX(-MAX_AI_LOVE, MIN(MAX_AI_LOVE, *love));
   } players_iterate_end;
-
-  if (!target) {
-    DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Found no target.");
-    ai->diplomacy.target = NULL;
-    return;
-  }
-
-  /* Switch to target */
-  if (target != ai->diplomacy.target) {
-    DIPLO_LOG(LOG_DIPL, pplayer, ai, "Setting target to %s", target->name);
-    ai->diplomacy.target = target;
-    if (ai->diplomacy.strategy == WIN_CAPITAL) {
-      ai->diplomacy.countdown = 1; /* Quickly!! */
-    } else if (pplayer->diplstates[target->player_no].has_reason_to_cancel > 
1) {
-      /* Turns until we lose our casus bellum, exploit that. */
-      ai->diplomacy.countdown = 
-                    pplayer->diplstates[target->player_no].has_reason_to_cancel
-                    - 1;
-    } else {
-      ai->diplomacy.countdown = 6; /* Take the time we need - WAG */
-    }
-    /* Don't reevaluate too often. */
-    ai->diplomacy.timer = myrand(6) + 6 + ai->diplomacy.countdown;
-    players_iterate(aplayer) {
-      ai->diplomacy.player_intel[aplayer->player_no].ally_patience = 0;
-    } players_iterate_end;
-  }
 }
+
 /********************************************************************** 
   Find two techs that can be exchanged and suggest that
 ***********************************************************************/
@@ -1000,7 +958,6 @@
     }
   } tech_type_iterate_end;
     
-    
   tech_type_iterate(tech) {
     if (worth[tech] <= 0) {
       continue;
@@ -1028,6 +985,7 @@
     } tech_type_iterate_end;
   } tech_type_iterate_end;
 }
+
 /********************************************************************** 
   Offer techs and stuff to other player and ask for techs we need.
 ***********************************************************************/
@@ -1068,13 +1026,63 @@
 }
 
 /********************************************************************** 
-  Go to war.
+  Go to war.  Explain to target why we did it, and set countdown to
+  some negative value to make us a bit stubborn to avoid immediate
+  reversal to ceasefire.
 ***********************************************************************/
 static void ai_go_to_war(struct player *pplayer, struct ai_data *ai,
-                         struct player *target)
+                         struct player *target, enum war_reason reason)
 {
+  struct ai_dip_intel *adip = &ai->diplomacy.player_intel[target->player_no];
+
   assert(pplayer != target);
 
+  switch (reason) {
+  case WAR_REASON_SPACE:
+    notify(target, _("*%s (AI)* Space will never be yours. "), pplayer->name);
+    adip->countdown = -10;
+    break;
+  case WAR_REASON_BEHAVIOUR:
+    notify(target, _("*%s (AI)* I have tolerated your vicious antics "
+           "long enough! To war!"), pplayer->name);
+    adip->countdown = -20;
+    break;
+  case WAR_REASON_NONE:
+    notify(target, _("*%s (AI)* Peace in ... some other time"),
+           pplayer->name);
+    adip->countdown = -10;
+    break;
+  case WAR_REASON_HATRED:
+    notify(target, _("*%s (AI)* Finally I get around to you! Did "
+           "you really think you could get away with your crimes?"),
+           pplayer->name);
+    adip->countdown = -20;
+    break;
+  case WAR_REASON_EXCUSE:
+    notify(target, _("*%s (AI)* Your covert hostilities brought "
+           "this war upon you!"), pplayer->name);
+    adip->countdown = -20;
+    break;
+  case WAR_REASON_ALLIANCE:
+    if (adip->at_war_with_ally) {
+      notify(target, _("*%s (AI)* Your aggression against %s was "
+                       "your last mistake!"),
+                       pplayer->name,
+                       adip->at_war_with_ally->name);
+      adip->countdown = -3;
+    } else {
+      /* Ooops! */
+      DIPLO_LOG(LOG_DIPL, pplayer, target, "Wanted to declare war "
+                "for his war against an ally, but can no longer find "
+                "this ally!  War declaration aborted.");
+      adip->countdown = -1;
+      return;
+    }
+    break;
+  }
+
+  assert(adip->countdown < 0);
+
   if (gives_shared_vision(pplayer, target)) {
     remove_shared_vision(pplayer, target);
   }
@@ -1088,16 +1096,87 @@
   /* This will take us straight to war. */
   handle_diplomacy_cancel_pact(pplayer, target->player_no, CLAUSE_LAST);
 
-  /* Continue war at least in this arbitrary number of turns to show 
-   * some spine */
-  ai->diplomacy.timer = myrand(4) + 3;
-  if (pplayer->ai.love[target->player_no] < 0) {
-    ai->diplomacy.timer -= pplayer->ai.love[target->player_no] / 10;
-  } else {
-    /* We DO NOT love our enemies! AIs are heatens! */
-    pplayer->ai.love[target->player_no] = -1; 
+  /* Throw a tantrum */
+  if (pplayer->ai.love[target->player_no] > 0) {
+    pplayer->ai.love[target->player_no] = -1;
   }
+  pplayer->ai.love[target->player_no] -= MAX_AI_LOVE / 8;
+
   assert(!gives_shared_vision(pplayer, target));
+  DIPLO_LOG(LOG_DIPL, pplayer, target, "war declared");
+}
+
+/********************************************************************** 
+  Do diplomatic actions. Must be called only after calculate function
+  above has been run for _all_ AI players.
+
+  Only ever called for AI players and never for barbarians.
+***********************************************************************/
+void static war_countdown(struct player *pplayer, struct player *target,
+                          int countdown, enum war_reason reason)
+{
+  struct ai_data *ai = ai_data_get(pplayer);
+  struct ai_dip_intel *adip = &ai->diplomacy.player_intel[target->player_no];
+
+  DIPLO_LOG(LOG_DIPL, pplayer, target, "countdown to war in %d", countdown);
+
+  /* Otherwise we're resetting an existing countdown, which is very bad */
+  assert(adip->countdown == -1);
+
+  adip->countdown = countdown;
+  adip->war_reason = reason;
+
+  players_iterate(ally) {
+    if (!pplayers_allied(pplayer, ally) || !ally->is_alive) {
+      continue;
+    }
+
+    switch (reason) {
+    case WAR_REASON_SPACE:
+      notify(ally, _("*%s (AI)* We will be launching an all-out war "
+                     "against %s in %d turns to stop the spaceship "
+                     "launch."), pplayer->name, target->name, countdown);
+      notify(ally, _("*%s (AI)* Your aid in this matter will be expected. "
+                     "Long live our glorious alliance!"), pplayer->name);
+      break;
+    case WAR_REASON_BEHAVIOUR:
+    case WAR_REASON_EXCUSE:
+      notify(ally, _("*%s (AI)* %s has grossly violated his treaties with us "
+                     "for own gain.  We will answer in force in %d turns " 
+                     "and expect you to honour your alliance with us and do "
+                     "likewise!"), pplayer->name, target->name, countdown);
+      break;
+    case WAR_REASON_NONE:
+      notify(ally, _("*%s (AI)* We intend to pillage and plunder the rich "
+                     "civilization of %s. We declare war in %d turns."), 
+                     pplayer->name, target->name, countdown);
+      notify(ally, _("*%s (AI)* If you want a piece of the loot, feel "
+                     "free to join in the action!"), pplayer->name);
+      break;
+    case WAR_REASON_HATRED:
+      notify(ally, _("*%s (AI)* We have had it with %s. Let us tear this "
+                     "pathetic civilization apart. We declare war in %d "
+                     "turns."), pplayer->name, target->name, countdown);
+      notify(ally, _("*%s (AI)* As our glorious allies, we expect your "
+                     "help in this war."), pplayer->name);
+      break;
+    case WAR_REASON_ALLIANCE:
+      if (WAR(ally, target)) {
+        notify(ally, _("*%s (AI)* We will honour our alliance and declare "
+                       "war on %s in %d turns.  Hold on - we are coming!"),
+                       pplayer->name, target->name, countdown);
+      } else if (adip->at_war_with_ally) {
+        notify(ally, _("*%s (AI)* We will honour our alliance with %s and "
+                       "declare war on %s in %d turns.  We expect you to "
+                       "do likewise."), pplayer->name, 
+                       adip->at_war_with_ally->name, target->name,
+                       countdown);
+      } else {
+        assert(FALSE); /* Huh? */
+      }
+      break;
+    }
+  } players_iterate_end;
 }
 
 /********************************************************************** 
@@ -1109,7 +1188,9 @@
 void ai_diplomacy_actions(struct player *pplayer)
 {
   struct ai_data *ai = ai_data_get(pplayer);
-  struct player *target = ai->diplomacy.target;
+  bool need_targets = TRUE;
+  struct player *target = NULL;
+  int most_hatred = MAX_AI_LOVE;
 
   assert(pplayer->ai.control);
   if (!pplayer->is_alive) {
@@ -1120,12 +1201,10 @@
 
   players_iterate(aplayer) {
     if (pplayer->ai.love[aplayer->player_no] < 0
-        && pplayer->diplstates[aplayer->player_no].has_reason_to_cancel >= 2) {
-      DIPLO_LOG(LOG_DIPL2, pplayer, ai, "Declaring war on %s in revenge",
-                 target->name);
-      notify(target, _("*%s (AI)* I will NOT accept such behaviour! This "
-             "means WAR!"), pplayer->name);
-      ai_go_to_war(pplayer, ai, aplayer);
+        && pplayer->diplstates[aplayer->player_no].has_reason_to_cancel >= 2
+        && ai->diplomacy.player_intel[aplayer->player_no].countdown == -1) {
+      DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "Plans war in revenge");
+      war_countdown(pplayer, aplayer, map.size, WAR_REASON_BEHAVIOUR);
     }
   } players_iterate_end;
 
@@ -1139,7 +1218,9 @@
 
       if (!aplayer->is_alive || aplayer == pplayer
           || players_on_same_team(pplayer, aplayer)
-          || ship->state == SSHIP_NONE) {
+          || adip->countdown >= 0
+          || ship->state == SSHIP_NONE
+          || NEVER_MET(pplayer, aplayer)) {
         continue;
       }
       /* A spaceship victory is always one single player's or team's victory */
@@ -1158,6 +1239,7 @@
         pplayer->ai.love[aplayer->player_no] = -(BIG_NUMBER);
       } else if (ship->state == SSHIP_STARTED 
                 && adip->warned_about_space == 0) {
+        pplayer->ai.love[aplayer->player_no] -= MAX_AI_LOVE / 10;
         adip->warned_about_space = 10 + myrand(6);
         notify(aplayer, _("*%s (AI)* Your attempt to unilaterally "
                "dominate outer space is highly offensive."), pplayer->name);
@@ -1167,38 +1249,44 @@
       if (aplayer->spaceship.state == SSHIP_LAUNCHED
           && aplayer == ai->diplomacy.spacerace_leader) {
         /* This means war!!! */
-        ai->diplomacy.timer = 0; /* Force reevaluation next turn */
+        pplayer->ai.love[aplayer->player_no] -= MAX_AI_LOVE / 2;
+        DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "plans war due to spaceship");
+        war_countdown(pplayer, aplayer, 4 + map.size, WAR_REASON_SPACE);
       }
     } players_iterate_end;
   }
 
-  /*** Declare war - against target ***/
+  /*** Declare war against somebody if we are out of targets ***/
+
+  players_iterate(aplayer) {
+    if (aplayer->is_alive 
+        && WAR(pplayer, aplayer)) {
+      need_targets = FALSE;
+    } else if (aplayer->is_alive
+               && pplayer->ai.love[aplayer->player_no] < most_hatred) {
+      most_hatred = pplayer->ai.love[aplayer->player_no];
+      target = aplayer;
+    }
+  } players_iterate_end;
+  if (need_targets && target && most_hatred < WAR_THRESHOLD
+      && ai->diplomacy.player_intel[target->player_no].countdown == -1) {
+    enum war_reason war_reason;
 
-  if (target && pplayers_at_war(pplayer, target)) {
-    ai->diplomacy.countdown = 0; /* cosmetic */
-  }
-  if (target && !pplayers_at_war(pplayer, target)
-      && ai->diplomacy.countdown <= 0
-      && !ai_handicap(pplayer, H_AWAY)) {
     if (pplayers_allied(pplayer, target)) {
-      DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Went to war against %s, who is "
-                 "an ally!", target->name); /* Oh, my. */
+      DIPLO_LOG(LOG_DEBUG, pplayer, target, "Plans war against an ally!");
     }
     if (pplayer->diplstates[target->player_no].has_reason_to_cancel > 0) {
       /* We have good reason */
-      notify(target, _("*%s (AI)* Your despicable actions will not go "
-             "unpunished!"), pplayer->name);
+      war_reason = WAR_REASON_EXCUSE;
     } if (pplayer->ai.love[target->player_no] < 0) {
-      /* We have a reason of sorts from way back. */
-      notify(target, _("*%s (AI)* Finally I get around to you! Did "
-             "you really think you could get away with your crimes?"),
-             pplayer->name);
+      /* We have a reason of sorts from way back, maybe? */
+      war_reason = WAR_REASON_HATRED;
     } else {
       /* We have no legimitate reason... So what? */
-      notify(target, _("*%s (AI)* Peace in ... some other time"),
-             pplayer->name);
+      war_reason = WAR_REASON_NONE;
     }
-    ai_go_to_war(pplayer, ai, target);
+    DIPLO_LOG(LOG_DEBUG, pplayer, target, "plans war for spoils");
+    war_countdown(pplayer, target, 4 + map.size, war_reason);
   }
 
   /*** Declare war - against enemies of allies ***/
@@ -1208,19 +1296,37 @@
 
     if (aplayer->is_alive
         && adip->at_war_with_ally
+        && adip->countdown == -1
         && !adip->is_allied_with_ally
         && !pplayers_at_war(pplayer, aplayer)
        && (pplayer_get_diplstate(pplayer, aplayer)->type != DS_CEASEFIRE || 
            myrand(5) < 1)) {
-      notify(aplayer, _("*%s (AI)* Your aggression against %s was "
-                       "your last mistake!"),
-                       pplayer->name,
-                       adip->at_war_with_ally->name);
-      ai_go_to_war(pplayer, ai, aplayer);
+      DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "plans war to help ally %s",
+                adip->at_war_with_ally->name);
+      war_countdown(pplayer, aplayer, 2 + map.size, WAR_REASON_ALLIANCE);
+    }
+  } players_iterate_end;
+
+  /*** Actually declare war (when we have moved units into position) ***/
+
+  players_iterate(aplayer) {
+    struct ai_dip_intel *adip = 
+                        &ai->diplomacy.player_intel[aplayer->player_no];
+
+    if (adip->countdown > 0) {
+      adip->countdown--;
+    } else if (adip->countdown == 0) {
+      if (!WAR(pplayer, aplayer)) {
+        DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "Declaring war!");
+        ai_go_to_war(pplayer, ai, aplayer, adip->war_reason);
+      }
+    } else if (adip->countdown < -1) {
+      /* negative countdown less than -1 is war stubbornness */
+      adip->countdown++;
     }
   } players_iterate_end;
 
-  /*** Opportunism, Inc. Try to make peace with everyone else ***/
+  /*** Try to make peace with everyone we love ***/
 
   players_iterate(aplayer) {
     enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;
@@ -1248,6 +1354,7 @@
         || aplayer == pplayer
         || aplayer == target     /* no mercy */
         || !aplayer->is_alive
+        || adip->countdown >= 0
         || !could_meet_with_player(pplayer, aplayer)
         || adip->at_war_with_ally) {
       continue;
@@ -1280,13 +1387,26 @@
       ai_share(pplayer, aplayer);
       break;
     case DS_ALLIANCE:
-      if (players_on_same_team(pplayer, aplayer)
-          || (target && (!pplayers_at_war(pplayer, target)
-              || pplayers_at_war(aplayer, target)))) {
-        /* Share techs only with team mates and _reliable_ allies.
-         * This means, if we have a target, then unless we are still
-         * in countdown mode, we _except_ our allies to be at war
-         * with our target too! */
+      /* See if our allies are diligently declaring war on our enemies... */
+      target = NULL;
+      players_iterate(eplayer) {
+        int e = eplayer->player_no;
+
+        /* Read the countdown check below carefully... Note that we check
+         * our ally's intentions directly here. */
+        if (WAR(pplayer, eplayer)
+            && (ai_data_get(aplayer)->diplomacy.player_intel[e].countdown 
+                == -1)
+                && !pplayers_at_war(aplayer, eplayer)) {
+          target = eplayer;
+          break;
+        }
+      } players_iterate_end;
+
+      if ((players_on_same_team(pplayer, aplayer)
+          || pplayer->ai.love[aplayer->player_no] > MAX_AI_LOVE / 2)
+          && !target) {
+        /* Share techs only with team mates and allies we really like. */
         ai_share(pplayer, aplayer);
         adip->ally_patience = 0;
         break;
@@ -1294,14 +1414,7 @@
         adip->ally_patience = 0;
         break;
       }
-      if (target && pplayer->ai.control) {
-        DIPLO_LOG(LOG_DIPL2, pplayer, ai, "Ally %s not at war with enemy %s "
-                  "(patience %d, %s %s)", aplayer->name, 
-                  target->name, adip->ally_patience, adip->at_war_with_ally
-                  ? "war_with_ally" : "", adip->is_allied_with_ally ? 
-                  "allied_with_ally" : "");
 
-      }
       switch (adip->ally_patience--) {
         case 0:
           notify(aplayer, _("*%s (AI)* Greetings our most trustworthy "
@@ -1318,8 +1431,7 @@
                  "alliance, and yet you remain at peace with our mortal "
                  "enemy, %s! This is unacceptable, our alliance is no "
                  "more!"), pplayer->name, target->name);
-          DIPLO_LOG(LOG_DIPL2, pplayer, ai, "breaking useless alliance with "
-                    "%s", aplayer->name);
+          DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "breaking useless alliance");
          /* to peace */
          handle_diplomacy_cancel_pact(pplayer, aplayer->player_no,
                                       CLAUSE_ALLIANCE);
@@ -1337,15 +1449,14 @@
       clause.type = CLAUSE_ALLIANCE;
       if (ai_goldequiv_clause(pplayer, aplayer,
                               &clause, ai, FALSE, DS_ALLIANCE) < 0
-          || (adip->asked_about_alliance > 0 && !aplayer->ai.control)
-          || !target) {
-        /* Note that we don't ever ask for alliance unless we have a target */
+          || (adip->asked_about_alliance > 0 && !aplayer->ai.control)) {
         break; 
       }
       ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_ALLIANCE, 0);
       adip->asked_about_alliance = !aplayer->ai.control ? 13 : 0;
       notify(aplayer, _("*%s (AI)* Greetings friend, may we suggest "
-             "a joint campaign against %s?"), pplayer->name, target->name);
+             "making a common cause and join in an alliance?"), 
+             pplayer->name);
       break;
 
     case DS_CEASEFIRE:
@@ -1353,15 +1464,13 @@
       clause.type = CLAUSE_PEACE;
       if (ai_goldequiv_clause(pplayer, aplayer, &clause,
                               ai, FALSE, CLAUSE_PEACE) < 0
-          || (adip->asked_about_peace > 0 && !aplayer->ai.control)
-          || !target) {
-        /* Note that we don't ever ask for peace unless we have a target */
+          || (adip->asked_about_peace > 0 && !aplayer->ai.control)) {
         break; /* never */
       }
       ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_PEACE, 0);
       adip->asked_about_peace = !aplayer->ai.control ? 12 : 0;
       notify(aplayer, _("*%s (AI)* Greetings neighbour, may we suggest "
-             "a joint campaign against %s?"), pplayer->name, target->name);
+             "more peaceful relations?"), pplayer->name);
       break;
 
     case DS_NO_CONTACT: /* but we do have embassy! weird. */
@@ -1369,15 +1478,14 @@
       clause.type = CLAUSE_CEASEFIRE;
       if (ai_goldequiv_clause(pplayer, aplayer,
                               &clause, ai, FALSE, CLAUSE_CEASEFIRE) < 0
-          || (adip->asked_about_ceasefire > 0 && !aplayer->ai.control)
-          || !target) {
+          || (adip->asked_about_ceasefire > 0 && !aplayer->ai.control)) {
         break; /* Fight until the end! */
       }
       ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_CEASEFIRE, 0);
       adip->asked_about_ceasefire = !aplayer->ai.control ? 9 : 0;
-      notify(aplayer, _("*%s (AI)* %s is threatening us both, may we "
-             "suggest a cessation of hostilities?"), pplayer->name,
-             target->name);
+      notify(aplayer, _("*%s (AI)* we grow weary of this constant "
+             "bloodshed, may we suggest a cessation of hostilities?"), 
+             pplayer->name);
       break;
     default:
       die("Unknown pact type");
@@ -1386,6 +1494,23 @@
   } players_iterate_end;
 }
 
+/********************************************************************** 
+  Are we going to be declaring war in a few turns time?  If so, go
+  on a war footing, and try to buy out as many units as possible.
+***********************************************************************/
+bool ai_on_war_footing(struct player *pplayer)
+{
+  struct ai_data *ai = ai_data_get(pplayer);
+
+  players_iterate(plr) {
+    if (ai->diplomacy.player_intel[plr->player_no].countdown >= 0) {
+      return TRUE;
+    }
+  } players_iterate_end;
+
+  return FALSE;
+}
+
 /* AI attitude call-backs */
 
 /********************************************************************** 
@@ -1396,6 +1521,10 @@
 {
   if (violator == victim) {
     players_iterate(pplayer) {
+      if (!pplayer->ai.control) {
+        continue;
+      }
+
       if (pplayer != violator) {
         pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 20;
       }
@@ -1403,6 +1532,10 @@
     return;
   } else {
     players_iterate(pplayer) {
+      if (!pplayer->ai.control) {
+        continue;
+      }
+
       if (pplayer != violator) {
         pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 10;
         if (victim == pplayer) {
@@ -1419,6 +1552,10 @@
 void ai_incident_diplomat(struct player *violator, struct player *victim)
 {
   players_iterate(pplayer) {
+    if (!pplayer->ai.control) {
+      continue;
+    }
+
     if (pplayer != violator) {
       /* Dislike backstabbing bastards */
       pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 100;
@@ -1440,6 +1577,10 @@
 void ai_incident_war(struct player *violator, struct player *victim)
 {
   players_iterate(pplayer) {
+    if (!pplayer->ai.control) {
+      continue;
+    }
+
     if (pplayer != violator) {
       /* Dislike backstabbing bastards */
       pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 30;
@@ -1454,6 +1595,16 @@
       if (victim == pplayer) {
         pplayer->ai.love[violator->player_no] -= 
           MIN(pplayer->ai.love[violator->player_no] - MAX_AI_LOVE / 3, -1);
+        /* Scream for help!! */
+        players_iterate(ally) {
+          if (!pplayers_allied(pplayer, ally) || !ally->is_alive) {
+            continue;
+          }
+          notify(ally, _("*%s (AI)* We have been savagely attacked by  "
+                         "%s, and we need your help!  Honour our glorious "
+                         "alliance and your name will never be forgotten!"),
+                         victim->name, violator->name);
+        } players_iterate_end;
       }
     }
   } players_iterate_end;
Index: ai/advdiplomacy.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdiplomacy.h,v
retrieving revision 1.4
diff -u -r1.4 advdiplomacy.h
--- ai/advdiplomacy.h   20 Jul 2005 18:28:48 -0000      1.4
+++ ai/advdiplomacy.h   28 Jul 2005 13:09:49 -0000
@@ -20,6 +20,11 @@
 struct Clause;
 struct ai_data;
 
+enum war_reason {
+  WAR_REASON_BEHAVIOUR, WAR_REASON_SPACE, WAR_REASON_EXCUSE,
+  WAR_REASON_HATRED, WAR_REASON_ALLIANCE, WAR_REASON_NONE
+};
+
 void ai_diplomacy_begin_new_phase(struct player *pplayer,
                                  struct ai_data *ai);
 void ai_diplomacy_actions(struct player *pplayer);
@@ -33,4 +38,6 @@
 void ai_incident_diplomat(struct player *violator, struct player *victim);
 void ai_incident_nuclear(struct player *violator, struct player *victim);
 
+bool ai_on_war_footing(struct player *pplayer);
+
 #endif
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.233
diff -u -r1.233 aicity.c
--- ai/aicity.c 26 Jul 2005 17:21:53 -0000      1.233
+++ ai/aicity.c 28 Jul 2005 13:09:50 -0000
@@ -933,6 +933,7 @@
 static void ai_city_choose_build(struct player *pplayer, struct city *pcity)
 {
   struct ai_choice newchoice;
+  struct ai_data *ai = ai_data_get(pplayer);
 
   init_choice(&newchoice);
 
@@ -947,7 +948,9 @@
     ai_barbarian_choose_build(pplayer, &(pcity->ai.choice));
   } else {
     /* FIXME: 101 is the "overriding military emergency" indicator */
-    if (pcity->ai.choice.want <= 100 || pcity->ai.urgency == 0) { 
+    if ((pcity->ai.choice.want <= 100 || pcity->ai.urgency == 0)
+        && !(ai_on_war_footing(pplayer) && pcity->ai.choice.want > 0
+             && pcity->id != ai->wonder_city)) {
       domestic_advisor_choose_build(pplayer, pcity, &newchoice);
       copy_if_better_choice(&newchoice, &(pcity->ai.choice));
     }
@@ -1046,11 +1049,10 @@
   unit_list_iterate(pcity->tile->units, punit) {
     struct unit_type *punittype = can_upgrade_unittype(pplayer, punit->type);
 
-    if (military && (!is_military_unit(punit) || !is_ground_unit(punit))) {
+    if (military && !IS_ATTACKER(punit)) {
       /* Only upgrade military units this round */
       continue;
-    } else if (!military && is_military_unit(punit)
-               && unit_type(punit)->transport_capacity == 0) {
+    } else if (!military && IS_ATTACKER(punit)) {
       /* Only civilians or tranports this round */
       continue;
     }
@@ -1081,6 +1083,7 @@
 {
   struct ai_choice bestchoice;
   int cached_limit = ai_gold_reserve(pplayer);
+  bool war_footing = ai_on_war_footing(pplayer);
 
   /* Disband explorers that are at home but don't serve a purpose. 
    * FIXME: This is a hack, and should be removed once we
@@ -1132,6 +1135,7 @@
       } else {
         /* If we have urgent want, spend more */
         int upgrade_limit = limit;
+
         if (pcity->ai.urgency > 1) {
           upgrade_limit = pplayer->ai.est_upkeep;
         }
@@ -1160,10 +1164,12 @@
         /* Don't buy settlers in size 1 cities unless we grow next turn */
         continue;
       } else if (city_list_size(pplayer->cities) > 6) {
-          /* Don't waste precious money buying settlers late game
-           * since this raises taxes, and we want science. Adjust this
-           * again when our tax algorithm is smarter. */
-          continue;
+        /* Don't waste precious money buying settlers late game
+         * since this raises taxes, and we want science. Adjust this
+         * again when our tax algorithm is smarter. */
+        continue;
+      } else if (war_footing) {
+        continue;
       }
     } else {
       /* We are not a settler. Therefore we increase the cash need we
@@ -1177,8 +1183,9 @@
                 || (pplayer->economic.gold - buycost < limit);
 
     if (bestchoice.type == CT_ATTACKER
-       && buycost
-       > unit_build_shield_cost(get_unit_type(bestchoice.choice)) * 2) {
+       && buycost 
+           > unit_build_shield_cost(get_unit_type(bestchoice.choice)) * 2
+        && !war_footing) {
        /* Too expensive for an offensive unit */
        continue;
     }
@@ -1214,10 +1221,12 @@
     }
   } while (TRUE);
 
-  /* Civilian upgrades now */
-  city_list_iterate(pplayer->cities, pcity) {
-    ai_upgrade_units(pcity, cached_limit, FALSE);
-  } city_list_iterate_end;
+  if (!war_footing) {
+    /* Civilian upgrades now */
+    city_list_iterate(pplayer->cities, pcity) {
+      ai_upgrade_units(pcity, cached_limit, FALSE);
+    } city_list_iterate_end;
+  }
 
   freelog(LOG_BUY, "%s wants to keep %d in reserve (tax factor %d)", 
           pplayer->name, cached_limit, pplayer->ai.maxbuycost);
@@ -1258,6 +1267,9 @@
     TIMING_LOG(AIT_CITY_MILITARY, TIMER_START);
     military_advisor_choose_build(pplayer, pcity, &pcity->ai.choice);
     TIMING_LOG(AIT_CITY_MILITARY, TIMER_STOP);
+    if (ai_on_war_footing(pplayer) && pcity->ai.choice.want > 0) {
+      continue; /* Go, soldiers! */
+    }
     /* Will record its findings in pcity->settler_want */ 
     TIMING_LOG(AIT_CITY_TERRAIN, TIMER_START);
     contemplate_terrain_improvements(pcity);
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.75
diff -u -r1.75 aidata.c
--- ai/aidata.c 26 Jul 2005 17:21:53 -0000      1.75
+++ ai/aidata.c 28 Jul 2005 13:09:50 -0000
@@ -226,8 +226,6 @@
   struct ai_data *ai = &aidata[pplayer->player_no];
   int i, nuke_units = num_role_units(F_NUCLEAR);
   bool danger_of_nukes = FALSE;
-  int ally_strength = -1;
-  struct player *ally_strongest = NULL;
 
   /*** Threats ***/
 
@@ -399,14 +397,6 @@
     ai->diplomacy.player_intel[i].at_war_with_ally = NULL;
     ai->diplomacy.player_intel[i].is_allied_with_ally = NULL;
 
-    /* Determine who is the leader of our alliance. That is,
-     * whoever has the more cities. */
-    if (pplayers_allied(pplayer, aplayer)
-        && city_list_size(aplayer->cities) > ally_strength) {
-      ally_strength = city_list_size(aplayer->cities);
-      ally_strongest = aplayer;
-    }
-
     players_iterate(check_pl) {
       if (check_pl == pplayer
           || check_pl == aplayer
@@ -427,9 +417,6 @@
       }
     } players_iterate_end;
   }
-  if (ally_strongest != ai->diplomacy.alliance_leader) {
-    ai->diplomacy.alliance_leader = ally_strongest;
-  }
   ai->diplomacy.spacerace_leader = player_leading_spacerace();
   
   ai->diplomacy.production_leader = NULL;
@@ -586,19 +573,18 @@
         (game.control.government_count + 1) * sizeof(*ai->government_want));
 
   ai->wonder_city = 0;
-  ai->diplomacy.target = NULL;
   ai->diplomacy.strategy = WIN_OPEN;
   ai->diplomacy.timer = 0;
-  ai->diplomacy.countdown = 0;
   ai->diplomacy.love_coeff = 4; /* 4% */
-  ai->diplomacy.love_incr = MAX_AI_LOVE * 4 / 100;
-  ai->diplomacy.req_love_for_peace = MAX_AI_LOVE * 8 / 100;
-  ai->diplomacy.req_love_for_alliance = MAX_AI_LOVE * 16 / 100;
+  ai->diplomacy.love_incr = MAX_AI_LOVE * 3 / 100;
+  ai->diplomacy.req_love_for_peace = MAX_AI_LOVE / 8;
+  ai->diplomacy.req_love_for_alliance = MAX_AI_LOVE / 4;
   ai->diplomacy.req_love_for_ceasefire = 0;
-  ai->diplomacy.alliance_leader = pplayer;
 
   for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
     ai->diplomacy.player_intel[i].spam = i % 5; /* pseudorandom */
+    ai->diplomacy.player_intel[i].countdown = -1;
+    ai->diplomacy.player_intel[i].war_reason = WAR_REASON_NONE;
     ai->diplomacy.player_intel[i].distance = 1;
     ai->diplomacy.player_intel[i].ally_patience = 0;
     pplayer->ai.love[i] = 1;
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.32
diff -u -r1.32 aidata.h
--- ai/aidata.h 26 Jul 2005 17:21:53 -0000      1.32
+++ ai/aidata.h 28 Jul 2005 13:09:51 -0000
@@ -21,6 +21,8 @@
 #include "fc_types.h"
 #include "improvement.h"
 
+#include "advdiplomacy.h"
+
 /* 
  * This file and aidata.c contains global data structures for the AI
  * and some of the functions that fill them with useful values at the 
@@ -49,6 +51,8 @@
 
   char spam;      /* timer to avoid spamming a player with chat */
   int distance;   /* average distance to that player's cities */
+  int countdown;  /* we're on a countdown to war declaration */
+  enum war_reason war_reason; /* why we declare war */
   char ally_patience; /* we EXPECT our allies to help us! */
   char asked_about_peace;     /* don't ask again */
   char asked_about_alliance;  /* don't nag! */
@@ -70,14 +74,11 @@
     struct ai_dip_intel player_intel[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
     enum winning_strategy strategy;
     int timer; /* pursue our goals with some stubbornness, in turns */
-    int countdown;          /* countdown to we actually declare war */
-    struct player *target;    /* Concentrate on this player */
     char love_coeff;          /* Reduce love with this % each turn */
     char love_incr;           /* Modify love with this fixed amount */
     int req_love_for_peace;
     int req_love_for_alliance;
     int req_love_for_ceasefire;
-    struct player *alliance_leader; /* Who is leading our alliance */
     struct player *spacerace_leader; /* who is leading the space pack */
     struct player *production_leader;
   } diplomacy;
Index: ai/aihand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aihand.c,v
retrieving revision 1.118
diff -u -r1.118 aihand.c
--- ai/aihand.c 29 Jun 2005 08:21:25 -0000      1.118
+++ ai/aihand.c 28 Jul 2005 13:09:51 -0000
@@ -242,7 +242,7 @@
 
   /* Ok, we now have the desired tax and luxury rates. Do we really want
    * science? If not, swap it with tax if it is bigger. */
-  if (ai_wants_no_science(pplayer)
+  if ((ai_wants_no_science(pplayer) || ai_on_war_footing(pplayer))
       && pplayer->economic.science > pplayer->economic.tax) {
     int science = pplayer->economic.science;
     /* Swap science and tax */
Index: ai/ailog.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/ailog.c,v
retrieving revision 1.28
diff -u -r1.28 ailog.c
--- ai/ailog.c  7 May 2005 13:35:25 -0000       1.28
+++ ai/ailog.c  28 Jul 2005 13:09:51 -0000
@@ -76,37 +76,32 @@
 
 /**************************************************************************
   Log player messages, they will appear like this
-    2: perrin [ti12 co6 lo5 e]  Increased love for a (now 9)
+    
   where ti is timer, co countdown and lo love for target, who is e.
 **************************************************************************/
-void DIPLO_LOG(int level, struct player *pplayer, struct ai_data *ai, 
+void DIPLO_LOG(int level, struct player *pplayer, struct player *aplayer,
                const char *msg, ...)
 {
-  char targetbuffer[250];
   char buffer[500];
   char buffer2[500];
   va_list ap;
   int minlevel = MIN(LOGLEVEL_PLAYER, level);
+  struct ai_data *ai;
+  struct ai_dip_intel *adip;
 
   if (BV_ISSET(pplayer->debug, PLAYER_DEBUG_DIPLOMACY)) {
     minlevel = LOG_NORMAL;
   } else if (minlevel > fc_log_level) {
     return;
   }
+  ai = ai_data_get(pplayer);
+  adip = &ai->diplomacy.player_intel[aplayer->player_no];
 
-  if (ai->diplomacy.target) {
-    my_snprintf(targetbuffer, sizeof(targetbuffer), "[ti%d co%d lo%d %s] ",
-                ai->diplomacy.timer, ai->diplomacy.countdown,
-                pplayer->ai.love[ai->diplomacy.target->player_no],
-                ai->diplomacy.target->name);
-  }
-  my_snprintf(buffer, sizeof(buffer), "%s %s%s%s ", pplayer->name,
-              ai->diplomacy.target ? targetbuffer : "",
-              ai->diplomacy.spacerace_leader &&
-              ai->diplomacy.spacerace_leader->player_no == pplayer->player_no 
? 
-                "(spacelead) " : "",
-              ai->diplomacy.alliance_leader->player_no == pplayer->player_no ?
-                "(*)" : "");
+  my_snprintf(buffer, sizeof(buffer), "%s->%s(l%d,c%d,d%d%s): ", 
+              pplayer->name, aplayer->name, 
+              pplayer->ai.love[aplayer->player_no], adip->countdown, 
+              adip->distance, adip->is_allied_with_enemy ? "?" :
+              (adip->at_war_with_ally ? "!" : ""));
 
   va_start(ap, msg);
   my_vsnprintf(buffer2, sizeof(buffer2), msg, ap);
Index: ai/ailog.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/ailog.h,v
retrieving revision 1.14
diff -u -r1.14 ailog.h
--- ai/ailog.h  7 May 2005 13:35:25 -0000       1.14
+++ ai/ailog.h  28 Jul 2005 13:09:51 -0000
@@ -74,7 +74,7 @@
 void TECH_LOG(int level, struct player *pplayer, Tech_type_id id,
               const char *msg, ...)
      fc__attribute((format (printf, 4, 5)));
-void DIPLO_LOG(int level, struct player *pplayer, struct ai_data *ai,
+void DIPLO_LOG(int level, struct player *pplayer, struct player *aplayer,
                const char *msg, ...)
      fc__attribute((format (printf, 4, 5)));
 void CITY_LOG(int level, struct city *pcity, const char *msg, ...)
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.158
diff -u -r1.158 aitools.c
--- ai/aitools.c        25 Jul 2005 11:58:33 -0000      1.158
+++ ai/aitools.c        28 Jul 2005 13:09:52 -0000
@@ -123,7 +123,7 @@
 
   return (pplayer != aplayer
           && (pplayers_at_war(pplayer, aplayer)
-              || ai->diplomacy.target == aplayer
+              || adip->countdown >= 0
               || reason != 0
               || adip->is_allied_with_enemy));
 }
@@ -1159,6 +1159,8 @@
   choice->want = want;
   choice->choice = id;
   choice->type = CT_BUILDING;
+  CITY_LOG(LOG_DEBUG, pcity, "wants most to build %s at %d",
+           get_improvement_name(id), want);
 }
 
 /**********************************************************************
Index: ai/aiunit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.h,v
retrieving revision 1.60
diff -u -r1.60 aiunit.h
--- ai/aiunit.h 22 Jul 2005 16:18:04 -0000      1.60
+++ ai/aiunit.h 28 Jul 2005 13:09:52 -0000
@@ -25,7 +25,14 @@
  */
 #define POWER_DIVIDER  (POWER_FACTOR * 3)
 
-/* Simple military power macros */
+/* Simple military macros */
+
+/* pplayers_at_war() thinks no contacts equals war, which often is
+ * very annoying. */
+#define WAR(plr1, plr2) \
+  (plr1->diplstates[plr2->player_no].type == DS_WAR)
+#define NEVER_MET(plr1, plr2) \
+  (plr1->diplstates[plr2->player_no].type == DS_NO_CONTACT)
 #define DEFENCE_POWER(punit) \
  (unit_type(punit)->defense_strength * unit_type(punit)->hp \
   * unit_type(punit)->firepower)
@@ -36,8 +43,8 @@
   (unit_type(punit)->attack_strength \
         > unit_type(punit)->transport_capacity)
 #define HOSTILE_PLAYER(pplayer, ai, aplayer) \
-  (pplayers_at_war(pplayer, aplayer)         \
-   || ai->diplomacy.target == aplayer)
+  (WAR(pplayer, aplayer)         \
+   || ai->diplomacy.player_intel[aplayer->player_no].countdown >= 0)
 #define UNITTYPE_COSTS(ut)                                             \
   (ut->pop_cost * 3 + ut->happy_cost                                   \
    + ut->upkeep[O_SHIELD] + ut->upkeep[O_FOOD] + ut->upkeep[O_GOLD])
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.403
diff -u -r1.403 plrhand.c
--- server/plrhand.c    22 Jul 2005 02:51:30 -0000      1.403
+++ server/plrhand.c    28 Jul 2005 13:09:59 -0000
@@ -516,6 +516,10 @@
   old_type = pplayer->diplstates[other_player_id].type;
   pplayer2 = get_player(other_player_id);
 
+  if (old_type == DS_WAR) {
+    return; /* Duh */
+  }
+
   /* can't break a pact with yourself */
   if (pplayer == pplayer2) {
     return;
@@ -568,6 +572,7 @@
     break;
   default:
     freelog(LOG_ERROR, "non-pact diplstate in handle_player_cancel_pact");
+    assert(FALSE);
     return;
   }
 
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.269
diff -u -r1.269 savegame.c
--- server/savegame.c   26 Jul 2005 16:36:00 -0000      1.269
+++ server/savegame.c   28 Jul 2005 13:10:04 -0000
@@ -1737,7 +1737,6 @@
   struct ai_data *ai;
   struct government *gov;
   int id;
-  int target_no;
   struct team *pteam;
   struct player_research *research;
 
@@ -1888,6 +1887,10 @@
          = secfile_lookup_int_default(file, 1, "player%d.ai%d.love", plrno, i);
     ai->diplomacy.player_intel[i].spam 
          = secfile_lookup_int_default(file, 0, "player%d.ai%d.spam", plrno, i);
+    ai->diplomacy.player_intel[i].countdown
+         = secfile_lookup_int_default(file, -1, "player%d.ai%d.countdown", 
plrno, i);
+    ai->diplomacy.player_intel[i].war_reason
+         = secfile_lookup_int_default(file, 0, "player%d.ai%d.war_reason", 
plrno, i);
     ai->diplomacy.player_intel[i].ally_patience
          = secfile_lookup_int_default(file, 0, "player%d.ai%d.patience", 
plrno, i);
     ai->diplomacy.player_intel[i].warned_about_space
@@ -1899,10 +1902,6 @@
     ai->diplomacy.player_intel[i].asked_about_ceasefire
          = secfile_lookup_int_default(file, 0, "player%d.ai%d.ask_ceasefire", 
plrno, i);
   }
-  /* Diplomacy target is saved as player number or -1 if none */ 
-  target_no = secfile_lookup_int_default(file, -1,
-                                         "player%d.ai.target", plrno);
-  ai->diplomacy.target = target_no == -1 ? NULL : &game.players[target_no];
 
   /* Backwards-compatibility: the tech goal value is still stored in the
    * "ai" section even though it was moved into the research struct. */
@@ -2690,6 +2689,10 @@
                        "player%d.ai%d.love", plrno, i);
     secfile_insert_int(file, ai->diplomacy.player_intel[i].spam, 
                        "player%d.ai%d.spam", plrno, i);
+    secfile_insert_int(file, ai->diplomacy.player_intel[i].countdown, 
+                       "player%d.ai%d.countdown", plrno, i);
+    secfile_insert_int(file, ai->diplomacy.player_intel[i].war_reason, 
+                       "player%d.ai%d.war_reason", plrno, i);
     secfile_insert_int(file, ai->diplomacy.player_intel[i].ally_patience, 
                        "player%d.ai%d.patience", plrno, i);
     secfile_insert_int(file, ai->diplomacy.player_intel[i].warned_about_space, 
@@ -2701,10 +2704,6 @@
     secfile_insert_int(file, 
ai->diplomacy.player_intel[i].asked_about_ceasefire, 
                        "player%d.ai%d.ask_ceasefire", plrno, i);
   }
-  secfile_insert_int(file,
-                     ai->diplomacy.target == NULL ? 
-                      -1 : ai->diplomacy.target->player_no,
-                    "player%d.ai.target", plrno);
   save_technology(file, "player%d.ai.tech_goal",
                  plrno, get_player_research(plr)->tech_goal);
   secfile_insert_int(file, plr->ai.skill_level,

[Prev in Thread] Current Thread [Next in Thread]