<URL: http://bugs.freeciv.org/Ticket/Display.html?id=39852 >

While trying to understand the reported air goto problems of PR#20772,
came across this incomprehensible (and manifestly incorrect) S2_1 code
(nearly identical in S2_2/trunk):

   int moves = SINGLE_MOVE * real_map_distance(param->start_tile, ptile);
   int fuel = param->fuel_left_initially - 1;
...

   if (param->moves_left_initially + param->move_rate * fuel >= moves * 2) {
     if (param->fuel_left_initially > 1
         || ((param->fuel_left_initially > 2
              || !BV_ISSET(param->unit_flags, F_ONEATTACK))
             && (is_enemy_unit_tile(ptile, param->owner)
                 || is_enemy_city_tile(ptile, param->owner)))) {
       /* allow movement if fuelled, and attacks, even suicidal ones */
       return FALSE;
     }
   }

The outer test probably ensures that there is enough fuel remaining to
return to base.  But fuel (0) isn't correct.  A simple thought experiment
(dividing out all the SINGLE_MOVE constants):

   moves = 1
   moves_left_initially = 1
   fuel_left_initially = 1
   fuel = 0

The fuel_left_initially is exactly needed for the move.  Yet the test
fails!  (1 + 0 >= 2)

Actually, the only thing that matters is the fuel.  The moves are just
for each turn spent traveling there.  There's no explanation in PR#15097
for using moves_left_initially....

The "> 1" line seems superfluous, as the outer test already determined
that enough fuel remains.

The "> 2" line cannot happen, as the "> 1 ||"  already determined that
"> 2" is not true (it is <= 1).

Why is a F_ONEATTACK unit *not* allowed to attack a city or unit?

And the comment certainly isn't true, as the outer test prevents any
attack without enough fuel to return....

===

Also, updated some logging to match S2_2/trunk.

Index: common/aicore/pf_tools.c
===================================================================
--- common/aicore/pf_tools.c    (revision 13940)
+++ common/aicore/pf_tools.c    (working copy)
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include "log.h"
 #include "mem.h"
 
 #include "game.h"
@@ -531,32 +532,35 @@
 /****************************************************************************
   Position-dangerous callback for air units.
 ****************************************************************************/
-static bool air_is_pos_dangerous(const struct tile *ptile,
-                                enum known_type known,
-                                struct pf_parameter *param)
+static bool is_pos_dangerous_fuel(const struct tile *ptile,
+                                  enum known_type known,
+                                  struct pf_parameter *param)
 {
   int moves = SINGLE_MOVE * real_map_distance(param->start_tile, ptile);
-  int fuel = param->fuel_left_initially - 1;
+  int fuel = param->move_rate * param->fuel_left_initially;
 
-  if (is_allied_city_tile(ptile, param->owner)) {
+  if (fuel < moves) {
+    /* not enough fuel. */
+    return TRUE;
+  }
+
+  if (fuel >= moves * 2) {
+    /* has enough fuel for round trip. */
     return FALSE;
   }
 
-  if (tile_has_special(ptile, S_AIRBASE)) {
+  if (fuel >= moves
+   && (is_allied_city_tile(ptile, param->owner)
+    || tile_has_special(ptile, S_AIRBASE))) {
     /* All airbases are considered non-dangerous, although non-allied ones
      * are inaccessible. */
     return FALSE;
   }
 
-  if (param->moves_left_initially + param->move_rate * fuel >= moves * 2) {
-    if (param->fuel_left_initially > 1
-        || ((param->fuel_left_initially > 2
-             || !BV_ISSET(param->unit_flags, F_ONEATTACK))
-            && (is_enemy_unit_tile(ptile, param->owner)
-                || (ptile->city && is_enemy_city_tile(ptile, param->owner))))) 
{
-      /* allow movement if fuelled, and attacks, even suicidal ones */
-      return FALSE;
-    }
+  if (is_enemy_unit_tile(ptile, param->owner)
+   || is_enemy_city_tile(ptile, param->owner)) {
+    /* allow attacks, even suicidal ones */
+    return FALSE;
   }
 
   /* Carriers are ignored since they are likely to move. */
@@ -629,16 +633,16 @@
     }
     break;
   case SEA_MOVING:
-    if (unit_has_type_flag(punit, F_NO_LAND_ATTACK)) {
+    if (!unit_has_type_flag(punit, F_NO_LAND_ATTACK)) {
+      parameter->get_MC = seamove;
+    } else {
       parameter->get_MC = seamove_no_bombard;
-    } else {
-      parameter->get_MC = seamove;
     }
     break;
   case AIR_MOVING:
     parameter->get_MC = single_airmove;
     if (unit_type(punit)->fuel > 0) {
-      parameter->is_pos_dangerous = air_is_pos_dangerous;
+      parameter->is_pos_dangerous = is_pos_dangerous_fuel;
     } else {
       parameter->is_pos_dangerous = NULL;
     }
@@ -653,10 +657,13 @@
       parameter->is_pos_dangerous = NULL;
     } else {
       /* Otherwise, don't risk fuel loss. */
-      parameter->is_pos_dangerous = air_is_pos_dangerous;
+      parameter->is_pos_dangerous = is_pos_dangerous_fuel;
       parameter->turn_mode = TM_WORST_TIME;
     }
     break;
+  default:
+    freelog(LOG_ERROR, "pft_fill_unit_parameter() impossible move type!");
+    break;
   }
 
   if (unit_type(punit)->move_type == LAND_MOVING 
@@ -714,6 +721,9 @@
     assert(!danger && !trireme_danger);
     parameter->get_MC = single_airmove; /* very crude */
     break;
+  default:
+    freelog(LOG_ERROR, "pft_fill_unit_overlap_param() impossible move type!");
+    break;
   }
 
   parameter->get_zoc = NULL;
@@ -738,6 +748,9 @@
   case HELI_MOVING:
     parameter->get_MC = single_airmove; /* very crude */
     break;
+  default:
+    freelog(LOG_ERROR, "pft_fill_unit_attack_param() impossible move type!");
+    break;
   }
 
   if (unit_type(punit)->move_type == LAND_MOVING 
@@ -790,19 +803,29 @@
                                            struct unit *punit)
 {
   parameter->turn_mode = TM_CAPPED;
-  if (is_air_unit(punit) || is_heli_unit(punit)) {
-    parameter->unknown_MC = SINGLE_MOVE;
-  } else if (is_sailing_unit(punit)) {
-    parameter->unknown_MC = 2 * SINGLE_MOVE;
-  } else {
-    assert(is_ground_unit(punit));
-    parameter->unknown_MC = SINGLE_MOVE;
+  parameter->unknown_MC = SINGLE_MOVE;
+
+  switch (unit_type(punit)->move_type) {
+  case AIR_MOVING:
+  case HELI_MOVING:
+    /* no change */;
+    break;
+  case SEA_MOVING:
+    /* Sailing units explore less? */
+    parameter->unknown_MC *= 2;
+    break;
+  case LAND_MOVING:
     terrain_type_iterate(pterrain) {
       int mr = 2 * pterrain->movement_cost;
 
       parameter->unknown_MC = MAX(mr, parameter->unknown_MC);
     } terrain_type_iterate_end;
+    break;
+  default:
+    freelog(LOG_ERROR, "pft_fill_unit_default_parameter() impossible move 
type!");
+    break;
   }
+
   parameter->get_TB = NULL;
   parameter->get_EC = NULL;
   parameter->is_pos_dangerous = NULL;
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to