diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/civclient.c freeciv-patched/client/civclient.c
--- freeciv-cvs/client/civclient.c	2003-06-07 19:58:20.000000000 +0100
+++ freeciv-patched/client/civclient.c	2003-06-30 12:28:19.000000000 +0100
@@ -397,6 +397,10 @@
     handle_ruleset_city((struct packet_ruleset_city *)packet);
     break;
 
+  case PACKET_RULESET_CALENDAR:
+    handle_ruleset_calendar((struct packet_ruleset_calendar *)packet);
+    break;
+
   case PACKET_RULESET_GAME:
     handle_ruleset_game((struct packet_ruleset_game *)packet);
     break;
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/gui-gtk/mapview.c freeciv-patched/client/gui-gtk/mapview.c
--- freeciv-cvs/client/gui-gtk/mapview.c	2003-06-26 20:13:14.000000000 +0100
+++ freeciv-patched/client/gui-gtk/mapview.c	2003-06-30 12:28:19.000000000 +0100
@@ -213,14 +213,16 @@
 {
   char buffer	[512];
   int  d;
+  const struct calendar *cal = game_get_current_calendar();
 
   gtk_frame_set_label( GTK_FRAME( main_frame_civ_name ), get_nation_name(game.player_ptr->nation) );
 
   my_snprintf(buffer, sizeof(buffer),
-	      _("Population: %s\nYear: %s\n"
+	      _("Population: %s\nYear: %s\n%s (%d yr/turn)\n"
 		"Gold: %d\nTax: %d Lux: %d Sci: %d"),
 	      population_to_text(civ_population(game.player_ptr)),
-	      textyear(game.year), game.player_ptr->economic.gold,
+	      textyear(game.year), cal->name, cal->turn_years,
+	      game.player_ptr->economic.gold,
 	      game.player_ptr->economic.tax,
 	      game.player_ptr->economic.luxury,
 	      game.player_ptr->economic.science);
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/gui-gtk-2.0/mapview.c freeciv-patched/client/gui-gtk-2.0/mapview.c
--- freeciv-cvs/client/gui-gtk-2.0/mapview.c	2003-06-26 20:13:14.000000000 +0100
+++ freeciv-patched/client/gui-gtk-2.0/mapview.c	2003-06-30 12:28:19.000000000 +0100
@@ -214,16 +214,18 @@
 {
   char buffer	[512];
   int  d;
+  const struct calendar *cal = game_get_current_calendar();
   int  sol, flake;
 
   gtk_frame_set_label(GTK_FRAME(main_frame_civ_name),
 		      get_nation_name(game.player_ptr->nation));
 
   my_snprintf(buffer, sizeof(buffer),
-	      _("Population: %s\nYear: %s\n"
+	      _("Population: %s\nYear: %s\n%s (%d yr/turn)\n"
 		"Gold: %d\nTax: %d Lux: %d Sci: %d"),
 	      population_to_text(civ_population(game.player_ptr)),
-	      textyear(game.year), game.player_ptr->economic.gold,
+	      textyear(game.year), cal->name, cal->turn_years,
+	      game.player_ptr->economic.gold,
 	      game.player_ptr->economic.tax,
 	      game.player_ptr->economic.luxury,
 	      game.player_ptr->economic.science);
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/packhand.c freeciv-patched/client/packhand.c
--- freeciv-cvs/client/packhand.c	2003-06-30 12:18:28.000000000 +0100
+++ freeciv-patched/client/packhand.c	2003-06-30 12:31:26.000000000 +0100
@@ -1127,6 +1127,7 @@
   game.end_year=pinfo->end_year;
   game.year=pinfo->year;
   game.turn=pinfo->turn;
+  game.spaceage_year = pinfo->spaceage_year;
   game.min_players=pinfo->min_players;
   game.max_players=pinfo->max_players;
   game.nplayers=pinfo->nplayers;
@@ -1822,6 +1823,10 @@
   game.government_when_anarchy = packet->government_when_anarchy;
   game.default_government = packet->default_government;
 
+  game.num_calendars  = packet->num_calendars;
+  if (game.num_calendars == 0) {
+    setup_default_calendars();
+  }
   game.num_unit_types = packet->num_unit_types;
   game.num_impr_types = packet->num_impr_types;
   game.num_tech_types = packet->num_tech_types;
@@ -2363,6 +2368,28 @@
 /**************************************************************************
 ...
 **************************************************************************/
+void handle_ruleset_calendar(struct packet_ruleset_calendar *p)
+{
+  struct calendar *c;
+
+  if (p->id < 0 || p->id >= game.num_calendars || p->id >= C_LAST) {
+    freelog(LOG_ERROR,
+            "Received bad calendar %d in handle_ruleset_calendar()", p->id);
+    return;
+  }
+  c = &game.calendars[p->id];
+
+  c->id = p->id;
+  sz_strlcpy(c->name, p->name);
+  c->first_year = p->first_year;
+  c->turn_years = p->turn_years;
+  c->req_tech   = p->req_tech;
+  c->early_tech = p->early_tech;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
 void handle_incite_cost(struct packet_generic_values *packet)
 {
   struct city *pcity=find_city_by_id(packet->id);
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/packhand.h freeciv-patched/client/packhand.h
--- freeciv-cvs/client/packhand.h	2003-06-27 15:51:10.000000000 +0100
+++ freeciv-patched/client/packhand.h	2003-06-30 12:28:20.000000000 +0100
@@ -57,6 +57,7 @@
 void handle_ruleset_nation(struct packet_ruleset_nation *p);
 void handle_ruleset_city(struct packet_ruleset_city *packet);
 void handle_ruleset_game(struct packet_ruleset_game *packet);
+void handle_ruleset_calendar(struct packet_ruleset_calendar *packet);
 void handle_diplomat_action(struct packet_diplomat_action *packet);
 void handle_sabotage_list(struct packet_sabotage_list *packet);
 void handle_player_attribute_chunk(struct packet_attribute_chunk *chunk);
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/capstr.c freeciv-patched/common/capstr.c
--- freeciv-cvs/common/capstr.c	2003-06-30 12:18:26.000000000 +0100
+++ freeciv-patched/common/capstr.c	2003-06-30 12:28:52.000000000 +0100
@@ -78,7 +78,7 @@
                    "city_struct_minor_cleanup obsolete_last class_legend " \
                    "+impr_req +waste +fastfocus +continent +small_dipl " \
                    "+no_nation_selected +diplomacy +no_extra_tiles " \
-                   "+diplomacy2 +citizens_style +root_tech"
+                   "+diplomacy2 +citizens_style +root_tech calendar"
 
 /* "+1.14.0" is protocol for 1.14.0 release.
  *
@@ -129,6 +129,8 @@
  * multi style citizens icons.
  *
  * "root_tech" restricts who can acquire technology
+ *
+ * "calendar" adds support for customised game calendars.
  */
 
 void init_our_capability(void)
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/game.c freeciv-patched/common/game.c
--- freeciv-cvs/common/game.c	2003-06-30 12:18:29.000000000 +0100
+++ freeciv-patched/common/game.c	2003-06-30 12:28:20.000000000 +0100
@@ -660,6 +660,7 @@
   game.end_year      = GAME_DEFAULT_END_YEAR;
   game.year          = GAME_START_YEAR;
   game.turn          = 0;
+  game.spaceage_year = GAME_MAX_END_YEAR + 1;
   game.min_players   = GAME_DEFAULT_MIN_PLAYERS;
   game.max_players  = GAME_DEFAULT_MAX_PLAYERS;
   game.aifill      = GAME_DEFAULT_AIFILL;
@@ -810,55 +811,63 @@
 }
 
 /***************************************************************
-  Returns the next year in the game.
+  Returns the relevant calendar for the given year
 ***************************************************************/
-int game_next_year(int year)
+const struct calendar *game_get_calendar(int year)
 {
-  int spaceshipparts, i;
-  Impr_Type_id parts[] = { B_SCOMP, B_SMODULE, B_SSTRUCTURAL, B_LAST };
-
-  if (year == 1) /* hacked it to get rid of year 0 */
-    year = 0;
+  const static struct calendar spaceage_cal = {
+    0, N_("Space Age"), 0, 1, A_NONE, A_NONE
+  };
+  int calind;
+
+  /* If a spaceship has been launched, then use the hard-coded 1 year/turn
+   * "space age" calendar (for Civ compatibility). Otherwise, we use a
+   * ruleset-defined calendar */
+  if (game.spacerace && year >= game.spaceage_year) {
+    return &spaceage_cal;
+  }
 
-    /* !McFred: 
-       - want year += 1 for spaceship.
-    */
-
-  /* test game with 7 normal AI's, gen 4 map, foodbox 10, foodbase 0: 
-   * Gunpowder about 0 AD
-   * Railroad  about 500 AD
-   * Electricity about 1000 AD
-   * Refining about 1500 AD (212 active units)
-   * about 1750 AD
-   * about 1900 AD
-   */
-
-  spaceshipparts= 0;
-  if (game.spacerace) {
-    for(i=0; parts[i] < B_LAST; i++) {
-      int t = improvement_types[parts[i]].tech_req;
-      if (tech_exists(t) && game.global_advances[t] != 0)
-	spaceshipparts++;
+  for (calind = 1; calind < game.num_calendars; ++calind) {
+    /* Someone must have the req_tech to reach a calendar. */
+    if (tech_exists(game.calendars[calind].req_tech)
+        && !game.global_advances[game.calendars[calind].req_tech]) {
+      break;
+    }
+    /* Either the first_year must be reached, or someone must have
+     * the early_tech, to reach a calendar. */
+    if (year < game.calendars[calind].first_year
+        && (game.calendars[calind].early_tech == A_NONE
+            || !game.global_advances[game.calendars[calind].early_tech])) {
+      break;
     }
   }
+  calind--;
 
-  if( year >= 1900 || ( spaceshipparts>=3 && year>0 ) )
-    year += 1;
-  else if( year >= 1750 || spaceshipparts>=2 )
-    year += 2;
-  else if( year >= 1500 || spaceshipparts>=1 )
-    year += 5;
-  else if( year >= 1000 )
-    year += 10;
-  else if( year >= 0 )
-    year += 20;
-  else if( year >= -1000 ) /* used this line for tuning (was -1250) */
-    year += 25;
-  else
-    year += 50; 
+  return &game.calendars[calind];
+}
 
-  if (year == 0) 
-    year = 1;
+/***************************************************************
+  Returns the relevant calendar for the current game year
+***************************************************************/
+const struct calendar *game_get_current_calendar(void)
+{
+  return game_get_calendar(game.year);
+}
+
+/***************************************************************
+  Returns the next year in the game.
+***************************************************************/
+int game_next_year(int year)
+{
+  int oldyear = year;
+  const struct calendar *cal = game_get_calendar(year);
+
+  year += cal->turn_years;
+
+  /* There is no such thing as "0AD", so skip a year if we passed it */
+  if (oldyear < 0 && year >= 0) {
+    year++;
+  }
 
   return year;
 }
@@ -1023,3 +1032,42 @@
 #undef name_strlcpy
 
 }
+
+/***************************************************************
+  Creates a set of calendars that reproduce the behaviour of
+  original Freeciv. These are used if the calendars cannot be
+  read from the rulesets (i.e. server and client do not share
+  the "calendars" capability).
+***************************************************************/
+void setup_default_calendars(void)
+{
+  int i;
+
+  assert(C_LAST >= 7);
+  game.num_calendars = 7;
+  for (i = 0; i < game.num_calendars; ++i) {
+    game.calendars[i].req_tech = A_NONE;
+    game.calendars[i].early_tech = A_NONE;
+  }
+  sz_strlcpy(game.calendars[0].name, N_("Prehistory"));
+  game.calendars[0].first_year = -4001;
+  game.calendars[0].turn_years = 50;
+  sz_strlcpy(game.calendars[1].name, N_("Ancient Age"));
+  game.calendars[1].first_year = -1001;
+  game.calendars[1].turn_years = 25;
+  sz_strlcpy(game.calendars[2].name, _("Classical Age"));
+  game.calendars[2].first_year = -1;
+  game.calendars[2].turn_years = 20;
+  sz_strlcpy(game.calendars[3].name, N_("Dark Ages"));
+  game.calendars[3].first_year = 1000;
+  game.calendars[3].turn_years = 10;
+  sz_strlcpy(game.calendars[4].name, N_("Middle Ages"));
+  game.calendars[4].first_year = 1500;
+  game.calendars[4].turn_years = 5;
+  sz_strlcpy(game.calendars[5].name, N_("Renaissance"));
+  game.calendars[5].first_year = 1750;
+  game.calendars[5].turn_years = 2;
+  sz_strlcpy(game.calendars[6].name, N_("Modern Age"));
+  game.calendars[6].first_year = 1900;
+  game.calendars[6].turn_years = 1;
+}
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/game.h freeciv-patched/common/game.h
--- freeciv-cvs/common/game.h	2003-06-30 12:18:29.000000000 +0100
+++ freeciv-patched/common/game.h	2003-06-30 12:28:20.000000000 +0100
@@ -28,6 +28,8 @@
 #define MAX_LEN_DEMOGRAPHY  16
 #define MAX_LEN_ALLOW_CONNECT 16
 #define MAX_ID_LEN 33
+#define MAX_CALENDAR 20
+#define C_LAST MAX_CALENDAR
 
 enum server_states { 
   PRE_GAME_STATE, 
@@ -48,6 +50,15 @@
 struct unit;
 struct city;
 
+struct calendar {
+  int id;
+  char name[MAX_LEN_NAME];
+  int first_year;
+  int turn_years;
+  int req_tech;
+  int early_tech;
+};
+
 #define OVERFLIGHT_NOTHING  1
 #define OVERFLIGHT_FRIGHTEN 2
 
@@ -79,6 +90,7 @@
   int end_year;
   int year;
   int turn;
+  int spaceage_year; /* The year in which the first space craft is launched */
   int researchcost; /* Multiplier on cost of new research */
   int diplcost, freecost, conquercost;
   int diplchance;
@@ -155,6 +167,7 @@
   int nation_count;
   int playable_nation_count;
   int styles_count;
+  int num_calendars;
 
   int watchtower_extra_vision;
   int watchtower_vision;
@@ -203,6 +216,8 @@
   char demography[MAX_LEN_DEMOGRAPHY];
   char allow_connect[MAX_LEN_ALLOW_CONNECT];
 
+  struct calendar calendars[C_LAST];
+
   /* used by the map editor to control game_save; could be used by the server too */
   struct {
     bool save_random;
@@ -233,6 +248,9 @@
 
 int game_next_year(int);
 void game_advance_year(void);
+const struct calendar *game_get_calendar(int year);
+const struct calendar *game_get_current_calendar(void);
+void setup_default_calendars(void);
 
 int civ_population(struct player *pplayer);
 struct city *game_find_city_by_name(const char *name);
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/packets.c freeciv-patched/common/packets.c
--- freeciv-cvs/common/packets.c	2003-06-30 12:18:26.000000000 +0100
+++ freeciv-patched/common/packets.c	2003-06-30 12:28:20.000000000 +0100
@@ -422,6 +422,8 @@
     return receive_packet_ruleset_city(pc);
   case PACKET_RULESET_GAME:
     return receive_packet_ruleset_game(pc);
+  case PACKET_RULESET_CALENDAR:
+    return receive_packet_ruleset_calendar(pc);
 
   case PACKET_SPACESHIP_INFO:
     return receive_packet_spaceship_info(pc);
@@ -1035,6 +1037,9 @@
   dio_put_uint32(&dout, pinfo->timeout);
   dio_put_uint32(&dout, pinfo->end_year);
   dio_put_uint32(&dout, pinfo->year);
+  if (has_capability("calendar", pc->capability)) {
+    dio_put_sint16(&dout, pinfo->spaceage_year);
+  }
   dio_put_uint8(&dout, pinfo->min_players);
   dio_put_uint8(&dout, pinfo->max_players);
   dio_put_uint8(&dout, pinfo->nplayers);
@@ -1083,6 +1088,11 @@
   dio_get_uint32(&din, &pinfo->timeout);
   dio_get_uint32(&din, &pinfo->end_year);
   dio_get_uint32(&din, &pinfo->year);
+  if (has_capability("calendar", pc->capability)) {
+    dio_get_sint16(&din, &pinfo->spaceage_year);
+  } else {
+    pinfo->spaceage_year = GAME_MAX_END_YEAR + 1;
+  }
   dio_get_uint8(&din, &pinfo->min_players);
   dio_get_uint8(&din, &pinfo->max_players);
   dio_get_uint8(&din, &pinfo->nplayers);
@@ -1862,6 +1872,10 @@
   dio_put_uint8(&dout, packet->num_unit_types);
   dio_put_uint8(&dout, packet->num_impr_types);
   dio_put_uint8(&dout, packet->num_tech_types);
+
+  if (has_capability("calendar", pc->capability)) {
+    dio_put_uint8(&dout, packet->num_calendars);
+  }
  
   dio_put_uint8(&dout, packet->nation_count);
   dio_put_uint8(&dout, packet->playable_nation_count);
@@ -1909,6 +1923,12 @@
   dio_get_uint8(&din, &packet->num_impr_types);
   dio_get_uint8(&din, &packet->num_tech_types);
 
+  if (has_capability("calendar", pc->capability)) {
+    dio_get_uint8(&din, &packet->num_calendars);
+  } else {
+    packet->num_calendars = 0;
+  }
+
   dio_get_uint8(&din, &packet->nation_count);
   dio_get_uint8(&din, &packet->playable_nation_count);
   dio_get_uint8(&din, &packet->style_count);
@@ -3149,6 +3169,42 @@
   RECEIVE_PACKET_END(packet);
 }
 
+/*************************************************************************
+...
+**************************************************************************/
+int send_packet_ruleset_calendar(struct connection *pc,
+    				 const struct packet_ruleset_calendar *packet)
+{
+  SEND_PACKET_START(PACKET_RULESET_CALENDAR);
+
+  dio_put_uint8(&dout, packet->id);
+  dio_put_string(&dout, packet->name);
+  dio_put_sint16(&dout, packet->first_year);
+  dio_put_uint8(&dout, packet->turn_years);
+  dio_put_uint8(&dout, packet->req_tech);
+  dio_put_uint8(&dout, packet->early_tech);
+
+  SEND_PACKET_END;
+}
+
+/*************************************************************************
+...
+**************************************************************************/
+struct packet_ruleset_calendar *
+receive_packet_ruleset_calendar(struct connection *pc)
+{
+  RECEIVE_PACKET_START(packet_ruleset_calendar, packet);
+
+  dio_get_uint8(&din, &packet->id);
+  dio_get_string(&din, packet->name, sizeof(packet->name));
+  dio_get_sint16(&din, &packet->first_year);
+  dio_get_uint8(&din, &packet->turn_years);
+  dio_get_uint8(&din, &packet->req_tech);
+  dio_get_uint8(&din, &packet->early_tech);
+
+  RECEIVE_PACKET_END(packet);
+}
+
 /**************************************************************************
 ...
 **************************************************************************/
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/packets.h freeciv-patched/common/packets.h
--- freeciv-cvs/common/packets.h	2003-06-30 12:18:26.000000000 +0100
+++ freeciv-patched/common/packets.h	2003-06-30 12:28:20.000000000 +0100
@@ -128,6 +128,7 @@
   PACKET_FREEZE_HINT,
   PACKET_THAW_HINT,
   PACKET_PING_INFO,
+  PACKET_RULESET_CALENDAR,
   PACKET_LAST  /* leave this last */
 };
 
@@ -583,6 +584,7 @@
   int playable_nation_count;
   int style_count;
   char team_name[MAX_NUM_TEAMS][MAX_LEN_NAME];
+  int num_calendars;
 };
 
 /*********************************************************
@@ -829,6 +831,15 @@
   int global_init_techs[MAX_NUM_TECH_LIST];
 };
 
+struct packet_ruleset_calendar {
+  int id;
+  char name[MAX_LEN_NAME];
+  int first_year;
+  int turn_years;
+  int req_tech;
+  int early_tech;
+};
+
 /*********************************************************
 ...
 *********************************************************/
@@ -842,6 +853,7 @@
   int end_year;
   int year;
   int turn;
+  int spaceage_year;
   int min_players, max_players, nplayers;
   int player_idx;
   int globalwarming;
@@ -1096,6 +1108,10 @@
                              const struct packet_ruleset_game *packet);
 struct packet_ruleset_game *
 receive_packet_ruleset_game(struct connection *pc);
+int send_packet_ruleset_calendar(struct connection *pc,
+    				 const struct packet_ruleset_calendar *packet);
+struct packet_ruleset_calendar *
+receive_packet_ruleset_calendar(struct connection *pc);
 
 int send_packet_generic_values(struct connection *pc, enum packet_type type,
 			       const struct packet_generic_values *req);
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/packets_lsend.c freeciv-patched/common/packets_lsend.c
--- freeciv-cvs/common/packets_lsend.c	2003-06-07 19:58:26.000000000 +0100
+++ freeciv-patched/common/packets_lsend.c	2003-06-30 12:28:20.000000000 +0100
@@ -311,6 +311,14 @@
   conn_list_iterate_end;
 }
 
+void lsend_packet_ruleset_calendar(struct conn_list *dest,
+    				 const struct packet_ruleset_calendar *packet)
+{
+  conn_list_iterate(*dest, pconn)
+    send_packet_ruleset_calendar(pconn, packet);
+  conn_list_iterate_end;
+}
+
 void lsend_packet_generic_values(struct conn_list *dest, enum packet_type type,
 			       const struct packet_generic_values *req)
 {
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/packets_lsend.h freeciv-patched/common/packets_lsend.h
--- freeciv-cvs/common/packets_lsend.h	2003-06-07 19:58:26.000000000 +0100
+++ freeciv-patched/common/packets_lsend.h	2003-06-30 12:28:20.000000000 +0100
@@ -90,6 +90,8 @@
 			     const struct packet_ruleset_city *packet);
 void lsend_packet_ruleset_game(struct conn_list *dest,
                              const struct packet_ruleset_game *packet);
+void lsend_packet_ruleset_calendar(struct conn_list *dest,
+    				 const struct packet_ruleset_calendar *packet);
 void lsend_packet_generic_values(struct conn_list *dest, enum packet_type type,
 			       const struct packet_generic_values *req);
 void lsend_packet_spaceship_info(struct conn_list *dest,
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ1/game.ruleset freeciv-patched/data/civ1/game.ruleset
--- freeciv-cvs/data/civ1/game.ruleset	2002-08-26 14:18:04.000000000 +0100
+++ freeciv-patched/data/civ1/game.ruleset	2003-06-30 12:28:20.000000000 +0100
@@ -17,6 +17,57 @@
 [options]
 global_init_techs=""
 
+; Below: One section for each calendar, in order (see default ruleset)
+
+[calendar_prehistory]
+name                   = _("Prehistory")
+first_year             = -4001
+turn_years             = 50
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_ancient_age]
+name                   = _("Ancient Age")
+first_year             = -1001
+turn_years             = 25
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_classical_age]
+name                   = _("Classical Age")
+first_year             = -1
+turn_years             = 20
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_dark_ages]
+name                   = _("Dark Ages")
+first_year             = 1000
+turn_years             = 10
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_middle_ages]
+name                   = _("Middle Ages")
+first_year             = 1500
+turn_years             = 5
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_renaissance]
+name                   = _("Renaissance")
+first_year             = 1750
+turn_years             = 2
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_modern]
+name                   = _("Modern Age")
+first_year             = 1900
+turn_years             = 1
+req_tech               = "None"
+early_tech             = "None"
+
 [civstyle]
 min_city_center_food	= 0
 min_city_center_shield	= 0
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/civ2/game.ruleset freeciv-patched/data/civ2/game.ruleset
--- freeciv-cvs/data/civ2/game.ruleset	2002-08-26 14:18:04.000000000 +0100
+++ freeciv-patched/data/civ2/game.ruleset	2003-06-30 12:28:20.000000000 +0100
@@ -17,6 +17,57 @@
 [options]
 global_init_techs=""
 
