diff -uNrX freeciv/diff_ignore freeciv/ai/aiunit.c freeciv-ai/ai/aiunit.c --- freeciv/ai/aiunit.c 2002-08-13 03:15:25.000000000 +0200 +++ freeciv-ai/ai/aiunit.c 2002-08-13 03:06:02.000000000 +0200 @@ -56,6 +56,7 @@ static void ai_military_findjob(struct player *pplayer,struct unit *punit); static void ai_military_gohome(struct player *pplayer,struct unit *punit); static void ai_military_attack(struct player *pplayer,struct unit *punit); +static struct unit *ai_military_rampage(struct unit *punit, int threshold); static int unit_move_turns(struct unit *punit, int x, int y); static bool unit_can_defend(Unit_Type_id type); @@ -939,9 +940,9 @@ If value <= 0 is returned, (dest_x, dest_y) is set to actual punit's position. **************************************************************************/ -static int ai_military_findvictim(struct player *pplayer, struct unit *punit, - int *dest_x, int *dest_y) +static int ai_military_findvictim(struct unit *punit, int *dest_x, int *dest_y) { + struct player *pplayer = unit_owner(punit); int bellig = unit_belligerence_primitive(punit); int x = punit->x, y = punit->y; int best = 0; @@ -1075,6 +1076,23 @@ } /************************************************************************* + Find and kill anything adjacent to us that we don't like with a + given threshold until we have run out of juicy targets or movement. + Wraps ai_military_findvictim(). +**************************************************************************/ +static struct unit *ai_military_rampage(struct unit *punit, int threshold) +{ + int x, y, id = punit->id; + + while (punit && punit->moves_left + && ai_military_findvictim(punit, &x, &y) >= threshold) { + ai_unit_attack(punit, x, y); + punit = find_unit_by_id(id); + } + return punit; +} + +/************************************************************************* If we are not covering our charge's ass, go do it now. Also check if we can kick some ass, which is always nice. **************************************************************************/ @@ -1116,12 +1134,7 @@ } } else { /* I had these guys set to just fortify, which is so dumb. -- Syela */ - int i = ai_military_findvictim(pplayer, punit, &x, &y); - freelog(LOG_DEBUG, "Stationary escort @(%d,%d) received %d best @(%d,%d)", - punit->x, punit->y, i, x, y); - if (i >= 40 * SHIELD_WEIGHTING) { ai_unit_attack(punit, x, y); } - /* otherwise don't bother, but free cities are free cities and must be - snarfed. -- Syela */ + punit = ai_military_rampage(punit, 40 * SHIELD_WEIGHTING); } /* is this insanity supposed to be a sanity check? -- per */ @@ -1567,7 +1580,6 @@ static void ai_military_gohome(struct player *pplayer,struct unit *punit) { struct city *pcity; - int dest_x, dest_y; if (punit->homecity != 0){ pcity=find_city_by_id(punit->homecity); freelog(LOG_DEBUG, "GOHOME (%d)(%d,%d)C(%d,%d)", @@ -1576,10 +1588,7 @@ freelog(LOG_DEBUG, "INHOUSE. GOTO AI_NONE(%d)", punit->id); punit->ai.ai_role=AIUNIT_NONE; /* aggro defense goes here -- Syela */ - if (ai_military_findvictim(pplayer, punit, &dest_x, &dest_y) > 1) { - assert(dest_x != punit->x || dest_y != punit->y); - ai_unit_attack(punit, dest_x, dest_y); /* might bash someone */ - } + punit = ai_military_rampage(punit, 2); /* 2 is better than pillage */ } else { freelog(LOG_DEBUG, "GOHOME(%d,%d)", punit->goto_dest_x, punit->goto_dest_y); @@ -1937,80 +1946,83 @@ } /************************************************************************* -This seems to do the attack. First find victim on the neighbouring tiles. -If no enemies nearby find_something_to_kill() anywhere else. If there is -nothing to kill, sailing units go home, others explore. +This does the attack until we have used up all our movement, unless we +should safeguard a city. First we rampage on adjacent tiles, then we go +looking for trouble elsewhere. If there is nothing to kill, sailing units +go home, others explore while barbs go berserk. **************************************************************************/ static void ai_military_attack(struct player *pplayer,struct unit *punit) { int dest_x, dest_y; - int id; - bool flag; - int went, ct = 10; - - if (punit->activity!=ACTIVITY_GOTO) { - id = punit->id; - do { - flag = FALSE; - ai_military_findvictim(pplayer, punit, &dest_x, &dest_y); - if (dest_x == punit->x && dest_y == punit->y) { -/* no one to bash here. Will try to move onward */ - find_something_to_kill(pplayer, punit, &dest_x, &dest_y); - if (same_pos(punit->x, punit->y, dest_x, dest_y)) { -/* nothing to kill. Adjacency is something for us to kill later. */ - if (is_sailing_unit(punit)) { - if (find_nearest_friendly_port(punit) - && do_unit_goto(punit, GOTO_MOVE_ANY, FALSE) == GR_DIED) { - return; - } - } else { - ai_manage_explorer(punit); /* nothing else to do */ - /* you can still have some moves left here, but barbarians should - not sit helplessly, but advance towards nearest known enemy city */ - punit = find_unit_by_id(id); /* unit might die while exploring */ - if( punit && punit->moves_left > 0 && is_barbarian(pplayer) ) { - struct city *pc; - int fx, fy; - freelog(LOG_DEBUG,"Barbarians looking for target"); - if( (pc = dist_nearest_city(pplayer, punit->x, punit->y, FALSE, TRUE)) ) { - if( map_get_terrain(punit->x,punit->y) != T_OCEAN ) { - freelog(LOG_DEBUG,"Marching to city"); - ai_military_gothere(pplayer, punit, pc->x, pc->y); - } - else { - /* sometimes find_beachhead is not enough */ - if (find_beachhead(punit, pc->x, pc->y, &fx, &fy) == 0) - find_city_beach(pc, punit, &fx, &fy); - freelog(LOG_DEBUG,"Sailing to city"); - ai_military_gothere(pplayer, punit, fx, fy); - } + int id = punit->id; + int ct = 10; + + assert(punit); + if (punit->activity == ACTIVITY_GOTO) { + return; + } + + do { + /* first find adjacent enemies; 2 is better than pillage */ + if (!(punit = ai_military_rampage(punit, 2))) { + return; /* we died */ + } + + /* we survived, will try to move onward */ + find_something_to_kill(pplayer, punit, &dest_x, &dest_y); + if (same_pos(punit->x, punit->y, dest_x, dest_y)) { + /* nothing to kill. Adjacency is something for us to kill later. */ + if (is_sailing_unit(punit) + && find_nearest_friendly_port(punit) + && do_unit_goto(punit, GOTO_MOVE_ANY, FALSE) == GR_DIED) { + /* sail towards safe harbour but we might encounter something + on the way that would require our attention, so don't stop + yet */ + return; + } else { + ai_manage_explorer(punit); /* nothing else to do */ + if (!(punit = find_unit_by_id(id))) { + /* died while exploring */ + return; + } + /* you can still have some moves left here, but barbarians should + not sit helplessly, but advance towards nearest known enemy city */ + if (punit->moves_left > 0 && is_barbarian(pplayer)) { + struct city *pc; + int fx, fy; + freelog(LOG_DEBUG,"Barbarians looking for target"); + if ((pc = dist_nearest_city(pplayer, punit->x, punit->y, FALSE, TRUE))) { + if (map_get_terrain(punit->x,punit->y) != T_OCEAN) { + freelog(LOG_DEBUG, "Barbarian marching to city"); + ai_military_gothere(pplayer, punit, pc->x, pc->y); + } else { + /* sometimes find_beachhead is not enough */ + if (find_beachhead(punit, pc->x, pc->y, &fx, &fy) == 0) { + find_city_beach(pc, punit, &fx, &fy); + freelog(LOG_DEBUG, "Barbarian sailing to city"); + ai_military_gothere(pplayer, punit, fx, fy); } } } - return; /* Jane, stop this crazy thing! */ - } else if (!is_tiles_adjacent(punit->x, punit->y, dest_x, dest_y)) { -/* if what we want to kill is adjacent, and findvictim didn't want it, WAIT! */ - if ((went = ai_military_gothere(pplayer, punit, dest_x, dest_y)) != 0) { - if (went > 0) { - flag = punit->moves_left > 0; - } else { - punit = NULL; - } - } /* else we're having ZOC hell and need to break out of the loop */ - } /* else nothing to kill */ - } else { /* goto does NOT work for fast units */ - freelog(LOG_DEBUG, "%s's %s at (%d, %d) bashing (%d, %d)", - pplayer->name, unit_type(punit)->name, - punit->x, punit->y, dest_x, dest_y); - ai_unit_attack(punit, dest_x, dest_y); - punit = find_unit_by_id(id); - if (punit) flag = punit->moves_left > 0; else flag = FALSE; - } - if (punit) - if (stay_and_defend_city(punit)) return; - ct--; /* infinite loops from railroads must be stopped */ - } while (flag && ct > 0); /* want units to attack multiple times */ - } /* end if */ + } /* end barb special */ + } + return; /* Jane, stop this crazy thing! */ + } else if (!is_tiles_adjacent(punit->x, punit->y, dest_x, dest_y)) { + (void) ai_military_gothere(pplayer, punit, dest_x, dest_y); + } else { /* close combat */ + freelog(LOG_DEBUG, "%s's %s at (%d, %d) bashing (%d, %d)", + pplayer->name, unit_type(punit)->name, + punit->x, punit->y, dest_x, dest_y); + ai_unit_attack(punit, dest_x, dest_y); + } + if (!(punit = find_unit_by_id(id))) { + return; /* we died */ + } + if (stay_and_defend_city(punit)) { + return; + } + ct--; /* infinite loops from railroads must be stopped */ + } while (punit->moves_left > 0 && ct > 0); } /************************************************************************* @@ -2209,9 +2221,9 @@ **************************************************************************/ static void ai_manage_military(struct player *pplayer, struct unit *punit) { - int id; + int id = punit->id; - id = punit->id; + assert(punit); if (punit->activity != ACTIVITY_IDLE) handle_unit_activity_request(punit, ACTIVITY_IDLE); @@ -2231,7 +2243,8 @@ } } #endif - + + assert(punit); switch (punit->ai.ai_role) { case AIUNIT_AUTO_SETTLER: punit->ai.ai_role = AIUNIT_NONE;