Complete.Org: Mailing Lists: Archives: freeciv-ai: April 2004:
[freeciv-ai] Re: paratroopers
Home

[freeciv-ai] Re: paratroopers

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Cc: freeciv-ai@xxxxxxxxxxx
Subject: [freeciv-ai] Re: paratroopers
From: Jordi Negrevernis i Font <jorneg@xxxxxxxxxxx>
Date: Tue, 06 Apr 2004 00:09:30 +0200


<<< text/html; charset=unknown-8bit: Unrecognized >>>
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore 
freeciv-cvs-Feb-27/ai/advmilitary.c 
freeciv-cvs-Feb-27-paratroop/ai/advmilitary.c
--- freeciv-cvs-Feb-27/ai/advmilitary.c 2004-02-26 07:01:21.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/advmilitary.c       2004-03-18 
02:37:15.000000000 +0100
@@ -35,6 +35,7 @@
 #include "aidiplomat.h"
 #include "aihand.h"
 #include "ailog.h"
+#include "aiparatrooper.h"
 #include "aitools.h"
 #include "aiunit.h"
 
@@ -1306,6 +1307,9 @@
   /* Consider making an airplane */
   (void) ai_choose_attacker_air(pplayer, pcity, choice);
 
+  /* Consider making a paratrooper */
+  ai_choose_paratrooper(pplayer, pcity, choice);
+
   /* Check if we want a sailing attacker. Have to put sailing first
      before we mung the seamap */
   unit_type = ai_choose_attacker(pcity, SEA_MOVING);
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore 
freeciv-cvs-Feb-27/ai/aiparatrooper.c 
freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.c
--- freeciv-cvs-Feb-27/ai/aiparatrooper.c       1970-01-01 01:00:00.000000000 
+0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.c     2004-04-05 
16:37:53.000000000 +0200
@@ -0,0 +1,389 @@
+/**********************************************************************
+ 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.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "city.h"
+#include "citytools.h"
+#include "log.h"
+#include "pf_tools.h"
+#include "player.h"
+#include "unit.h"
+#include "unittools.h"
+
+#include "ailog.h"
+#include "aiparatrooper.h"
+#include "aiunit.h"
+#include "aitools.h"
+
+#define LOGLEVEL_PARATROOPER LOG_NORMAL
+
+/**********************************************************************
+  Find own city to go there to recover and paradroop.
+
+  TODO: Actually check how safe the city is. This is a difficult
+  decision not easily taken, since we also want to protect unsafe
+  cities, at least most of the time.
+**********************************************************************/
+static struct city *find_nearest_own_city_at(struct player *pplayer,
+                                             int x, int y)
+{ int best = 0, cur = 100;
+  int continent = map_get_continent(x, y);
+  struct city *acity = NULL;
+
+  city_list_iterate(pplayer->cities, pcity) {
+    cur = real_map_distance(pcity->x, pcity->y, x ,y);
+    if (city_got_building(pcity, B_BARRACKS)
+       || city_got_building(pcity, B_BARRACKS2)
+       || city_got_building(pcity, B_BARRACKS3)) {
+      cur /= 3;
+    }
+    if (continent != map_get_continent(pcity->x, pcity->y)) {
+      /* it must be in the same continent */
+      cur = 0;
+    }
+    if (cur < best && (cur > 0) ) {
+      best = cur;
+      acity = pcity;
+    }
+  } city_list_iterate_end;
+
+  return acity;
+}
+
+/**********************************************************************
+ This function does manage the paratrooper units of the AI.
+ 1st.- checks for cities left alone without defenders
+ 2nd.- checks for enemy cities left alone
+ 3th.- checks for enemy units in range
+**********************************************************************/
+void ai_manage_paratrooper(struct player *pplayer, struct unit *punit)
+{
+  struct city *pcity = map_get_city(punit->x, punit->y);
+  struct city *acity = NULL;
+  int sanity = punit->id;
+  int x_dest = 0, y_dest = 0, best = 0;
+
+  CHECK_UNIT(punit);
+
+  /* defend attacking (and be opportunistic too)*/
+  if (!ai_military_rampage(punit, RAMPAGE_ANYTHING,
+                           RAMPAGE_FREE_CITY_OR_BETTER)) {
+    /* dead */
+    return;
+  }
+
+  /* check to recover hit points */
+  if ((punit->hp < unit_type(punit)->hp) && pcity) {
+    UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "recovering hit points.",
+             pplayer->name, unit_type(punit)->name,
+             punit->id, punit->x, punit->y);
+    return;
+  }
+
+  /* nothing to do! */
+  if (punit->moves_left == 0) {
+    return;
+  }
+
+  /* we must defend the city! */
+  if (stay_and_defend(punit)) {
+    UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "defending the city.",
+             pplayer->name, unit_type(punit)->name,
+            punit->id, punit->x, punit->y);
+    return;
+  }
+
+  if (can_unit_paradrop(punit)) {
+    /* unit can paradrop, so use it! */
+    int range = unit_type(punit)->paratroopers_range;
+
+    /* first, we search for undefended cities in danger */
+    square_iterate(punit->x, punit->y, range, x, y) {
+      acity = map_get_city(x,y);
+      if ((acity) && (city_owner(acity) == pplayer) &&
+          (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+        /* own city and empty! */
+        if ((acity->size * acity->ai.urgency) > best) {
+          best = acity->size * acity->ai.urgency;
+          x_dest = acity->x; y_dest = acity->y;
+        }
+      }
+    } square_iterate_end;
+
+    /* second, we search for undefended enemy cities near us */
+    if (best == 0) {
+      square_iterate(punit->x, punit->y, range, x, y) {
+        acity = map_get_city(x,y);
+        if ((acity) && pplayers_at_war(pplayer, city_owner(acity)) &&
+            (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+          /* enemy empty city! */
+          if (acity->size > best) {
+            best = acity->size;
+            x_dest = acity->x; y_dest = acity->y;
+          }
+        }
+      } square_iterate_end;
+    }
+
+    /* third, we search for enemy units near us,
+       if we don't find any own empty city */
+    if (best == 0) {
+      square_iterate(punit->x, punit->y, range, x, y) {
+        struct tile *ptile = map_get_tile(x, y);
+        if (unit_list_size(&(ptile->units)) > 0) {
+          struct unit *pdef = unit_list_get(&ptile->units, 0);
+         if (pplayers_at_war(pplayer, unit_owner(pdef))) {
+           int benefit = stack_cost(pdef);
+            benefit = (benefit * punit->hp) / unit_type(punit)->hp;
+            if (benefit > best) {
+              /* best enemy unit to kill! */
+             best = benefit;
+             x_dest = x; y_dest = y;
+           }
+         }
+        }
+      } square_iterate_end;
+
+      if (best > 0) {
+        /* now we have the location of the enemy unit,
+          we find the best tile around it,
+          to attack him */
+       struct city *acity = find_nearest_own_city_at(unit_owner(punit),
+                                                     x_dest, y_dest);
+       int xd = 0, yd = 0, dist = 0;
+
+       if (acity) {
+         /* we continue if we find a city in that continent */
+         dist = real_map_distance(x_dest, y_dest, acity->x, acity->y);
+         best = 0;
+         square_iterate(x_dest, y_dest, 1, x, y) {
+           int rating = 0;
+           if (is_ocean(map_get_terrain(x, y))) {
+             /*  do not paradroop to ocean! */
+             continue;
+           }
+            if (is_non_allied_unit_tile(map_get_tile(x, y), pplayer)) {
+             /* do not paradroop on an enemy unit! */
+             continue;
+            }
+           if (real_map_distance(punit->x, punit->y, x, y) > range) {
+             /* do not paradroop outside the range */
+             continue;
+           }
+
+           switch(map_get_terrain(x, y)) {
+             case T_FOREST:
+             case T_HILLS:
+             case T_JUNGLE:
+               rating = 2; break;
+             case T_MOUNTAINS:
+               rating = 4; break;
+             default:
+               rating = 0; break;
+           };
+           rating += (dist - real_map_distance(x, y, acity->x, acity->y));
+
+           if (rating > best) {
+             /* we assign the best location to attack the unit */
+             best = rating;
+             xd = x; yd = y;
+           }
+
+         } square_iterate_end;
+
+          /* we assign the last best values */
+         if (best) {
+           x_dest = xd; y_dest = yd;
+         }
+       } else {
+         best = 0;
+         x_dest = 0; y_dest = 0;
+       }
+      }
+    }
+
+    if (best) {
+      /* we move the unit */
+      set_goto_dest(punit, x_dest, y_dest);
+      UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "paradroping.",
+               pplayer->name, unit_type(punit)->name,
+              punit->id, punit->x, punit->y);
+      if (do_paradrop(punit, x_dest, y_dest)) {
+        /* successfull! */
+        if (!find_unit_by_id(sanity)) {
+          /* the unit did not survive the move */
+          return;
+        }
+        /* and we attack the target */
+        (void)ai_military_rampage(punit, RAMPAGE_ANYTHING, RAMPAGE_ANYTHING);
+      }
+      if (find_unit_by_id(sanity)) {
+        clear_goto_dest(punit);
+      }
+    } else {
+      UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "dind't find objective to paradrop 
to.",
+               pplayer->name, unit_type(punit)->name,
+              punit->id, punit->x, punit->y);
+      /* go to zones in danger */
+      square_iterate(punit->x, punit->y, range, x, y) {
+        struct city *acity = map_get_city(x, y);
+        if (acity && pplayers_allied(city_owner(acity), pplayer)) {
+          if (acity->ai.danger > best) {
+            best = acity->ai.danger;
+            x_dest = acity->x; y_dest = acity->y;
+          }
+        }
+      } square_iterate_end;
+
+      if (best && ((punit->x != x_dest) && (punit->y != y_dest))) {
+        set_goto_dest(punit, x_dest, y_dest);
+        UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "moving to zones in danger.",
+                 pplayer->name, unit_type(punit)->name,
+                punit->id, punit->x, punit->y);
+        (void)do_paradrop(punit, x_dest, y_dest);
+        if (find_unit_by_id(sanity)) {
+          clear_goto_dest(punit);
+        }
+      }
+    }
+  } else {
+    /* we can't paradrop :-(  */
+    struct city *acity = NULL;
+
+    /* we are in a city, so don't try to find another */
+    if (pcity) {
+      UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "waiting in a city for next turn.",
+               pplayer->name, unit_type(punit)->name,
+              punit->id, punit->x, punit->y);
+      return;
+    }
+
+    /* find a city to go to recover and paradrop from */
+    acity = find_nearest_own_city_at(unit_owner(punit), punit->x, punit->y);
+
+    if (acity) {
+      if (!ai_unit_goto(punit, acity->x, acity->y)) {
+        /* die or unsuccessfull move */
+       return;
+      }
+    } else {
+        UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "didn't find city to go and 
recover.",
+                 pplayer->name, unit_type(punit)->name,
+                punit->id, punit->x, punit->y);
+       /* TODO: decide what to do now! */
+    }
+  }
+}
+
+/*******************************************************************
+  Computes the want for an operation
+ ******************************************************************/
+static int find_something_to_paradrop(struct unit *punit, int x, int y)
+{ int profit = 0;
+  int range = unit_type(punit)->paratroopers_range;
+  struct city *acity = NULL;
+  struct player *pplayer = unit_owner(punit);
+
+  /* first, we search for undefended cities */
+  square_iterate(punit->x, punit->y, range, x, y) {
+    acity = map_get_city(x,y);
+    if ((acity) && (city_owner(acity) == pplayer) &&
+        (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+      /* own city and empty! */
+      if ((acity->size *
+           (acity->trade_prod + acity->shield_prod + acity->food_prod) *
+           acity->ai.urgency) > profit) {
+        profit = (acity->size *
+                 (acity->trade_prod + acity->shield_prod + acity->food_prod) *
+                  acity->ai.urgency);
+      }
+    }
+  } square_iterate_end;
+
+  /* second, we search for undefended enemy cities near us */
+  square_iterate(punit->x, punit->y, range, x, y) {
+    acity = map_get_city(x,y);
+    if ((acity) && pplayers_at_war(city_owner(acity), pplayer) &&
+        (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+      /* enemy city and empty! */
+      if ((acity->size *
+           (acity->trade_prod + acity->shield_prod + acity->food_prod)) > 
profit) {
+        profit = (acity->size *
+                 (acity->trade_prod + acity->shield_prod + acity->food_prod));
+      }
+    }
+  } square_iterate_end;
+
+  /* third, we search for enemy units near us */
+  square_iterate(punit->x, punit->y, range, x, y) {
+    struct tile *ptile = map_get_tile(x, y);
+    if (unit_list_size(&(ptile->units)) > 0) {
+      struct unit *pdef = unit_list_get(&ptile->units, 0);
+      if (pplayers_at_war(pplayer, unit_owner(pdef))) {
+        int benefit = stack_cost(pdef);
+        benefit = (benefit * punit->hp) / unit_type(punit)->hp;
+        if (benefit > profit) {
+          /* best enemy unit to kill! */
+          profit = benefit;
+        }
+      }
+    }
+  } square_iterate_end;
+
+  return profit;
+}
+
+/*******************************************************************
+ * Chooses to build a paratroop if necessary
+ ******************************************************************/
+void ai_choose_paratrooper(struct player *pplayer, struct city *pcity,
+                           struct ai_choice *choice)
+{
+
+  /* military_advisor_choose_build does something idiotic,
+   * this function should not be called if there is danger... */
+  if (choice->want >= 100 && choice->type != CT_ATTACKER) {
+    return;
+  }
+
+  unit_type_iterate(u_type) {
+    if (!unit_type_flag(u_type, F_PARATROOPERS)) {
+      continue;
+    }
+
+    if (!can_build_unit(pcity, u_type)) {
+      continue;
+    }
+
+    struct unit *virtual_unit =
+      create_unit_virtual(pplayer, pcity, u_type,
+                          do_make_unit_veteran(pcity, u_type));
+    int profit = find_something_to_paradrop(virtual_unit, pcity->x, pcity->y);
+    if (profit > choice->want){
+      /* Update choice */
+      choice->want = profit;
+      choice->choice = u_type;
+      choice->type = CT_ATTACKER;
+      freelog(LOGLEVEL_PARATROOPER, "%s wants to build %s (want=%d)",
+              pcity->name, get_unit_type(u_type)->name, profit);
+    }
+    destroy_unit_virtual(virtual_unit);
+  } unit_type_iterate_end;
+
+  return;
+}
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore 
freeciv-cvs-Feb-27/ai/aiparatrooper.h 
freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.h
--- freeciv-cvs-Feb-27/ai/aiparatrooper.h       1970-01-01 01:00:00.000000000 
+0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.h     2004-03-18 
02:34:36.000000000 +0100
@@ -0,0 +1,25 @@
+/**********************************************************************
+ 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.
+***********************************************************************/
+#ifndef FC__AIPARATROOPER_H
+#define FC__AIPARATROOPER_H
+
+struct ai_choice;
+struct city;
+struct player;
+struct unit;
+
+void ai_manage_paratrooper(struct player *pplayer, struct unit *punit);
+void ai_choose_paratrooper(struct player *pplayer, struct city *pcity,
+                          struct ai_choice *choice);
+
+#endif /* FC__AIPARATROOPER_H */
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/aiunit.c 
freeciv-cvs-Feb-27-paratroop/ai/aiunit.c
--- freeciv-cvs-Feb-27/ai/aiunit.c      2004-02-26 07:01:21.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiunit.c    2004-03-30 14:26:38.000000000 
+0200
@@ -55,6 +55,7 @@
 #include "aidiplomat.h"
 #include "aihand.h"
 #include "ailog.h"
+#include "aiparatrooper.h"
 #include "aitools.h"
 
 #include "aiunit.h"
@@ -67,11 +68,6 @@
 static void ai_manage_barbarian_leader(struct player *pplayer,
                                       struct unit *leader);
 
-#define RAMPAGE_ANYTHING                 1
-#define RAMPAGE_HUT_OR_BETTER        99998
-#define RAMPAGE_FREE_CITY_OR_BETTER  99999
-static bool ai_military_rampage(struct unit *punit, int thresh_adj, 
-                                int thresh_move);
 static void ai_military_findjob(struct player *pplayer,struct unit *punit);
 static void ai_military_gohome(struct player *pplayer,struct unit *punit);
 static void ai_military_attack(struct player *pplayer,struct unit *punit);
@@ -665,7 +661,7 @@
 
   FIXME: We should check for fortresses here.
 **************************************************************************/
-static bool stay_and_defend(struct unit *punit)
+bool stay_and_defend(struct unit *punit)
 {
   struct city *pcity = map_get_city(punit->x, punit->y);
   bool has_defense = FALSE;
@@ -1052,7 +1048,7 @@
 
   Returns TRUE if survived the rampage session.
 **************************************************************************/
-static bool ai_military_rampage(struct unit *punit, int thresh_adj, 
+bool ai_military_rampage(struct unit *punit, int thresh_adj,
                                 int thresh_move)
 {
   int count = punit->moves_left + 1; /* break any infinite loops */
@@ -2653,6 +2649,9 @@
   } else if (unit_has_role(punit->type, L_BARBARIAN_LEADER)) {
     ai_manage_barbarian_leader(pplayer, punit);
     return;
+  } else if (unit_flag(punit, F_PARATROOPERS)) {
+    ai_manage_paratrooper(pplayer, punit);
+    return;
   } else if (get_transporter_capacity(punit) > 0) {
     ai_manage_ferryboat(pplayer, punit);
     return;
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/aiunit.h 
freeciv-cvs-Feb-27-paratroop/ai/aiunit.h
--- freeciv-cvs-Feb-27/ai/aiunit.h      2004-01-12 07:16:15.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiunit.h    2004-03-30 14:27:31.000000000 
+0200
@@ -46,6 +46,11 @@
 
 extern Unit_Type_id simple_ai_types[U_LAST];
 
+#define RAMPAGE_ANYTHING                 1
+#define RAMPAGE_HUT_OR_BETTER        99998
+#define RAMPAGE_FREE_CITY_OR_BETTER  99999
+bool ai_military_rampage(struct unit *punit, int thresh_adj,
+                         int thresh_move);
 void ai_manage_units(struct player *pplayer); 
 int could_unit_move_to_tile(struct unit *punit, int dest_x, int dest_y);
 int look_for_charge(struct player *pplayer, struct unit *punit,
@@ -64,6 +69,7 @@
                     int *x, int *y);
 
 int build_cost_balanced(Unit_Type_id type);
+bool stay_and_defend(struct unit *punit);
 int unittype_att_rating(Unit_Type_id type, int veteran,
                         int moves_left, int hp);
 int unit_att_rating(struct unit *punit);
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/Makefile.am 
freeciv-cvs-Feb-27-paratroop/ai/Makefile.am
--- freeciv-cvs-Feb-27/ai/Makefile.am   2003-09-22 07:00:04.000000000 +0200
+++ freeciv-cvs-Feb-27-paratroop/ai/Makefile.am 2004-03-18 01:07:19.000000000 
+0100
@@ -25,6 +25,8 @@
                aihand.h        \
                ailog.c         \
                ailog.h         \
+               aiparatrooper.c \
+               aiparatrooper.h \
                aitech.c        \
                aitech.h        \
                aitools.c       \

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