Complete.Org: Mailing Lists: Archives: freeciv-dev: October 2004:
[Freeciv-Dev] (PR#2415) Re: Patch: autoattack
Home

[Freeciv-Dev] (PR#2415) Re: Patch: autoattack

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Cc: andy@xxxxxxxxxxxxxx
Subject: [Freeciv-Dev] (PR#2415) Re: Patch: autoattack
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Mon, 18 Oct 2004 11:08:10 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=2415 >

New version. I intend to commit this shortly unless there are any
objections. 

Defaults are off for humans (use /set autoattack 1 to turn on), and off
for AI on all difficulty levels except 'experimental'. The latter is
because this patch opens a whole new box of bugs, since it stress tests
some AI code that so far has gotten away with it easy so far, thinking
units cannot die while merely moving around on the map. One such bug
fixed in patch.

  - Per
Index: ai/aiferry.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiferry.c,v
retrieving revision 1.6
diff -u -r1.6 aiferry.c
--- ai/aiferry.c        29 Sep 2004 02:24:18 -0000      1.6
+++ ai/aiferry.c        18 Oct 2004 17:51:46 -0000
@@ -708,6 +708,7 @@
 void ai_manage_ferryboat(struct player *pplayer, struct unit *punit)
 {
   struct city *pcity;
+  int sanity = punit->id;
 
   CHECK_UNIT(punit);
 
@@ -773,7 +774,6 @@
     if (punit->ai.passenger > 0) {
       int bossid = punit->ai.passenger;    /* Loop prevention */
       struct unit *boss = find_unit_by_id(punit->ai.passenger);
-      int id = punit->id;                  /* To check if survived */
 
       assert(boss != NULL);
 
@@ -787,7 +787,7 @@
                unit_type(boss)->name, boss->id);
       ai_manage_unit(pplayer, boss);
     
-      if (!find_unit_by_id(id) || punit->moves_left <= 0) {
+      if (!find_unit_by_id(sanity) || punit->moves_left <= 0) {
         return;
       }
       if (find_unit_by_id(bossid)) {
@@ -844,7 +844,7 @@
   UNIT_LOG(LOGLEVEL_FERRY, punit, "Passing control of ferry to explorer code");
   (void) ai_manage_explorer(punit);
 
-  if (punit->moves_left > 0) {
+  if (find_unit_by_id(sanity) && punit->moves_left > 0) {
     struct city *pcity = find_nearest_safe_city(punit);
     if (pcity) {
       punit->goto_tile = pcity->tile;
Index: common/game.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.c,v
retrieving revision 1.187
diff -u -r1.187 game.c
--- common/game.c       29 Sep 2004 02:24:22 -0000      1.187
+++ common/game.c       18 Oct 2004 17:51:46 -0000
@@ -252,6 +252,7 @@
   game.onsetbarbarian = GAME_DEFAULT_ONSETBARBARIAN;
   game.nbarbarians = 0;
   game.occupychance= GAME_DEFAULT_OCCUPYCHANCE;
+  game.autoattack = GAME_DEFAULT_AUTOATTACK;
   game.revolution_length = GAME_DEFAULT_REVOLUTION_LENGTH;
 
   game.heating     = 0;
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.153
diff -u -r1.153 game.h
--- common/game.h       13 Oct 2004 15:47:42 -0000      1.153
+++ common/game.h       18 Oct 2004 17:51:46 -0000
@@ -95,6 +95,7 @@
   int onsetbarbarian;
   int nbarbarians;
   int occupychance;
+  bool autoattack;
   int unhappysize;
   bool angrycitizen;
   char *startmessage;
@@ -470,6 +471,8 @@
 #define GAME_MIN_OCCUPYCHANCE        0
 #define GAME_MAX_OCCUPYCHANCE        100
 
+#define GAME_DEFAULT_AUTOATTACK      FALSE
+
 #define GAME_DEFAULT_RULESETDIR      "default"
 
 #define GAME_DEFAULT_SAVE_NAME       "civgame"
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.201
diff -u -r1.201 savegame.c
--- server/savegame.c   15 Oct 2004 21:34:24 -0000      1.201
+++ server/savegame.c   18 Oct 2004 17:51:48 -0000
@@ -3203,6 +3203,8 @@
                             1.10.0 */
     game.occupychance = secfile_lookup_int_default(file, game.occupychance,
                                                   "game.occupychance");
+    game.autoattack = secfile_lookup_bool_default(file, game.autoattack,
+                                                  "game.autoattack");
     game.seed = secfile_lookup_int_default(file, game.seed,
                                           "game.randseed");
     game.allowed_city_names =
@@ -3655,6 +3657,7 @@
   secfile_insert_int(file, game.onsetbarbarian, "game.onsetbarbs");
   secfile_insert_int(file, game.revolution_length, "game.revolen");
   secfile_insert_int(file, game.occupychance, "game.occupychance");
+  secfile_insert_bool(file, game.autoattack, "game.autoattack");
   secfile_insert_str(file, game.demography, "game.demography");
   secfile_insert_int(file, game.borders, "game.borders");
   secfile_insert_bool(file, game.happyborders, "game.happyborders");
Index: server/settings.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settings.c,v
retrieving revision 1.9
diff -u -r1.9 settings.c
--- server/settings.c   15 Oct 2004 09:39:06 -0000      1.9
+++ server/settings.c   18 Oct 2004 17:51:48 -0000
@@ -645,6 +645,13 @@
          GAME_MIN_OCCUPYCHANCE, GAME_MAX_OCCUPYCHANCE, 
          GAME_DEFAULT_OCCUPYCHANCE)
 
+  GEN_BOOL("autoattack", game.autoattack, SSET_RULES_FLEXIBLE, SSET_MILITARY,
+         SSET_VITAL, SSET_TO_CLIENT,
+         N_("Turn on/off server-side autoattack"),
+         N_("If set to on, units with move left will automatically "
+            "consider attacking enemy units that move adjacent to them."), 
+         NULL, GAME_DEFAULT_AUTOATTACK)
+
   GEN_INT("killcitizen", game.killcitizen,
          SSET_RULES, SSET_MILITARY, SSET_RARE, SSET_TO_CLIENT,
          N_("Reduce city population after attack"),
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.203
diff -u -r1.203 srv_main.c
--- server/srv_main.c   15 Oct 2004 09:39:06 -0000      1.203
+++ server/srv_main.c   18 Oct 2004 17:51:48 -0000
@@ -68,7 +68,6 @@
 #include "timing.h"
 #include "version.h"
 
-#include "autoattack.h"
 #include "barbarian.h"
 #include "cityhand.h"
 #include "citytools.h"
@@ -601,9 +600,6 @@
 
   do_reveal_effects();
   do_have_embassies_effect();
-
-  freelog(LOG_DEBUG, "Auto-Attack phase");
-  auto_attack();
 }
 
 /**************************************************************************
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.307
diff -u -r1.307 unittools.c
--- server/unittools.c  14 Oct 2004 21:01:05 -0000      1.307
+++ server/unittools.c  18 Oct 2004 17:51:49 -0000
@@ -55,6 +55,8 @@
 
 #include "unittools.h"
 
+/* We need this global variable for our sort algorithm */
+static struct tile *autoattack_target;
 
 static void unit_restore_hitpoints(struct player *pplayer, struct unit *punit);
 static void unit_restore_movepoints(struct player *pplayer, struct unit 
*punit);
@@ -2430,7 +2432,129 @@
 }
 
 /*****************************************************************
-Will wake up any neighboring enemy sentry units or patrolling units
+  This function is passed to unit_list_sort() to sort a list of
+  units according to their win chance against autoattack_x|y.
+  If the unit is being transported, then push it to the front of
+  the list, since we wish to leave its transport out of combat
+  if at all possible.
+*****************************************************************/
+static int compare_units(const void *p, const void *q)
+{
+  struct unit *p1 = (struct unit *)*(void**)p;
+  struct unit *q1 = (struct unit *)*(void**)q;
+  struct unit *p1def = get_defender(p1, autoattack_target);
+  struct unit *q1def = get_defender(q1, autoattack_target);
+  int p1uwc = unit_win_chance(p1, p1def);
+  int q1uwc = unit_win_chance(q1, q1def);
+
+  if (p1uwc < q1uwc || q1->transported_by > 0) {
+    return -1; /* q is better */
+  } else if (p1uwc == q1uwc) {
+    return 0;
+  } else {
+    return 1; /* p is better */
+  }
+}
+
+/*****************************************************************
+  Check if unit survives enemy autoattacks. We assume that any
+  unit that is adjacent to us can see us.
+*****************************************************************/
+static bool unit_survive_autoattack(struct unit *punit)
+{
+  struct unit_list autoattack;
+  int moves = punit->moves_left;
+  int sanity1 = punit->id;
+
+  /* Kludge to prevent attack power from dropping to zero during calc */
+  punit->moves_left = MAX(punit->moves_left, 1);
+
+  unit_list_init(&autoattack);
+  adjc_iterate(punit->tile, ptile) {
+    /* First add all eligible units to a unit list */
+    unit_list_iterate(ptile->units, penemy) {
+      struct player *enemyplayer = unit_owner(penemy);
+      enum diplstate_type ds = 
+            pplayer_get_diplstate(unit_owner(punit), enemyplayer)->type;
+
+      if ((enemyplayer->ai.control || game.autoattack)
+          && ai_handicap(enemyplayer, H_EXPERIMENTAL)
+          && penemy->moves_left > 0
+          && ds == DS_WAR
+          && can_unit_attack_unit_at_tile(penemy, punit, punit->tile)) {
+        unit_list_insert(&autoattack, penemy);
+      }
+    } unit_list_iterate_end;
+  } adjc_iterate_end;
+
+  /* The unit list is now sorted according to win chance against punit */
+  autoattack_target = punit->tile; /* global variable */
+  if (unit_list_size(&autoattack) >= 2) {
+    unit_list_sort(&autoattack, &compare_units);
+  }
+
+  unit_list_iterate_safe(autoattack, penemy) {
+    int sanity2 = penemy->id;
+    struct unit *enemy_defender = get_defender(punit, penemy->tile);
+    struct unit *punit_defender = get_defender(penemy, punit->tile);
+    double punitwin = unit_win_chance(punit, enemy_defender);
+    double penemywin = unit_win_chance(penemy, punit_defender);
+    double threshold = 0.25;
+    struct tile *ptile = penemy->tile;
+
+    if (ptile->city && unit_list_size(&ptile->units) == 1) {
+      /* Don't leave city defenseless */
+      threshold = 0.90;
+    }
+
+    if ((penemywin > 1.0 - punitwin
+         || unit_flag(punit, F_DIPLOMAT)
+         || get_transporter_capacity(punit) > 0)
+        && penemywin > threshold) {
+#ifdef REALLY_DEBUG_THIS
+      freelog(LOG_NORMAL, "AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
+              unit_type(penemy)->name, unit_type(punit)->name, 
+              punit->tile->x, punit->tile->y, penemywin, 1.0 - punitwin, 
+              threshold);
+#endif
+
+      handle_unit_activity_request(penemy, ACTIVITY_IDLE);
+      (void) handle_unit_move_request(penemy, punit->tile, FALSE, FALSE);
+    }
+#ifdef REALLY_DEBUG_THIS
+      else {
+      freelog(LOG_NORMAL, "!AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
+              unit_type(penemy)->name, unit_type(punit)->name, 
+              punit->tile->x, punit->tile->y, penemywin, 1.0 - punitwin, 
+              threshold);
+      continue;
+    }
+#endif
+
+    if (find_unit_by_id(sanity2)) {
+      send_unit_info(NULL, penemy);
+    }
+    if (find_unit_by_id(sanity1)) {
+      send_unit_info(NULL, punit);
+    } else {
+      return FALSE; /* done, gone */
+    }
+  } unit_list_iterate_safe_end;
+
+  unit_list_unlink_all(&autoattack);
+  if (find_unit_by_id(sanity1)) {
+    /* We could have lost movement in combat */
+    punit->moves_left = MIN(punit->moves_left, moves);
+    send_unit_info(NULL, punit);
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/*****************************************************************
+  Will wake up any neighboring enemy sentry units or patrolling 
+  units.
 *****************************************************************/
 static void wakeup_neighbor_sentries(struct unit *punit)
 {
@@ -2764,6 +2888,9 @@
 
   handle_unit_move_consequences(punit, psrctile, pdesttile);
   wakeup_neighbor_sentries(punit);
+  if (!unit_survive_autoattack(punit)) {
+    return FALSE;
+  }
   maybe_make_contact(pdesttile, unit_owner(punit));
 
   conn_list_do_unbuffer(&pplayer->connections);

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#2415) Re: Patch: autoattack, Per I. Mathisen <=