<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

Reply via email to