Example #1
0
/**************************************************************************
  Do sanity checks on a guard, reporting error messages to the log
  if necessary.

  Inconsistent references do not always indicate an error, because units
  can change owners (for example, because of civil war) outside the control
  the the AI code.
**************************************************************************/
void aiguard_check_guard(const struct unit *guard)
{
  struct unit_ai *guard_data = def_ai_unit_data(guard);
  const struct unit *charge_unit = game_unit_by_number(guard_data->charge);
  const struct city *charge_city = game_city_by_number(guard_data->charge);
  const struct player *guard_owner = unit_owner(guard);
  const struct player *charge_owner = NULL;
  struct unit_ai *charge_data = NULL;

  fc_assert_ret(BODYGUARD_NONE <= guard_data->charge);
  /* IDs always distinct */
  fc_assert_ret(charge_unit == NULL || charge_city == NULL);

  if (charge_unit) {
    charge_owner = unit_owner(charge_unit);
    charge_data = def_ai_unit_data(charge_unit);
  } else if (charge_city) {
    charge_owner = city_owner(charge_city);
  }

  if (charge_unit && charge_data->bodyguard != guard->id) {
    BODYGUARD_LOG(LOG_DEBUG, guard, "inconsistent guard references");
  } else if (!charge_unit && !charge_city && 0 < guard_data->charge) {
    BODYGUARD_LOG(LOG_DEBUG, guard, "dangling guard reference");
  }
  if (charge_owner && pplayers_at_war(charge_owner, guard_owner)) {
    /* Probably due to civil war */
    BODYGUARD_LOG(LOG_DEBUG, guard, "enemy charge");
  } else if (charge_owner && charge_owner != guard_owner) {
    /* Probably sold a city with its supported units. */
    BODYGUARD_LOG(LOG_DEBUG, guard, "foreign charge");
  }
}
Example #2
0
/**************************************************************************
  Assign a guard to a city.
**************************************************************************/
void aiguard_assign_guard_city(struct city *charge, struct unit *guard)
{
  struct unit_ai *guard_data = def_ai_unit_data(guard);

  fc_assert_ret(charge != NULL);
  fc_assert_ret(guard != NULL);
  /*
   * Usually, but not always, city_owner(charge) == unit_owner(guard).
   */

  if (0 < guard_data->charge
      && guard_data->charge != charge->id) {
    /* Remove previous assignment: */
    aiguard_clear_charge(guard);
  }

  guard_data->charge = charge->id;
  if (city_owner(charge) != unit_owner(guard)) {
    /* Peculiar, but not always an error */
    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "assigned foreign charge");
  } else {
    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "assigned charge");
  }

  CHECK_GUARD(guard);
}
Example #3
0
/**************************************************************************
  Check whether the assignment of a guard is still sane, and fix and problems.
  It was once sane, but might have been destroyed or become an enemy since.
**************************************************************************/
void aiguard_update_charge(struct unit *guard)
{
  struct unit_ai *guard_data = def_ai_unit_data(guard);
  const struct unit *charge_unit = game_unit_by_number(guard_data->charge);
  const struct city *charge_city = game_city_by_number(guard_data->charge);
  const struct player *guard_owner = unit_owner(guard);
  const struct player *charge_owner = NULL;

  fc_assert_ret(BODYGUARD_NONE <= guard_data->charge);
  /* IDs always distinct */
  fc_assert_ret(charge_unit == NULL || charge_city == NULL);

  if (charge_unit) {
    charge_owner = unit_owner(charge_unit);
  } else if (charge_city) {
    charge_owner = city_owner(charge_city);
  }

  if (!charge_unit && !charge_city && 0 < guard_data->charge) {
    guard_data->charge = BODYGUARD_NONE;
    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "charge was destroyed");
  }
  if (charge_owner && charge_owner != guard_owner) {
    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "charge transferred, dismiss");
    aiguard_clear_charge(guard);
  }

  CHECK_GUARD(guard);
}
Example #4
0
/**************************************************************************
  Assign a bodyguard to a unit.

  Assumes that a unit can have at most one guard.
**************************************************************************/
void aiguard_assign_guard_unit(struct unit *charge, struct unit *guard)
{
  fc_assert_ret(NULL != charge);
  fc_assert_ret(NULL != guard);
  fc_assert_ret(charge != guard);
  fc_assert_ret(unit_owner(charge) == unit_owner(guard));

  /* Remove previous assignment: */
  aiguard_clear_charge(guard);
  aiguard_clear_guard(charge);

  def_ai_unit_data(guard)->charge = charge->id;
  def_ai_unit_data(charge)->bodyguard = guard->id;

  BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "assigned charge");
  CHECK_GUARD(guard);
  CHECK_CHARGE_UNIT(charge);
}
Example #5
0
/**************************************************************************
  Request a (new) bodyguard for the unit.
**************************************************************************/
void aiguard_request_guard(struct unit *punit)
{
  /* Remove previous assignment */
  aiguard_clear_guard(punit);

  UNIT_LOG(LOGLEVEL_BODYGUARD, punit, "requests a guard");
  def_ai_unit_data(punit)->bodyguard = BODYGUARD_WANTED;

  CHECK_CHARGE_UNIT(punit);
}
Example #6
0
/**************************************************************************
  Remove the assignment of a charge to a guard.

  Assumes that a unit can have at most one guard.
**************************************************************************/
void aiguard_clear_charge(struct unit *guard)
{
  struct unit_ai *guard_data = def_ai_unit_data(guard);
  struct unit *charge_unit = game_unit_by_number(guard_data->charge);
  struct city *charge_city = game_city_by_number(guard_data->charge);

  /* IDs always distinct */
  fc_assert_ret(charge_unit == NULL || charge_city == NULL);

  if (charge_unit) {
    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "unassigned (unit)");
    def_ai_unit_data(charge_unit)->bodyguard = BODYGUARD_NONE;
  } else if (charge_city) {
    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "unassigned (city)");
  }
  /* else not assigned or charge was destroyed */
  guard_data->charge = BODYGUARD_NONE;

  CHECK_GUARD(guard);
}
Example #7
0
/**************************************************************************
  Do sanity checks on a charge, reporting error messages to the log
  if necessary.

  Inconsistent references do not always indicate an error, because units
  can change owners (for example, because of civil war) outside the control
  the the AI code.
**************************************************************************/
void aiguard_check_charge_unit(const struct unit *charge)
{
  struct unit_ai *charge_data = def_ai_unit_data(charge);
  const struct player *charge_owner = unit_owner(charge);
  const struct unit *guard = game_unit_by_number(charge_data->bodyguard);
  struct unit_ai *guard_data = NULL;

  if (guard) {
    guard_data = def_ai_unit_data(guard);
  }

  fc_assert_ret(guard == NULL
                || (guard_data && BODYGUARD_WANTED <= guard_data->bodyguard));

  if (guard && guard_data->charge != charge->id) {
    UNIT_LOG(LOG_DEBUG, charge,
             "inconsistent guard references");
  } else if (guard && unit_owner(guard) != charge_owner) {
    UNIT_LOG(LOG_DEBUG, charge, "foreign guard");
  }
}
Example #8
0
/**************************************************************************
  Remove assignment of bodyguard for a unit.

  Assumes that a unit can have at most one guard.

  There is no analogous function for cities, because cities can have many
  guards: instead use aiguard_clear_charge for each city guard.
**************************************************************************/
void aiguard_clear_guard(struct unit *charge)
{
  struct unit_ai *charge_data = def_ai_unit_data(charge);

  if (0 < charge_data->bodyguard) {
    struct unit *guard = game_unit_by_number(charge_data->bodyguard);

    if (guard) {
      struct unit_ai *guard_data = def_ai_unit_data(guard);

      if (guard_data->charge == charge->id) {
        /* charge doesn't want us anymore */
        guard_data->charge = BODYGUARD_NONE;
      }
    }
  }

  charge_data->bodyguard = BODYGUARD_NONE;

  CHECK_CHARGE_UNIT(charge);
}
Example #9
0
/************************************************************************
  Trying to manage bombers and stuff.
  If we are in the open {
    if moving intelligently on a valid GOTO, {
      carry on doing it.
    } else {
      go refuel
    }
  } else {
    try to attack something
  } 
  TODO: distant target selection, support for fuel > 2
***********************************************************************/
void dai_manage_airunit(struct ai_type *ait, struct player *pplayer,
                        struct unit *punit)
{
  struct tile *dst_tile = unit_tile(punit);
  /* Loop prevention */
  int moves = punit->moves_left;
  int id = punit->id;
  struct pf_parameter parameter;
  struct pf_map *pfm;
  struct pf_path *path;