+; Below: One section for each calendar, in order (see default ruleset)
+
+[calendar_prehistory]
+name                   = _("Prehistory")
+first_year             = -4001
+turn_years             = 50
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_ancient_age]
+name                   = _("Ancient Age")
+first_year             = -1001
+turn_years             = 25
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_classical_age]
+name                   = _("Classical Age")
+first_year             = -1
+turn_years             = 20
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_dark_ages]
+name                   = _("Dark Ages")
+first_year             = 1000
+turn_years             = 10
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_middle_ages]
+name                   = _("Middle Ages")
+first_year             = 1500
+turn_years             = 5
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_renaissance]
+name                   = _("Renaissance")
+first_year             = 1750
+turn_years             = 2
+req_tech               = "None"
+early_tech             = "None"
+
+[calendar_modern]
+name                   = _("Modern Age")
+first_year             = 1900
+turn_years             = 1
+req_tech               = "None"
+early_tech             = "None"
+
 [civstyle]
 min_city_center_food	= 1
 min_city_center_shield	= 1
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/data/default/game.ruleset freeciv-patched/data/default/game.ruleset
--- freeciv-cvs/data/default/game.ruleset	2002-08-26 14:18:04.000000000 +0100
+++ freeciv-patched/data/default/game.ruleset	2003-06-30 12:28:20.000000000 +0100
@@ -17,6 +17,105 @@
 [options]
 global_init_techs=""
 
