diff -ur -X freeciv_st/diff_ignore freeciv_clean/ai/advmilitary.c freeciv_st/ai/advmilitary.c --- freeciv_clean/ai/advmilitary.c Tue Dec 24 23:45:11 2002 +++ freeciv_st/ai/advmilitary.c Wed Dec 25 19:13:38 2002 @@ -811,25 +811,25 @@ int value, Unit_Type_id victim_unit_type, bool veteran, int x, int y, bool unhap, int *best_value, int *best_choice, - int boatx, int boaty, int boatspeed, + struct unit *boat, Unit_Type_id boattype, int needferry) { /* The enemy city. acity == NULL means stray enemy unit */ struct city *acity = map_get_city(x, y); bool shore = is_terrain_near_tile(pcity->x, pcity->y, T_OCEAN); int orig_move_type = unit_types[*best_choice].move_type; - int victim_move_rate = 1; int victim_count = 1; + if ( !(orig_move_type == SEA_MOVING || orig_move_type == LAND_MOVING) ) { + freelog(LOG_ERROR, "Attempting to deal with non-trivial move_type" + "in process_attacker_want"); + return; + } + if (acity) { /* If it is a city, we may have to whack it many times */ /* FIXME: Also valid for fortresses! */ victim_count += unit_list_size(&(map_get_tile(x, y)->units)); - } else { - victim_move_rate = unit_types[victim_unit_type].move_rate; - if (unit_type_flag(victim_unit_type, F_IGTER)) { - victim_move_rate *= SINGLE_MOVE; - } } simple_ai_unit_type_iterate (unit_type) { @@ -880,43 +880,13 @@ } /* Set the move_time appropriatelly. */ - - switch(move_type) { - case LAND_MOVING: - if (boatspeed > 0) { - /* It's either city or too far away, so don't bother with - * victim_move_rate. */ - move_time = (warmap.cost[boatx][boaty] + move_rate - 1) / move_rate - + 1 + warmap.seacost[x][y] / boatspeed; /* kludge */ - if (unit_type_flag(unit_type, F_MARINES)) move_time -= 1; - - } else if (warmap.cost[x][y] <= move_rate) { - /* It's adjacent. */ - move_time = 1; - - } else { - /* Cost for attacking the victim. */ - /* FIXME? Why we should multiply the cost by move rate?! --pasky */ - move_time = (warmap.cost[x][y] * victim_move_rate + move_rate - 1) - / move_rate; - } - break; - case SEA_MOVING: - if (warmap.seacost[x][y] <= move_rate) { - /* It's adjectent. */ - move_time = 1; - - } else { - /* See above. */ - move_time = (warmap.seacost[x][y] * victim_move_rate + move_rate - 1) - / move_rate; - } - break; - default: - /* This should be never reached. */ - freelog(LOG_ERROR, "Attempting to deal with non-trivial move_type" - "in process_attacker_want"); - continue; + if (acity) { + move_time = time_to_enemy_city(unit_type, acity, move_rate, + (boattype < U_LAST), boat, boattype); + } else { + /* Target is in the field */ + move_time = time_to_enemy_unit(unit_type, move_rate, x, y, + victim_unit_type); } /* Estimate strength of the enemy. */ @@ -1044,7 +1014,10 @@ struct unit *pdef; /* Coordinates of the boat */ int bx = 0, by = 0; - int needferry = 0, boatspeed; + /* Type of the boat (real or a future one) */ + Unit_Type_id boattype = U_LAST; + int boatspeed; + int needferry = 0; bool go_by_boat; /* Is the defender veteran? */ bool def_vet; @@ -1065,14 +1038,16 @@ ferryboat = player_find_unit_by_id(pplayer, boatid); } - /* FIXME: hardcoded boat speed */ if (ferryboat) { - boatspeed = (unit_flag(ferryboat, F_TRIREME) - ? 2*SINGLE_MOVE : 4*SINGLE_MOVE); - } else { - boatspeed = (get_invention(pplayer, game.rtech.nav) != TECH_KNOWN - ? 2*SINGLE_MOVE : 4*SINGLE_MOVE); + boattype = ferryboat->type; + } else { + boattype = best_role_unit_for_player(pplayer, L_FERRYBOAT); + if (boattype == U_LAST) { + /* We pretend that we can have the simplest boat -- to stimulate tech */ + boattype = get_role_unit(L_FERRYBOAT, 0); + } } + boatspeed = unit_types[boattype].move_rate; (void) find_something_to_kill(pplayer, myunit, &x, &y); @@ -1110,33 +1085,9 @@ go_by_boat = !(goto_is_sane(myunit, acity->x, acity->y, TRUE) && warmap.cost[x][y] <= (MIN(6, move_rate) * THRESHOLD)); - if (is_ground_unit(myunit)) { - if (go_by_boat) { - if (ferryboat) { - /* Time to boat and then to destination and then disembark */ - move_time = (warmap.cost[bx][by] + move_rate - 1) / move_rate - + warmap.seacost[acity->x][acity->y] / boatspeed + 1; - } else { - /* We will build a boat here */ - move_time = warmap.seacost[acity->x][acity->y] / boatspeed + 1; - } - if (unit_flag(myunit, F_MARINES)) { - /* No need to lose a turn getting off the boat */ - move_time -= 1; - } - freelog(LOG_DEBUG, "%s attempting to attack via ferryboat" - " (move_time = %d)", unit_types[att_type].name, move_time); - } else { - /* We are just walking */ - move_time = (warmap.cost[acity->x][acity->y] + move_rate - 1) - / move_rate; - } - } else { - /* We are a boat */ - move_time = (warmap.seacost[acity->x][acity->y] + move_rate - 1) - / move_rate; - } - + move_time = time_to_enemy_city(myunit->type, acity, move_rate, go_by_boat, + ferryboat, boattype); + def_type = ai_choose_defender_versus(acity, att_type); if (move_time > 1) { def_vet = do_make_unit_veteran(acity, def_type); @@ -1174,8 +1125,6 @@ /* end dealing with cities */ } else { - /* variable of unknown meaning */ - int dist; pdef = get_defender(myunit, x, y); if (!pdef) { @@ -1188,28 +1137,9 @@ benefit = unit_type(pdef)->build_cost; go_by_boat = FALSE; - - if (is_ground_unit(myunit)) { - dist = warmap.cost[x][y]; - } else { - /* We ar a boat */ - dist = warmap.seacost[x][y]; - } - - /* FIXME: WHATS THIS??? - * Seems like a poor attempt to take into account that - * the victim can run away */ - if (dist > benefit) { - dist *= unit_type(pdef)->move_rate; - if (unit_flag(pdef, F_IGTER)) { - dist *= 3; - } - } - if (dist == 0) { - dist = 1; - } - move_time = ((dist + move_rate - 1) / move_rate); + move_time + = time_to_enemy_unit(myunit->type, move_rate, x, y, pdef->type); def_type = pdef->type; vuln = unit_vulnerability_virtual2(att_type, def_type, x, y, @@ -1265,16 +1195,15 @@ } if (!go_by_boat) { - process_attacker_want(pplayer, pcity, benefit, def_type, def_vet, - x, y, unhap, &want, &att_type, 0, 0, 0, needferry); + process_attacker_want(pplayer, pcity, benefit, def_type, def_vet, x, y, + unhap, &want, &att_type, NULL, U_LAST, needferry); } else if (ferryboat) { - process_attacker_want(pplayer, pcity, benefit, def_type, def_vet, - x, y, unhap, &want, &att_type, - bx, by, boatspeed, needferry); + process_attacker_want(pplayer, pcity, benefit, def_type, def_vet, x, y, + unhap, &want, &att_type, ferryboat, + boattype, needferry); } else { - process_attacker_want(pplayer, pcity, benefit, def_type, def_vet, - x, y, unhap, &want, &att_type, - myunit->x, myunit->y, boatspeed, needferry); + process_attacker_want(pplayer, pcity, benefit, def_type, def_vet, x, y, + unhap, &want, &att_type, NULL, boattype, needferry); } if (want > choice->want) { diff -ur -X freeciv_st/diff_ignore freeciv_clean/ai/aiunit.c freeciv_st/ai/aiunit.c --- freeciv_clean/ai/aiunit.c Wed Dec 25 13:10:30 2002 +++ freeciv_st/ai/aiunit.c Wed Dec 25 19:18:52 2002 @@ -1544,6 +1544,92 @@ } } +/*************************************************************************** + * A rough estimate of time (measured in turns) to get to the enemy city, + * taking into account ferry transfer. + * If boat == NULL, we will build a boat of type boattype right here, so + * we wouldn't have to walk to it. + * + * Requires ready warmap(s). Assumes punit is ground or sailing. + ***************************************************************************/ +int time_to_enemy_city(Unit_Type_id our_type, struct city *acity, + int speed, bool go_by_boat, + struct unit *boat, Unit_Type_id boattype) +{ + switch(unit_types[our_type].move_type) { + case LAND_MOVING: + if (go_by_boat) { + int boatspeed = unit_types[boattype].move_rate; + int move_time = (warmap.seacost[acity->x][acity->y]) / boatspeed; + + if (unit_type_flag(boattype, F_TRIREME) && move_time > 2) { + /* Return something prohibitive */ + return 999; + } + if (boat) { + /* Time to get to the boat */ + move_time += (warmap.cost[boat->x][boat->y] + speed - 1) / speed; + } + + if (!unit_type_flag(our_type, F_MARINES)) { + /* Time to get off the boat (Marines do it from the vessel) */ + move_time += 1; + } + + return move_time; + } else { + /* We are walking */ + return (warmap.cost[acity->x][acity->y] + speed - 1) / speed; + } + case SEA_MOVING: + /* We are a boat: time to sail */ + return (warmap.seacost[acity->x][acity->y] + speed - 1) / speed; + default: + freelog(LOG_ERROR, "Unsupported move_type in time_to_enemy_city"); + /* Return something prohibitive */ + return 999; + } + +} + +/************************************************************************ + * Rough estimate of time (in turns) to catch up with the enemy unit. + * FIXME: Take enemy speed into account in a more sensible way + * + * Requires precomputed warmap. Assumes punit is ground or sailing. + ************************************************************************/ +int time_to_enemy_unit(Unit_Type_id our_type, int speed, int x, int y, + Unit_Type_id enemy_type) +{ + int dist; + + switch(unit_types[our_type].move_type) { + case LAND_MOVING: + dist = warmap.cost[x][y]; + break; + case SEA_MOVING: + dist = warmap.seacost[x][y]; + break; + default: + /* Compiler warning */ + dist = 0; + freelog(LOG_ERROR, "Unsupported unit_type in time_to_enemy_city"); + /* Return something prohibitive */ + return 999; + } + + /* if dist <= move_rate, we hit the enemy right now */ + if (dist > speed) { + /* Weird attempt to take into account enemy running away... */ + dist *= unit_types[enemy_type].move_rate; + if (unit_type_flag(enemy_type, F_IGTER)) { + dist *= 3; + } + } + + return (dist + speed - 1) / speed; +} + /************************************************************************* Mark invasion possibilities of punit in the surrounding cities. The given radius limites the area which is searched for cities. The @@ -1615,7 +1701,8 @@ int bcost, bcost_bal; bool handicap = ai_handicap(pplayer, H_TARGETS); struct unit *ferryboat = NULL; - int boatspeed; + /* Type of our boat (a future one if ferryboat == NULL) */ + Unit_Type_id boattype = U_LAST; bool unhap = FALSE; struct city *pcity; /* this is a kluge, because if we don't set x and y with !punit->id, @@ -1718,16 +1805,15 @@ } if (ferryboat) { + boattype = ferryboat->type; really_generate_warmap(map_get_city(ferryboat->x, ferryboat->y), ferryboat, SEA_MOVING); - } - - if (ferryboat) { - boatspeed = (unit_flag(ferryboat, F_TRIREME) - ? 2 * SINGLE_MOVE : 4 * SINGLE_MOVE); } else { - boatspeed = ((get_invention(pplayer, game.rtech.nav) != TECH_KNOWN) - ? 2 * SINGLE_MOVE : 4 * SINGLE_MOVE); + boattype = best_role_unit_for_player(pplayer, L_FERRYBOAT); + if (boattype == U_LAST) { + /* We pretend that we can have the simplest boat -- to stimulate tech */ + boattype = get_role_unit(L_FERRYBOAT, 0); + } } if (is_ground_unit(punit) && punit->id == 0 @@ -1742,20 +1828,19 @@ } city_list_iterate(aplayer->cities, acity) { - bool go_by_boat; + bool go_by_boat = (is_ground_unit(punit) + && !(goto_is_sane(punit, acity->x, acity->y, TRUE) + && warmap.cost[acity->x][acity->y] < maxd)); if (handicap && !map_get_known(acity->x, acity->y, pplayer)) { /* Can't see it */ continue; } - go_by_boat = !(goto_is_sane(punit, acity->x, acity->y, TRUE) - && warmap.cost[acity->x][acity->y] < maxd); - - if (is_ground_unit(punit) && go_by_boat - && (!(ferryboat || harbor) + if (go_by_boat + && (!(ferryboat || harbor) || warmap.seacost[acity->x][acity->y] > 6 * THRESHOLD)) { - /* Too far to go by boat */ + /* Too far or impossible to go by boat */ continue; } @@ -1773,34 +1858,8 @@ benefit = 0; } - if (is_ground_unit(punit)) { - if (go_by_boat) { - move_time = (warmap.seacost[acity->x][acity->y]) / boatspeed; - if (boatspeed < 9 && move_time > 2) { - /* I guess that's for triremes -- GB */ - move_time = 999; - } - if (ferryboat) { - /* Time to get to the boat + get off the boat */ - move_time += (warmap.cost[bx][by] + move_rate - 1) / move_rate + 1; - } else { - /* Time to get off the boat */ - move_time += 1; - } - if (unit_flag(punit, F_MARINES)) { - /* They can do it from the boat */ - move_time -= 1; - } - } else { - /* Time to walk */ - move_time - = (warmap.cost[acity->x][acity->y] + move_rate - 1) / move_rate; - } - } else { - /* We are boat: time to sail */ - move_time - = (warmap.seacost[acity->x][acity->y] + move_rate - 1) / move_rate; - } + move_time = time_to_enemy_city(punit->type, acity, move_rate, + go_by_boat, ferryboat, boattype); if (move_time > 1) { Unit_Type_id def_type = ai_choose_defender_versus(acity, punit->type); @@ -1860,9 +1919,9 @@ } want -= move_time * (unhap ? SHIELD_WEIGHTING + 2 * TRADE_WEIGHTING : SHIELD_WEIGHTING); - /* FIXME: build_cost of ferry */ - needferry = - (go_by_boat && !ferryboat && is_ground_unit(punit) ? 40 : 0); + /* build_cost of ferry */ + needferry = (go_by_boat && !ferryboat ? unit_value(boattype) : 0); + /* FIXME: add time to build the ferry? */ want = military_amortize(want, MAX(1, move_time), bcost_bal + needferry); /* BEGIN STEAM-ENGINES-ARE-OUR-FRIENDS KLUGE */ @@ -1917,9 +1976,6 @@ * I am deliberately not adding ferryboat code to the unit_list_iterate. * -- Syela */ unit_list_iterate(aplayer->units, aunit) { - /* Variable of unknown meaning */ - int dist; - if (map_get_city(aunit->x, aunit->y)) { /* already dealt with it */ continue; @@ -1958,20 +2014,8 @@ vuln = unit_vulnerability(punit, aunit); benefit = unit_type(aunit)->build_cost; - if (is_ground_unit(punit)) { - dist = warmap.cost[aunit->x][aunit->y]; - } else { - dist = warmap.seacost[aunit->x][aunit->y]; - } - - if (dist > move_rate) { - /* if dist <= move_rate, it can't run away -- Syela */ - dist *= unit_type(aunit)->move_rate; - if (unit_flag(aunit, F_IGTER)) { - dist *= 3; - } - } - move_time = (dist + move_rate - 1) / move_rate; + move_time = time_to_enemy_unit(punit->type, move_rate, + aunit->x, aunit->y, aunit->type); if (!CAN_OCCUPY(punit) && vuln == 0) { /* FIXME: There is something with defence 0 there, maybe a diplomat. diff -ur -X freeciv_st/diff_ignore freeciv_clean/ai/aiunit.h freeciv_st/ai/aiunit.h --- freeciv_clean/ai/aiunit.h Wed Dec 25 13:09:02 2002 +++ freeciv_st/ai/aiunit.h Wed Dec 25 19:16:04 2002 @@ -51,6 +51,11 @@ bool ai_manage_explorer(struct unit *punit); +int time_to_enemy_city(Unit_Type_id our_type, struct city *acity, + int speed, bool go_by_boat, + struct unit *boat, Unit_Type_id boattype); +int time_to_enemy_unit(Unit_Type_id our_type, int speed, int x, int y, + Unit_Type_id enemy_type); int find_something_to_kill(struct player *pplayer, struct unit *punit, int *x, int *y); int find_beachhead(struct unit *punit, int dest_x, int dest_y, int *x, int *y);