diff -r -u -Xdiff_ignore freeciv.CVS160900/common/game.c freeciv/common/game.c --- freeciv.CVS160900/common/game.c Fri Sep 1 12:33:27 2000 +++ freeciv/common/game.c Sun Sep 17 15:11:48 2000 @@ -750,6 +750,7 @@ game.foodbox = GAME_DEFAULT_FOODBOX; game.aqueductloss= GAME_DEFAULT_AQUEDUCTLOSS; game.killcitizen = GAME_DEFAULT_KILLCITIZEN; + game.unitstacklimit = GAME_DEFAULT_UNITSTACKLIMIT; game.scorelog = GAME_DEFAULT_SCORELOG; game.techpenalty = GAME_DEFAULT_TECHPENALTY; game.civstyle = GAME_DEFAULT_CIVSTYLE; diff -r -u -Xdiff_ignore freeciv.CVS160900/common/game.h freeciv/common/game.h --- freeciv.CVS160900/common/game.h Fri Sep 1 12:33:28 2000 +++ freeciv/common/game.h Sun Sep 17 15:13:18 2000 @@ -99,6 +99,7 @@ int foodbox; int aqueductloss; int killcitizen; + int unitstacklimit; int techpenalty; int razechance; int scorelog; @@ -291,6 +292,10 @@ #define GAME_DEFAULT_KILLCITIZEN 1 #define GAME_MIN_KILLCITIZEN 0 #define GAME_MAX_KILLCITIZEN 15 + +#define GAME_DEFAULT_UNITSTACKLIMIT 0 +#define GAME_MIN_UNITSTACKLIMIT 0 +#define GAME_MAX_UNITSTACKLIMIT 256 #define GAME_DEFAULT_TECHPENALTY 100 #define GAME_MIN_TECHPENALTY 0 diff -r -u -Xdiff_ignore freeciv.CVS160900/server/citytools.c freeciv/server/citytools.c --- freeciv.CVS160900/server/citytools.c Fri Sep 1 12:33:39 2000 +++ freeciv/server/citytools.c Sun Sep 17 15:55:05 2000 @@ -723,7 +723,8 @@ Returns NULL if no satisfactory city can be found. ***********************************************************************/ struct city *find_closest_owned_city(struct player *pplayer, int x, int y, - int sea_required, struct city *pexclcity) + int sea_required, int unit_space_required, + struct city *pexclcity) { int dist = -1; struct city *rcity = NULL; @@ -731,8 +732,11 @@ if ((real_map_distance(x, y, pcity->x, pcity->y) < dist || dist == -1) && (!sea_required || is_terrain_near_tile(pcity->x, pcity->y, T_OCEAN)) && (!pexclcity || (pexclcity != pcity))) { - dist = real_map_distance(x, y, pcity->x, pcity->y); - rcity = pcity; + if (unit_space_required || unit_space_on_tile(map_get_tile(pcity->x, + pcity->y), NULL)) { + dist = real_map_distance(x, y, pcity->x, pcity->y); + rcity = pcity; + } } city_list_iterate_end; diff -r -u -Xdiff_ignore freeciv.CVS160900/server/citytools.h freeciv/server/citytools.h --- freeciv.CVS160900/server/citytools.h Mon Jul 24 12:33:31 2000 +++ freeciv/server/citytools.h Sun Sep 17 15:21:29 2000 @@ -64,8 +64,9 @@ struct city *transfer_city(struct player *pplayer, struct player *cplayer, struct city *pcity, int kill_outside, int transfer_unit_verbose, int resolve_stack, int raze); -struct city *find_closest_owned_city(struct player *pplayer, int x, int y, - int sea_required, struct city *pexclcity); +struct city *find_closest_owned_city(struct player *pplayer, int x, int y, + int sea_required, int unit_space_required, + struct city *pexclcity); void adjust_city_free_cost(int *num_free, int *this_cost); diff -r -u -Xdiff_ignore freeciv.CVS160900/server/cityturn.c freeciv/server/cityturn.c --- freeciv.CVS160900/server/cityturn.c Fri Sep 1 12:33:39 2000 +++ freeciv/server/cityturn.c Sun Sep 17 15:24:49 2000 @@ -1345,8 +1345,17 @@ */ if(pcity->shield_stock>=unit_value(pcity->currently_building)) { if (unit_flag(pcity->currently_building, F_CITIES)) { - if (pcity->size==1) { + /********* check unit stack limits, added sep2000 ********/ + if (!unit_space_on_tile(map_get_tile(pcity->x, pcity->y), NULL)) { + notify_player_ex(pplayer, pcity->x, pcity->y, E_CITY_CANTBUILD, + _("Game: %s can't build %s. No space is available (only l%d units allowed per tile)."), + pcity->name, unit_name(pcity->currently_building), game.unitstacklimit); + return 1; + } + /*****************************************************/ + + if (pcity->size==1) { /* Should we disband the city? -- Massimo */ if (pcity->city_options & ((1<owner].ai.control || !punit->ai.passenger || punit->moves_left >= 6)) d[k] = 1; +/********* check unit stacksize limits - code added sep2000 */ + if (!unit_space_on_tile(ptile, punit)) + d[k] = 0; /* do not choose a tile that is already full with your other units */ if (d[k] > best) { best = d[k]; freelog(LOG_DEBUG, "New best = %d: (%d, %d) -> (%d, %d)", diff -r -u -Xdiff_ignore freeciv.CVS160900/server/savegame.c freeciv/server/savegame.c --- freeciv.CVS160900/server/savegame.c Mon Sep 11 12:32:26 2000 +++ freeciv/server/savegame.c Sun Sep 17 15:28:53 2000 @@ -1614,6 +1614,8 @@ "game.aqueductloss"); game.killcitizen = secfile_lookup_int_default(file, game.killcitizen, "game.killcitizen"); + game.unitstacklimit = secfile_lookup_int_default(file, game.unitstacklimit, + "game.unitstacklimit"); game.turnblock = secfile_lookup_int_default(file,game.turnblock, "game.turnblock"); game.fixedlength = secfile_lookup_int_default(file,game.fixedlength, @@ -1894,6 +1896,7 @@ secfile_insert_int(file, game.diplchance, "game.diplchance"); secfile_insert_int(file, game.aqueductloss, "game.aqueductloss"); secfile_insert_int(file, game.killcitizen, "game.killcitizen"); + secfile_insert_int(file, game.unitstacklimit, "game.unitstacklimit"); secfile_insert_int(file, game.turnblock, "game.turnblock"); secfile_insert_int(file, game.fixedlength, "game.fixedlength"); secfile_insert_int(file, game.barbarianrate, "game.barbarians"); diff -r -u -Xdiff_ignore freeciv.CVS160900/server/stdinhand.c freeciv/server/stdinhand.c --- freeciv.CVS160900/server/stdinhand.c Mon Sep 11 12:32:27 2000 +++ freeciv/server/stdinhand.c Sun Sep 17 18:18:40 2000 @@ -497,6 +497,16 @@ " 4 = heli\n" " 8 = air") }, + { "unitstacklimit", &game.unitstacklimit, + SSET_RULES, SSET_TO_CLIENT, + GAME_MIN_UNITSTACKLIMIT, GAME_MAX_UNITSTACKLIMIT, GAME_DEFAULT_UNITSTACKLIMIT, + N_("Limit amount of units per tile (0=no limit)"), + N_("Use this setting to limit the maximum amount of units that may " + "occupy one tile (ai will not yet cope well with this option):\n" + " (default) 0 = no limit\n" + " 256 = maximum setting\n" + " 5 - 9 = reasonable for interesting tactics\n") }, + /* Flexible rules: these can be changed after the game has started. * * The distinction between "rules" and "flexible rules" is not always diff -r -u -Xdiff_ignore freeciv.CVS160900/server/unitfunc.c freeciv/server/unitfunc.c --- freeciv.CVS160900/server/unitfunc.c Sat Sep 2 12:36:09 2000 +++ freeciv/server/unitfunc.c Sun Sep 17 15:38:04 2000 @@ -2506,6 +2506,14 @@ return 0; if (!unit_can_airlift_to(punit, city2)) return 0; + if (!unit_space_on_tile(map_get_tile(dest_x, dest_y), punit)) { + notify_player_ex(unit_owner(punit), dest_x, dest_y, E_NOEVENT, + _("Game: %s transport unsuccesfull. %s is " + "full (no more than %d units per tile)"), + unit_name(punit->type), + city2->name, game.unitstacklimit); + return 0; + } city1->airlift=0; city2->airlift=0; @@ -2570,7 +2578,13 @@ " enemy units on the destination location.")); return 0; } - + /* check stacksize on destination tile and see if there's space */ + if (!unit_space_on_tile(map_get_tile(dest_x, dest_y), punit)) { + notify_player_ex(unit_owner(punit), dest_x, dest_y, E_NOEVENT, + _("Game: Cannot paradrop because the" + " destination tile is already full.")); + return 0; + } /* All ok */ { int move_cost = get_unit_type(punit->type)->paratroopers_mr_sub; diff -r -u -Xdiff_ignore freeciv.CVS160900/server/unithand.c freeciv/server/unithand.c --- freeciv.CVS160900/server/unithand.c Sat Sep 2 12:36:10 2000 +++ freeciv/server/unithand.c Sun Sep 17 15:39:04 2000 @@ -1081,7 +1081,15 @@ return 0; } } - + /********* check unit stack limits, added sep2000 ********/ + if (!unit_space_on_tile(pdesttile, punit)) { + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: Moving %s failed. Only %d units " + "can occupy the same tile"), + get_unit_type(punit->type)->name, + game.unitstacklimit); + return 0; + } /******* ok now move the unit *******/ if(can_unit_move_to_tile(punit, dest_x, dest_y, igzoc) && try_move_unit(punit, dest_x, dest_y)) { diff -r -u -Xdiff_ignore freeciv.CVS160900/server/unittools.c freeciv/server/unittools.c --- freeciv.CVS160900/server/unittools.c Thu Aug 17 12:28:44 2000 +++ freeciv/server/unittools.c Sun Sep 17 15:44:50 2000 @@ -257,6 +257,69 @@ return NULL; } +/******************************************************************** + is the tile full? how many units can be on the same tile is determined by the + server option 'unitstacklimit', stored in game.unitstacklimit. This function is + called by all functions related to unit movement: handle_unit_move_request + do_airline, do_paradrop, find_a_direction, is_airunit_refuel_point, + find_closest_owned_city, city_build_stuff +*******************************************************************/ +int unit_space_on_tile(struct tile *ptile, struct unit *punit) +{ + if (!game.unitstacklimit) return 1; + freelog(LOG_DEBUG, "Checking unitstacksizes on destination tile"); + /* check if the unit pointer is valid. if not, perform a + simple test */ + if (punit == NULL) { + if (unit_list_size(&(ptile->units)) >= game.unitstacklimit) + return 0; + return 1; + } + if (is_non_allied_unit_tile(ptile, punit->owner)!=NULL) + return 1; /* there is space but it is occupied by somebody else*/ + + if ((ptile->city && ((ptile->city)->owner)==punit->owner) || + ptile->special&S_AIRBASE) + { + /* in a city or airbase, all units are on the same stack, + otherwise air units are assumed to be in the air and + helies depend on their fuel */ + /* now check how many units are being moved: */ + int unitcount = 1; + unit_list_iterate (map_get_tile(punit->x, punit->y)->units, punitX) + if (punitX->transported_by == punit->id) + unitcount++; + unit_list_iterate_end; + if ((unit_list_size(&(ptile->units)) + unitcount) > game.unitstacklimit) + return 0; + } else { + int units_on_bottom=0; + int units_in_air=0; + int itsmovetype = get_unit_type(punit->type)->move_type; + unit_list_iterate (ptile->units, punitX) + if (punitX->transported_by==-1) { + if (get_unit_type(punitX->type)->move_type==AIR_MOVING) { + units_in_air++; + } else { + units_on_bottom++; + } + } + unit_list_iterate_end; + if ((itsmovetype==AIR_MOVING && + units_in_air >= game.unitstacklimit ) || + (itsmovetype < HELI_MOVING && + units_on_bottom >= game.unitstacklimit)) + return 0; + if (itsmovetype==HELI_MOVING && + ((punit->moves_left==1 && punit->fuel==0 && + units_on_bottom >= game.unitstacklimit) || ((units_in_air == + game.unitstacklimit) && (punit->moves_left > 1 || + punit->fuel > 0)))) + return 0; + } + return 1; +} + /************************************************************************** Is this square controlled by the unit's owner? @@ -842,7 +905,7 @@ punit = unit_list_get(&(ptile->units), 0); pcity = find_closest_owned_city(unit_owner(punit), x, y, - is_sailing_unit(punit), NULL); + is_sailing_unit(punit), 1, NULL); /* If punit is in an enemy city we send it to the closest friendly city This is not always caught by the other checks which require that @@ -860,7 +923,7 @@ break; ccity = find_closest_owned_city(get_player(cunit->owner), x, y, - is_sailing_unit(cunit), NULL); + is_sailing_unit(cunit), 1, NULL); if (pcity && ccity) { /* Both unit owners have cities; teleport unit farthest from its @@ -908,7 +971,7 @@ unit_list_iterate(ptile->units, wunit) { if (is_ground_unit(wunit) && wunit->owner == vunit->owner) { struct city *wcity = - find_closest_owned_city(get_player(wunit->owner), x, y, 0, NULL); + find_closest_owned_city(get_player(wunit->owner), x, y, 0, 1, NULL); if (wcity) teleport_unit_to_city(wunit, wcity, 0, verbose); else @@ -928,6 +991,9 @@ Unit_Type_id type, int unit_is_on_tile) { struct player_tile *plrtile = map_get_player_tile(x, y, playerid); + + if (!unit_space_on_tile(map_get_tile(x, y), NULL)) + return 0; if ((is_allied_city_tile(map_get_tile(x, y), playerid) && !is_non_allied_unit_tile(map_get_tile(x, y), playerid)) diff -r -u -Xdiff_ignore freeciv.CVS160900/server/unittools.h freeciv/server/unittools.h --- freeciv.CVS160900/server/unittools.h Mon Jul 24 12:33:36 2000 +++ freeciv/server/unittools.h Sun Sep 17 15:45:39 2000 @@ -26,6 +26,7 @@ struct unit *is_enemy_unit_tile(struct tile *ptile, int playerid); struct unit *is_non_allied_unit_tile(struct tile *ptile, int playerid); struct unit *is_non_attack_unit_tile(struct tile *ptile, int playerid); +int unit_space_on_tile(struct tile *ptile, struct unit *punit); int is_my_zoc(struct unit *myunit, int x0, int y0); int zoc_ok_move(struct unit *punit,int x, int y); int zoc_ok_move_gen(struct unit *punit, int x1, int y1, int x2, int y2);