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

The attached patch fixes many related with pf code for air goto:
- Revisions 13941, 13944 and 13958 are reversed, because there are
totally inefficient (notably way points) and non-tested (many crashes).
- Air patrol doesn't crash any more.
- Way points works as expected.
- Client's goto command forbid to move to dangerous tiles (like it
already does for triremes). Using numeric pad can be used instead to
reach dangerous positions.

"is_dangerous" boolean is replaced by "enum danger_level" in the pf
code. There are 3 possible values:
- DL_SAFE: A safe position.
- DL_UNSAFE: A position the unit can move to in the middle of the turn,
but cannot stay here at the end of the turn (then the server sends the
unit to a safe position).
- DL_DANGEROUS: A position that the unit shouldn't be able to reach in
any case.

Index: common/aicore/path_finding.h
===================================================================
--- common/aicore/path_finding.h	(révision 15283)
+++ common/aicore/path_finding.h	(copie de travail)
@@ -285,6 +285,13 @@
   TM_WORST_TIME
 };
 
+/* Dangerous level */
+enum danger_level {
+  DL_SAFE,      /* Safe tile */
+  DL_UNSAFE,    /* Not safe for a end of turn, but ok for middle-turn move */
+  DL_DANGEROUS, /* Not safe at all */
+};
+
 /* Full specification of a position and time to reach it. */
 struct pf_position {
   struct tile *tile;
@@ -357,11 +364,12 @@
    * If this callback is NULL, ZoC are ignored.*/
   bool (*get_zoc) (const struct player *pplayer, const struct tile *ptile);
 
-  /* If this callback is non-NULL and returns TRUE this position is
-   * dangerous. The unit will never end a turn at a dangerous
-   * position. Can be NULL. */
-  bool (*is_pos_dangerous) (const struct tile *ptile, enum known_type,
-                            struct pf_parameter * param);
+  /* If this callback is non-NULL and returns DL_DANGEROUS this position is
+   * dangerous. If the position is safe, it returns DL_SAFE, else DL_UNSAFE.
+   * The unit will never end a turn at a dangerous position. Can be NULL. */
+  enum danger_level (*pos_danger_level) (const struct tile *ptile,
+					 enum known_type,
+					 struct pf_parameter * param);
 
   /* This is a jumbo callback which overrides all previous ones.  It takes 
    * care of everything (ZOC, known, costs etc).  
@@ -397,7 +405,7 @@
 /* The map itself.  Opaque type. */
 struct pf_map;
 
-/* ==================== Map/Path Functions ========================== */
+/* ==================== Functions =================================== */
 
 /* Returns a map which can be used to query for paths or to iterate
  * over all paths. Does not perform any computations itself, just sets
@@ -449,8 +457,4 @@
 /* Return the current parameters for the given map. */
 struct pf_parameter *pf_get_parameter(struct pf_map *map);
 
-/* ==================== Parameter Functions ========================= */
-
-int get_moves_left_initially(const struct pf_parameter *param);
-
 #endif
Index: common/aicore/pf_tools.c
===================================================================
--- common/aicore/pf_tools.c	(révision 15283)
+++ common/aicore/pf_tools.c	(copie de travail)
@@ -18,7 +18,6 @@
 #include <assert.h>
 #include <string.h>
 
-#include "log.h"
 #include "mem.h"
 
 #include "game.h"
@@ -511,82 +510,91 @@
   Allow one move onto land (for use for ferries and land
   bombardment)
 ***********************************************************************/
-static bool trireme_is_pos_dangerous(const struct tile *ptile,
-				     enum known_type known,
-				     struct pf_parameter *param)
+static enum danger_level trireme_pos_danger_level(const struct tile *ptile,
+						  enum known_type known,
+						  struct pf_parameter *param)
 {
   /* Assume that unknown tiles are unsafe. */
   if (known == TILE_UNKNOWN) {
-    return TRUE;
+    return DL_DANGEROUS;
   }
 
   /* We test TER_UNSAFE even though under the current ruleset there is no
    * way for a trireme to be on a TER_UNSAFE tile. */
   /* Unsafe or unsafe-ocean tiles without cities are dangerous. */
   /* Pretend all land tiles are safe. */
-  return (ptile->city == NULL
-	  && is_ocean(ptile->terrain)
-	  && (terrain_has_flag(ptile->terrain, TER_UNSAFE) 
-	      || (is_ocean(ptile->terrain) && !is_safe_ocean(ptile))));
+  if (!tile_get_city(ptile)
+      && (terrain_has_flag(ptile->terrain, TER_UNSAFE)
+          || (is_ocean(ptile->terrain) && !is_safe_ocean(ptile)))) {
+    return DL_DANGEROUS;
+  }
+  return DL_SAFE;
 }
 
 /****************************************************************************
-  Refueling base for air units.
+  Check if there is a safe position to move.
 ****************************************************************************/
-static bool is_possible_base_fuel(const struct tile *ptile,
-                                  struct pf_parameter *param)
+#include "log.h"
+static bool is_there_safe_pos_near(const struct tile *src_tile,
+                                   struct player *pplayer, int max_moves)
 {
-  /* All airbases are considered possible, simply attack enemies. */
-  return (is_allied_city_tile(ptile, param->owner)
-       || tile_has_special(ptile, S_AIRBASE));
+  square_iterate(src_tile, max_moves / SINGLE_MOVE, ptile) {
+    if (tile_get_known(ptile, pplayer) != TILE_KNOWN) {
+      /* Cannot guess if the tile is safe */
+      continue;
+    }
+    if (is_allied_city_tile(ptile, pplayer)
+        || tile_has_special(ptile, S_AIRBASE)) {
+      return TRUE;
+    }
+  } square_iterate_end;
+
+  return FALSE;
 }
 
 /****************************************************************************
   Position-dangerous callback for air units.
 ****************************************************************************/
-static bool is_pos_dangerous_fuel(const struct tile *ptile,
-                                  enum known_type known,
-                                  struct pf_parameter *param)
+static enum danger_level air_pos_danger_level(const struct tile *ptile,
+					      enum known_type known,
+					      struct pf_parameter *param)
 {
-  int moves = SINGLE_MOVE * real_map_distance(param->start_tile, ptile);
-  int have = get_moves_left_initially(param);
-  int left = have - moves;
+  int moves_left;
+  bool is_enemy_tile;
 
-  if (left < 0) {
-    /* not enough fuel. */
-    return TRUE;
+  if (is_allied_city_tile(ptile, param->owner)) {
+    return DL_SAFE;
   }
 
-  if (have >= moves * 2
-   && (is_possible_base_fuel(param->start_tile, param)
-    || !param->owner->ai.control)) {
-    /* has enough fuel for round trip. */
-    return FALSE;
+  if (tile_has_special(ptile, S_AIRBASE)) {
+    /* All airbases are considered non-dangerous, although non-allied ones
+     * are inaccessible. */
+    return DL_SAFE;
   }
 
-  if (TILE_UNKNOWN != known
-   && (is_possible_base_fuel(ptile, param)
-    || is_enemy_city_tile(ptile, param->owner))) {
-    /* allow attacks, even suicidal ones */
-    return FALSE;
-  }
+  moves_left = param->moves_left_initially
+               + param->move_rate * (param->fuel_left_initially - 1)
+               - SINGLE_MOVE * real_map_distance(param->start_tile, ptile);
+  is_enemy_tile = (is_enemy_unit_tile(ptile, param->owner)
+                   || (ptile->city && is_enemy_city_tile(ptile, param->owner)));
 
-  if (TILE_KNOWN == known
-   && is_enemy_unit_tile(ptile, param->owner)) {
-    /* don't reveal unknown units */
-    return FALSE;
+  if (BV_ISSET(param->unit_flags, F_MISSILE)
+      && moves_left >= 0 && is_enemy_tile) {
+    /* Suicidal attack */
+    return DL_SAFE;
   }
 
-  /* similar to find_nearest_airbase() */
-  iterate_outward(ptile, left / SINGLE_MOVE, atile) {
-    if (TILE_UNKNOWN != tile_get_known(atile, param->owner)
-     && is_possible_base_fuel(atile, param)) {
-      return FALSE;
+  if (is_there_safe_pos_near(ptile, param->owner, moves_left)) {
+    if (!BV_ISSET(param->unit_flags, F_ONEATTACK)
+        || param->fuel == 0 || !is_enemy_tile
+        || (param->fuel_left_initially > 1 && moves_left >= param->move_rate)) {
+      /* Safe move or attack in the middle of the turn, but not for turn end */
+      return DL_UNSAFE;
     }
-  } iterate_outward_end;
-  
+  }
+
   /* Carriers are ignored since they are likely to move. */
-  return TRUE;
+  return DL_DANGEROUS;
 }
 
 /**********************************************************************
@@ -594,46 +602,53 @@
   Allow one move onto land (for use for ferries and land
   bombardment)
 ***********************************************************************/
-static bool is_overlap_pos_dangerous(const struct tile *ptile,
-				     enum known_type known,
-				     struct pf_parameter *param)
+static enum danger_level overlap_pos_danger_level(const struct tile *ptile,
+						  enum known_type known,
+						  struct pf_parameter *param)
 {
   /* Unsafe tiles without cities are dangerous. */
   /* Pretend all land tiles are safe. */
-  return (ptile->city == NULL
-	  && is_ocean(ptile->terrain)
-	  && terrain_has_flag(ptile->terrain, TER_UNSAFE));
+  if (ptile->city == NULL
+      && is_ocean(ptile->terrain)
+      && terrain_has_flag(ptile->terrain, TER_UNSAFE)) {
+    return DL_DANGEROUS;
+  }
+  return DL_SAFE;
 }
 
 /**********************************************************************
   Position-dangerous callback for typical units.
 ***********************************************************************/
-static bool is_pos_dangerous(const struct tile *ptile, enum known_type known,
-			     struct pf_parameter *param)
+static enum danger_level pos_danger_level(const struct tile *ptile,
+					  enum known_type known,
+					  struct pf_parameter *param)
 {
   /* Unsafe tiles without cities are dangerous. */
-  return (ptile->terrain != T_UNKNOWN
-	  && terrain_has_flag(ptile->terrain, TER_UNSAFE)
-	  && ptile->city == NULL);
+  if (ptile->terrain != T_UNKNOWN
+      && terrain_has_flag(ptile->terrain, TER_UNSAFE)
+      && ptile->city == NULL) {
+    return DL_DANGEROUS;
+  }
+  return DL_SAFE;
 }
 
 /****************************************************************************
   Position-dangerous callback for amphibious movement.
 ****************************************************************************/
-static bool amphibious_is_pos_dangerous(const struct tile *ptile,
-					enum known_type known,
-					struct pf_parameter *param)
+static enum danger_level amphibious_pos_danger_level(const struct tile *ptile,
+						     enum known_type known,
+						     struct pf_parameter *param)
 {
   struct pft_amphibious *amphibious = param->data;
   const bool ocean = is_ocean(ptile->terrain);
 
   /* Simply a wrapper for the sea or land danger callbacks. */
-  if (ocean && amphibious->sea.is_pos_dangerous) {
-    return amphibious->sea.is_pos_dangerous(ptile, known, param);
-  } else if (!ocean && amphibious->land.is_pos_dangerous) {
-    return amphibious->land.is_pos_dangerous(ptile, known, param);
+  if (ocean && amphibious->sea.pos_danger_level) {
+    return amphibious->sea.pos_danger_level(ptile, known, param);
+  } else if (!ocean && amphibious->land.pos_danger_level) {
+    return amphibious->land.pos_danger_level(ptile, known, param);
   }
-  return FALSE;
+  return DL_SAFE;
 }
 
 /* =====================  Tools for filling parameters =============== */
@@ -655,18 +670,18 @@
     }
     break;
   case SEA_MOVING:
-    if (!unit_has_type_flag(punit, F_NO_LAND_ATTACK)) {
-      parameter->get_MC = seamove;
-    } else {
+    if (unit_has_type_flag(punit, F_NO_LAND_ATTACK)) {
       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 = is_pos_dangerous_fuel;
+      parameter->pos_danger_level = air_pos_danger_level;
     } else {
-      parameter->is_pos_dangerous = NULL;
+      parameter->pos_danger_level = NULL;
     }
     parameter->turn_mode = TM_WORST_TIME;
     break;
@@ -676,16 +691,13 @@
     if (get_player_bonus(unit_owner(punit), EFT_UNIT_RECOVER)
 	>= unit_type(punit)->hp / 10) {
       /* United nations cancels out helicoptor fuel loss. */
-      parameter->is_pos_dangerous = NULL;
+      parameter->pos_danger_level = NULL;
     } else {
       /* Otherwise, don't risk fuel loss. */
-      parameter->is_pos_dangerous = is_pos_dangerous_fuel;
+      parameter->pos_danger_level = NULL;
       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 
@@ -698,10 +710,10 @@
   if (unit_has_type_flag(punit, F_TRIREME)
       && base_trireme_loss_pct(unit_owner(punit), punit) > 0) {
     parameter->turn_mode = TM_WORST_TIME;
-    parameter->is_pos_dangerous = trireme_is_pos_dangerous;
+    parameter->pos_danger_level = trireme_pos_danger_level;
   } else if (base_unsafe_terrain_loss_pct(unit_owner(punit), punit) > 0) {
     parameter->turn_mode = TM_WORST_TIME;
-    parameter->is_pos_dangerous = is_pos_dangerous;
+    parameter->pos_danger_level = pos_danger_level;
   }
 }
 
@@ -726,16 +738,16 @@
 
     assert(!trireme_danger);
     if (danger) {
-      parameter->is_pos_dangerous = is_pos_dangerous;
+      parameter->pos_danger_level = pos_danger_level;
     }
     break;
   case SEA_MOVING:
     parameter->get_MC = sea_overlap_move;
 
     if (trireme_danger) {
-      parameter->is_pos_dangerous = trireme_is_pos_dangerous;
+      parameter->pos_danger_level = trireme_pos_danger_level;
     } else if (danger) {
-      parameter->is_pos_dangerous = is_overlap_pos_dangerous;
+      parameter->pos_danger_level = overlap_pos_danger_level;
     }
     break;
   case AIR_MOVING:
@@ -743,9 +755,6 @@
     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;
@@ -770,9 +779,6 @@
   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 
@@ -783,7 +789,7 @@
   }
 
   /* It is too complicated to work with danger here */
-  parameter->is_pos_dangerous = NULL;
+  parameter->pos_danger_level = NULL;
 }
 
 /****************************************************************************
@@ -812,7 +818,7 @@
   parameter->combined.get_MC = amphibious_move;
   parameter->combined.get_TB = amphibious_behaviour;
   parameter->combined.get_EC = amphibious_extra_cost;
-  parameter->combined.is_pos_dangerous = amphibious_is_pos_dangerous;
+  parameter->combined.pos_danger_level = amphibious_pos_danger_level;
   BV_CLR_ALL(parameter->combined.unit_flags);
 
   parameter->combined.data = parameter;
@@ -825,32 +831,22 @@
 					    struct unit *punit)
 {
   parameter->turn_mode = TM_CAPPED;
-  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:
+  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;
     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;
+  parameter->pos_danger_level = NULL;
   parameter->get_costs = NULL;
   parameter->get_zoc = NULL;
   BV_CLR_ALL(parameter->unit_flags);
Index: common/aicore/path_finding.c
===================================================================
--- common/aicore/path_finding.c	(révision 15283)
+++ common/aicore/path_finding.c	(copie de travail)
@@ -66,7 +66,7 @@
  * from mainstream node.
  */
 struct danger_node {
-  bool is_dangerous;
+  enum danger_level danger_level;
   bool waited;			/* TRUE if waited to get here */
   struct pf_danger_pos {
     enum direction8 dir;
@@ -121,7 +121,7 @@
   turn.  Thus the rest of the PF code doesn't actually know that the unit
   has fuel, it just thinks it has that many more MP.
 ****************************************************************************/
-int get_moves_left_initially(const struct pf_parameter *param)
+static int get_moves_left_initially(const struct pf_parameter *param)
 {
   return (param->moves_left_initially
 	  + (param->fuel_left_initially - 1) * param->move_rate);
@@ -340,10 +340,10 @@
 bool pf_next(struct pf_map *pf_map)
 {
   mapindex_t index;
-  struct pf_node *node = &pf_map->lattice[pf_map->tile->index];
+  struct pf_node *node;
 
-  if (pf_map->params->is_pos_dangerous) {
-    /* It's a lot different if is_pos_dangerous is defined */
+  if (pf_map->params->pos_danger_level) {
+    /* It's a lot different if pos_danger_level is defined */
     return danger_iterate_map(pf_map);
   }
 
@@ -353,6 +353,7 @@
   }
 
   pf_map->status[pf_map->tile->index] = NS_PROCESSED;
+  node = &pf_map->lattice[pf_map->tile->index];
 
   /* There is no exit from DONT_LEAVE tiles! */
   if (node->behavior != TB_DONT_LEAVE) {
@@ -475,7 +476,8 @@
 ***************************************************************/
 struct pf_map *pf_create_map(const struct pf_parameter *const parameter)
 {
-  struct pf_map *pf_map = create_map((parameter->is_pos_dangerous != NULL));
+  struct pf_map *pf_map = create_map((parameter->pos_danger_level != NULL));
+  struct pf_node *node;
 
   /* MC callback must be set */
   assert(parameter->get_MC != NULL);
@@ -488,18 +490,19 @@
   pf_map->tile = pf_map->params->start_tile;
 
   /* Initialise starting node */
-  init_node(pf_map, &pf_map->lattice[pf_map->tile->index], pf_map->tile);
+  node = &pf_map->lattice[pf_map->tile->index];
+  init_node(pf_map, node, pf_map->tile);
   /* This makes calculations of turn/moves_left more convenient, but we 
    * need to subtract this value before we return cost to the user.  Note
    * that cost may be negative if moves_left_initially > move_rate
    * (see get_turn()). */
-  pf_map->lattice[pf_map->tile->index].cost = get_move_rate(pf_map->params)
+  node->cost = get_move_rate(pf_map->params)
     - get_moves_left_initially(pf_map->params);
-  pf_map->lattice[pf_map->tile->index].extra_cost = 0;
-  pf_map->lattice[pf_map->tile->index].dir_to_here = -1;
-  if (pf_map->params->is_pos_dangerous) {
-    /* The starting point is safe */
-    pf_map->d_lattice[pf_map->tile->index].is_dangerous = FALSE;
+  node->extra_cost = 0;
+  node->dir_to_here = -1;
+  if (pf_map->params->pos_danger_level) {
+    /* We don't know yet if it is dangerous or not. */
+    pf_map->d_lattice[pf_map->tile->index].danger_level = DL_UNSAFE;
   }
 
   return pf_map;
@@ -566,7 +569,7 @@
   for *_get_position functions.  This also "finalizes" the position.
 ****************************************************************************/
 static void fill_position(const struct pf_map *pf_map, struct tile *ptile,
-			     struct pf_position *pos)
+			  struct pf_position *pos)
 {
   mapindex_t index = ptile->index;
   struct pf_node *node = &pf_map->lattice[index];
@@ -654,7 +657,7 @@
   struct tile *ptile;
 
   /* Debug period only!  Please remove after PF is settled */
-  assert(!pf_map->params->is_pos_dangerous);
+  assert(!pf_map->params->pos_danger_level);
   if (pf_map->status[index] != NS_PROCESSED
       && !same_pos(dest_tile, pf_map->tile)) {
     die("construct_path to an unreached destination");
@@ -709,7 +712,7 @@
 ************************************************************************/
 struct pf_path *pf_next_get_path(const struct pf_map *pf_map)
 {
-  if (!pf_map->params->is_pos_dangerous) {
+  if (!pf_map->params->pos_danger_level) {
     return construct_path(pf_map, pf_map->tile);
   } else {
     /* It's very different in the presence of danger */
@@ -726,7 +729,7 @@
   mapindex_t index = ptile->index;
   utiny_t status = pf_map->status[index];
 
-  if (pf_map->params->is_pos_dangerous) {
+  if (pf_map->params->pos_danger_level) {
     /* It's very different in the presence of danger */
     return danger_get_path(pf_map, ptile);
   }
@@ -805,12 +808,12 @@
   struct pf_parameter *params = pf_map->params;
 
   /* Is the tile dangerous (i.e. no ending turn there) */
-  if (params->is_pos_dangerous) {
-    d_node->is_dangerous =
-	params->is_pos_dangerous(ptile, node->node_known_type, params);
+  if (params->pos_danger_level) {
+    d_node->danger_level =
+	params->pos_danger_level(ptile, node->node_known_type, params);
   } else {
     freelog(LOG_ERROR, "PF: init_danger_node called without"
-	    "is_pos_dangerous callback");
+	    "pos_danger_level callback");
   }
 
 }
@@ -825,6 +828,7 @@
   struct tile *ptile = pf_map->tile;
   struct pf_node *node = &pf_map->lattice[ptile->index];
   struct danger_node *d_node = &pf_map->d_lattice[ptile->index];
+  struct pf_danger_pos *danger_pos;
   int length = 0;
 
   /* Allocating memory */
@@ -833,7 +837,7 @@
   }
 
   /* First iteration for determining segment length */
-  while(d_node->is_dangerous) {
+  while (d_node->danger_level == DL_DANGEROUS) {
     length++;
     ptile = mapstep(ptile, DIR_REVERSE(node->dir_to_here));
     node = &pf_map->lattice[ptile->index];
@@ -850,8 +854,9 @@
   /* Now fill the positions */
   for (i = 0; i < length; i++) {
     /* Record the direction */
-    d_node1->danger_segment[i].dir = node->dir_to_here;
-    d_node1->danger_segment[i].cost = node->cost;
+    danger_pos = &d_node1->danger_segment[i];
+    danger_pos->dir = node->dir_to_here;
+    danger_pos->cost = node->cost;
     d_node1->danger_segment[i].extra_cost = node->extra_cost;
     if (i == length - 1) {
       /* The last dangerous node contains "waiting" info */
@@ -864,14 +869,14 @@
   }
 
   /* Make sure we reached a safe node */
-  assert(!pf_map->d_lattice[ptile->index].is_dangerous);
+  assert(pf_map->d_lattice[ptile->index].danger_level != DL_DANGEROUS);
 }
 
 /**********************************************************************
   Adjust cost taking into account possibility of making the move
 **********************************************************************/
-static int danger_adjust_cost(const struct pf_map *pf_map, int cost, 
-                              bool to_danger, int moves_left)
+static int danger_adjust_cost(const struct pf_map *pf_map, int cost,
+                              enum danger_level to_danger, int moves_left)
 {
 
   if (cost == PF_IMPOSSIBLE_MC) {
@@ -881,7 +886,7 @@
   cost = MIN(cost, get_move_rate(pf_map->params));
 
   if (pf_map->params->turn_mode == TM_BEST_TIME) {
-    if (to_danger && cost >= moves_left) {
+    if (to_danger != DL_SAFE && cost >= moves_left) {
       /* We would have to end the turn on a dangerous tile! */
       return PF_IMPOSSIBLE_MC;
     }
@@ -889,7 +894,7 @@
     /* Default is TM_WORST_TIME.  
      * It should be specified explicitly though! */
     if (cost > moves_left
-        || (to_danger && cost == moves_left)) {
+        || (to_danger != DL_SAFE && cost == moves_left)) {
       /* This move is impossible (at least without waiting) 
        * or we would end our turn on a dangerous tile */
       return PF_IMPOSSIBLE_MC;
@@ -950,8 +955,8 @@
 
       /* Dangerous tiles can be updated even after being processed */
       if ((pf_map->status[index1] == NS_PROCESSED 
-           || pf_map->status[index1] == NS_WAITING) 
-          && !d_node1->is_dangerous) {
+	   || pf_map->status[index1] == NS_WAITING) 
+	  && d_node1->danger_level == DL_SAFE) {
 	continue;
       }
 
@@ -982,7 +987,7 @@
       if (cost == PF_IMPOSSIBLE_MC) {
 	continue;
       }
-      cost = danger_adjust_cost(pf_map, cost, d_node1->is_dangerous,
+      cost = danger_adjust_cost(pf_map, cost, d_node1->danger_level,
 				get_moves_left(pf_map, loc_cost));
 
       if (cost == PF_IMPOSSIBLE_MC) {
@@ -999,7 +1004,7 @@
       }
 
       /* Update costs and add to queue, if this is a better route to xy1 */
-      if (!d_node1->is_dangerous) {
+      if (d_node1->danger_level != DL_DANGEROUS) {
 	int cost_of_path = get_total_CC(pf_map, cost, extra);
 
 	if (pf_map->status[index1] == NS_UNINIT
@@ -1013,7 +1018,7 @@
             free(d_node1->danger_segment);
             d_node1->danger_segment = NULL;
           }
-	  if (d_node->is_dangerous) {
+	  if (d_node->danger_level == DL_DANGEROUS) {
 	    /* Transition from red to blue, need to record the path back */
 	    create_danger_segment(pf_map, d_node1);
 	  } else {
@@ -1033,7 +1038,8 @@
 	 *    overwrite anything useful */
 	if (pf_map->status[index1] == NS_UNINIT
 	    || (get_moves_left(pf_map, cost)
-		> get_moves_left(pf_map, node1->cost))
+		> get_moves_left(pf_map, node1->cost)
+		&& pf_map->status[index1] == NS_PROCESSED)
 	    || (get_total_CC(pf_map, cost, extra)
 		< get_total_CC(pf_map, node1->cost, node1->extra_cost)
 		&& pf_map->status[index1] == NS_PROCESSED)) {
@@ -1047,11 +1053,10 @@
 	  pq_insert(pf_map->danger_queue, index1, -cost);
 	}
       }
-    }
-    adjc_dir_iterate_end;
+    } adjc_dir_iterate_end;
   }
 
-  if (!d_node->is_dangerous
+  if (d_node->danger_level == DL_SAFE
       && pf_map->status[pf_map->tile->index] != NS_WAITING
       && (get_moves_left(pf_map, node->cost)
 	  < get_move_rate(pf_map->params))) {
@@ -1086,7 +1091,7 @@
     freelog(LOG_DEBUG, "Considering waiting at (%d, %d)",
 	    pf_map->tile->x, pf_map->tile->y);
     return danger_iterate_map(pf_map);
-  } else if (pf_map->d_lattice[index].is_dangerous) {
+  } else if (pf_map->d_lattice[index].danger_level == DL_DANGEROUS) {
     /* We don't return dangerous tiles */
     freelog(LOG_DEBUG, "Reached dangerous tile (%d, %d)",
 	    pf_map->tile->x, pf_map->tile->y);
@@ -1114,6 +1119,7 @@
   struct danger_node *d_node = &pf_map->d_lattice[ptile->index];
   int length = 1;
   struct tile *iter_tile = ptile;
+  struct pf_position *position;
 
   if (pf_map->params->turn_mode != TM_BEST_TIME &&
       pf_map->params->turn_mode != TM_WORST_TIME) {
@@ -1122,15 +1128,15 @@
   }
 
   /* First iterate to find path length */
-  while(!same_pos(iter_tile, pf_map->params->start_tile)) {
+  while (!same_pos(iter_tile, pf_map->params->start_tile)) {
 
-    if (!d_node->is_dangerous && d_node->waited) {
+    if (d_node->danger_level == DL_SAFE && d_node->waited) {
       length += 2;
     } else {
       length++;
     }
 
-    if (!d_node->is_dangerous) {
+    if (d_node->danger_level != DL_DANGEROUS) {
       /* We are in the normal node and dir_to_here field is valid */
       dir_next = node->dir_to_here;
       /* d_node->danger_segment is the indicator of what lies ahead
@@ -1165,19 +1171,20 @@
     bool old_waited = FALSE;
 
     /* 1: Deal with waiting */
-    if (!d_node->is_dangerous) {
+    if (d_node->danger_level == DL_SAFE) {
       if (waited) {
         /* Waited at _this_ tile, need to record it twice in the path.
          * Here we record our state _after_ waiting (e.g. full move points) */
-        path->positions[i].tile = iter_tile;
-        path->positions[i].total_EC = node->extra_cost;
-        path->positions[i].turn = get_turn(pf_map, node->cost) + 1;
-        path->positions[i].moves_left = get_move_rate(pf_map->params);
-        path->positions[i].total_MC 
-          = ((path->positions[i].turn - 1) * pf_map->params->move_rate
+	position = &path->positions[i];
+        position->tile = iter_tile;
+        position->total_EC = node->extra_cost;
+        position->turn = get_turn(pf_map, node->cost) + 1;
+        position->moves_left = get_move_rate(pf_map->params);
+        position->total_MC
+          = ((position->turn - 1) * pf_map->params->move_rate
              + pf_map->params->moves_left_initially);
         path->positions[i].dir_to_next_pos = dir_next;
-	finalize_position(pf_map, &path->positions[i]);
+	finalize_position(pf_map, position);
         /* Set old_waited so that we record -1 as a direction at the step 
          * we were going to wait */
         old_waited = TRUE;
@@ -1188,23 +1195,23 @@
     }
 
     /* 2: Fill the current position */
-    path->positions[i].tile = iter_tile;
-    if (!d_node->is_dangerous) {
-      path->positions[i].total_MC = node->cost;
-      path->positions[i].total_EC = node->extra_cost;
+    position = &path->positions[i];
+    position->tile = iter_tile;
+    if (d_node->danger_level != DL_DANGEROUS) {
+      position->total_MC = node->cost;
+      position->total_EC = node->extra_cost;
     } else {
       /* When on dangerous tiles, must have a valid danger segment */
       assert(danger_seg != NULL);
-      path->positions[i].total_MC = danger_seg[segment_index].cost;
-      path->positions[i].total_EC = danger_seg[segment_index].extra_cost;
+      position->total_MC = danger_seg[segment_index].cost;
+      position->total_EC = danger_seg[segment_index].extra_cost;
     } 
-    path->positions[i].turn = get_turn(pf_map, path->positions[i].total_MC);
-    path->positions[i].moves_left 
-      = get_moves_left(pf_map, path->positions[i].total_MC);
-    path->positions[i].total_MC -= get_move_rate(pf_map->params)
+    position->turn = get_turn(pf_map, position->total_MC);
+    position->moves_left = get_moves_left(pf_map, position->total_MC);
+    position->total_MC -= get_move_rate(pf_map->params)
       - get_moves_left_initially(pf_map->params);
-    path->positions[i].dir_to_next_pos = (old_waited ? -1 : dir_next);
-    finalize_position(pf_map, &path->positions[i]);
+    position->dir_to_next_pos = (old_waited ? -1 : dir_next);
+    finalize_position(pf_map, position);
 
     /* 3: Check if we finished */
     if (i == 0) {
@@ -1214,7 +1221,7 @@
     }
 
     /* 4: Calculate the next direction */
-    if (!d_node->is_dangerous) {
+    if (d_node->danger_level != DL_DANGEROUS) {
       /* We are in the normal node and dir_to_here field is valid */
       dir_next = node->dir_to_here;
       /* d_node->danger_segment is the indicator of what lies ahead
@@ -1232,7 +1239,6 @@
     iter_tile = mapstep(iter_tile, DIR_REVERSE(dir_next));
     node = &pf_map->lattice[iter_tile->index];
     d_node = &pf_map->d_lattice[iter_tile->index];
-
   }
 
   die("danger_get_path: cannot get to the starting point!");
@@ -1249,7 +1255,7 @@
   utiny_t status = pf_map->status[index];
   struct danger_node *d_node = &pf_map->d_lattice[index];
 
-  if (d_node->is_dangerous) {
+  if (d_node->danger_level == DL_DANGEROUS) {
     /* "Best" path to a dangerous tile is undefined */
     /* TODO: return the "safest" path */
     return NULL;
Index: ai/aitools.c
===================================================================
--- ai/aitools.c	(révision 15283)
+++ ai/aitools.c	(copie de travail)
@@ -691,7 +691,7 @@
    * but probably ought to be more cautious for non military units
    */
   if (is_ai && !is_ferry && !is_air) {
-    parameter->is_pos_dangerous = NULL;
+    parameter->pos_danger_level = NULL;
   }
 
   if (is_ai && long_path) {
Index: client/goto.c
===================================================================
--- client/goto.c	(révision 15283)
+++ client/goto.c	(copie de travail)
@@ -749,7 +749,7 @@
     } else {
       parameter->get_costs = get_connect_road;
     }
-    parameter->is_pos_dangerous = NULL;
+    parameter->pos_danger_level = NULL;
 
     *connect_speed = get_activity_rate(punit) / ACTIVITY_FACTOR;
     parameter->data = connect_speed;
@@ -768,7 +768,7 @@
     }
     break;
   case HOVER_NUKE:
-    parameter->is_pos_dangerous = NULL; /* nuclear safety? pwah! */
+    parameter->pos_danger_level = NULL; /* nuclear safety? pwah! */
     /* FALLTHRU */
   default:
     *connect_initial = 0;
@@ -1082,7 +1082,9 @@
     map = pf_create_map(&parameter);
     return_path = pf_get_path(map, goto_map->parts[0].start_tile);
     if (!return_path) {
-      die("No return path found!");
+      /* Cannot make a path */
+      pf_destroy_map(map);
+      continue;
     }
 
     for (i = 0; i < goto_map->num_parts; i++) {
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to