diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/map.h auto_return_home/common/map.h --- freeciv/common/map.h Wed May 10 02:19:01 2000 +++ auto_return_home/common/map.h Thu May 11 19:00:22 2000 @@ -261,6 +261,71 @@ extern struct terrain_misc terrain_control; extern struct tile_type tile_types[T_LAST]; +/* This iterates outwards from the starting point (Duh?). + every tile within max_dist will show up exactly once. (even takes + into account wrap). All positions given correspond to real tiles. + The values given are adjusted. + You should make sure that the arguments passed to the macro are adjusted, + or you could have some very nasty intermediate errors. + The results are in x_itr and y_itr, which must allready be defined. + + Internally it works by for a given distance + 1) assume y positive and iterate over x + 2) assume y negative and iterate over x + 3) assume x positive and iterate over y + 4) assume x negative and iterate over y + Where in this we are is decided by the variables xcycle and positive. + each of there distances give a box of tiles; to ensure each tile is only + retuned once we only return the corner when iterating over x. + As a speciel case positive is initialized as 0 (ie we start in step 2) ), + as the center tile would else be returned by both step 1) and 2). +*/ +#define iterate_outward(MACRO_start_x, MACRO_start_y, MACRO_max_dist) \ +{ \ + int MACRO_max_dx = map.xsize/2; \ + int MACRO_min_dx = -(MACRO_max_dx - (map.xsize%2 ? 0 : 1)); \ + int MACRO_xcycle = 1; \ + int MACRO_positive = 0; \ + int MACRO_dxy = 0, MACRO_do_xy; \ + while(MACRO_dxy <= MACRO_max_dist) { \ + for (MACRO_do_xy = -MACRO_dxy; MACRO_do_xy <= MACRO_dxy; MACRO_do_xy++) { \ + if (MACRO_xcycle) { \ + x_itr = MACRO_start_x + MACRO_do_xy; \ + if (MACRO_positive) \ + y_itr = MACRO_start_y + MACRO_dxy; \ + else \ + y_itr = MACRO_start_y - MACRO_dxy; \ + } else { /* ! MACRO_xcycle */ \ + if (MACRO_dxy == MACRO_do_xy || MACRO_dxy == -MACRO_do_xy) \ + continue; \ + y_itr = MACRO_start_y + MACRO_do_xy; \ + if (MACRO_positive) \ + x_itr = MACRO_start_x + MACRO_dxy; \ + else \ + x_itr = MACRO_start_x - MACRO_dxy; \ + } \ + if (y_itr<0 || y_itr >= map.ysize) \ + continue; \ + { \ + int MACRO_dx = MACRO_start_x - x_itr; \ + if (MACRO_dx > MACRO_max_dx || MACRO_dx < MACRO_min_dx) \ + continue; \ + } \ + if (x_itr > map.xsize) \ + x_itr -= map.xsize; \ + else if (x_itr < 0) \ + x_itr += map.xsize; + +#define iterate_outward_end \ + } \ + if (!MACRO_positive) { \ + if (!MACRO_xcycle) \ + MACRO_dxy++; \ + MACRO_xcycle = !MACRO_xcycle; \ + } \ + MACRO_positive = !MACRO_positive; \ + } \ +} #define MAP_DEFAULT_HUTS 50 #define MAP_MIN_HUTS 0 diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/unit.c auto_return_home/common/unit.c --- freeciv/common/unit.c Wed May 10 02:19:02 2000 +++ auto_return_home/common/unit.c Thu May 11 19:39:30 2000 @@ -1458,3 +1458,75 @@ { return (&game.players[punit->owner]); } + +/************************************************************************** +Returns the number of free spaces for missiles. Can be 0 or negative. +**************************************************************************/ +int missile_carrier_capacity(int x, int y, int playerid) +{ + int misonly = 0; + int airall = 0; + int totalcap; + + unit_list_iterate(map_get_tile(x, y)->units, punit) { + if (punit->owner == playerid) { + if (unit_flag(punit->type, F_CARRIER)) { + airall += get_transporter_capacity(punit); + continue; + } + if (unit_flag(punit->type, F_MISSILE_CARRIER)) { + misonly += get_transporter_capacity(punit); + continue; + } + if (is_air_unit(punit)) { + if (unit_flag(punit->type, F_MISSILE)) + misonly--; + else + airall--; + } + } + } + unit_list_iterate_end; + + if (airall < 0) + airall = 0; + + totalcap = airall + misonly; + + return totalcap; +} + +/************************************************************************** +Returns the number of free spaces for airunits (includes missiles). +Can be 0 or negative. +**************************************************************************/ +int airunit_carrier_capacity(int x, int y, int playerid) +{ + int misonly = 0; + int airall = 0; + + unit_list_iterate(map_get_tile(x, y)->units, punit) { + if (punit->owner == playerid) { + if (unit_flag(punit->type, F_CARRIER)) { + airall += get_transporter_capacity(punit); + continue; + } + if (unit_flag(punit->type, F_MISSILE_CARRIER)) { + misonly += get_transporter_capacity(punit); + continue; + } + if (is_air_unit(punit)) { + if (unit_flag(punit->type, F_MISSILE)) + misonly--; + else + airall--; + } + } + } + unit_list_iterate_end; + + if (misonly < 0) + airall += misonly; + + return airall; +} diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/unit.h auto_return_home/common/unit.h --- freeciv/common/unit.h Wed May 10 02:19:02 2000 +++ auto_return_home/common/unit.h Thu May 11 19:36:49 2000 @@ -296,6 +296,8 @@ int is_enough_transporter_space(struct player *pplayer, int x, int y); int get_transporter_capacity(struct unit *punit); int is_ground_units_transport(struct unit *punit); +int missile_carrier_capacity(int x, int y, int playerid); +int airunit_carrier_capacity(int x, int y, int playerid); int utype_shield_cost(struct unit_type *ut, struct government *g); int utype_food_cost(struct unit_type *ut, struct government *g); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/gotohand.c auto_return_home/server/gotohand.c --- freeciv/server/gotohand.c Wed May 10 02:19:09 2000 +++ auto_return_home/server/gotohand.c Thu May 11 19:00:22 2000 @@ -74,8 +74,6 @@ static void make_list_of_refuel_points(struct player *pplayer); static void dealloc_refuel_stack(); static int find_air_first_destination(struct unit *punit, int *dest_x, int *dest_y); -static int naive_air_can_move_between(int moves, int src_x, int src_y, - int dest_x, int dest_y, int playerid); /************************************************************************** ... @@ -1287,8 +1285,8 @@ Create a movemap to decide with certainty in O(moves2) time. Each step should catch the vast majority of tries. **************************************************************************/ -static int naive_air_can_move_between(int moves, int src_x, int src_y, - int dest_x, int dest_y, int playerid) +int naive_air_can_move_between(int moves, int src_x, int src_y, + int dest_x, int dest_y, int playerid) { int x, y, go_x, go_y, i, movescount; struct tile *ptile; diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/gotohand.h auto_return_home/server/gotohand.h --- freeciv/server/gotohand.h Wed May 10 02:19:09 2000 +++ auto_return_home/server/gotohand.h Thu May 11 19:00:22 2000 @@ -26,6 +26,8 @@ enum unit_move_type which); int calculate_move_cost(struct player *pplayer, struct unit *punit, int dest_x, int dest_y); +int naive_air_can_move_between(int moves, int src_x, int src_y, + int dest_x, int dest_y, int playerid); /* all other functions are internal */ diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unitfunc.c auto_return_home/server/unitfunc.c --- freeciv/server/unitfunc.c Wed May 10 02:19:10 2000 +++ auto_return_home/server/unitfunc.c Thu May 11 19:07:40 2000 @@ -1320,7 +1320,29 @@ unit_name(punit->type)); wipe_unit(0, punit); } - else if(is_air_unit(punit)) { + else if (is_air_unit(punit)) { + /* Shall we emergency return home on the last vapors? */ + if (punit->fuel == 1 + && !is_airunit_refuel_point(punit->x, punit->y, + punit->owner, punit->type, 1)) { + int x_itr, y_itr; + iterate_outward(punit->x, punit->y, punit->moves_left/3) { + if (is_airunit_refuel_point(x_itr, y_itr, punit->owner, punit->type, 0) + && naive_air_can_move_between(punit->moves_left/3, punit->x, punit->y, + x_itr, y_itr, punit->owner)) { + punit->goto_dest_x = x_itr; + punit->goto_dest_y = y_itr; + set_unit_activity(punit, ACTIVITY_GOTO); + do_unit_goto(pplayer, punit, GOTO_MOVE_ANY); + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: Your %s has returned to refuel"), + unit_name(punit->type)); + goto OUT; + } + } iterate_outward_end; + } + OUT: + punit->fuel--; if(map_get_city(punit->x, punit->y) || map_get_special(punit->x, punit->y)&S_AIRBASE) diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unittools.c auto_return_home/server/unittools.c --- freeciv/server/unittools.c Wed May 10 02:19:10 2000 +++ auto_return_home/server/unittools.c Thu May 11 19:37:54 2000 @@ -840,3 +840,31 @@ } } } + +/************************************************************************** +... +**************************************************************************/ +int is_airunit_refuel_point(int x, int y, int playerid, + Unit_Type_id type, int unit_is_on_tile) +{ + struct player_tile *plrtile = map_get_player_tile(&game.players[playerid],x,y); + + if (is_friendly_city_tile(x, y, playerid) + || (plrtile->special&S_AIRBASE + && !is_enemy_unit_tile(x, y, playerid))) + return 1; + + if (unit_flag(type, F_MISSILE)) { + int cap = missile_carrier_capacity(x, y, playerid); + if (unit_is_on_tile) + cap++; + return cap>0; + } else { + int cap = airunit_carrier_capacity(x, y, playerid); + if (unit_is_on_tile) + cap++; + return cap>0; + } + + return 0; +} diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unittools.h auto_return_home/server/unittools.h --- freeciv/server/unittools.h Wed May 10 02:19:10 2000 +++ auto_return_home/server/unittools.h Thu May 11 19:00:22 2000 @@ -55,5 +55,7 @@ int verbose); struct unit *is_enemy_unit_on_tile(int x, int y, int owner); void resolve_unit_stack(int x, int y, int verbose); +int is_airunit_refuel_point(int x, int y, int playerid, + Unit_Type_id type, int unit_is_on_tile); #endif /* FC__UNITTOOLS_H */