+; /* <-- avoid gettext warnings
+;
+; Below: One section for each calendar.
+;
+; The actual tag used (the * in [calendar_*]) does not matter, except
+; it must be unique within this file, and may be used in debug output
+; when reading this file.
+;
+; The order is important; earlier calendars must come first. You
+; cannot use more than 20 calendars in total. Note that there is no
+; year zero in Freeciv, just as in the real world - the year after
+; 1BC is 1AD.
+; 
+; Notes:
+; 
+; name         = name as seen by user (if it's ever seen; usually not)
+;                these can be names like "Ancient", "Medieval", etc.,
+;                or whatever is appropriate, but more specific names
+;                like "Iron Age" may be a bad idea, as it may seem a
+;                bit strange to users that they're in the Iron Age when
+;                nobody has Iron Working yet....
+; first_year   = year when this calendar starts
+; turn_years   = number of years the game advances each turn
+; req_tech     = technology which some player must reach before we can 
+;                start this calendar, even if we've already passed the
+;                appropriate year, or "None" if there is no such tech
+; early_tech   = technology at which we jump to this calendar, even if
+;                we haven't yet reached the appropriate year, or "None"
+;                if there is no such tech
+;
+; Normally you won't want to use both req_tech and early_tech.  However,
+; you could set first_year to 9999 for every calendar and use the two of
+; them together, so that the calendar advances when both are researched.
+;
+; Note that special rules apply for the Space Race. Once any player
+; launches a space craft, the game will switch to an internal "Space Age"
+; (1 year/turn) calendar, regardless of those defined in this ruleset.
+; This is for partial compatibility with older Civ games; however, merely
+; discovering the technology required to build space components now has
+; no effect on the game calendar.
+;
+; */ <-- avoid gettext warnings
+
+[calendar_prehistory]
+name                   = _("Prehistory")
+first_year             = -4001
+turn_years             = 50
+req_tech               = "None"
+early_tech             = "None"
+; 4001BC - 1001BC = 60 turns
+
+[calendar_ancient_age]
+name                   = _("Ancient Age")
+first_year             = -1001
+turn_years             = 25
+req_tech               = "None"
+early_tech             = "None"
+; 1001BC - 1BC = 40 turns, 100 cumulative
+
+[calendar_classical_age]
+name                   = _("Classical Age")
+first_year             = -1
+turn_years             = 20
+req_tech               = "None"
+early_tech             = "None"
+; 1BC - 1000AD = 50 turns, 150 cumulative
+
+[calendar_dark_ages]
+name                   = _("Dark Ages")
+first_year             = 1000
+turn_years             = 10
+req_tech               = "None"
+early_tech             = "None"
+; 1000 AD - 1500 AD = 50 turns, 200 cumulative
+
+[calendar_middle_ages]
+name                   = _("Middle Ages")
+first_year             = 1500
+turn_years             = 5
+req_tech               = "None"
+early_tech             = "None"
+; 1500 AD - 1750 AD = 50 turns, 250 cumulative
+
+[calendar_renaissance]
+name                   = _("Renaissance")
+first_year             = 1750
+turn_years             = 2
+req_tech               = "None"
+early_tech             = "None"
+; 1750 AD - 1900 AD = 75 turns, 325 cumulative
+
+[calendar_modern]
+name                   = _("Modern Age")
+first_year             = 1900
+turn_years             = 1
+req_tech               = "None"
+early_tech             = "None"
+; 1900 AD - 2000 AD = 100 turns, 425 cumulative
+
 [civstyle]
 min_city_center_food	= 1
 min_city_center_shield	= 1
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/gamehand.c freeciv-patched/server/gamehand.c
--- freeciv-cvs/server/gamehand.c	2003-06-30 12:18:29.000000000 +0100
+++ freeciv-patched/server/gamehand.c	2003-06-30 12:28:20.000000000 +0100
@@ -221,6 +221,7 @@
   ginfo.end_year = game.end_year;
   ginfo.year = game.year;
   ginfo.turn = game.turn;
