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

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

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: per@xxxxxxxxxxx
Cc: andy@xxxxxxxxxxxxxx
Subject: [Freeciv-Dev] (PR#2415) Patch: autoattack
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 19 Oct 2004 13:29:13 -0700
Reply-to: rt@xxxxxxxxxxx

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

This patch:

- Changes the setting to situational.
- Removes unnecessary casts.
- In secfile_lookup_int, takes as default the default value rather than
the current value.  (They could differ if you did /load twice.  However
most other settings have this problem also.)

jason

? newtiles
? data/isotrident/selection.png
? data/isotrident/selection.spec
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        19 Oct 2004 20:27:01 -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       19 Oct 2004 20:27:01 -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       19 Oct 2004 20:27:01 -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   19 Oct 2004 20:27:02 -0000
@@ -3203,6 +3203,9 @@
                             1.10.0 */
     game.occupychance = secfile_lookup_int_default(file, game.occupychance,
                                                   "game.occupychance");
+    game.autoattack = secfile_lookup_bool_default(file,
+                                                 GAME_DEFAULT_AUTOATTACK,
+                                                  "game.autoattack");
     game.seed = secfile_lookup_int_default(file, game.seed,
                                           "game.randseed");
     game.allowed_city_names =
@@ -3655,6 +3658,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   19 Oct 2004 20:27:03 -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_SITUATIONAL, 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.204
diff -u -r1.204 srv_main.c
--- server/srv_main.c   18 Oct 2004 23:49:27 -0000      1.204
+++ server/srv_main.c   19 Oct 2004 20:27:03 -0000
@@ -68,7 +68,6 @@
 #include "timing.h"
 #include "version.h"
 
-#include "autoattack.h"
 #include "barbarian.h"
 #include "cityhand.h"
 #include "citytools.h"
@@ -602,9 +601,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.308
diff -u -r1.308 unittools.c
--- server/unittools.c  18 Oct 2004 22:40:02 -0000      1.308
+++ server/unittools.c  19 Oct 2004 20:27:04 -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 * const *p1 = p;
+  struct unit * const *q1 = 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]