  CHECK_UNIT(punit);

  if (!is_unit_being_refueled(punit)) {
    /* We are out in the open, what shall we do? */
    if (punit->activity == ACTIVITY_GOTO
        /* We are on a GOTO.  Check if it will get us anywhere */
        && NULL != punit->goto_tile
        && !same_pos(unit_tile(punit), punit->goto_tile)
        && is_airunit_refuel_point(punit->goto_tile, 
                                   pplayer, unit_type(punit), FALSE)) {
      pfm = pf_map_new(&parameter);
      path = pf_map_path(pfm, punit->goto_tile);
      if (path) {
        bool alive = adv_follow_path(punit, path, punit->goto_tile);

        pf_path_destroy(path);
        pf_map_destroy(pfm);
        if (alive && punit->moves_left > 0) {
          /* Maybe do something else. */
          dai_manage_airunit(ait, pplayer, punit);
        }
        return;
      }
      pf_map_destroy(pfm);
    } else if ((dst_tile = find_nearest_airbase(punit, &path))) {
      /* Go refuelling */
      if (!adv_follow_path(punit, path, dst_tile)) {
        pf_path_destroy(path);
        return; /* The unit died. */
      }
      pf_path_destroy(path);
    } else {
      if (punit->fuel == 1) {
	UNIT_LOG(LOG_DEBUG, punit, "Oops, fallin outta the sky");
      }
      def_ai_unit_data(punit, ait)->done = TRUE; /* Won't help trying again */
      return;
    }

  } else if (punit->fuel == unit_type(punit)->fuel) {
    /* We only leave a refuel point when we are on full fuel */

    if (find_something_to_bomb(ait, punit, &path, &dst_tile) > 0) {
      /* Found target, coordinates are in punit's goto_dest.
       * TODO: separate attacking into a function, check for the best 
       * tile to attack from */
      fc_assert_ret(path != NULL && dst_tile != NULL);
      if (!adv_follow_path(punit, path, dst_tile)) {
        pf_path_destroy(path);
        return; /* The unit died. */
      }
      pf_path_destroy(path);

      /* goto would be aborted: "Aborting GOTO for AI attack procedures"
       * now actually need to attack */
      /* We could use ai_military_findvictim here, but I don't trust it... */
      unit_activity_handling(punit, ACTIVITY_IDLE);
      if (is_tiles_adjacent(unit_tile(punit), dst_tile)) {
        (void) unit_move_handling(punit, dst_tile, TRUE, FALSE);
      }
    } else if ((dst_tile = dai_find_strategic_airbase(ait, punit, &path))) {
      log_debug("%s will fly to (%i, %i) (%s) to fight there",
                unit_rule_name(punit), TILE_XY(dst_tile),
                tile_city(dst_tile) ? city_name(tile_city(dst_tile)) : "");
      def_ai_unit_data(punit, ait)->done = TRUE; /* Wait for next turn */
      if (!adv_follow_path(punit, path, dst_tile)) {
        pf_path_destroy(path);
        return; /* The unit died. */
      }
      pf_path_destroy(path);
    } else {
      log_debug("%s cannot find anything to kill and is staying put", 
                unit_rule_name(punit));
      def_ai_unit_data(punit, ait)->done = TRUE;
      unit_activity_handling(punit, ACTIVITY_IDLE);
    }
  }