+  ginfo.spaceage_year = game.spaceage_year;
   ginfo.min_players = game.min_players;
   ginfo.max_players = game.max_players;
   ginfo.nplayers = game.nplayers;
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/ruleset.c freeciv-patched/server/ruleset.c
--- freeciv-cvs/server/ruleset.c	2003-06-30 12:18:28.000000000 +0100
+++ freeciv-patched/server/ruleset.c	2003-06-30 12:28:20.000000000 +0100
@@ -79,6 +79,7 @@
 static void load_terrain_names(struct section_file *file);
 static void load_citystyle_names(struct section_file *file);
 static void load_nation_names(struct section_file *file);
+static void load_calendar_names(struct section_file *file);
 static struct city_name* load_city_name_list(struct section_file *file,
 					     const char *secfile_str1,
 					     const char *secfile_str2);
@@ -90,8 +91,7 @@
 static void load_ruleset_terrain(struct section_file *file);
 static void load_ruleset_cities(struct section_file *file);
 static void load_ruleset_nations(struct section_file *file);
-
-static void load_ruleset_game(void);
+static void load_ruleset_game(struct section_file *file);
 
 static void send_ruleset_techs(struct conn_list *dest);
 static void send_ruleset_units(struct conn_list *dest);
@@ -101,6 +101,7 @@
 static void send_ruleset_nations(struct conn_list *dest);
 static void send_ruleset_cities(struct conn_list *dest);
 static void send_ruleset_game(struct conn_list *dest);
