diff -Nur -X/mnt/data/freeciv-dev/freeciv/diff_ignore freeciv/ai/aiunit.c codeciv/ai/aiunit.c --- freeciv/ai/aiunit.c Tue Apr 17 18:13:57 2001 +++ codeciv/ai/aiunit.c Wed Apr 18 00:17:56 2001 @@ -206,28 +206,24 @@ } /********************************************************************** - ... +Returns how many turn it would take punit to reach x,y. IE, if the unit +can arrive this turn it returns 0. +The warmap must be created beforehand. ***********************************************************************/ static int unit_move_turns(struct unit *punit, int x, int y) { - int m, d; - m = unit_types[punit->type].move_rate; - if (unit_flag(punit->type, F_IGTER)) m *= SINGLE_MOVE; - if(is_sailing_unit(punit)) { - struct player *pplayer = get_player(punit->owner); - if (player_owns_active_wonder(pplayer, B_LIGHTHOUSE)) - m += SINGLE_MOVE; - if (player_owns_active_wonder(pplayer, B_MAGELLAN)) - m += (improvement_variant(B_MAGELLAN)==1) ? SINGLE_MOVE : 2 * SINGLE_MOVE; - m += player_knows_techs_with_flag(pplayer,TF_BOAT_FAST)*3; - } + int move_rate = unit_move_rate(punit); + int cost; if (unit_types[punit->type].move_type == LAND_MOVING) - d = warmap.cost[x][y] / m; + cost = warmap.cost[x][y]; else if (unit_types[punit->type].move_type == SEA_MOVING) - d = warmap.seacost[x][y] / m; - else d = real_map_distance(punit->x, punit->y, x, y) * 3 / m; - return(d); + cost = warmap.seacost[x][y]; + else cost = real_map_distance(punit->x, punit->y, x, y) * 3; + + cost = MAX(0, cost - punit->moves_left); + + return (cost + move_rate - 1)/move_rate; } /************************************************************************** @@ -669,9 +665,10 @@ work of Syela - mostly to fix the ZOC/goto strangeness **************************************************************************/ -static int ai_military_findvictim(struct player *pplayer, struct unit *punit, +static int ai_military_findvictim(struct unit *punit, int *dest_x, int *dest_y) { + struct player *pplayer = unit_owner(punit); int x, y, x1, y1, k; int best = 0, a, b, c, d, e, f; struct unit *pdef; @@ -796,7 +793,7 @@ do_unit_goto(punit, GOTO_MOVE_ANY, 0); } else punit->ai.charge = 0; /* can't possibly get there to help */ } else { /* I had these guys set to just fortify, which is so dumb. -- Syela */ - i = ai_military_findvictim(pplayer, punit, &x, &y); + i = ai_military_findvictim(punit, &x, &y); freelog(LOG_DEBUG, "Stationary escort @(%d,%d) received %d best @(%d,%d)", punit->x, punit->y, i, x, y); @@ -1156,6 +1153,11 @@ } } + if (punit->hp < unit_types[punit->type].hp) { + punit->ai.ai_role = AIUNIT_REGENERATE; + return; + } + /* I'm not 100% sure this is the absolute best place for this... -- Syela */ generate_warmap(map_get_city(punit->x, punit->y), punit); /* I need this in order to call unit_move_turns, here and in look_for_charge */ @@ -1210,7 +1212,7 @@ if ((punit->x == pcity->x)&&(punit->y == pcity->y)) { freelog(LOG_DEBUG, "INHOUSE. GOTO AI_NONE(%d)", punit->id); /* aggro defense goes here -- Syela */ - ai_military_findvictim(pplayer, punit, &dest_x, &dest_y); + ai_military_findvictim(punit, &dest_x, &dest_y); punit->ai.ai_role=AIUNIT_NONE; handle_unit_move_request(punit, dest_x, dest_y, FALSE, FALSE); /* might bash someone */ @@ -1558,7 +1560,7 @@ id = punit->id; do { flag = 0; - ai_military_findvictim(pplayer, punit, &dest_x, &dest_y); + ai_military_findvictim(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); @@ -1798,6 +1800,74 @@ } /************************************************************************** +The unit does not have full HP. Regenerate! +The criteria for doing this is minimalizing the number of turns before the +unit is up to full hp, fx by moving the unit into a city. We do not take +into account the usefullness of the new unit pos. + +FIXME: it would be nice to prefer to regenerate on a tile with high +defense value! +**************************************************************************/ +static void ai_regenerate_unit(struct unit *punit) +{ + int best_x, best_y; + struct player *pplayer = unit_owner(punit); + int full_hp = unit_types[punit->type].hp; + int need_hp = full_hp - punit->hp; + int hp_gain = hp_gain_coord(punit, punit->x, punit->y); + int best_turns = (need_hp+hp_gain-1)/hp_gain; + int id = punit->id; + + assert(need_hp > 0); + + /* See if there is any obvious goodies adjacent. */ + if (ai_military_findvictim(punit, &best_x, &best_y)) { + /* FIXME: This only checks the adjacent tiles. + We could check a bit further. */ + handle_unit_move_request(punit, best_x, best_y, 0, 1); + return; + } else { /* Nope. Continue regeneration. */ + best_x = punit->x; + best_y = punit->y; + } + + /* Determine best place to go. */ + generate_warmap(NULL, punit); + whole_map_iterate(x, y) { + int regen_turns; + if (is_non_allied_city_tile(map_get_tile(x, y), punit->owner) + || is_non_allied_unit_tile(map_get_tile(x, y), punit->owner)) + continue; + + hp_gain = hp_gain_coord(punit, x, y); + regen_turns = unit_move_turns(punit, x, y) + 1 + (need_hp+hp_gain-1)/hp_gain; + + if (regen_turns < best_turns) { + best_turns = regen_turns; + best_x = x; + best_y = y; + } + } whole_map_iterate_end; + + /* Go there! */ + if (best_x != punit->x || best_y != punit->y) { + punit->goto_dest_x = best_x; + punit->goto_dest_y = best_y; + do_unit_goto(punit, GOTO_MOVE_ANY, 0); + } + + if (!player_find_unit_by_id(pplayer, id)) + return; /* died. */ + + /* Fortifying is always good. You also gain HP's faster that way! */ + if (punit->x == best_x && punit->y == punit->y) { + if (can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) { + handle_unit_activity_request(punit, ACTIVITY_FORTIFYING); + } + } +} + +/************************************************************************** decides what to do with a military unit. **************************************************************************/ static void ai_manage_military(struct player *pplayer, struct unit *punit) @@ -1852,6 +1922,9 @@ break; case AIUNIT_EXPLORE: ai_manage_explorer(punit); + break; + case AIUNIT_REGENERATE: + ai_regenerate_unit(punit); break; default: abort(); diff -Nur -X/mnt/data/freeciv-dev/freeciv/diff_ignore freeciv/common/unit.h codeciv/common/unit.h --- freeciv/common/unit.h Tue Apr 17 18:14:24 2001 +++ codeciv/common/unit.h Wed Apr 18 00:15:50 2001 @@ -50,7 +50,7 @@ enum ai_unit_task { AIUNIT_NONE, AIUNIT_AUTO_SETTLER, AIUNIT_BUILD_CITY, AIUNIT_DEFEND_HOME, AIUNIT_ATTACK, AIUNIT_FORTIFY, AIUNIT_RUNAWAY, AIUNIT_ESCORT, AIUNIT_EXPLORE, - AIUNIT_PILLAGE }; + AIUNIT_PILLAGE, AIUNIT_REGENERATE }; enum goto_move_restriction { GOTO_MOVE_ANY, GOTO_MOVE_CARDINAL_ONLY, GOTO_MOVE_STRAIGHTEST diff -Nur -X/mnt/data/freeciv-dev/freeciv/diff_ignore freeciv/server/unittools.c codeciv/server/unittools.c --- freeciv/server/unittools.c Tue Apr 17 18:14:35 2001 +++ codeciv/server/unittools.c Wed Apr 18 00:15:50 2001 @@ -1053,12 +1053,9 @@ was_lower=(punit->hp < get_unit_type(punit->type)->hp); if(!punit->moved) { - punit->hp+=hp_gain_coord(punit); + punit->hp+=hp_gain_coord(punit, punit->x, punit->y); } - if (player_owns_active_wonder(pplayer, B_UNITED)) - punit->hp+=2; - if(is_heli_unit(punit)) { struct city *pcity = map_get_city(punit->x,punit->y); if(!pcity) { @@ -1106,15 +1103,16 @@ ports will regen navalunits completely fortify will add a little extra. ***************************************************************************/ -int hp_gain_coord(struct unit *punit) +int hp_gain_coord(struct unit *punit, int x, int y) { int hp; struct city *pcity; + struct player *pplayer = unit_owner(punit); if (unit_on_fortress(punit)) hp=get_unit_type(punit->type)->hp/4; else hp=0; - if((pcity=map_get_city(punit->x,punit->y))) { + if ((pcity=map_get_city(x, y))) { if ((city_got_barracks(pcity) && (is_ground_unit(punit) || improvement_variant(B_BARRACKS)==1)) || (city_got_building(pcity, B_AIRPORT) && is_air_unit(punit)) || @@ -1130,7 +1128,10 @@ if(punit->activity==ACTIVITY_FORTIFIED) hp++; - + + if (player_owns_active_wonder(pplayer, B_UNITED)) + hp += 2; + return hp; } diff -Nur -X/mnt/data/freeciv-dev/freeciv/diff_ignore freeciv/server/unittools.h codeciv/server/unittools.h --- freeciv/server/unittools.h Tue Apr 17 18:14:35 2001 +++ codeciv/server/unittools.h Wed Apr 18 00:15:50 2001 @@ -53,7 +53,7 @@ /* turn update related */ void player_restore_units(struct player *pplayer); void update_unit_activities(struct player *pplayer); -int hp_gain_coord(struct unit *punit); +int hp_gain_coord(struct unit *punit, int x, int y); /* various */