Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2004:
[Freeciv-Dev] Re: (PR#11340) Unit orders aborted glitch
Home

[Freeciv-Dev] Re: (PR#11340) Unit orders aborted glitch

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] Re: (PR#11340) Unit orders aborted glitch
From: "Dave Vandervies" <dj3vande@xxxxxxxxxx>
Date: Sat, 4 Dec 2004 22:06:06 -0800
Reply-to: rt@xxxxxxxxxxx

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

Jason Short wrote:
> 
> > [dj3vande@xxxxxxxxxx - Sun Dec 05 00:38:34 2004]:
> 
> > I'm willing to share my changes if anybody is interested in cleaning
> > them up and getting them into the official code repository.
> 
> Great.  Why don't you clean them up while you're at it ;-).  Follow the
> instructions on "how to contribute" to make a patch of the changes.

I've cleaned up what I can without guidance from somebody who knows
more than just the few lines around the change in execute_orders.

This patch calls execute_orders recursively to have the unit carry on
with its orders; this should probably be changed to do it The Right
Way.  I can make the change and re-submit if somebody tells me what The
Right Way is.

Attached:
server-patch   Patch in server directory (unittools.c)
common-patch   Patch in common directory (unit.c and unit.h)


dave


--- unit.c.orig 2004-11-11 17:51:13.000000000 -0500
+++ unit.c      2004-12-05 00:53:43.000000000 -0500
@@ -990,6 +990,167 @@
   return FALSE;
 }
 
+
+/**************************************************************************
+...
+**************************************************************************/
+bool can_unit_fake_activity(struct unit *punit, enum unit_activity activity)
+{
+  return can_unit_fake_activity_targeted(punit, activity, S_NO_SPECIAL);
+}
+
+/**************************************************************************
+  Return whether the unit can fake the targeted activity at its current
+  location.
+**************************************************************************/
+bool can_unit_fake_activity_targeted(struct unit *punit,
+                                  enum unit_activity activity,
+                                  enum tile_special_type target)
+{
+  return can_unit_fake_activity_targeted_at(punit, activity, target,
+                                         punit->tile);
+}
+
+/**************************************************************************
+  Return TRUE if the unit can fake the targeted activity at the given
+  location (whatever it's being asked to do has already been done there,
+  and had it not been done this unit would be able to do it)
+
+  If the unit can actually DO the activity, FALSE will always be returned;
+  this is intended as an additional check to avoid getting "Orders for
+  unit aborted since they gave an invalid activity" if, f'rexample, we're
+  asking them to connect with a road and there's already a road there.   --DV
+**************************************************************************/
+bool can_unit_fake_activity_targeted_at(struct unit *punit,
+                                     enum unit_activity activity,
+                                     enum tile_special_type target,
+                                     const struct tile *ptile)
+{
+  struct player *pplayer = unit_owner(punit);
+  struct tile_type *type = get_tile_type(ptile->terrain);
+
+  switch(activity) {
+
+  case ACTIVITY_POLLUTION:
+    return (unit_flag(punit, F_SETTLERS)
+           && !tile_has_special(ptile, S_POLLUTION));
+
+  case ACTIVITY_FALLOUT:
+    return (unit_flag(punit, F_SETTLERS)
+           && !tile_has_special(ptile, S_FALLOUT));
+
+  case ACTIVITY_ROAD:
+    return (terrain_control.may_road
+           && unit_flag(punit, F_SETTLERS)
+           && tile_has_special(ptile, S_ROAD)
+           && type->road_time != 0
+           && (!tile_has_special(ptile, S_RIVER)
+               || player_knows_techs_with_flag(pplayer, TF_BRIDGE)));
+
+  case ACTIVITY_MINE:
+    /* Don't allow it if someone else is irrigating this tile.
+     * *Do* allow it if they're transforming - the mine may survive */
+    if (terrain_control.may_mine
+       && unit_flag(punit, F_SETTLERS)
+       && ((ptile->terrain == type->mining_result
+            && tile_has_special(ptile, S_MINE))
+           || (ptile->terrain != type->mining_result
+               && type->mining_result != T_NONE
+               && (!is_ocean(ptile->terrain)
+                   || is_ocean(type->mining_result)
+                   || can_reclaim_ocean(ptile))
+               && (is_ocean(ptile->terrain)
+                   || !is_ocean(type->mining_result)
+                   || can_channel_land(ptile))
+               && (!is_ocean(type->mining_result)
+                   || !map_get_city(ptile))))) {
+      unit_list_iterate(ptile->units, tunit) {
+       if (tunit->activity == ACTIVITY_IRRIGATE) {
+         return FALSE;
+       }
+      } unit_list_iterate_end;
+      return TRUE;
+    } else {
+      return FALSE;
+    }
+
+  case ACTIVITY_IRRIGATE:
+    /* Don't allow it if someone else is mining this tile.
+     * *Do* allow it if they're transforming - the irrigation may survive */
+    if (terrain_control.may_irrigate
+       && unit_flag(punit, F_SETTLERS)
+       && (tile_has_special(ptile, S_IRRIGATION)
+           || (tile_has_special(ptile, S_FARMLAND)
+               && player_knows_techs_with_flag(pplayer, TF_FARMLAND)))
+       && ((ptile->terrain == type->irrigation_result
+            && is_water_adjacent_to_tile(ptile))
+           || (ptile->terrain != type->irrigation_result
+               && type->irrigation_result != T_NONE
+               && (!is_ocean(ptile->terrain)
+                   || is_ocean(type->irrigation_result)
+                   || can_reclaim_ocean(ptile))
+               && (is_ocean(ptile->terrain)
+                   || !is_ocean(type->irrigation_result)
+                   || can_channel_land(ptile))
+               && (!is_ocean(type->irrigation_result)
+                   || !map_get_city(ptile))))) {
+      unit_list_iterate(ptile->units, tunit) {
+       if (tunit->activity == ACTIVITY_MINE) {
+         return FALSE;
+       }
+      } unit_list_iterate_end;
+      return TRUE;
+    } else {
+      return FALSE;
+    }
+
+  case ACTIVITY_FORTIFYING:
+    return (is_ground_unit(punit)
+           && punit->activity == ACTIVITY_FORTIFIED
+           && !unit_flag(punit, F_SETTLERS)
+           && !is_ocean(ptile->terrain));
+
+  case ACTIVITY_FORTRESS:
+    return (unit_flag(punit, F_SETTLERS)
+           && !map_get_city(ptile)
+           && player_knows_techs_with_flag(pplayer, TF_FORTRESS)
+           && tile_has_special(ptile, S_FORTRESS)
+           && !is_ocean(ptile->terrain));
+
+  case ACTIVITY_AIRBASE:
+    return (unit_flag(punit, F_AIRBASE)
+           && player_knows_techs_with_flag(pplayer, TF_AIRBASE)
+           && tile_has_special(ptile, S_AIRBASE)
+           && !is_ocean(ptile->terrain));
+
+  case ACTIVITY_RAILROAD:
+    /* if the tile has road, the terrain must be ok.. */
+    return (terrain_control.may_road
+           && unit_flag(punit, F_SETTLERS)
+           && tile_has_special(ptile, S_ROAD)
+           && tile_has_special(ptile, S_RAILROAD)
+           && player_knows_techs_with_flag(pplayer, TF_RAILROAD));
+
+  case ACTIVITY_IDLE:
+  case ACTIVITY_FORTIFIED:
+  case ACTIVITY_SENTRY:
+  case ACTIVITY_PILLAGE:
+  case ACTIVITY_GOTO:
+  case ACTIVITY_EXPLORE:
+  case ACTIVITY_TRANSFORM:
+  case ACTIVITY_UNKNOWN:
+  case ACTIVITY_PATROL_UNUSED:
+  case ACTIVITY_LAST:
+    /*Non-fakable activity or we wouldn't've been able to do it here if
+       it hadn't already been done
+    */
+    return FALSE;
+  }
+
+  assert(0);
+  return FALSE;
+}
+
 /**************************************************************************
   assign a new task to a unit.
 **************************************************************************/