+static void send_ruleset_calendars(struct conn_list *dest);
 
 /**************************************************************************
   datafilename() wrapper: tries to match in two ways.
@@ -1811,6 +1812,7 @@
   packet.num_unit_types = game.num_unit_types;
   packet.num_impr_types = game.num_impr_types;
   packet.num_tech_types = game.num_tech_types;
+  packet.num_calendars = game.num_calendars;
 
   packet.nation_count = game.nation_count;
   packet.playable_nation_count = game.playable_nation_count;
@@ -1908,6 +1910,40 @@
 }
 
 /**************************************************************************
+  ...
+**************************************************************************/
+static void load_calendar_names(struct section_file *file)
+{
+  char **sec;
+  int num_calendars; /* number of calendars in game.ruleset */
+  int i;
+  const char *filename = secfile_filename(file);
+
+  section_file_lookup(file, "datafile.description"); /* unused */
+
+  /* The names: */
+  sec = secfile_get_secnames_prefix(file, "calendar_", &num_calendars);
+  freelog(LOG_VERBOSE, "%d calendars (including possibly unused)", 
+	  num_calendars);
+  if (num_calendars == 0) {
+    freelog(LOG_NORMAL, "No calendars; using default (%s)", filename);
+  }
+  if (num_calendars > C_LAST) {
+    freelog(LOG_FATAL, "Too many calendars (%d, max %d) (%s)",
+	    num_calendars, C_LAST, filename);
+    exit(EXIT_FAILURE);
+  }
+
+  game.num_calendars = num_calendars;
+  for (i = 0; i < num_calendars; ++i) {
+    char *name = secfile_lookup_str(file, "%s.name", sec[i]);
+    game.calendars[i].id = i;
+    name_strlcpy(game.calendars[i].name, name);
+  }
+  free(sec);
+}
+
+/**************************************************************************
   This function loads a city name list from a section file.  The file and
   two section names (which will be concatenated) are passed in.  The
   malloc'ed city name list (which is all filled out) will be returned.
@@ -2364,33 +2400,62 @@
   section_file_free(file);
 }
 
+static void load_calendars(struct section_file *file)
+{
+  char **sec;
+  const char *filename = secfile_filename(file);
+  int i, nval;
+
+  sec = secfile_get_secnames_prefix(file, "calendar_", &nval);
+  for (i = 0; i < game.num_calendars; ++i ) {
+    game.calendars[i].first_year =
+	secfile_lookup_int(file, "%s.first_year", sec[i]);
+    game.calendars[i].turn_years =
+	secfile_lookup_int(file, "%s.turn_years", sec[i]);
+    game.calendars[i].req_tech =
+	lookup_tech(file, sec[i], "req_tech", 0, filename,
+		    game.calendars[i].name);
+    if (game.calendars[i].req_tech == A_LAST) {
+      game.calendars[i].req_tech = A_NONE;
+    }
+    game.calendars[i].early_tech =
+	lookup_tech(file, sec[i], "early_tech", 0, filename,
+		    game.calendars[i].name);
+    if (game.calendars[i].early_tech == A_LAST) {
+      game.calendars[i].early_tech = A_NONE;
+    }
+  }
+  free(sec);
+
+  if (game.num_calendars == 0) {
+    setup_default_calendars();
+  }
+}
+
 /**************************************************************************
 Load ruleset file
 **************************************************************************/
