<URL: http://bugs.freeciv.org/Ticket/Display.html?id=19132 >
This version of the patch modifies also mapgenerator. Only tiles native to initial unit are considered as starting positions. - ML
diff -Nurd -X.diff_ignore freeciv/server/gamehand.c freeciv/server/gamehand.c --- freeciv/server/gamehand.c 2006-07-17 23:56:22.000000000 +0300 +++ freeciv/server/gamehand.c 2007-01-10 19:49:31.000000000 +0200 @@ -59,30 +59,13 @@ } /**************************************************************************** - Place a starting unit for the player. + Get unit_type for given role character ****************************************************************************/ -static void place_starting_unit(struct tile *ptile, struct player *pplayer, - char crole) +struct unit_type *crole_to_unit_type(char crole,struct player *pplayer) { - struct unit_type *utype; + struct unit_type *utype = NULL; enum unit_flag_id role; - assert(!is_non_allied_unit_tile(ptile, pplayer)); - - /* For scenarios or dispersion, huts may coincide with player starts (in - * other cases, huts are avoided as start positions). Remove any such hut, - * and make sure to tell the client, since we may have already sent this - * tile (with the hut) earlier: */ - if (tile_has_special(ptile, S_HUT)) { - tile_clear_special(ptile, S_HUT); - update_tile_knowledge(ptile); - freelog(LOG_VERBOSE, "Removed hut on start position for %s", - pplayer->name); - } - - /* Expose visible area. */ - map_show_circle(pplayer, ptile, game.info.init_vis_radius_sq); - switch(crole) { case 'c': role = L_CITIES; @@ -116,16 +99,65 @@ break; default: assert(FALSE); - return; + return NULL; } /* Create the unit of an appropriate type, if it exists */ if (num_role_units(role) > 0) { - utype = first_role_unit_for_player(pplayer, role); + if (pplayer != NULL) { + utype = first_role_unit_for_player(pplayer, role); + } if (utype == NULL) { utype = get_role_unit(role, 0); } + } + + return utype; +} + +/**************************************************************************** + Place a starting unit for the player. Returns tile where unit was really + placed. +****************************************************************************/ +static struct tile *place_starting_unit(struct tile *starttile, + struct player *pplayer, + char crole) +{ + struct tile *ptile = NULL; + struct unit_type *utype = crole_to_unit_type(crole, pplayer); + + if (utype != NULL) { + iterate_outward(starttile, map.xsize + map.ysize, itertile) { + if (!is_non_allied_unit_tile(itertile, pplayer) + && is_native_tile(utype, itertile)) { + ptile = itertile; + break; + } + } iterate_outward_end; + } + + if (ptile == NULL) { + /* No place where unit may exist. */ + return NULL; + } + + assert(!is_non_allied_unit_tile(ptile, pplayer)); + + /* For scenarios or dispersion, huts may coincide with player starts (in + * other cases, huts are avoided as start positions). Remove any such hut, + * and make sure to tell the client, since we may have already sent this + * tile (with the hut) earlier: */ + if (tile_has_special(ptile, S_HUT)) { + tile_clear_special(ptile, S_HUT); + update_tile_knowledge(ptile); + freelog(LOG_VERBOSE, "Removed hut on start position for %s", + pplayer->name); + } + + /* Expose visible area. */ + map_show_circle(pplayer, ptile, game.info.init_vis_radius_sq); + if (utype != NULL) { /* We cannot currently handle sea units as start units. * TODO: remove this code block when we can. */ if (get_unit_move_type(utype) == SEA_MOVING) { @@ -134,11 +166,14 @@ notify_player(pplayer, NULL, E_BAD_COMMAND, _("Sea moving start units are not yet supported. " "Nobody gets %s."), utype->name); - return; + return NULL; } (void) create_unit(pplayer, ptile, utype, FALSE, 0, 0); + return ptile; } + + return NULL; } /**************************************************************************** @@ -170,6 +205,7 @@ { const int NO_START_POS = -1; int start_pos[game.info.nplayers]; + int placed_units[game.info.nplayers]; bool pos_used[map.num_start_positions]; int i, num_used = 0; @@ -239,7 +275,12 @@ = map.start_positions[start_pos[pplayer->player_no]]; /* Place the first unit. */ - place_starting_unit(pos.tile, pplayer, game.info.start_units[0]); + if (place_starting_unit(pos.tile, pplayer, + game.info.start_units[0]) != NULL) { + placed_units[pplayer->player_no] = 1; + } else { + placed_units[pplayer->player_no] = 0; + } } players_iterate_end; /* Place all other units. */ @@ -255,7 +296,10 @@ ptile = find_dispersed_position(pplayer, &p); /* Create the unit of an appropriate type. */ - place_starting_unit(ptile, pplayer, game.info.start_units[i]); + if (place_starting_unit(ptile, pplayer, + game.info.start_units[i]) != NULL) { + placed_units[pplayer->player_no]++; + } } /* Place nation specific start units (not role based!) */ @@ -263,10 +307,18 @@ while (nation->init_units[i] != NULL && i < MAX_NUM_UNIT_LIST) { ptile = find_dispersed_position(pplayer, &p); create_unit(pplayer, ptile, nation->init_units[i], FALSE, 0, 0); + placed_units[pplayer->player_no]++; i++; } } players_iterate_end; + players_iterate(pplayer) { + if (placed_units[pplayer->player_no] == 0) { + /* No units at all for some player! */ + die(_("No units placed for %s!"), pplayer->name); + } + } players_iterate_end; + shuffle_players(); } diff -Nurd -X.diff_ignore freeciv/server/gamehand.h freeciv/server/gamehand.h --- freeciv/server/gamehand.h 2006-07-17 23:56:22.000000000 +0300 +++ freeciv/server/gamehand.h 2007-01-10 19:49:59.000000000 +0200 @@ -23,6 +23,8 @@ void send_game_state(struct conn_list *dest, int state); void send_start_phase_to_clients(void); +struct unit_type *crole_to_unit_type(char crole,struct player *pplayer); + int update_timeout(void); void increase_timeout_because_unit_moved(void); diff -Nurd -X.diff_ignore freeciv/server/generator/mapgen.c freeciv/server/generator/mapgen.c --- freeciv/server/generator/mapgen.c 2006-07-17 23:56:22.000000000 +0300 +++ freeciv/server/generator/mapgen.c 2007-01-10 19:39:46.000000000 +0200 @@ -1127,7 +1127,7 @@ based on the map.size server parameter and the specified topology. If not map.xsize and map.ysize will be used. **************************************************************************/ -void map_fractal_generate(bool autosize) +void map_fractal_generate(bool autosize, struct unit_type *initial_unit) { /* save the current random state: */ RANDOM_STATE rstate = get_myrand_state(); @@ -1232,7 +1232,7 @@ } for(;;) { - success = create_start_positions(mode); + success = create_start_positions(mode, initial_unit); if (success) { break; } diff -Nurd -X.diff_ignore freeciv/server/generator/mapgen.h freeciv/server/generator/mapgen.h --- freeciv/server/generator/mapgen.h 2006-07-17 23:56:22.000000000 +0300 +++ freeciv/server/generator/mapgen.h 2007-01-10 19:39:33.000000000 +0200 @@ -15,6 +15,6 @@ #include "shared.h" /* bool type */ -void map_fractal_generate(bool autosize); +void map_fractal_generate(bool autosize, struct unit_type *initial_unit); #endif /* FC__MAPGEN_H */ diff -Nurd -X.diff_ignore freeciv/server/generator/startpos.c freeciv/server/generator/startpos.c --- freeciv/server/generator/startpos.c 2006-08-18 10:51:26.000000000 +0300 +++ freeciv/server/generator/startpos.c 2007-01-10 19:39:18.000000000 +0200 @@ -17,6 +17,7 @@ #include "game.h" #include "log.h" #include "fcintl.h" +#include "movement.h" #include "map.h" @@ -82,6 +83,7 @@ struct start_filter_data { int count; /* Number of existing start positions. */ int min_value; + struct unit_type *initial_unit; int *value; }; @@ -119,6 +121,11 @@ return FALSE; } + /* Has to be native for tile for initial unit */ + if (!is_native_tile(pdata->initial_unit, ptile)) { + return FALSE; + } + /* A longstanding bug allowed starting positions to exist on poles, * sometimes. This hack prevents it by setting a fixed distance from * the pole (dependent on map temperature) that a start pos must be. @@ -193,7 +200,8 @@ Returns true on success **************************************************************************/ -bool create_start_positions(enum start_mode mode) +bool create_start_positions(enum start_mode mode, + struct unit_type *initial_unit) { struct tile *ptile; int k, sum; @@ -350,6 +358,7 @@ data.count = 0; data.value = tile_value; data.min_value = 900; + data.initial_unit = initial_unit; sum = 0; for (k = 1; k <= map.num_continents; k++) { sum += islands[islands_index[k]].starters; diff -Nurd -X.diff_ignore freeciv/server/generator/startpos.h freeciv/server/generator/startpos.h --- freeciv/server/generator/startpos.h 2006-07-17 23:56:22.000000000 +0300 +++ freeciv/server/generator/startpos.h 2007-01-10 19:39:27.000000000 +0200 @@ -21,6 +21,7 @@ MT_VARIABLE }; -bool create_start_positions(enum start_mode mode); +bool create_start_positions(enum start_mode mode, + struct unit_type *initial_unit); #endif diff -Nurd -X.diff_ignore freeciv/server/srv_main.c freeciv/server/srv_main.c --- freeciv/server/srv_main.c 2006-07-21 23:18:07.000000000 +0300 +++ freeciv/server/srv_main.c 2007-01-10 19:53:13.000000000 +0200 @@ -1878,7 +1878,9 @@ /* If we have a tile map, and map.generator==0, call map_fractal_generate * anyway to make the specials, huts and continent numbers. */ if (map_is_empty() || (map.generator == 0 && game.info.is_new_game)) { - map_fractal_generate(TRUE); + struct unit_type *utype = crole_to_unit_type(game.info.start_units[0], NULL); + + map_fractal_generate(TRUE, utype); } /* start the game */
_______________________________________________ Freeciv-dev mailing list Freeciv-dev@gna.org https://mail.gna.org/listinfo/freeciv-dev