Complete.Org: Mailing Lists: Archives: freeciv-ai: July 2005:
[freeciv-ai] Paratroopers
Home

[freeciv-ai] Paratroopers

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-ai@xxxxxxxxxxx
Subject: [freeciv-ai] Paratroopers
From: Jordi Negrevernis i Font <jorneg@xxxxxxxxxxx>
Date: Fri, 01 Jul 2005 22:55:21 +0200


If so one wants to play with the paratroppers patch I send the version syncred with Freeciv 2.0.2.

diff -u -r --new-file -Xfreeciv-cvs-Jun-14/diff_ignore 
freeciv-2.0.2/ai/advmilitary.c freeciv-2.0.2-paratroop/ai/advmilitary.c
--- freeciv-2.0.2/ai/advmilitary.c      2005-04-01 06:10:16.000000000 +0200
+++ freeciv-2.0.2-paratroop/ai/advmilitary.c    2005-06-29 00:39:57.000000000 
+0200
@@ -36,6 +36,7 @@
 #include "aihand.h"
 #include "aihunt.h"
 #include "ailog.h"
+#include "aiparatrooper.h"
 #include "aitools.h"
 #include "aiunit.h"
 
@@ -1367,6 +1368,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 -u -r --new-file -Xfreeciv-cvs-Jun-14/diff_ignore 
freeciv-2.0.2/ai/aiparatrooper.c freeciv-2.0.2-paratroop/ai/aiparatrooper.c
--- freeciv-2.0.2/ai/aiparatrooper.c    1970-01-01 01:00:00.000000000 +0100
+++ freeciv-2.0.2-paratroop/ai/aiparatrooper.c  2005-06-30 13:21:55.000000000 
+0200
@@ -0,0 +1,383 @@
+/**********************************************************************
+ 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, struct 
tile *ptile)
+{ int best = 100, cur = 100;
+  Continent_id con = map_get_continent(ptile);
+  struct city *acity = NULL;
+
+  city_list_iterate(pplayer->cities, pcity) {
+    cur = real_map_distance(pcity->tile, ptile);
+    if (get_city_bonus(pcity, EFT_LAND_REGEN) > 0) {
+      cur /= 3;
+    }
+    if (con != map_get_continent(pcity->tile)) {
+      /* 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->tile);
+  struct city *acity = NULL;
+  struct tile *ptile_dest = NULL;
+  int sanity = punit->id;
+  int 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.");
+    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.");
+    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->tile, range, ptile) {
+      acity = map_get_city(ptile);
+      if ((acity) && (city_owner(acity) == pplayer) &&
+          (unit_list_size(&(ptile->units)) == 0)) {
+        /* own city and empty! */
+        if ((acity->size * acity->ai.urgency) > best) {
+          best = acity->size * acity->ai.urgency;
+          ptile_dest = ptile;
+        }
+      }
+    } square_iterate_end;
+
+    /* second, we search for undefended enemy cities near us */
+    if (best == 0) {
+      square_iterate(punit->tile, range, ptile) {
+        acity = map_get_city(ptile);
+        if ((acity) && pplayers_at_war(pplayer, city_owner(acity)) &&
+            (unit_list_size(&(ptile->units)) == 0)) {
+          /* enemy empty city! */
+          if (acity->size > best) {
+            best = acity->size;
+            ptile_dest = ptile;
+          }
+        }
+      } 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->tile, range, ptile) {
+        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;
+             ptile_dest = ptile;
+           }
+         }
+        }
+      } square_iterate_end;
+
+      if (best > 0) {
+        /* now we have the location of the enemy unit or empty city ,
+          we find the best tile around it,
+          to attack him */
+       struct city *acity = find_nearest_own_city_at(unit_owner(punit), 
ptile_dest);
+       struct tile *ptile_best = NULL;
+       int dist = 0;
+
+       if (acity) {
+         /* we continue only if we find a city in that continent */
+         dist = real_map_distance(ptile_dest, acity->tile);
+         best = 0;
+         square_iterate(ptile_dest, 1, ptile) {
+           int rating = 0;
+           if (is_ocean(map_get_terrain(ptile))) {
+             /*  do not paradroop to ocean! */
+             continue;
+           }
+            if (is_non_allied_unit_tile(ptile, pplayer)) {
+             /* do not paradroop on an enemy unit! */
+             continue;
+            }
+           if (real_map_distance(punit->tile, ptile) > range) {
+             /* do not paradroop outside the range */
+             continue;
+           }
+
+           rating = get_tile_type(ptile->terrain)->defense_bonus +
+                    (dist - real_map_distance(ptile, acity->tile));
+
+           if (rating > best) {
+             /* we assign the best location to attack the unit */
+             best = rating;
+             ptile_best= ptile;
+           }
+
+         } square_iterate_end;
+
+          /* we assign the last best values */
+         if (best) {
+           ptile_dest = ptile_best;
+         }
+       } else {
+         best = 0;
+         ptile_dest = NULL;
+       }
+      }
+    }
+
+    if (best) {
+      /* we move the unit */
+      UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "paradroping.");
+      if (do_paradrop(punit, ptile_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);
+      }
+    } else {
+      UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "dind't find objective to paradrop 
to.");
+      /* go to zones in danger */
+      square_iterate(punit->tile, range, ptile) {
+        struct city *acity = map_get_city(ptile);
+        if (acity && pplayers_allied(city_owner(acity), pplayer)) {
+          if (acity->ai.danger > best) {
+            best = acity->ai.danger;
+            ptile_dest = acity->tile;
+          }
+        }
+      } square_iterate_end;
+
+      if (best && (!same_pos(punit->tile, ptile_dest))) {
+        UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "moving to zones in danger.");
+        (void)do_paradrop(punit, ptile_dest);
+      }
+    }
+  } 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.");
+      return;
+    }
+
+    /* find a city to go to recover and paradrop from */
+    acity = find_nearest_own_city_at(unit_owner(punit), punit->tile);
+
+    if (acity) {
+      if (!ai_unit_goto(punit, acity->tile)) {
+        /* die or unsuccessfull move */
+       return;
+      }
+    } else {
+        UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "didn't find city to go and 
recover.");
+       /* TODO: decide what to do now! */
+    }
+  }
+}
+
+/*******************************************************************
+  Computes the want for an operation
+ ******************************************************************/
+static int find_want_to_paradrop(struct unit *punit, struct tile *ptile_city)
+{ 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(ptile_city, range, ptile) {
+    acity = map_get_city(ptile);
+    if ((acity) && (city_owner(acity) == pplayer) &&
+        (unit_list_size(&(ptile->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(ptile_city, range, ptile) {
+    acity = map_get_city(ptile);
+    if ((acity) && pplayers_at_war(city_owner(acity), pplayer) &&
+        (unit_list_size(&(ptile->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(ptile_city, range, ptile) {
+    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)
+{ Tech_Type_id tech_para = 0;
+  int acum_profit = 0;
+
+  /* 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;
+    }
+    /* assign tech for paratroopers */
+    tech_para = u_type;
+
+    /*it's worth building that unit? */
+    struct unit *virtual_unit =
+      create_unit_virtual(pplayer, pcity, u_type,
+                          do_make_unit_veteran(pcity, u_type));
+    int profit = find_want_to_paradrop(virtual_unit, pcity->tile);
+    acum_profit += profit;
+    destroy_unit_virtual(virtual_unit);
+
+    /* we only update choice struct if we can build it! */
+    if (!can_build_unit(pcity, u_type)) {
+      continue;
+    }
+
+    /* update choise struct if it's worth */
+    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);
+    }
+
+  } unit_type_iterate_end;
+
+  /* we raise want if the required tech is not known */
+  if ((get_invention(pplayer, tech_para) != TECH_KNOWN) &&
+      (acum_profit > 0) && (tech_para != 0)) {
+    if (tech_exists(tech_para) && tech_is_available(pplayer, tech_para)) {
+      pplayer->ai.tech_want[tech_para] += 2;
+      freelog(LOG_NORMAL, "raising tech want in city %s for %s "
+              "stimulating %s with %d (%d) and req",
+              pcity->name, pplayer->name, get_tech_name(pplayer, tech_para),
+             2, pplayer->ai.tech_want[tech_para]);
+
+      /* now, we rise want for prerequisites */
+      tech_type_iterate(k) {
+      if (is_tech_a_req_for_goal(pplayer, k, tech_para)) {
+        pplayer->ai.tech_want[k] += 1;
+      }
+      } tech_type_iterate_end;
+
+    }
+  }
+
+  return;
+}
diff -u -r --new-file -Xfreeciv-cvs-Jun-14/diff_ignore 
freeciv-2.0.2/ai/aiparatrooper.h freeciv-2.0.2-paratroop/ai/aiparatrooper.h
--- freeciv-2.0.2/ai/aiparatrooper.h    1970-01-01 01:00:00.000000000 +0100
+++ freeciv-2.0.2-paratroop/ai/aiparatrooper.h  2005-06-29 00:39:57.000000000 
+0200
@@ -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 -u -r --new-file -Xfreeciv-cvs-Jun-14/diff_ignore 
freeciv-2.0.2/ai/aiunit.c freeciv-2.0.2-paratroop/ai/aiunit.c
--- freeciv-2.0.2/ai/aiunit.c   2005-04-01 06:10:17.000000000 +0200
+++ freeciv-2.0.2-paratroop/ai/aiunit.c 2005-06-29 02:33:21.000000000 +0200
@@ -1,4 +1,4 @@
-/********************************************************************** 
+/**********************************************************************
  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
@@ -56,6 +56,7 @@
 #include "aihand.h"
 #include "aihunt.h"
 #include "ailog.h"
+#include "aiparatrooper.h"
 #include "aitools.h"
 
 #include "aiunit.h"
@@ -70,8 +71,8 @@
 #define RAMPAGE_HUT_OR_BETTER        99998
 #define RAMPAGE_FREE_CITY_OR_BETTER  99999
 #define BODYGUARD_RAMPAGE_THRESHOLD (SHIELD_WEIGHTING * 4)
-static bool ai_military_rampage(struct unit *punit, int thresh_adj, 
-                                int thresh_move);
+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);
@@ -149,7 +150,7 @@
     if (!transported) {
       return;
     }
-    UNIT_LOG(LOG_DEBUG, transported, "airlifted to defend %s", 
+    UNIT_LOG(LOG_DEBUG, transported, "airlifted to defend %s",
              most_needed->name);
     do_airline(transported, most_needed);
   } while (TRUE);
@@ -332,7 +333,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->tile);
   bool has_defense = FALSE;
@@ -661,7 +662,7 @@
 /*************************************************************************
   Look for worthy targets within a one-turn horizon.
 *************************************************************************/
-static struct pf_path *find_rampage_target(struct unit *punit, 
+static struct pf_path *find_rampage_target(struct unit *punit,
                                            int thresh_adj, int thresh_move)
 {
   struct pf_map *tgt_map;
@@ -724,7 +725,7 @@
 }
 
 /*************************************************************************
-  Find and kill anything reachable within this turn and worth more than 
+  Find and kill anything reachable within this turn and worth more than
   the relevant of the given thresholds until we have run out of juicy 
   targets or movement.  The first threshold is for attacking which will 
   leave us where we stand (attacking adjacent units), the second is for 
@@ -737,12 +738,12 @@
 
   Returns TRUE if survived the rampage session.
 **************************************************************************/
-static bool ai_military_rampage(struct unit *punit, int thresh_adj, 
-                                int thresh_move)
+bool ai_military_rampage(struct unit *punit, int thresh_adj,
+                         int thresh_move)
 {
   int count = punit->moves_left + 1; /* break any infinite loops */
   struct pf_path *path = NULL;
-  
+
   CHECK_UNIT(punit);
 
   assert(thresh_adj <= thresh_move);
@@ -818,7 +819,7 @@
 }
 
 /*************************************************************************
-  Tries to find a land tile adjacent to water and to our target 
+  Tries to find a land tile adjacent to water and to our target
   (dest_x, dest_y).  Prefers tiles which are more defensible and/or
   where we will have moves left.
   FIXME: It checks if the ocean tile is in our Zone of Control?!
@@ -918,7 +919,7 @@
 
   Requires an initialized warmap!
 **************************************************************************/
-int look_for_charge(struct player *pplayer, struct unit *punit, 
+int look_for_charge(struct player *pplayer, struct unit *punit,
                     struct unit **aunit, struct city **acity)
 {
   int dist, def, best = 0;
@@ -2170,6 +2171,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
              && !unit_flag(punit, F_MISSILE_CARRIER)
              && punit->ai.ai_role != AIUNIT_HUNTER) {
diff -u -r --new-file -Xfreeciv-cvs-Jun-14/diff_ignore 
freeciv-2.0.2/ai/aiunit.h freeciv-2.0.2-paratroop/ai/aiunit.h
--- freeciv-2.0.2/ai/aiunit.h   2005-04-01 06:10:17.000000000 +0200
+++ freeciv-2.0.2-paratroop/ai/aiunit.h 2005-06-29 00:39:57.000000000 +0200
@@ -47,6 +47,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); 
 void ai_manage_unit(struct player *pplayer, struct unit *punit);
 void ai_manage_military(struct player *pplayer,struct unit *punit);
@@ -66,6 +71,7 @@
                    struct tile **ptile);
 
 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 -u -r --new-file -Xfreeciv-cvs-Jun-14/diff_ignore 
freeciv-2.0.2/ai/Makefile.am freeciv-2.0.2-paratroop/ai/Makefile.am
--- freeciv-2.0.2/ai/Makefile.am        2004-08-18 07:24:44.000000000 +0200
+++ freeciv-2.0.2-paratroop/ai/Makefile.am      2005-06-29 00:51:54.000000000 
+0200
@@ -31,6 +31,8 @@
                aihunt.h        \
                ailog.c         \
                ailog.h         \
+               aiparatrooper.c \
+               aiparatrooper.h \
                aisettler.c     \
                aisettler.h     \
                aitech.c        \
diff -u -r --new-file -Xfreeciv-cvs-Jun-14/diff_ignore 
freeciv-2.0.2/server/.kdbgrc.civserver 
freeciv-2.0.2-paratroop/server/.kdbgrc.civserver
--- freeciv-2.0.2/server/.kdbgrc.civserver      1970-01-01 01:00:00.000000000 
+0100
+++ freeciv-2.0.2-paratroop/server/.kdbgrc.civserver    2005-06-30 
11:40:46.000000000 +0200
@@ -0,0 +1,10 @@
+[General]
+DebuggerCmdStr=
+FileVersion=1
+ProgramArgs=
+TTYLevel=7
+WorkingDirectory=
+
+[Memory]
+ColumnWidths=80,0
+NumExprs=0

[Prev in Thread] Current Thread [Next in Thread]
  • [freeciv-ai] Paratroopers, Jordi Negrevernis i Font <=