[freeciv-ai] Re: (PR#6308) Cleanup of ferry handling
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
As requested, I've hacked on this patch, and here is a new version of it.
CHANGES:
- replaced ugly boat register. now aidata keeps track of this stuff.
- replaced ugly 'find passengers' iteration (leftover Syelaism)
- we now try hard to get bodyguard along on the ride
- stack_attack_value() removed and replaced by two additional lines of
code in the only function that called it (duh)
- renamed FERRY_SEEKING to FERRY_AVAILABLE
I think it is ready to go in. Greg, please have a last look at it and
check that I didn't mess up something ;)
- Per
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.20
diff -u -r1.20 aidata.c
--- ai/aidata.c 8 Aug 2003 22:11:41 -0000 1.20
+++ ai/aidata.c 1 Oct 2003 14:34:11 -0000
@@ -189,7 +189,10 @@
ai->stats.workers = fc_calloc(ai->num_continents + 1, sizeof(int));
ai->stats.cities = fc_calloc(ai->num_continents + 1, sizeof(int));
+ ai->stats.passengers = fc_calloc(ai->num_continents + 1, sizeof(int));
ai->stats.average_production = 0;
+ ai->stats.boats = 0;
+ ai->stats.available_boats = 0;
city_list_iterate(pplayer->cities, pcity) {
ai->stats.cities[(int)map_get_continent(pcity->x, pcity->y)]++;
ai->stats.average_production += pcity->shield_surplus;
@@ -199,6 +202,15 @@
unit_list_iterate(pplayer->units, punit) {
struct tile *ptile = map_get_tile(punit->x, punit->y);
+ if (punit->ai.passenger == FERRY_AVAILABLE) {
+ ai->stats.available_boats++;
+ }
+ if (is_sailing_unit(punit) && is_ground_units_transport(punit)) {
+ ai->stats.boats++;
+ }
+ if (punit->ai.ferryboat == FERRY_WANTED) {
+ ai->stats.passengers++;
+ }
if (!is_ocean(ptile->terrain) && unit_flag(punit, F_SETTLERS)) {
ai->stats.workers[(int)map_get_continent(punit->x, punit->y)]++;
}
@@ -352,6 +364,38 @@
ai->diplomacy.player_intel[i].asked_about_alliance = 0;
ai->diplomacy.player_intel[i].asked_about_ceasefire = 0;
ai->diplomacy.player_intel[i].warned_about_space = 0;
+ }
+}
+
+/**************************************************************************
+ Use this wrapper to correctly update the statistics. Use NULL to
+ unregister any ferry that might be there.
+**************************************************************************/
+void ai_set_ferry(struct unit *punit, struct unit *ferry)
+{
+ if (!ferry && punit->ai.ferryboat != FERRY_WANTED) {
+ struct ai_data *ai = ai_data_get(unit_owner(punit));
+
+ ai->stats.passengers++;
+ punit->ai.ferryboat = FERRY_WANTED;
+ } else if (ferry) {
+ punit->ai.ferryboat = ferry->id;
+ }
+}
+
+/**************************************************************************
+ Use this wrapper to correctly update the statistics. Use NULL to
+ unregister any passenger that might be there.
+**************************************************************************/
+void ai_set_passenger(struct unit *punit, struct unit *passenger)
+{
+ if (!passenger && punit->ai.passenger != FERRY_AVAILABLE) {
+ struct ai_data *ai = ai_data_get(unit_owner(punit));
+
+ ai->stats.available_boats++;
+ punit->ai.passenger = FERRY_AVAILABLE;
+ } else if (passenger) {
+ punit->ai.passenger = passenger->id;
}
}
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.10
diff -u -r1.10 aidata.h
--- ai/aidata.h 8 Aug 2003 22:11:41 -0000 1.10
+++ ai/aidata.h 1 Oct 2003 14:34:11 -0000
@@ -86,11 +86,14 @@
bool sea_done; /* nothing more to explore at sea */
} explore;
- /* This struct is used for statistical unit building, to ensure
- that we don't build too few or too many units of a given type */
+ /* This struct is used for statistical unit building, eg to ensure
+ * that we don't build too few or too many units of a given type. */
struct {
int *workers; /* cities to workers on continent*/
int *cities; /* number of cities on continent */
+ int *passengers; /* number of passengers on continent */
+ int boats;
+ int available_boats;
int average_production;
bv_id diplomat_reservations;
} stats;
@@ -131,5 +134,8 @@
void ai_data_done(struct player *pplayer);
struct ai_data *ai_data_get(struct player *pplayer);
+
+void ai_set_passenger(struct unit *punit, struct unit *passenger);
+void ai_set_ferry(struct unit *punit, struct unit *ferry);
#endif
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.92
diff -u -r1.92 aitools.c
--- ai/aitools.c 28 Sep 2003 01:04:59 -0000 1.92
+++ ai/aitools.c 1 Oct 2003 14:34:12 -0000
@@ -137,6 +137,8 @@
/**************************************************************************
This will eventually become the ferry-enabled goto. For now, it just
wraps ai_unit_goto()
+
+ TODO: Kill me. Use ai_gothere instead.
**************************************************************************/
bool ai_unit_gothere(struct unit *punit)
{
@@ -146,6 +148,238 @@
} else {
return FALSE; /* we died */
}
+}
+
+/****************************************************************************
+ A helper function for ai_gothere. Estimates the dangers we will
+ be facing at our destination and tries to find/request a bodyguard if
+ needed.
+****************************************************************************/
+static void ai_gothere_bodyguard(struct unit *punit, int dest_x, int dest_y)
+{
+ int danger = 0;
+ struct city *dcity;
+ struct tile *ptile;
+
+ if (is_barbarian(unit_owner(punit))) {
+ /* barbarians must have more courage (ie less brains) */
+ punit->ai.bodyguard = BODYGUARD_NONE;
+ return;
+ }
+
+ /* Estimate enemy attack power. */
+ unit_list_iterate(map_get_tile(dest_x, dest_y)->units, aunit) {
+ danger += unit_att_rating(aunit);
+ } unit_list_iterate_end;
+ if ((dcity = map_get_city(dest_x, dest_y))) {
+ /* Assume enemy will build another defender, add it's attack strength */
+ int d_type = ai_choose_defender_versus(dcity, punit->type);
+ danger +=
+ unittype_att_rating(d_type, do_make_unit_veteran(dcity, d_type),
+ SINGLE_MOVE, unit_types[d_type].hp);
+ }
+ danger *= POWER_DIVIDER;
+
+ /* If we are fast, there is less danger. */
+ danger /= (unit_type(punit)->move_rate / SINGLE_MOVE);
+ if (unit_flag(punit, F_IGTER)) {
+ danger /= 1.5;
+ }
+
+ ptile = map_get_tile(punit->x, punit->y);
+ /* We look for the bodyguard where we stand. */
+ if (!unit_list_find(&ptile->units, punit->ai.bodyguard)) {
+ int my_def = (punit->hp * (punit->veteran ? 15 : 10)
+ * unit_type(punit)->defense_strength);
+
+ /* FIXME: danger is multiplied by POWER_FACTOR, my_def isn't. */
+ if (danger >= my_def) {
+ UNIT_LOG(LOGLEVEL_BODYGUARD, punit,
+ "wants a bodyguard, danger=%d, my_def=%d", danger, my_def);
+ punit->ai.bodyguard = BODYGUARD_WANTED;
+ } else {
+ punit->ai.bodyguard = BODYGUARD_NONE;
+ }
+ }
+
+ /* What if we have a bodyguard, but don't need one? */
+}
+
+#define LOGLEVEL_GOTHERE LOG_DEBUG
+/****************************************************************************
+ This is ferry-enabled goto. Should not normally be used for non-ferried
+ units (i.e. planes or ships), use ai_unit_goto instead.
+
+ Return values: TRUE if got to or next to our destination, FALSE otherwise.
+
+ TODO: A big one is rendezvous points. When this is implemented, we won't
+ have to be at the coast to ask for a boat to come to us.
+****************************************************************************/
+bool ai_gothere(struct player *pplayer, struct unit *punit,
+ int dest_x, int dest_y)
+{
+ struct unit *bodyguard = find_unit_by_id(punit->ai.bodyguard);
+
+ CHECK_UNIT(punit);
+
+ if (same_pos(dest_x, dest_y, punit->x, punit->y)) {
+ /* Nowhere to go */
+ return TRUE;
+ }
+
+ /* See if we need a bodyguard at our destination */
+ /* FIXME: If bodyguard is _really_ necessary, don't go anywhere */
+ ai_gothere_bodyguard(punit, dest_x, dest_y);
+
+ /* If we can, we will walk, take boat only if necessary */
+ if (punit->transported_by > 0
+ || !goto_is_sane(punit, dest_x, dest_y, TRUE)) {
+ int boatid = punit->transported_by;
+ struct unit *ferryboat = NULL;
+
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "will have to go to (%d,%d) by boat",
+ dest_x, dest_y);
+
+ if (boatid <= 0) {
+ int bx, by;
+ boatid = find_boat(pplayer, &bx, &by, 2);
+ }
+ ferryboat = find_unit_by_id(boatid);
+
+ if (!ferryboat) {
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "No boat found.");
+ ai_set_ferry(punit, NULL);
+ return FALSE;
+ } else {
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "Found boat at (%d,%d)",
+ ferryboat->x, ferryboat->y);
+ }
+
+ punit->ai.ferryboat = boatid;
+ if (!same_pos(punit->x, punit->y, ferryboat->x, ferryboat->y)
+ && (!is_at_coast(punit->x, punit->y)
+ || is_tiles_adjacent(punit->x, punit->y,
+ ferryboat->x, ferryboat->y))) {
+ /* Go to the boat only if it cannot reach us or it's parked
+ * next to us. Otherwise just wait (boats are normally faster) */
+ /* FIXME: agree on a rendez-vous point */
+ /* FIXME: this can lose bodyguard */
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "going to boat[%d](%d,%d).", boatid,
+ ferryboat->x, ferryboat->y);
+ if (!ai_unit_goto(punit, ferryboat->x, ferryboat->y)) {
+ /* Died. */
+ return FALSE;
+ }
+ }
+
+ if (!same_pos(punit->x, punit->y, ferryboat->x, ferryboat->y)) {
+ /* Didn't get to the boat */
+ if (is_at_coast(punit->x, punit->y)) {
+ /* At least got to the coast, wave to the boats! */
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "asking a boat to come nearer");
+ ai_set_ferry(punit, NULL);
+ }
+ return FALSE;
+ }
+
+ /* Check if we are the passenger-in-charge */
+ if (ferryboat->ai.passenger <= 0
+ || ferryboat->ai.passenger == punit->id) {
+ int beach_x, beach_y; /* Destination for the boat */
+ struct tile *dest_tile = map_get_tile(dest_x, dest_y);
+
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "got boat[%d], going (%d,%d)",
+ ferryboat->id, dest_x, dest_y);
+ handle_unit_activity_request(punit, ACTIVITY_SENTRY);
+ ferryboat->ai.passenger = punit->id;
+
+ /* If the location is not accessible directly from sea
+ * or is defended and we are not marines, we will need a
+ * landing beach */
+ if (!is_at_coast(dest_x, dest_y)
+ ||((is_non_allied_city_tile(dest_tile, pplayer)
+ || is_non_allied_unit_tile(dest_tile, pplayer))
+ && !unit_flag(punit, F_MARINES))) {
+ if (!find_beachhead(punit, dest_x, dest_y, &beach_x, &beach_y)) {
+ /* Nowhere to go */
+ return FALSE;
+ }
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit,
+ "Found beachhead (%d,%d)", beach_x, beach_y);
+ } else {
+ beach_x = dest_x;
+ beach_y = dest_y;
+ }
+
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "All aboard!");
+ set_goto_dest(ferryboat, beach_x, beach_y);
+ set_goto_dest(punit, dest_x, dest_y);
+ handle_unit_activity_request(punit, ACTIVITY_SENTRY);
+ /* Grab bodyguard */
+ if (bodyguard
+ && !same_pos(punit->x, punit->y, bodyguard->x, bodyguard->y)) {
+ if (!goto_is_sane(bodyguard, punit->x, punit->y, TRUE)
+ || !ai_unit_goto(punit, punit->x, punit->y)) {
+ /* Bodyguard can't get there or died en route */
+ punit->ai.bodyguard = BODYGUARD_WANTED;
+ bodyguard = NULL;
+ } else if (bodyguard->moves_left <= 0) {
+ /* Wait for me, I'm cooooming!! */
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "waiting for bodyguard");
+ return TRUE;
+ } else {
+ /* Crap bodyguard. Got stuck somewhere. Ditch it! */
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "ditching useless bodyguard");
+ punit->ai.bodyguard = BODYGUARD_WANTED;
+ ai_unit_new_role(bodyguard, AIUNIT_NONE, -1, -1);
+ bodyguard = NULL;
+ }
+ }
+ if (bodyguard) {
+ assert(same_pos(punit->x, punit->y, bodyguard->x, bodyguard->y));
+ handle_unit_activity_request(bodyguard, ACTIVITY_SENTRY);
+ }
+ if (!ai_unit_goto(ferryboat, beach_x, beach_y)) {
+ /* died */
+ return FALSE;
+ }
+ if (!is_tiles_adjacent(ferryboat->x, ferryboat->y, beach_x, beach_y)
+ && !same_pos(ferryboat->x, ferryboat->y, beach_x, beach_y)) {
+ /* We are in still transit */
+ return FALSE;
+ }
+ } else {
+ /* Waiting for the boss to load and move us */
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "Cannot command boat [%d],"
+ " its boss is [%d]",
+ ferryboat->id, ferryboat->ai.passenger);
+ return FALSE;
+ }
+
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "Our boat has arrived");
+ handle_unit_activity_request(punit, ACTIVITY_IDLE);
+ }
+
+ /* Go where we should be going if we can, and are at our destination
+ * if we are on a ferry */
+ if (goto_is_sane(punit, dest_x, dest_y, TRUE) && punit->moves_left > 0) {
+ set_goto_dest(punit, dest_x, dest_y);
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "Walking to (%d,%d)", dest_x, dest_y);
+ if (!ai_unit_goto(punit, dest_x, dest_y)) {
+ /* died */
+ return FALSE;
+ }
+ /* liable to bump into someone that will kill us. Should avoid? */
+ } else {
+ UNIT_LOG(LOGLEVEL_GOTHERE, punit, "Not moving");
+ return FALSE;
+ }
+
+ /* Dead unit shouldn't reach this point */
+ CHECK_UNIT(punit);
+
+ return (same_pos(punit->x, punit->y, dest_x, dest_y)
+ || is_tiles_adjacent(punit->x, punit->y, dest_x, dest_y));
}
/**************************************************************************
Index: ai/aitools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.h,v
retrieving revision 1.39
diff -u -r1.39 aitools.h
--- ai/aitools.h 27 Sep 2003 11:22:40 -0000 1.39
+++ ai/aitools.h 1 Oct 2003 14:34:12 -0000
@@ -38,15 +38,21 @@
BODYGUARD_NONE
};
+#define FERRY_WANTED -1 /* For passengers in need of a boat */
+#define FERRY_AVAILABLE -1 /* For boats looking for a passenger */
+
int military_amortize(struct player *pplayer, struct city *pcity,
int value, int delay, int build_cost);
int stack_cost(struct unit *pdef);
bool ai_unit_execute_path(struct unit *punit, struct pf_path *path);
bool ai_unit_gothere(struct unit *punit);
+bool ai_gothere(struct player *pplayer, struct unit *punit,
+ int dest_x, int dest_y);
bool ai_unit_goto(struct unit *punit, int x, int y);
-void ai_unit_new_role(struct unit *punit, enum ai_unit_task task, int x, int
y);
+void ai_unit_new_role(struct unit *punit, enum ai_unit_task task,
+ int x, int y);
bool ai_unit_make_homecity(struct unit *punit, struct city *pcity);
bool ai_unit_attack(struct unit *punit, int x, int y);
bool ai_unit_move(struct unit *punit, int x, int y);
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.297
diff -u -r1.297 aiunit.c
--- ai/aiunit.c 28 Sep 2003 09:33:21 -0000 1.297
+++ ai/aiunit.c 1 Oct 2003 14:34:12 -0000
@@ -61,6 +61,7 @@
#define LOGLEVEL_RECOVERY LOG_DEBUG
+static void ai_manage_unit(struct player *pplayer, struct unit *punit);
static void ai_manage_military(struct player *pplayer,struct unit *punit);
static void ai_manage_caravan(struct player *pplayer, struct unit *punit);
static void ai_manage_barbarian_leader(struct player *pplayer,
@@ -804,19 +805,6 @@
return v * v;
}
-/**********************************************************************
- Total attack power of the units in this square.
-***********************************************************************/
-static int stack_attack_value(int x, int y)
-{
- int val = 0;
- struct tile *ptile = map_get_tile(x, y);
- unit_list_iterate(ptile->units, aunit)
- val += unit_att_rating(aunit);
- unit_list_iterate_end;
- return val;
-}
-
/**************************************************************************
Compute how much we want to kill certain victim we've chosen, counted in
SHIELDs.
@@ -1123,8 +1111,13 @@
if (aunit && aunit->owner == punit->owner) {
/* protect a unit */
- x = aunit->x;
- y = aunit->y;
+ if (is_sailing_unit(aunit)) {
+ x = goto_dest_x(aunit);
+ y = goto_dest_y(aunit);
+ } else {
+ x = aunit->x;
+ y = aunit->y;
+ }
} else if (acity && acity->owner == punit->owner) {
/* protect a city */
x = acity->x;
@@ -1238,174 +1231,6 @@
*y = best_y;
}
-/**************************************************************************
- A helper function for ai_military_gothere. Estimates the dangers we will
- be facing a out destination and tries to find/request a bodyguard if
- needed.
-**************************************************************************/
-static void ai_gothere_bodyguard(struct unit *punit, int dest_x, int dest_y)
-{
- int danger;
- struct city *dcity;
- struct tile *ptile;
-
-
- if (is_barbarian(unit_owner(punit))) {
- /* barbarians must have more courage (= less brains) */
- punit->ai.bodyguard = BODYGUARD_NONE;
- return;
- }
-
- /* Estimate enemy attack power. */
- danger = stack_attack_value(dest_x, dest_y);
- if ((dcity = map_get_city(dest_x, dest_y))) {
- /* Assume enemy will build another defender, add it's attack strength */
- int d_type = ai_choose_defender_versus(dcity, punit->type);
- danger +=
- unittype_att_rating(d_type, do_make_unit_veteran(dcity, d_type),
- SINGLE_MOVE, unit_types[d_type].hp);
- }
- danger *= POWER_DIVIDER;
-
- /* If we are fast, there is less danger. */
- danger /= (unit_type(punit)->move_rate / SINGLE_MOVE);
- if (unit_flag(punit, F_IGTER)) {
- danger /= 1.5;
- }
-
- ptile = map_get_tile(punit->x, punit->y);
- /* We look for the bodyguard where we stand. */
- if (!unit_list_find(&ptile->units, punit->ai.bodyguard)) {
- int my_def = (punit->hp * (punit->veteran ? 15 : 10)
- * unit_type(punit)->defense_strength);
-
- /* FIXME: danger is multiplied by POWER_FACTOR, my_def isn't. */
- if (danger >= my_def) {
- UNIT_LOG(LOGLEVEL_BODYGUARD, punit,
- "wants a bodyguard, danger=%d, my_def=%d", danger, my_def);
- punit->ai.bodyguard = BODYGUARD_WANTED;
- } else {
- punit->ai.bodyguard = BODYGUARD_NONE;
- }
- }
-
- /* What if we have a bodyguard, but don't need one? */
-}
-
-/**************************************************************************
- Return values: FALSE if died or stuck, TRUE otherwise. (This function
- is not server-side autoattack safe.)
-**************************************************************************/
-static bool ai_military_gothere(struct player *pplayer, struct unit *punit,
- int dest_x, int dest_y)
-{
- int id, x, y, boatid = 0, bx = -1, by = -1;
- struct unit *ferryboat = NULL;
- struct unit *def;
- struct tile *ptile;
- bool boat_arrived;
-
- CHECK_UNIT(punit);
-
- id = punit->id; x = punit->x; y = punit->y;
-
- if (same_pos(dest_x, dest_y, x, y)) {
- /* Nowhere to go */
- return FALSE;
- }
-
- if (is_ground_unit(punit)) {
- boatid = find_boat(pplayer, &bx, &by, 2);
- /* NB: ferryboat is set only if the boat is where we are */
- ferryboat = unit_list_find(&(map_get_tile(x, y)->units), boatid);
- }
-
- /* See if we need a bodyguard at our destination */
- ai_gothere_bodyguard(punit, dest_x, dest_y);
-
- if (!goto_is_sane(punit, dest_x, dest_y, TRUE)
- || (ferryboat && goto_is_sane(ferryboat, dest_x, dest_y, TRUE))) {
- punit->ai.ferryboat = boatid;
- UNIT_LOG(LOG_DEBUG, punit, "Looking for boat[%d].", boatid);
- if (boatid > 0 && !same_pos(x, y, bx, by)) {
- /* Go to the boat */
- /* FIXME: this can lose bodyguard */
- if (!ai_unit_goto(punit, bx, by)) {
- /* Died. */
- return FALSE;
- }
- }
- ptile = map_get_tile(punit->x, punit->y);
- ferryboat = unit_list_find(&ptile->units, punit->ai.ferryboat);
-
- if (ferryboat && (ferryboat->ai.passenger == 0
- || ferryboat->ai.passenger == punit->id)) {
- int boat_x, boat_y;
-
- UNIT_LOG(LOG_DEBUG, punit, "Found boat[%d], going (%d,%d)",
- ferryboat->id, dest_x, dest_y);
- handle_unit_activity_request(punit, ACTIVITY_SENTRY);
- ferryboat->ai.passenger = punit->id;
-
- /* Last ingredient: a beachhead. */
- if (find_beachhead(punit, dest_x, dest_y, &boat_x, &boat_y)) {
- UNIT_LOG(LOG_DEBUG, punit, "Found beachhead (%d,%d), all aboard",
- boat_x, boat_y);
- set_goto_dest(ferryboat, boat_x, boat_y);
- set_goto_dest(punit, dest_x, dest_y);
- unit_list_iterate(ptile->units, mypass) {
- if (mypass->ai.ferryboat == ferryboat->id
- && punit->owner == mypass->owner) {
- handle_unit_activity_request(mypass, ACTIVITY_SENTRY);
- def = unit_list_find(&ptile->units, mypass->ai.bodyguard);
- if (def) {
- handle_unit_activity_request(def, ACTIVITY_SENTRY);
- }
- }
- } unit_list_iterate_end; /* passengers are safely stowed away */
- if (!ai_unit_goto(ferryboat, dest_x, dest_y)) {
- return FALSE; /* died */
- }
- }
- }
- }
-
- if (ferryboat && is_goto_dest_set(ferryboat)) {
- /* we are on a ferry! did we arrive? */
- boat_arrived = same_pos(ferryboat->x, ferryboat->y,
- goto_dest_x(ferryboat), goto_dest_y(ferryboat))
- || is_tiles_adjacent(ferryboat->x, ferryboat->y,
- goto_dest_x(ferryboat), goto_dest_y(ferryboat));
- } else {
- boat_arrived = FALSE;
- }
-
- if (boat_arrived) {
- handle_unit_activity_request(punit, ACTIVITY_IDLE);
- UNIT_LOG(LOG_DEBUG, punit, "Our boat has arrived");
- }
-
- /* Go where we should be going if we can, and are at our destination
- * if we are on a ferry */
- if (goto_is_sane(punit, dest_x, dest_y, TRUE) && punit->moves_left > 0
- && (!ferryboat || boat_arrived)) {
- set_goto_dest(punit, dest_x, dest_y);
- UNIT_LOG(LOG_DEBUG, punit, "Attempt to walk to (%d,%d)", dest_x, dest_y);
- if (!ai_unit_goto(punit, dest_x, dest_y)) {
- /* died */
- return FALSE;
- }
- /* liable to bump into someone that will kill us. Should avoid? */
- } else {
- UNIT_LOG(LOG_DEBUG, punit, "Not moving");
- }
-
- /* Dead unit shouldn't reach this point */
- CHECK_UNIT(punit);
-
- return (!same_pos(punit->x, punit->y, x, y));
-}
-
/*************************************************************************
Does the unit with the id given have the flag L_DEFEND_GOOD?
**************************************************************************/
@@ -2249,32 +2074,28 @@
/* Then find enemies the hard way */
find_something_to_kill(pplayer, punit, &dest_x, &dest_y);
if (!same_pos(punit->x, punit->y, dest_x, dest_y)) {
- int repeat;
-
- for(repeat = 0; repeat < 2; repeat++) {
if (!is_tiles_adjacent(punit->x, punit->y, dest_x, dest_y)
- || !can_unit_attack_tile(punit, dest_x, dest_y)
- || (could_unit_move_to_tile(punit, dest_x, dest_y) == 0)) {
- /* Can't attack or move usually means we are adjacent but
- * on a ferry. This fixes the problem (usually). */
+ || !can_unit_attack_tile(punit, dest_x, dest_y)) {
+ /* Adjacent and can't attack usually means we are not marines
+ * and on a ferry. This fixes the problem (usually). */
UNIT_LOG(LOG_DEBUG, punit, "mil att gothere -> (%d,%d)",
dest_x, dest_y);
- if (!ai_military_gothere(pplayer, punit, dest_x, dest_y)) {
+ if (!ai_gothere(pplayer, punit, dest_x, dest_y)) {
/* Died or got stuck */
return;
}
- } else {
- /* Close combat. fstk sometimes want us to attack an adjacent
- * enemy that rampage wouldn't */
- UNIT_LOG(LOG_DEBUG, punit, "mil att bash -> %d, %d", dest_x, dest_y);
- if (!ai_unit_attack(punit, dest_x, dest_y)) {
- /* Died */
+ /* Must be adjacent now. */
+ }
+
+ /* Close combat. fstk sometimes want us to attack an adjacent
+ * enemy that rampage wouldn't */
+ UNIT_LOG(LOG_DEBUG, punit, "mil att bash -> %d, %d", dest_x, dest_y);
+ if (!ai_unit_attack(punit, dest_x, dest_y)) {
+ /* Died */
return;
- }
}
- } /* for-loop */
} else {
/* FIXME: This happens a bit too often! */
UNIT_LOG(LOG_DEBUG, punit, "fstk didn't find us a worthy target!");
@@ -2304,14 +2125,14 @@
if ((pc = dist_nearest_city(pplayer, punit->x, punit->y, FALSE, TRUE))) {
if (!is_ocean(map_get_terrain(punit->x, punit->y))) {
UNIT_LOG(LOG_DEBUG, punit, "Barbarian marching to conquer %s",
pc->name);
- (void) ai_military_gothere(pplayer, punit, pc->x, pc->y);
+ (void) ai_gothere(pplayer, punit, pc->x, pc->y);
} else {
/* sometimes find_beachhead is not enough */
if (!find_beachhead(punit, pc->x, pc->y, &fx, &fy)) {
find_city_beach(pc, punit, &fx, &fy);
}
UNIT_LOG(LOG_DEBUG, punit, "Barbarian sailing to %s", pc->name);
- (void) ai_military_gothere(pplayer, punit, fx, fy);
+ (void) ai_gothere(pplayer, punit, fx, fy);
}
}
}
@@ -2406,164 +2227,188 @@
}
}
-/**************************************************************************
-This seems to manage the ferryboat. When it carries units on their way
-to invade something, it goes there. If it carries other units, it returns home.
-When empty, it tries to find some units to carry or goes home or explores.
-Military units handled by ai_manage_military()
-**************************************************************************/
-static void ai_manage_ferryboat(struct player *pplayer, struct unit *punit)
-{ /* It's about 12 feet square and has a capacity of almost 1000 pounds.
- It is well constructed of teak, and looks seaworthy. */
- struct city *pcity;
- struct city *port = NULL;
- struct unit *bodyguard = NULL;
- struct unit_type *punittype = get_unit_type(punit->type);
- int best = 4 * punittype->move_rate, x = punit->x, y = punit->y;
- int n = 0, p = 0;
+#define LOGLEVEL_FERRY LOG_DEBUG
+/****************************************************************************
+ A helper for ai_manage_ferryboat. Finds a passenger for the ferry.
+ Potential passengers signal the boats by setting their ai.ferry field to
+ FERRY_WANTED.
+
+ TODO: lift the path off the map
+****************************************************************************/
+static bool ai_ferry_findcargo(struct unit *punit)
+{
+ /* Path-finding stuff */
+ struct pf_map *map;
+ struct pf_parameter parameter;
+
+ UNIT_LOG(LOGLEVEL_FERRY, punit, "Ferryboat is looking for cargo.");
- CHECK_UNIT(punit);
+ pft_fill_default_parameter(¶meter);
+ pft_fill_unit_overlap_param(¶meter, punit);
+ /* We are looking for our units, no need to look into the unknown */
+ parameter.get_TB = no_fights_or_unknown;
+ parameter.omniscience = FALSE;
+
+ map = pf_create_map(¶meter);
+ while (pf_next(map)) {
+ struct pf_position pos;
- if (!unit_list_find(&map_get_tile(punit->x, punit->y)->units,
punit->ai.passenger)) {
- punit->ai.passenger = 0;
+ pf_next_get_position(map, &pos);
+
+ unit_list_iterate(map_get_tile(pos.x, pos.y)->units, aunit) {
+ if (aunit->ai.ferryboat == FERRY_WANTED) {
+ UNIT_LOG(LOGLEVEL_FERRY, punit,
+ "Found a potential cargo %s[%d](%d,%d), going there",
+ unit_type(aunit)->name, aunit->id, aunit->x, aunit->y);
+ set_goto_dest(punit, aunit->x, aunit->y);
+ /* Exchange phone numbers */
+ ai_set_passenger(punit, aunit);
+ ai_set_ferry(aunit, punit);
+ pf_destroy_map(map);
+ return TRUE;
+ }
+ } unit_list_iterate_end;
}
+
+ pf_destroy_map(map);
+ return FALSE;
+}
- unit_list_iterate(map_get_tile(punit->x, punit->y)->units, aunit)
- if (punit->owner != aunit->owner) {
- continue;
- }
- if (aunit->ai.ferryboat == punit->id) {
- if (punit->ai.passenger == 0) {
- punit->ai.passenger = aunit->id; /* oops */
- }
- if (is_military_unit(aunit) && punit->ai.bodyguard == BODYGUARD_NONE) {
- /* Acquire some protection as we deliver an invasion army */
- UNIT_LOG(LOG_DEBUG, punit, "shout out for a bodyguard");
- punit->ai.bodyguard = BODYGUARD_WANTED;
- }
- p++;
- bodyguard = unit_list_find(&map_get_tile(punit->x, punit->y)->units,
aunit->ai.bodyguard);
- if (is_goto_dest_set(aunit)) { /* HACK */
- pcity = map_get_city(goto_dest_x(aunit), goto_dest_y(aunit));
- } else {
- pcity = NULL;
- }
- if (aunit->ai.bodyguard == BODYGUARD_NONE || bodyguard ||
- (pcity && pcity->ai.invasion >= 2)) {
- if (pcity) {
- UNIT_LOG(LOG_DEBUG, punit, "Ferrying to %s to %s, invasion = %d, body
= %d",
- unit_name(aunit->type), pcity->name,
- pcity->ai.invasion, aunit->ai.bodyguard);
- }
- n++;
- handle_unit_activity_request(aunit, ACTIVITY_SENTRY);
- if (bodyguard) {
- handle_unit_activity_request(bodyguard, ACTIVITY_SENTRY);
- }
- }
- }
- unit_list_iterate_end;
+/****************************************************************************
+ It's about 12 feet square and has a capacity of almost 1000 pounds.
+ It is well constructed of teak, and looks seaworthy.
+
+ Manage ferryboat. If there is a passenger-in-charge, we let it drive the
+ boat. If there isn't, appoint one from those we have on board.
+
+ If there is no one aboard, look for potential cargo. If none found,
+ explore and then go to the nearest port.
+****************************************************************************/
+static void ai_manage_ferryboat(struct player *pplayer, struct unit *punit)
+{
+ struct city *pcity;
+ struct tile *ptile = map_get_tile(punit->x, punit->y);
+
+ CHECK_UNIT(punit);
- /* we try to recover hitpoints if we are in a city, before we leave */
- if (punit->hp < punittype->hp
+ /* Try to recover hitpoints if we are in a city, before we do anything */
+ if (punit->hp < unit_type(punit)->hp
&& (pcity = map_get_city(punit->x, punit->y))) {
- /* Don't do anything, just wait in the city */
- UNIT_LOG(LOG_DEBUG, punit, "waiting in %s to recover hitpoints "
- "before ferrying", pcity->name);
+ UNIT_LOG(LOGLEVEL_FERRY, punit, "waiting in %s to recover hitpoints",
+ pcity->name);
return;
}
- if (p != 0) {
- UNIT_LOG(LOG_DEBUG, punit, "in manage_ferryboat p=%d, n=%d", p, n);
- if (is_goto_dest_set(punit) && punit->moves_left > 0 && n != 0) {
- (void) ai_unit_gothere(punit);
- } else if (n == 0 && !map_get_city(punit->x, punit->y)) { /* rest in a
city, for unhap */
- port = find_nearest_safe_city(punit);
- if (port && !ai_unit_goto(punit, port->x, port->y)) {
- return; /* oops! */
- }
- send_unit_info(pplayer, punit); /* to get the crosshairs right -- Syela
*/
- } else {
- UNIT_LOG(LOG_DEBUG, punit, "Ferryboat %d@(%d,%d) stalling.",
- punit->id, punit->x, punit->y);
- if(is_barbarian(pplayer)) /* just in case */
- (void) ai_manage_explorer(punit);
- }
+ /* Check if we are an empty barbarian boat and so not needed */
+ if (is_barbarian(pplayer)
+ && unit_list_size(&ptile->units) < 2 ) {
+ wipe_unit(punit);
return;
}
- /* check if barbarian boat is empty and so not needed - the crew has landed
*/
- if( is_barbarian(pplayer) && unit_list_size(&map_get_tile(punit->x,
punit->y)->units)<2 ) {
- wipe_unit(punit);
- return;
+ /* Do we have the passenger-in-charge on board? */
+ if (punit->ai.passenger > 0
+ && !unit_list_find(&ptile->units, punit->ai.passenger)) {
+ UNIT_LOG(LOGLEVEL_FERRY, punit, "lost passenger-in-charge[%d], resetting",
+ punit->ai.passenger);
+ punit->ai.passenger = 0;
}
- /* ok, not carrying anyone, even the ferryman */
- punit->ai.passenger = 0;
- UNIT_LOG(LOG_DEBUG, punit, "Ferryboat is lonely.");
- handle_unit_activity_request(punit, ACTIVITY_IDLE);
-
- /* Release bodyguard and let it roam */
- ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
- if (bodyguard) {
- ai_military_attack(pplayer, bodyguard);
+ if (punit->ai.passenger <= 0) {
+ struct unit *bodyguard = NULL;
+
+ /* Try to select passanger-in-charge from among their passengers */
+ unit_list_iterate(ptile->units, aunit) {
+ if (aunit->ai.ferryboat != punit->id) {
+ continue;
+ }
+
+ if (aunit->ai.ai_role != AIUNIT_ESCORT) {
+ /* Bodyguards shouldn't be in charge of boats... */
+ UNIT_LOG(LOGLEVEL_FERRY, punit,
+ "appointed %s[%d] our passenger-in-charge",
+ unit_type(aunit)->name, aunit->id);
+ punit->ai.passenger = aunit->id;
+ break;
+ } else {
+ bodyguard = aunit;
+ }
+ } unit_list_iterate_end;
+
+ if (punit->ai.passenger <= 0 && bodyguard) {
+ UNIT_LOG(LOGLEVEL_FERRY, punit,
+ "has to take %s[%d] as our passenger-in-charge",
+ unit_type(bodyguard)->name, bodyguard->id);
+ punit->ai.passenger = bodyguard->id;
+ }
}
- if (IS_ATTACKER(punit)) {
- if (punit->moves_left > 0) ai_manage_military(pplayer, punit);
- return;
- } /* AI used to build frigates to attack and then use them as ferries --
Syela */
+ if (punit->ai.passenger > 0) {
+ int bossid = punit->ai.passenger; /* For reference */
+ struct unit *boss = find_unit_by_id(bossid);
+ int id = punit->id; /* To check if survived */
+ int moves_left = punit->moves_left; /* Loop prevention */
- /*** Find work ***/
- CHECK_UNIT(punit);
+ assert(boss);
- generate_warmap(map_get_city(punit->x, punit->y), punit);
- p = 0; /* yes, I know it's already zero. -- Syela */
- best = 9999;
- x = -1; y = -1;
- unit_list_iterate(pplayer->units, aunit) {
- if (aunit->ai.ferryboat != 0
- && WARMAP_SEACOST(aunit->x, aunit->y) < best
- && ground_unit_transporter_capacity(aunit->x, aunit->y, pplayer) <= 0
- && is_at_coast(aunit->x, aunit->y)) {
- UNIT_LOG(LOG_DEBUG, punit, "Found a potential pickup %d@(%d, %d)",
- aunit->id, aunit->x, aunit->y);
- x = aunit->x;
- y = aunit->y;
- best = WARMAP_SEACOST(x, y);
+ if (unit_flag(boss, F_SETTLERS) || unit_flag(boss, F_CITIES)) {
+ /* Temporary hack: settlers all go in the end, forcing them
+ * earlier might mean uninitialised cache, so just wait for them */
+ return;
}
- if (is_sailing_unit(aunit)
- && is_ocean(map_get_terrain(aunit->x, aunit->y))) {
- p++;
+
+ UNIT_LOG(LOGLEVEL_FERRY, punit, "passing control to %s[%d]",
+ unit_type(boss)->name, bossid);
+ ai_manage_unit(pplayer, boss);
+
+ if (!find_unit_by_id(id) || punit->moves_left < moves_left) {
+ return;
}
- } unit_list_iterate_end;
- if (best < 4 * unit_type(punit)->move_rate) {
- /* Pickup is within 4 turns to grab, so move it! */
- set_goto_dest(punit, x, y);
- UNIT_LOG(LOG_DEBUG, punit, "Found a friend and going to him @(%d, %d)",
- x, y);
- (void) ai_unit_gothere(punit);
- return;
- }
+ /* We are alive and didn't spend any moves. We are stuck!
+ * NB: it can be that punit->ai.passenger has changed by now,
+ * for example if the boss has landed */
+ UNIT_LOG(LOGLEVEL_FERRY, punit, "taking control back from [%d]",
+ bossid);
- /* do cool stuff here */
- CHECK_UNIT(punit);
+ } else {
+ /* Not carrying anyone, even the ferryman */
- if (punit->moves_left == 0) return;
- pcity = find_city_by_id(punit->homecity);
- if (pcity) {
- if (!ai_handicap(pplayer, H_TARGETS) ||
- unit_move_turns(punit, pcity->x, pcity->y) < p) {
- set_goto_dest(punit, pcity->x, pcity->y);
- UNIT_LOG(LOG_DEBUG, punit, "No friends. Going home.");
- (void) ai_unit_gothere(punit);
+ if (IS_ATTACKER(punit) && punit->moves_left > 0) {
+ /* AI used to build frigates to attack and then use them as ferries
+ * -- Syela */
+ ai_manage_military(pplayer, punit);
+ return;
+ }
+
+ UNIT_LOG(LOGLEVEL_FERRY, punit, "Ferryboat is not carrying anyone.");
+ ai_set_passenger(punit, NULL);
+ handle_unit_activity_request(punit, ACTIVITY_IDLE);
+ CHECK_UNIT(punit);
+
+ /* Try to find passengers */
+ if (ai_ferry_findcargo(punit)) {
+ ai_unit_goto(punit, goto_dest_x(punit), goto_dest_y(punit));
return;
}
}
- if (is_ocean(map_get_terrain(punit->x, punit->y))) {
- /* thanks, Tony */
- (void) ai_manage_explorer(punit);
+
+ CHECK_UNIT(punit);
+
+ if (punit->moves_left == 0
+ || !is_ocean(map_get_terrain(punit->x, punit->y))) {
+ return;
+ }
+
+ (void) ai_manage_explorer(punit);
+ if (punit->moves_left > 0) {
+ struct city *pcity = find_nearest_safe_city(punit);
+ if (pcity) {
+ set_goto_dest(punit, pcity->x, pcity->y);
+ UNIT_LOG(LOGLEVEL_FERRY, punit, "No work, going home");
+ (void) ai_unit_goto(punit, pcity->x, pcity->y);
+ }
}
+
return;
}
Index: server/settlers.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settlers.c,v
retrieving revision 1.173
diff -u -r1.173 settlers.c
--- server/settlers.c 23 Sep 2003 15:59:05 -0000 1.173
+++ server/settlers.c 1 Oct 2003 14:34:14 -0000
@@ -54,6 +54,8 @@
BV_DEFINE(enemy_mask, MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS);
static enemy_mask enemies[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
+static void auto_settler_findwork(struct player *pplayer,
+ struct unit *punit);
static void auto_settlers_player(struct player *pplayer);
static bool is_already_assigned(struct unit *myunit, struct player *pplayer,
int x, int y);
@@ -1188,75 +1190,6 @@
}
/**************************************************************************
- Handles GOTO for settlers. Only ever used in auto_settler_findwork
- below.
-**************************************************************************/
-static bool ai_gothere(struct unit *punit, int gx, int gy, struct unit
*ferryboat)
-{
- struct player *pplayer = unit_owner(punit);
-
- if (same_pos(gx, gy, punit->x, punit->y)) {
- return TRUE;
- }
-
- /*
- * Go by boat if we can't go by foot, or we have already found a boat
- * (since boat travel is usually faster).
- */
- if (!goto_is_sane(punit, gx, gy, TRUE)
- || (ferryboat
- && goto_is_sane(ferryboat, gx, gy, TRUE)
- && (!is_tiles_adjacent(punit->x, punit->y, gx, gy)
- || could_unit_move_to_tile(punit, gx, gy) == 0))) {
- int x, y;
-
- punit->ai.ferryboat = find_boat(pplayer, &x, &y, 1);
- /* TODO: check if we found a boat */
- freelog(LOG_DEBUG, "%d@(%d, %d): Looking for BOAT.",
- punit->id, punit->x, punit->y);
- if (!same_pos(x, y, punit->x, punit->y)) {
- if (!ai_unit_goto(punit, x, y)) {
- return FALSE; /* died */
- }
- }
- ferryboat = unit_list_find(&(map_get_tile(punit->x, punit->y)->units),
- punit->ai.ferryboat);
- set_goto_dest(punit, gx, gy);
-
- if (ferryboat && (ferryboat->ai.passenger == 0
- || ferryboat->ai.passenger == punit->id)) {
- UNIT_LOG(LOG_DEBUG, punit, "We have FOUND BOAT %d, ABOARD",
- ferryboat->id);
- handle_unit_activity_request(punit, ACTIVITY_SENTRY);
- ferryboat->ai.passenger = punit->id;
- set_goto_dest(ferryboat, gx, gy);
- if (!ai_unit_goto(ferryboat, gx, gy)) {
- return FALSE; /* died */
- }
- handle_unit_activity_request(punit, ACTIVITY_IDLE);
- } /* need to zero pass & ferryboat at some point. */
- }
-
- /*
- * Now check if we can walk by foot to our destination
- * (possibly exiting our ferry)
- */
- if (goto_is_sane(punit, gx, gy, TRUE)
- && punit->moves_left > 0
- && (!ferryboat
- || (is_tiles_adjacent(punit->x, punit->y, gx, gy)
- && could_unit_move_to_tile(punit, gx, gy) != 0))) {
- set_goto_dest(punit, gx, gy);
- if (!ai_unit_goto(punit, gx, gy)) {
- return FALSE; /* died */
- }
- punit->ai.ferryboat = 0;
- }
-
- return TRUE;
-}
-
-/**************************************************************************
find some work for the settler
**************************************************************************/
static void auto_settler_findwork(struct player *pplayer, struct unit *punit)
@@ -1311,8 +1244,8 @@
}
/* We've now worked out what to do; go to it! */
- if (!ai_gothere(punit, gx, gy, ferryboat)) {
- /* died */
+ if (!ai_gothere(pplayer, punit, gx, gy)) {
+ /* Died or got stuck */
return;
}
@@ -1384,7 +1317,7 @@
freelog(LOG_DEBUG, "Warmth = %d, game.globalwarming=%d",
pplayer->ai.warmth, game.globalwarming);
unit_list_iterate(pplayer->units, punit) {
- if (punit->ai.control
+ if ((punit->ai.control || pplayer->ai.control)
&& (unit_flag(punit, F_SETTLERS)
|| unit_flag(punit, F_CITIES))) {
freelog(LOG_DEBUG, "%s's settler at (%d, %d) is ai controlled.",
- [freeciv-ai] Re: (PR#6308) Cleanup of ferry handling, Per I. Mathisen, 2003/10/01
- [freeciv-ai] Re: (PR#6308) Cleanup of ferry handling, Gregory Berkolaiko, 2003/10/01
- [freeciv-ai] Re: (PR#6308) Cleanup of ferry handling,
Per I. Mathisen <=
- [freeciv-ai] Re: (PR#6308) Cleanup of ferry handling, Gregory Berkolaiko, 2003/10/01
- [freeciv-ai] Re: (PR#6308) Cleanup of ferry handling, Gregory Berkolaiko, 2003/10/02
- [freeciv-ai] Re: (PR#6308) Cleanup of ferry handling, Per I. Mathisen, 2003/10/02
- [freeciv-ai] Re: (PR#6308) Cleanup of ferry handling, Gregory Berkolaiko, 2003/10/05
|
|