Index: ai/advmilitary.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v retrieving revision 1.93 diff -u -r1.93 advmilitary.c --- ai/advmilitary.c 2002/03/01 14:07:28 1.93 +++ ai/advmilitary.c 2002/03/01 20:15:19 @@ -614,13 +614,11 @@ unit_types[i].move_type == HELI_MOVING) && acity && acity->ai.invasion == 2) b0 = f * SHIELD_WEIGHTING; else { - int a_squared = acity->ai.a * acity->ai.a; - /* See aiunit.c:find_something_to_kill() for comments. */ b0 = kill_desire(b, a, (f + (acity ? acity->ai.f : 0)), d, g); - if (acity && b * a_squared > acity->ai.f * d) { - b0 -= kill_desire(b, a_squared, acity->ai.f, d, g); + if (acity && b * acity->ai.a * acity->ai.a > acity->ai.f * d) { + b0 -= kill_desire(b, acity->ai.a * acity->ai.a, acity->ai.f, d, g); } } if (b0 > 0) { @@ -820,13 +818,11 @@ unit_types[v].move_type == HELI_MOVING) && acity && acity->ai.invasion == 2) b0 = f * SHIELD_WEIGHTING; else { - int a_squared = acity->ai.a * acity->ai.a; - /* See aiunit.c:find_something_to_kill() for comments. */ b0 = kill_desire(b, a, (f + (acity ? acity->ai.f : 0)), d, g); - if (acity && b * a_squared > acity->ai.f * d) { - b0 -= kill_desire(b, a_squared, acity->ai.f, d, g); + if (acity && b * acity->ai.a * acity->ai.a > acity->ai.f * d) { + b0 -= kill_desire(b, acity->ai.a * acity->ai.a, acity->ai.f, d, g); } } b0 -= c * (unhap ? SHIELD_WEIGHTING + 2 * TRADE_WEIGHTING : SHIELD_WEIGHTING); @@ -860,38 +856,19 @@ if (e > choice->want && /* Without this &&, the AI will try to make attackers */ choice->want <= 100) { /* instead of defenders when being attacked -- Syela */ - if (!city_got_barracks(pcity) && is_ground_unit(myunit)) { - if (player_knows_improvement_tech(pplayer, B_BARRACKS3)) - choice->choice = B_BARRACKS3; - else if (player_knows_improvement_tech(pplayer, B_BARRACKS2)) - choice->choice = B_BARRACKS2; - else choice->choice = B_BARRACKS; - choice->want = e; - choice->type = CT_BUILDING; + if (!myunit->id) { + choice->choice = v; + choice->type = CT_ATTACKER; + choice->want = e; + if (needferry) ai_choose_ferryboat(pplayer, pcity, choice); + freelog(LOG_DEBUG, "%s has chosen attacker, %s, want=%d", + pcity->name, unit_types[choice->choice].name, choice->want); } else { - if (!myunit->id) { - choice->choice = v; - choice->type = CT_ATTACKER; - choice->want = e; - if (needferry) ai_choose_ferryboat(pplayer, pcity, choice); - freelog(LOG_DEBUG, "%s has chosen attacker, %s", - pcity->name, unit_types[choice->choice].name); - } else { - choice->choice = ai_choose_defender(pcity); - freelog(LOG_DEBUG, "%s has chosen defender, %s", - pcity->name, unit_types[choice->choice].name); - choice->type = CT_NONMIL; - choice->want = e; - } - if (is_sailing_unit(myunit) && improvement_exists(B_PORT) - && !city_got_building(pcity, B_PORT)) { - Tech_Type_id tech = get_improvement_type(B_PORT)->tech_req; - if (get_invention(pplayer, tech) == TECH_KNOWN) { - choice->choice = B_PORT; - choice->want = e; - choice->type = CT_BUILDING; - } else pplayer->ai.tech_want[tech] += e; - } + choice->choice = ai_choose_defender(pcity); + freelog(LOG_DEBUG, "%s has chosen defender, %s, want=%d", + pcity->name, unit_types[choice->choice].name, choice->want); + choice->type = CT_NONMIL; + choice->want = e; } } } @@ -923,6 +900,98 @@ return FALSE; } +/******************************************************************* + * Chooses the best available and usable air unit and records it in + * choice, if it's better than previous choice + * The interface is somewhat different from other ai_choose, but + * that's what it should be like, I believe -- GB + ******************************************************************/ +bool ai_choose_attacker_air(struct player *pplayer, struct city *pcity, + struct ai_choice *choice) +{ + Unit_Type_id u_type; + bool want_something = FALSE; + + /* military_advisor_choose_build does something idiotic, + * this function should not be called if there is danger... */ + if (choice->want >= 100 && choice->type != CT_ATTACKER) return 0; + + if (!player_knows_techs_with_flag(pplayer, TF_BUILD_AIRBORNE)) return FALSE; + /* TODO: unit_types_iterate */ + for (u_type = 0; u_type < game.num_unit_types; u_type++) { + if (get_unit_type(u_type)->move_type != AIR_MOVING) continue; + if (can_build_unit(pcity, u_type)){ + struct unit *virtual_unit = + create_unit_virtual(pplayer, pcity->x, pcity->y, u_type, TRUE); + int profit = find_something_to_bomb(virtual_unit); + if (profit > choice->want){ + /* Update choice */ + choice->want = profit; + choice->choice = u_type; + choice->type = CT_ATTACKER; + want_something = TRUE; + freelog(LOG_NORMAL, "%s wants to build %s (want=%d)", + pcity->name, get_unit_type(u_type)->name, profit); + } else { + freelog(LOG_DEBUG, "%s doesn't want to build %s (want=%d)", + pcity->name, get_unit_type(u_type)->name, profit); + } + destroy_virtual_unit(virtual_unit); + } + } + + return want_something; +} + +/********************************************************************* + * Before building attacker, AI builds a barracks/port/airport + * TODO: something more sophisticated, like estimating future demand + * for military units, considering Sun Tzu instead. + ********************************************************************/ +static void adjust_ai_attacker_choice(struct city *pcity, + struct ai_choice *choice) +{ + enum unit_move_type move_type; + struct player *pplayer = city_owner(pcity); + + if (choice->type != CT_ATTACKER) return; + if (do_make_unit_veteran(pcity, choice->choice)) return; + + move_type = get_unit_type(choice->choice)->move_type; + if (improvement_variant(B_BARRACKS)==1) { + /* Barracks will work for all units! */ + move_type = LAND_MOVING; + } + + switch(move_type) { + case LAND_MOVING: + if (player_knows_improvement_tech(pplayer, B_BARRACKS3)) { + choice->choice = B_BARRACKS3; + } else if (player_knows_improvement_tech(pplayer, B_BARRACKS2)) { + choice->choice = B_BARRACKS2; + } else { + choice->choice = B_BARRACKS; + } + choice->type = CT_BUILDING; + break; + case SEA_MOVING: + if (player_knows_improvement_tech(pplayer, B_PORT)) { + choice->choice = B_PORT; + choice->type = CT_BUILDING; + } + break; + case HELI_MOVING: + case AIR_MOVING: + if (player_knows_improvement_tech(pplayer, B_AIRPORT)) { + choice->choice = B_AIRPORT; + choice->type = CT_BUILDING; + } + break; + default: + freelog(LOG_ERROR, "Unknown move_type in adjust_ai_attacker_choice"); + } +} + /********************************************************************** ... this function should assign a value to choice and want and type, where want is a value between 1 and 100. @@ -1068,16 +1137,21 @@ virtualunit.hp = unit_types[v].hp; kill_something_with(pplayer, pcity, &virtualunit, choice); } /* ok. can now mung seamap for ferryboat code. Proceed! */ + ai_choose_attacker_air(pplayer, pcity, choice); v = ai_choose_attacker_ground(pcity); virtualunit.type = v; /* virtualunit.veteran = do_make_unit_veteran(pcity, v);*/ virtualunit.veteran = TRUE; virtualunit.hp = unit_types[v].hp; kill_something_with(pplayer, pcity, &virtualunit, choice); + adjust_ai_attacker_choice(pcity, choice); } return; } +/*********************************************************************** +... +***********************************************************************/ void establish_city_distances(struct player *pplayer, struct city *pcity) { int dist, wonder_continent, moverate; Index: ai/aitools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v retrieving revision 1.45 diff -u -r1.45 aitools.c --- ai/aitools.c 2002/02/21 09:44:50 1.45 +++ ai/aitools.c 2002/03/01 20:15:19 @@ -15,19 +15,24 @@ #include #include "city.h" +#include "combat.h" #include "game.h" #include "government.h" #include "log.h" #include "map.h" +#include "mem.h" #include "packets.h" #include "player.h" #include "shared.h" #include "unit.h" +#include "barbarian.h" #include "citytools.h" #include "cityturn.h" +#include "gotohand.h" #include "maphand.h" #include "plrhand.h" +#include "settlers.h" #include "unittools.h" #include "aicity.h" @@ -35,6 +40,68 @@ #include "aitools.h" +/********************************************************** + * Create a virtual unit to use in build want estimation + *********************************************************/ +struct unit *create_unit_virtual(struct player *pplayer, int x, int y, + Unit_Type_id type, bool make_veteran) +{ + struct unit *punit; + punit=fc_calloc(1,sizeof(struct unit)); + + punit->type=type; + punit->owner=pplayer->player_no; + CHECK_MAP_POS(x, y); + punit->x = x; + punit->y = y; + punit->goto_dest_x=0; + punit->goto_dest_y=0; + punit->veteran=make_veteran; + punit->homecity=0; + punit->upkeep=0; + punit->upkeep_food=0; + punit->upkeep_gold=0; + punit->unhappiness=0; + /* A unit new and fresh ... */ + punit->foul = FALSE; + punit->fuel=unit_type(punit)->fuel; + punit->hp=unit_type(punit)->hp; + punit->moves_left=unit_move_rate(punit); + punit->moved = FALSE; + punit->paradropped = FALSE; + if( is_barbarian(pplayer) ) + punit->fuel = BARBARIAN_LIFE; + /* AI.control is robably always true... */ + punit->ai.control = FALSE; + punit->ai.ai_role = AIUNIT_NONE; + punit->ai.ferryboat = 0; + punit->ai.passenger = 0; + punit->ai.bodyguard = 0; + punit->ai.charge = 0; + punit->bribe_cost=-1; /* flag value */ + punit->transported_by = -1; + punit->pgr = NULL; + set_unit_activity(punit, ACTIVITY_IDLE); + + return punit; +} + +/********************************************************************* + * Free the memory used by virtual unit + * It is assumed (since it's virtual) that it's not registered or + * listed anywhere. + ********************************************************************/ +void destroy_virtual_unit(struct unit *punit) +{ + if (punit->pgr) { + free(punit->pgr->pos); + free(punit->pgr); + punit->pgr = NULL; + } + + free(punit); +} + /* dist_nearest_enemy_* are no longer ever used. This is dist_nearest_enemy_city, respaced so I can read it and therefore debug it into something useful. -- Syela @@ -72,6 +139,148 @@ } /************************************************************************** +Looks for nearest airbase for punit. +Returns 0 if not found. +**************************************************************************/ +int find_nearest_airbase(int x, int y, struct unit *punit, int *xref, int *yref) +{ + struct player *pplayer = unit_owner(punit); + int moves_left = punit->moves_left / SINGLE_MOVE; + + iterate_outward(x, y, moves_left, x1, y1) { + if (is_airunit_refuel_point(x1, y1, pplayer, punit->type, 0) + && (air_can_move_between (moves_left, x, y, x1, y1, pplayer) >= 0)) { + *xref = x1; + *yref = y1; + return TRUE; + } + } iterate_outward_end; + + return FALSE; +} + +/******************************************************************** + * Is it a city/fortress or will the whole stack die in an attack + * TODO: use new killstack thing + *******************************************************************/ +static int is_stack_vulnerable(int x, int y) +{ + return !(map_get_city(x, y) != NULL || + map_has_special(x, y, S_FORTRESS) || + map_has_special(x, y, S_AIRBASE) ); +} + +/********************************************************************** +Returns an estimate for the profit gained through attack. +Assumes that the victim is within one day's flight +***********************************************************************/ +int ai_evaluate_tile_for_attack(struct unit *punit, + int dest_x, int dest_y) +{ + struct unit *pdefender = get_defender(punit, dest_x, dest_y); + /* unit costs in shields */ + int balanced_cost, unit_cost, victim_cost = 0; + /* unit stats */ + int unit_attack, victim_defence; + /* final answer */ + int profit; + /* time spent in the air */ + int sortie_time; + + if ((pdefender == NULL) + || !can_unit_attack_unit_at_tile(punit, pdefender, dest_x, dest_y)) { + return 0; + } + + /* Ok, we can attack, but is it worth it? */ + + /* Cost of our unit */ + unit_cost = unit_type(punit)->build_cost; + + /* Determine cost of enemy units */ + if( is_stack_vulnerable(dest_x, dest_y) ) { + /* lotsa people die */ + unit_list_iterate(map_get_tile(dest_x, dest_y)->units, aunit) { + victim_cost += unit_type(aunit)->build_cost; + } unit_list_iterate_end; + } else { + /* Only one unit dies if attack is successful */ + victim_cost = unit_type(pdefender)->build_cost; + } + + /* Missile would die 100% so we adjust the victim_cost -- GB */ + if (unit_flag(punit, F_MISSILE)) { + victim_cost -= unit_type(punit)->build_cost; + } + + /* Attack value of our unit */ + unit_attack = unit_belligerence_basic(punit); + /* Punish unhealthy units */ + unit_attack = unit_attack * punit->hp / unit_type(punit)->hp; + + /* Defence value of the enemy */ + victim_defence = unit_vulnerability_basic(punit, pdefender); + + balanced_cost = build_cost_balanced(punit->type); + + sortie_time = (unit_flag(punit, F_ONEATTACK) ? 2 : 1); + profit = kill_desire(victim_cost, unit_attack, unit_cost, victim_defence, 1) + - SHIELD_WEIGHTING + 2 * TRADE_WEIGHTING; + if (profit > 0) { + profit = military_amortize(profit, sortie_time, balanced_cost); + freelog(LOG_NORMAL, + "%s at (%d, %d) is a worthy target with profit %d", + unit_type(pdefender)->name, dest_x, dest_y, profit); + } else { + freelog(LOG_NORMAL, + "%s at (%d, %d) is unworthy with profit %d", + unit_type(pdefender)->name, dest_x, dest_y, profit); + profit = 0; + } + + return profit; +} + + +/********************************************************************** + * Find something to bomb + * Air-units specific victim search + * Returns the want for the best target, records target in goto_dest_x,y + * TODO: take dangers into account + *********************************************************************/ +int find_something_to_bomb(struct unit *punit) +{ + struct player *pplayer = unit_owner(punit); + int max_dist = punit->moves_left / SINGLE_MOVE; + int x = punit->x; + int y = punit->y; + int best = 0; + + /* Adjust the max distance so Fighters can attack safely */ + if (punit->fuel < 2) { + /* -1 is to take into account the attack itself */ + max_dist = (max_dist - 1) / 2; + } + + /* Let's find something to bomb */ + iterate_outward(x, y, max_dist, x1, y1) { + if (is_enemy_unit_tile(map_get_tile(x1,y1), pplayer) + && (air_can_move_between (max_dist, x, y, x1, y1, pplayer) >= 0)){ + int new_best = ai_evaluate_tile_for_attack(punit, x1, y1); + if (new_best > best) { + punit->goto_dest_x = x1; + punit->goto_dest_y = y1; + best = new_best; + freelog(LOG_DEBUG, "%s wants to attack tile (%d, %d)", + unit_type(punit)->name, x1, y1); + } + } + } iterate_outward_end; + + return best; +} + +/************************************************************************** .. change government,pretty fast.... **************************************************************************/ void ai_government_change(struct player *pplayer, int gov) @@ -113,6 +322,13 @@ void copy_if_better_choice(struct ai_choice *cur, struct ai_choice *best) { if (cur->want > best->want) { + freelog(LOG_DEBUG, "Overriding choice (%s, %d) with (%s, %d)", + (best->type == CT_BUILDING ? + get_improvement_name(best->choice) : unit_types[best->choice].name), + best->want, + (cur->type == CT_BUILDING ? + get_improvement_name(cur->choice) : unit_types[cur->choice].name), + cur->want); best->choice =cur->choice; best->want = cur->want; best->type = cur->type; Index: ai/aitools.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aitools.h,v retrieving revision 1.16 diff -u -r1.16 aitools.h --- ai/aitools.h 2002/02/19 16:41:14 1.16 +++ ai/aitools.h 2002/03/01 20:15:19 @@ -18,11 +18,17 @@ struct government; struct player; +struct unit *create_unit_virtual(struct player *pplayer, int x, int y, + Unit_Type_id type, bool make_veteran); +void destroy_virtual_unit(struct unit *punit); struct city *dist_nearest_city(struct player *pplayer, int x, int y, bool everywhere, bool enemy); +int find_nearest_airbase(int x, int y, struct unit *punit, + int *xref, int *yref); +int ai_can_unit_attack_tile(struct unit *punit, int dest_x, int dest_y); -void ai_government_change(struct player *pplayer, int gov); +void ai_government_change(struct player *pplayer, int gov); int ai_gold_reserve(struct player *pplayer); void adjust_choice(int value, struct ai_choice *choice); @@ -31,5 +37,8 @@ int ai_assess_military_unhappiness(struct city *pcity, struct government *g); int ai_evaluate_government(struct player *pplayer, struct government *g); +int ai_evaluate_tile_for_attack(struct unit *punit, + int dest_x, int dest_y); +bool find_something_to_bomb(struct unit *punit); #endif /* FC__AITOOLS_H */ Index: ai/aiunit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v retrieving revision 1.183 diff -u -r1.183 aiunit.c --- ai/aiunit.c 2002/03/01 14:07:28 1.183 +++ ai/aiunit.c 2002/03/01 20:15:20 @@ -2105,6 +2105,92 @@ return TRUE; } +/************************************************************************ + * 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 + ***********************************************************************/ +static void ai_manage_airunit(struct player *pplayer, struct unit *punit) +{ + enum goto_result result = GR_FAILED; + + if (!is_airunit_refuel_point(punit->x, punit->y, + pplayer, punit->type, 0)) { + /* We are out in the open, what shall we do? */ + int refuel_x, refuel_y; + + if (punit->activity == ACTIVITY_GOTO + /* We are on a GOTO. Check if it will get us anywhere */ + && is_airunit_refuel_point(punit->goto_dest_x, punit->goto_dest_y, + pplayer, punit->type, 0) + && air_can_move_between (punit->moves_left/SINGLE_MOVE, punit->x, punit->y, + punit->goto_dest_x, punit->goto_dest_y, + pplayer) >= 0) { + /* It's an ok GOTO, just go there */ + result = do_unit_goto(punit, GOTO_MOVE_ANY, 0); + } else if (find_nearest_airbase(punit->x, punit->y, punit, + &refuel_x, &refuel_y)) { + /* Go refuelling */ + punit->goto_dest_x = refuel_x; + punit->goto_dest_y = refuel_y; + freelog(LOG_DEBUG, "Sent %s to refuel", unit_type(punit)->name); + set_unit_activity(punit, ACTIVITY_GOTO); + result = do_unit_goto(punit, GOTO_MOVE_ANY, 0); + } else { + if (punit->fuel == 1) { + freelog(LOG_DEBUG, "Oops, %s is fallin outta sky", + unit_type(punit)->name); + } + return; + } + + /* Check if we got there okay */ + if (result != GR_ARRIVED) { + freelog(LOG_DEBUG, "Something happened to our unit along the way"); + /* TODO: some rescuing, but not running into dead-loop */ + } + + } else if (punit->fuel == unit_type(punit)->fuel + && find_something_to_bomb(punit) > 0) { + + /* Found target, coordinates are in punit->goto_dest_[xy] + * TODO: separate attacking into a function, check for the best + * tile to attack from */ + set_unit_activity(punit, ACTIVITY_GOTO); + do_unit_goto(punit, GOTO_MOVE_ANY, 0); + /* 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... */ + set_unit_activity(punit, ACTIVITY_IDLE); + if (is_tiles_adjacent(punit->x, punit->y, + punit->goto_dest_x, punit->goto_dest_y)) { + int id = punit->id; + handle_unit_move_request(punit, punit->goto_dest_x, punit->goto_dest_y, + TRUE, FALSE); + if ((punit = find_unit_by_id(id)) != NULL && punit->moves_left > 0) { + /* Fly home now */ + ai_manage_airunit(pplayer, punit); + } + } else { + /* Ooops. Now better come back home */ + ai_manage_airunit(pplayer, punit); + } + + } else { + freelog(LOG_DEBUG, "%s staying put", unit_type(punit)->name); + } + +} + /************************************************************************** manage one unit Careful: punit may have been destroyed upon return from this routine! @@ -2147,6 +2233,9 @@ return; } else if (get_transporter_capacity(punit)) { ai_manage_ferryboat(pplayer, punit); + return; + } else if (is_air_unit(punit)) { + ai_manage_airunit(pplayer, punit); return; } else if (is_military_unit(punit)) { if (punit->moves_left == 0) return; /* can't do anything with no moves */ Index: common/tech.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/tech.c,v retrieving revision 1.45 diff -u -r1.45 tech.c --- common/tech.c 2002/02/26 16:58:13 1.45 +++ common/tech.c 2002/03/01 20:15:20 @@ -36,7 +36,8 @@ static const char *flag_names[] = { "Bonus_Tech", "Boat_Fast", "Bridge", "Railroad", "Fortress", "Watchtower", "Population_Pollution_Inc", "Trade_Revenue_Reduce", - "Airbase", "Farmland", "Reduce_Trireme_Loss1", "Reduce_Trireme_Loss2" + "Airbase", "Farmland", "Reduce_Trireme_Loss1", "Reduce_Trireme_Loss2", + "Build_Airborne" }; /* Note that these strings must correspond with the enums in tech_flag_id, in common/tech.h */ @@ -547,3 +548,32 @@ || game.rgame.tech_cost_style == 2) && game.rgame.tech_leakage == 0); } + +/********************************************************************** + * Does this (newly-discovered) tech allow us to build airborne units? + ********************************************************************* +static bool tech_allows_building_airborne(Tech_Type_id tech) +{ + UnitType_id j; + + for(j=0; jtech_requirement + && (get_unit_type(j)->move_type == AIR_MOVING + || get_unit_type(j)->move_type == HELI_MOVING)) { + return TRUE; + } + } + return FALSE; +} +*/ + +/********************************************************************* + * Can AI now do something else than just spawn? + ******************************************************************** +static void update_ai_abilities(struct player *pplayer, Tech_Type_id tech) +{ + if (!(pplayer->ai.can_build_airborne) + && tech_allows_building_airborne(Tech_Type_id tech)) { + pplayer->ai.can_build_airborne = TRUE; +} +*/ Index: common/tech.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/tech.h,v retrieving revision 1.32 diff -u -r1.32 tech.h --- common/tech.h 2002/02/14 15:17:20 1.32 +++ common/tech.h 2002/03/01 20:15:20 @@ -53,6 +53,7 @@ TF_FARMLAND, /* "Settler" unit types can build farmland */ TF_REDUCE_TRIREME_LOSS1, /* Reduces chance of Trireme being lost at sea */ TF_REDUCE_TRIREME_LOSS2, /* Reduces chance of Trireme being lost at sea */ + TF_BUILD_AIRBORNE, /* Player can build air units */ TF_LAST }; Index: data/default/techs.ruleset =================================================================== RCS file: /home/freeciv/CVS/freeciv/data/default/techs.ruleset,v retrieving revision 1.17 diff -u -r1.17 techs.ruleset --- data/default/techs.ruleset 2001/12/11 16:16:42 1.17 +++ data/default/techs.ruleset 2002/03/01 20:15:20 @@ -46,6 +46,7 @@ ; route reduces the initial revenue by cumulative ; factors of 2/3 ; "Airbase" = "Airbase" unit types can build Airbases +; "Build_Airborne" = from now on can build air units (for use by AI) [advance_advanced_flight] name = _("Advanced Flight") @@ -225,7 +226,7 @@ name = _("Flight") req1 = "Combustion" req2 = "Theory of Gravity" -flags = "Trade_Revenue_Reduce" +flags = "Trade_Revenue_Reduce","Build_Airborne" [advance_fundamentalism] name = _("Fundamentalism") Index: server/unittools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v retrieving revision 1.164 diff -u -r1.164 unittools.c --- server/unittools.c 2002/02/27 11:12:55 1.164 +++ server/unittools.c 2002/03/01 20:15:21 @@ -68,8 +68,6 @@ int x, int y, bool missile); static struct unit *choose_more_important_refuel_target(struct unit *punit1, struct unit *punit2); -static bool is_airunit_refuel_point(int x, int y, struct player *pplayer, - Unit_Type_id type, bool unit_is_on_tile); static int maybe_cancel_patrol_due_to_enemy(struct unit *punit); /************************************************************************** @@ -1540,8 +1538,8 @@ /************************************************************************** ... **************************************************************************/ -static bool is_airunit_refuel_point(int x, int y, struct player *pplayer, - Unit_Type_id type, bool unit_is_on_tile) +bool is_airunit_refuel_point(int x, int y, struct player *pplayer, + Unit_Type_id type, bool unit_is_on_tile) { struct player_tile *plrtile = map_get_player_tile(x, y, pplayer); Index: server/unittools.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.h,v retrieving revision 1.42 diff -u -r1.42 unittools.h --- server/unittools.h 2002/02/24 10:45:16 1.42 +++ server/unittools.h 2002/03/01 20:15:21 @@ -27,6 +27,12 @@ void maybe_make_veteran(struct unit *punit); void unit_versus_unit(struct unit *attacker, struct unit *defender); +/* move check related */ +bool is_airunit_refuel_point(int x, int y, struct player *pplayer, + Unit_Type_id type, int unit_is_on_tile); +bool can_unit_move_to_tile_with_notify(struct unit *punit, int dest_x, + int dest_y, bool igzoc); + /* turn update related */ void player_restore_units(struct player *pplayer); void update_unit_activities(struct player *pplayer);