--- unit.h.orig 2004-11-16 16:33:55.000000000 -0500
+++ unit.h      2004-12-05 00:47:19.000000000 -0500
@@ -245,6 +245,14 @@
                                      enum unit_activity activity,
                                      enum tile_special_type target,
                                      const struct tile *ptile);
+bool can_unit_fake_activity(struct unit *punit, enum unit_activity activity);
+bool can_unit_fake_activity_targeted(struct unit *punit,
+                                  enum unit_activity activity,
+                                  enum tile_special_type target);
+bool can_unit_fake_activity_targeted_at(struct unit *punit,
+                                     enum unit_activity activity,
+                                     enum tile_special_type target,
+                                     const struct tile *ptile);
 void set_unit_activity(struct unit *punit, enum unit_activity new_activity);
 void set_unit_activity_targeted(struct unit *punit,
                                enum unit_activity new_activity,
--- unittools.c.orig    2004-11-11 17:51:15.000000000 -0500
+++ unittools.c 2004-12-05 00:57:35.000000000 -0500
@@ -2952,6 +2952,12 @@
     case ORDER_ACTIVITY:
       activity = order.activity;
       if (!can_unit_do_activity(punit, activity)) {
+       if (can_unit_fake_activity(punit,activity)) {
+         if(unit_has_orders(punit))
+           return execute_orders(punit);
+         else
+           return TRUE;
+       }
        cancel_orders(punit, "  orders canceled because of failed activity");
        notify_player_ex(pplayer, punit->tile, E_UNIT_ORDERS,
                         _("Game: Orders for %s aborted since they "

[Prev in Thread] Current Thread [Next in Thread]