  if ((punit = game_unit_by_number(id)) != NULL && punit->moves_left > 0
      && punit->moves_left != moves) {
    /* We have moved this turn, might have ended up stuck out in the fields
     * so, as a safety measure, let's manage again */
    dai_manage_airunit(ait, pplayer, punit);
  }

}
Example #10
0
/**************************************************************************
  Which city (if any) has a guard been assigned to?
  Returns NULL if the unit is not a guard for a city.
**************************************************************************/
struct city *aiguard_charge_city(struct unit *guard)
{
  CHECK_GUARD(guard);
  return game_city_by_number(def_ai_unit_data(guard)->charge);
}
Example #11
0
/**************************************************************************
  Which unit, if any, is the body guard of a unit?
  Returns NULL if the unit has not been assigned a guard.
**************************************************************************/
struct unit *aiguard_guard_of(struct unit *charge)
{
  CHECK_CHARGE_UNIT(charge);
  return game_unit_by_number(def_ai_unit_data(charge)->bodyguard);
}
Example #12
0
/**************************************************************************
  Has a guard been assigned to a charge?
**************************************************************************/
bool aiguard_has_guard(struct unit *charge)
{
  CHECK_CHARGE_UNIT(charge);
  return (0 < def_ai_unit_data(charge)->bodyguard);
}
Example #13
0
/**************************************************************************
  Has a charge unit been assigned to a guard?
**************************************************************************/
bool aiguard_has_charge(struct unit *guard)
{
  CHECK_GUARD(guard);
  return (def_ai_unit_data(guard)->charge != BODYGUARD_NONE);
}
Example #14
0
/**************************************************************************
  Has a unit requested a guard and not (yet) been provided with one?
**************************************************************************/
bool aiguard_wanted(struct unit *charge)
{
  CHECK_CHARGE_UNIT(charge);
  return (def_ai_unit_data(charge)->bodyguard == BODYGUARD_WANTED);
}