-static void load_ruleset_game()
+static void load_ruleset_game(struct section_file *file)
 {
-  struct section_file file;
   char *datafile_options;
   char *sval;
-  const char *filename;
+  const char *filename = secfile_filename(file);
 
-  openload_ruleset_file(&file, "game");
-  filename = secfile_filename(&file);
-  datafile_options = check_ruleset_capabilities(&file, "+1.11.1", filename);
-  (void) section_file_lookup(&file, "datafile.description");	/* unused */
+  datafile_options = check_ruleset_capabilities(file, "+1.11.1", filename);
+  (void) section_file_lookup(file, "datafile.description");	/* unused */
 
   game.rgame.min_city_center_food =
-    secfile_lookup_int(&file, "civstyle.min_city_center_food");
+    secfile_lookup_int(file, "civstyle.min_city_center_food");
   game.rgame.min_city_center_shield =
-    secfile_lookup_int(&file, "civstyle.min_city_center_shield");
+    secfile_lookup_int(file, "civstyle.min_city_center_shield");
   game.rgame.min_city_center_trade =
-    secfile_lookup_int(&file, "civstyle.min_city_center_trade");
+    secfile_lookup_int(file, "civstyle.min_city_center_trade");
 
   /* if the server variable citymindist is set (!= 0) the ruleset
      setting is overwritten by citymindist */
   if (game.citymindist == 0) {
     game.rgame.min_dist_bw_cities =
-	secfile_lookup_int(&file, "civstyle.min_dist_bw_cities");
+	secfile_lookup_int(file, "civstyle.min_dist_bw_cities");
     if (game.rgame.min_dist_bw_cities < 1) {
       freelog(LOG_ERROR, "Bad value %i for min_dist_bw_cities. Using 2.",
 	      game.rgame.min_dist_bw_cities);
@@ -2401,9 +2466,9 @@
   }
 
   game.rgame.init_vis_radius_sq =
-    secfile_lookup_int(&file, "civstyle.init_vis_radius_sq");
+    secfile_lookup_int(file, "civstyle.init_vis_radius_sq");
 
-  sval = secfile_lookup_str(&file, "civstyle.hut_overflight" );
+  sval = secfile_lookup_str(file, "civstyle.hut_overflight" );
   if (mystrcasecmp(sval, "Nothing") == 0) {
     game.rgame.hut_overflight = OVERFLIGHT_NOTHING;
   } else if (mystrcasecmp(sval, "Frighten") == 0) {
@@ -2415,9 +2480,9 @@
   }
 
   game.rgame.pillage_select =
-      secfile_lookup_bool(&file, "civstyle.pillage_select");
+      secfile_lookup_bool(file, "civstyle.pillage_select");
 
-  sval = secfile_lookup_str(&file, "civstyle.nuke_contamination" );
+  sval = secfile_lookup_str(file, "civstyle.nuke_contamination" );
   if (mystrcasecmp(sval, "Pollution") == 0) {
     game.rgame.nuke_contamination = CONTAMINATION_POLLUTION;
   } else if (mystrcasecmp(sval, "Fallout") == 0) {
@@ -2429,14 +2494,14 @@
   }
 
   game.rgame.granary_food_ini =
-    secfile_lookup_int(&file, "civstyle.granary_food_ini");
+    secfile_lookup_int(file, "civstyle.granary_food_ini");
   if (game.rgame.granary_food_ini < 0) {
     freelog(LOG_ERROR, "Bad value %i for granary_food_ini. Using 1.",
 	    game.rgame.granary_food_ini);
     game.rgame.granary_food_ini = 1;
   }
   game.rgame.granary_food_inc =
-    secfile_lookup_int(&file, "civstyle.granary_food_inc");
+    secfile_lookup_int(file, "civstyle.granary_food_inc");
   if (game.rgame.granary_food_inc < 0 ||
       /* can't have a granary size of zero */
       (game.rgame.granary_food_ini == 0 && 
@@ -2447,7 +2512,7 @@
   }
 
   game.rgame.tech_cost_style =
-      secfile_lookup_int(&file, "civstyle.tech_cost_style");
+      secfile_lookup_int(file, "civstyle.tech_cost_style");
   if (game.rgame.tech_cost_style < 0 || game.rgame.tech_cost_style > 2) {
     freelog(LOG_ERROR, "Bad value %i for tech_cost_style. Using 0.",
 	    game.rgame.tech_cost_style);
@@ -2455,7 +2520,7 @@
   }
 
   game.rgame.tech_leakage =
-      secfile_lookup_int(&file, "civstyle.tech_leakage");
+      secfile_lookup_int(file, "civstyle.tech_leakage");
   if (game.rgame.tech_leakage < 0 || game.rgame.tech_leakage > 3) {
     freelog(LOG_ERROR, "Bad value %i for tech_leakage. Using 0.",
 	    game.rgame.tech_leakage);
@@ -2472,11 +2537,13 @@
   /*
    * Load global initial techs
    */
-  lookup_tech_list(&file, "options", "global_init_techs",
+  lookup_tech_list(file, "options", "global_init_techs",
 		   game.rgame.global_init_techs, filename);
 
-  section_file_check_unused(&file, filename);
-  section_file_free(&file);
+  load_calendars(file);
+
+  section_file_check_unused(file, filename);
+  section_file_free(file);
 }
 
 /**************************************************************************
@@ -2837,13 +2904,34 @@
   lsend_packet_ruleset_game(dest, &misc_p);
 }
 
+ /**************************************************************************
+  Send the calendar information from the game ruleset (all calendars)
+  to the specified connections.
+**************************************************************************/
+static void send_ruleset_calendars(struct conn_list *dest)
+{
+  struct packet_ruleset_calendar packet;
+  struct calendar *c;
+
+  for(c = game.calendars; c < game.calendars + game.num_calendars; ++c) {
+    packet.id = c->id;
+    sz_strlcpy(packet.name, c->name);
+    packet.first_year = c->first_year;
+    packet.turn_years = c->turn_years;
+    packet.req_tech = c->req_tech;
+    packet.early_tech = c->early_tech;
+
+    lsend_packet_ruleset_calendar(dest, &packet);
+  }
+}
+
 /**************************************************************************
 ...  
 **************************************************************************/
 void load_rulesets(void)
 {
   struct section_file techfile, unitfile, buildfile, govfile, terrfile;
-  struct section_file cityfile, nationfile;
+  struct section_file cityfile, nationfile, gamefile;
 
   freelog(LOG_NORMAL, _("Loading rulesets"));
 
@@ -2868,6 +2956,9 @@
   openload_ruleset_file(&nationfile, "nations");
   load_nation_names(&nationfile);
 
+  openload_ruleset_file(&gamefile, "game");
+  load_calendar_names(&gamefile);
+
   load_ruleset_techs(&techfile);
   load_ruleset_cities(&cityfile);
   load_ruleset_governments(&govfile);
@@ -2875,7 +2966,7 @@
   load_ruleset_terrain(&terrfile);    /* terrain must precede nations */
   load_ruleset_buildings(&buildfile);
   load_ruleset_nations(&nationfile);
-  load_ruleset_game();
+  load_ruleset_game(&gamefile);
   translate_data_names();
 }
 
@@ -2895,6 +2986,7 @@
   send_ruleset_buildings(dest);
   send_ruleset_nations(dest);
   send_ruleset_cities(dest);
+  send_ruleset_calendars(dest);
 
   conn_list_do_unbuffer(dest);
 }
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/savegame.c freeciv-patched/server/savegame.c
--- freeciv-cvs/server/savegame.c	2003-06-30 12:18:29.000000000 +0100
+++ freeciv-patched/server/savegame.c	2003-06-30 12:28:20.000000000 +0100
@@ -1828,6 +1828,9 @@
       game.researchcost = secfile_lookup_int(file, "game.techlevel");
 
     game.year          = secfile_lookup_int(file, "game.year");
+    game.spaceage_year = secfile_lookup_int_default(file,
+						    GAME_MAX_END_YEAR + 1,
+						    "game.spaceage_year");
 
     if (has_capability("turn", savefile_options)) {
       game.turn = secfile_lookup_int(file, "game.turn");
@@ -2221,6 +2224,7 @@
   secfile_insert_int(file, game.end_year, "game.end_year");
   secfile_insert_int(file, game.year, "game.year");
   secfile_insert_int(file, game.turn, "game.turn");
+  secfile_insert_int(file, game.spaceage_year, "game.spaceage_year");
   secfile_insert_int(file, game.researchcost, "game.researchcost");
   secfile_insert_int(file, game.min_players, "game.min_players");
   secfile_insert_int(file, game.max_players, "game.max_players");
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/spacerace.c freeciv-patched/server/spacerace.c
--- freeciv-cvs/server/spacerace.c	2003-06-07 19:58:49.000000000 +0100
+++ freeciv-patched/server/spacerace.c	2003-06-30 12:28:20.000000000 +0100
@@ -26,6 +26,7 @@
 #include "shared.h"
 #include "spaceship.h"
 
+#include "gamehand.h"
 #include "gamelog.h"
 #include "plrhand.h"
 #include "srv_main.h"
@@ -186,6 +187,9 @@
 		   textyear(arrival));
 
   send_spaceship_info(pplayer, NULL);
+
+  game.spaceage_year = game.year;
+  send_game_info(NULL);
 }
 
 /**************************************************************************
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/srv_main.c freeciv-patched/server/srv_main.c
--- freeciv-cvs/server/srv_main.c	2003-06-30 12:18:26.000000000 +0100
+++ freeciv-patched/server/srv_main.c	2003-06-30 12:28:20.000000000 +0100
@@ -1617,6 +1617,7 @@
   if (game.is_new_game) {
     load_rulesets();
     /* otherwise rulesets were loaded when savegame was loaded */
+    game.year = game.calendars[0].first_year;
   }
 
   nations_avail = fc_calloc(game.playable_nation_count, sizeof(int));
