On Sat, 10 Feb 2007, Jason Short wrote:
One weird situation is if you fly a bomber out from a carrier to hit a
spot 12 tiles away...then move the carrier in the other direction 9 (or
however many is the maximum) tiles.  Then at the start of the next turn
(it does happen at the start right?) the bomber gets automatically
returned to the carrier even though it's now 20 tiles away.  This would
seem just a bit odd to the player.

Indeed. However, the opposite solution, to let the aircraft fail to return because you accidentially moved your carrier out of range, would be nasty.

One solution could be to require a carrier that launches aircraft to stay put where it is until your next turn. Real life carriers do not move out of an area while its aircraft are still flying missions there...

A technical problem is that the return point is sometimes a city, a
unit, or just a tile.  And if it is a unit there is limited transporting
capacity and it's possible when the plane tries to return it finds that
the carrier is full.

Yes. I wrote code for this, and it gets rather complicated due to all the possible corner cases:

/***************************************************************************
  Return or relocate aircraft (and other UCF_RETURN_TO_BASE class units).
  Function returns FALSE if unit died for some reason.
  1) Try using goto coordinates.
  2) Try to return to a carrier.
  3) Try returning to last city.
  4) Look for anywhere in range.
****************************************************************************/
static bool player_return_to_base(struct player *pplayer, struct unit *punit)
{
  /* 1) Goto coordinates set, try to relocate to new base. */
  if (punit->goto_tile) {
    struct unit *carrier = find_transport_from_tile(punit, punit->goto_tile);

    if (real_map_distance(punit->tile, punit->goto_tile)
         < (unit_move_rate(punit) + punit->moves_left) / SINGLE_MOVE
        && !is_non_allied_unit_tile(punit->goto_tile, pplayer)
        && (carrier || can_unit_survive_at_tile(punit, punit->goto_tile))) {
      if (move_unit(punit, punit->goto_tile, 0)) {
        punit->goto_tile = NULL;
        if (carrier) {
          put_unit_onto_transporter(punit, carrier);
        }
        return TRUE;
      } else {
        return FALSE;
      }
    } else {
      /* Invalidate goto */
      notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
                    _("Your %s could not relocate to target base."),
                    unit_name(punit->type));
      punit->goto_tile = NULL;
    }
  }

  if (punit->base.unit != -1 || punit->base.tile != punit->tile) {
    struct unit *carrier = find_unit_by_id(punit->base.unit);

    /* 2) Return to mobile base (carrier). If carrier moves out of range,
     * we still allow it to land on it for convenience and ease of mind. */
    if (carrier && could_unit_load(punit, carrier)) {
      if (move_unit(punit, carrier->tile, 0)) {
        put_unit_onto_transporter(punit, carrier);
        return TRUE;
      } else {
        return FALSE;
      }
    }
    /* 3) Return to fixed base (terrain base). If base is set, we can by
     * definition reach it, unless it was destroyed. */
    if (punit->base.tile
        && !is_non_allied_unit_tile(punit->base.tile, pplayer)
        && can_unit_survive_at_tile(punit, punit->base.tile)) {
      return move_unit(punit, punit->base.tile, 0);
    }
    /* Invalidate return */
    notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
                  _("Your %s could not return to base."),
                  unit_name(punit->type));
    punit->base.unit = -1;
    punit->base.tile = NULL;
  }

  /* 4) Ooops - lost our base! Search for a new base to land on. First
   * we check the tile we stand on, then any other possible bases. */
  if (can_unit_survive_at_tile(punit, punit->tile)) {
    return TRUE; /* one lucky bastard! */
  } else {
    struct unit *carrier = find_transport_from_tile(punit, punit->tile);

    if (carrier) {
      put_unit_onto_transporter(punit, carrier);
      return TRUE; /* should be a rare occurance, but possible */
    }
  }
  players_iterate(aplayer) {
    if (!pplayers_allied(pplayer, aplayer)) {
      continue;
    }
    city_list_iterate(aplayer->cities, pcity) {
      if (real_map_distance(punit->tile, pcity->tile)
           < (unit_move_rate(punit) + punit->moves_left) / SINGLE_MOVE
          && !is_non_allied_unit_tile(pcity->tile, pplayer)
          && can_unit_survive_at_tile(punit, pcity->tile)) {
        notify_player(pplayer, pcity->tile, E_UNIT_ORDERS,
                      _("Your %s made an emergency relocation to %s."),
                      unit_name(punit->type), pcity->name);
        return move_unit(punit, pcity->tile, 0);
      }
    } city_list_iterate_end;
    unit_list_iterate(aplayer->units, carrier) {
      if (could_unit_load(punit, carrier)
          && real_map_distance(punit->tile, carrier->tile)
              < (unit_move_rate(punit) + punit->moves_left) / SINGLE_MOVE
          && !is_non_allied_unit_tile(carrier->tile, pplayer)) {
        notify_player(pplayer, carrier->tile, E_UNIT_ORDERS,
                      _("Your %s made an emergency relocation to your %s."),
                      unit_name(punit->type), unit_name(carrier->type));
        if (move_unit(punit, carrier->tile, 0)) {
          put_unit_onto_transporter(punit, carrier);
          return TRUE;
        } else {
          return FALSE;
        }
      }
    } unit_list_iterate_end;
  } players_iterate_end;

  /* Crash and burn */
  notify_player(pplayer, punit->tile, E_UNIT_LOST,
                _("Your %s has run out of fuel."),
                unit_name(punit->type));
  wipe_unit(punit);
  return FALSE;
}

But nevertheless, I think the results of the corner cases will be intuitive to the player, and figuring out which corner cases that exist does not seem particularly hard.

  - Per

_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to