AI defense fix

Per Inge Mathisen <per-0/[email protected]> Tue, 5 Apr 2005 19:45:27 +0000 (GMT)
Newsgroups gmane.games.freeciv.ai
Message-ID <[email protected]>
While playtesting Benedict's don't-stack patch, I came across some rather
odd AI behaviour. This patch that I will commit immediately fixes this.

CHANGES:
 - Do not attempt to become a unit bodyguard when assigned to guard duty
   for a city. I noticed defenders defecting from defense to bodyguard,
   leaving behind totally undefended cities with enemy nearby! Yikes.
 - Do not yoyo between cities attempting to defend them all.
   look_for_charge() has the problem that it calculates current defense in
   each city in the world, but forgets to calculate in that once we leave
   the city we are currently in, that city might become the most needy! So
   instead we try harder to stay where we are. (look_for_charge() is
   desperately in need of a cleanup btw)
 - When military code can't find us work to do, actually do go home. Now
   using ai_military_defend() (previously named ai_manage_gohome()). This
   stops the ridiculously looking AI behaviour of leaving units out in the
   field doing nothing when they could be defending its cities. Nevermind
   the happiness penalty!

  - Per
defense1.diff (text/plain, 2 KB)
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.349
diff -u -r1.349 aiunit.c
--- ai/aiunit.c	4 Apr 2005 21:45:48 -0000	1.349
+++ ai/aiunit.c	5 Apr 2005 19:40:32 -0000
@@ -899,6 +899,10 @@
         || unit_type(buddy)->move_type != unit_type(punit)->move_type) { 
       continue;
     }
+    if (punit->tile->city
+        && punit->ai.ai_role == AIUNIT_DEFEND_HOME) {
+      continue; /* Do not run away from defense duty! */
+    }
     dist = unit_move_turns(punit, buddy->tile);
     def = (toughness - unit_def_rating_basic_sq(buddy));
     if (def <= 0) {
@@ -921,7 +925,17 @@
    city_list_iterate(pplayer->cities, mycity) {
     if (!goto_is_sane(punit, mycity->tile, TRUE)
         || mycity->ai.urgency == 0) {
-      continue; 
+      continue;
+    }
+    if (punit->tile->city
+        && (punit->tile->city->ai.grave_danger > 0
+            || punit->tile->city->ai.urgency > mycity->ai.urgency
+            || ((punit->tile->city->ai.danger > mycity->ai.danger
+                 || punit->ai.ai_role == AIUNIT_DEFEND_HOME)
+                && mycity->ai.grave_danger == 0))) {
+      /* Do not yoyo between cities in need of defense. Chances are
+       * we'll be between cities when we are needed the most! */
+      continue;
     }
     dist = unit_move_turns(punit, mycity->tile);
     def = (mycity->ai.danger - assess_defense_quadratic(mycity));
@@ -1746,16 +1760,7 @@
     }
   }
   if ((punit = find_unit_by_id(id)) && punit->moves_left > 0) {
-    struct city *pcity = map_get_city(punit->tile);
-
-    if (pcity) {
-      punit->ai.done = TRUE;
-      UNIT_LOG(LOG_DEBUG, punit, "could not find work");
-      ai_unit_new_role(punit, AIUNIT_NONE, NULL);
-    } else {
-      UNIT_LOG(LOG_DEBUG, punit, "we are homeless and useless :(");
-      ai_unit_new_role(punit, AIUNIT_NONE, NULL);
-    }
+    ai_military_defend(pplayer, punit);
   }
 }