tWe now support dates properly. Names.Month and Names.Year no longer exist; they are replaced by StartDate and Names.Date. This changes the protocol; old clients without the A_DATE ability will be fed suitable defaults for Names.Month and Names.Year so as not to upset them. - vaccinewars - be a doctor and try to vaccinate the world
 (HTM) git clone git://src.adamsgaard.dk/vaccinewars
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 9a9ff0d914d62a5f3dd56db880f7a1aca7887d20
 (DIR) parent ce396c47d1a0063856c581d2028b88bbd91111a9
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Mon, 12 Aug 2002 11:33:56 +0000
       
       We now support dates properly. Names.Month and Names.Year no longer exist;
       tthey are replaced by StartDate and Names.Date. This changes the protocol;
       old clients without the A_DATE ability will be fed suitable defaults for
       Names.Month and Names.Year so as not to upset them.
       
       
       Diffstat:
         M ChangeLog                           |       3 +++
         M TODO                                |       1 -
         M doc/configfile.html                 |      23 +++++++++++++++--------
         M src/curses_client/curses_client.c   |       2 +-
         M src/dopewars.c                      |      57 +++++++++++++++++++++++--------
         M src/dopewars.h                      |      11 ++++++++++-
         M src/gui_client/gtk_client.c         |       2 +-
         M src/message.c                       |      41 +++++++++++++++++++++++++------
         M src/serverside.c                    |       1 +
       
       9 files changed, 107 insertions(+), 34 deletions(-)
       ---
 (DIR) diff --git a/ChangeLog b/ChangeLog
       t@@ -8,6 +8,9 @@ cvs
              all network messages will be sent in UTF-8 (Unicode) encoding (without
              the ability, all messages are assumed to be in your locale's default
              codeset, which may cause problems on non-US ASCII systems)
       +    - Names.Month and Names.Year have been replaced with StartDate.Day,
       +      StartDate.Month, StartDate.Year and Names.Date; these can be used to
       +      handle the date display properly after the turn number exceeds 31
            - Encoding config variable added, to allow the config file's encoding
              (usually taken from the locale) to be overridden
            - Spanish translation added by Quique
 (DIR) diff --git a/TODO b/TODO
       t@@ -1,7 +1,6 @@
        - Fix the Encoding variable so that a) it works only on the current file
          (not on _all_ config files) and b) it only translates config file variables,
          not the defaults (which could be in a different codeset)
       -- Support for "proper" game dates, e.g. mm-dd-yy or dd-mm-yy
        - Limit rate of server connections to combat DOS attacks / players trying
          to get a good starting day?
        - Add support for reading/writing multiple configuration files to GUI client's
 (DIR) diff --git a/doc/configfile.html b/doc/configfile.html
       t@@ -572,14 +572,21 @@ replaced by "candy bar" or something similarly innocuous).</dd>
        <dt><b>Names.Drugs=<i>"drugs"</i></b></dt>
        <dd>Sets the word used to describe two or more "drugs".</dd>
        
       -<dt><b>Names.Month=<i>"12-"</i></b></dt>
       -<dd>Sets the text which is displayed on the client's screen to the immediate
       -left of the current turn (by default, a "turn" is a day, and so this part
       -is the month, in displaying the date in MM-DD-YYYY format)</dd>
       +<dt><b>Names.Date=<i>"%m-%d-%Y"</i></b></dt>
       +<dd>Sets the format string (which is passed to the strftime() function) for
       +displaying the current game date. This example (the default) displays the
       +date in MM-DD-YYYY format, as is commonplace in the US. Only date (not time)
       +formats can be used, and the special format %T is used to display the
       +current game turn.</dd>
        
       -<dt><b>Names.Year=<i>"-1984"</i></b></dt>
       -<dd>Sets the text displayed to the immediate right of the current turn (by
       -default, the year).</dd>
       +<dt><b>StartDate.Day=<i>"1"</i></b></dt>
       +<dd>Sets the day of the month on which the game starts to <i>1</i>.</dd>
       +
       +<dt><b>StartDate.Month=<i>"12"</i></b></dt>
       +<dd>Sets the month in which the game starts to <i>12</i> (i.e. December).</dd>
       +
       +<dt><b>StartDate.Year=<i>"1984"</i></b></dt>
       +<dd>Sets the year in which the game starts to <i>1984</i>.</dd>
        
        <dt><b>Prices.Spy=<i>20000</i></b></dt>
        <dd>Sets the price to pay a bitch to spy on another player to be
       t@@ -662,7 +669,7 @@ can be configured in the same way are: <b>FightMiss</b>, <b>FightReload</b>,
        <li><a href="index.html">Main index</a></li>
        </ul>
        <p>
       -  Last update: <b>04-08-2002</b><br />
       +  Last update: <b>11-08-2002</b><br />
          Valid <a href="http://validator.w3.org/check/referer">XHTML 1.1</a>
        </p>
        </body>
 (DIR) diff --git a/src/curses_client/curses_client.c b/src/curses_client/curses_client.c
       t@@ -1703,7 +1703,7 @@ void print_status(Player *Play, gboolean DispDrug)
          text = g_string_new(NULL);
          attrset(TitleAttr);
          clear_line(0);
       -  g_string_sprintf(text, "%s%02d%s", Names.Month, Play->Turn, Names.Year);
       +  GetDateString(text, Play);
          mvaddstr(0, 3, text->str);
        
          attrset(StatsAttr);
 (DIR) diff --git a/src/dopewars.c b/src/dopewars.c
       t@@ -84,6 +84,10 @@ gchar *Encoding = NULL;
        gboolean WantHelp, WantVersion, WantAntique, WantColour, WantNetwork;
        gboolean WantConvert, WantAdmin;
        
       +struct DATE StartDate = {
       +  1, 12, 1984
       +};
       +
        #ifdef CYGWIN
        gboolean MinToSysTray = TRUE;
        #else
       t@@ -154,7 +158,7 @@ struct DRUG StaticDrug, *Drug = NULL;
        struct GUN StaticGun, *Gun = NULL;
        struct COP StaticCop, *Cop = NULL;
        struct NAMES Names = {
       -  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
       +  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
        };
        struct SOUNDS Sounds = {
          NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
       t@@ -179,13 +183,10 @@ struct NAMES DefaultNames = {
          N_("drug"),
          /* Word used for two or more drugs */
          N_("drugs"),
       -  /* Text that is printed before the turn number. In US mm-dd-yyyy date
       -   * notation, with MaxTurns at 31 or less, this works out as the month -
       -   * i.e. December in this case */
       -  N_("12-"),
       -  /* Text that is printed _after_ the turn number (the year, in US
       -   * notation) */
       -  N_("-1984"),
       +  /* String for displaying the game date or turn number. This is passed
       +   * to the strftime() function, with the exception that %T is used to
       +   * mean the turn number rather than the calendar date. */
       +  N_("%m-%d-%Y"),
          /* Names of the loan shark, the bank, the gun shop, and the pub,
           * respectively */
          N_("the Loan Shark"), N_("the Bank"),
       t@@ -332,6 +333,15 @@ struct GLOBALS Globals[] = {
          {&NumTurns, NULL, NULL, NULL, NULL, "NumTurns",
           N_("No. of game turns (if 0, game never ends)"),
           NULL, NULL, 0, "", NULL, NULL, FALSE, 0},
       +  {&StartDate.day, NULL, NULL, NULL, NULL, "StartDate.Day",
       +   N_("Day of the month on which the game starts"),
       +   NULL, NULL, 0, "", NULL, NULL, FALSE, 0},
       +  {&StartDate.month, NULL, NULL, NULL, NULL, "StartDate.Month",
       +   N_("Month in which the game starts"),
       +   NULL, NULL, 0, "", NULL, NULL, FALSE, 0},
       +  {&StartDate.year, NULL, NULL, NULL, NULL, "StartDate.Year",
       +   N_("Year in which the game starts"),
       +   NULL, NULL, 0, "", NULL, NULL, FALSE, 0},
          {NULL, NULL, NULL, &Currency.Symbol, NULL, "Currency.Symbol",
           N_("The currency symbol (e.g. $)"),
           NULL, NULL, 0, "", NULL, NULL, FALSE, 0},
       t@@ -582,11 +592,8 @@ struct GLOBALS Globals[] = {
          {NULL, NULL, NULL, &Names.Drugs, NULL, "Names.Drugs",
           N_("Word used to denote two or more drugs"), NULL, NULL, 0, "", NULL,
           NULL, FALSE, 0},
       -  {NULL, NULL, NULL, &Names.Month, NULL, "Names.Month",
       -   N_("Text prefixed to the turn number (i.e. the month)"),
       -   NULL, NULL, 0, "", NULL, NULL, FALSE, 0},
       -  {NULL, NULL, NULL, &Names.Year, NULL, "Names.Year",
       -   N_("Text appended to the turn number (i.e. the year)"),
       +  {NULL, NULL, NULL, &Names.Date, NULL, "Names.Date",
       +   N_("strftime() format string for displaying the game turn"),
           NULL, NULL, 0, "", NULL, NULL, FALSE, 0},
          {NULL, NULL, &Prices.Spy, NULL, NULL, "Prices.Spy",
           N_("Cost for a bitch to spy on the enemy"),
       t@@ -836,6 +843,8 @@ GSList *AddPlayer(int fd, Player *NewPlayer, GSList *First)
          InitList(&(NewPlayer->SpyList));
          InitList(&(NewPlayer->TipList));
          NewPlayer->Turn = 1;
       +  NewPlayer->date = g_date_new_dmy(StartDate.day, StartDate.month,
       +                                   StartDate.year);
          NewPlayer->Cash = StartCash;
          NewPlayer->Debt = StartDebt;
          NewPlayer->Bank = 0;
       t@@ -893,6 +902,7 @@ GSList *RemovePlayer(Player *Play, GSList *First)
        #endif
          ClearList(&(Play->SpyList));
          ClearList(&(Play->TipList));
       +  g_date_free(Play->date);
          g_free(Play->Name);
          g_free(Play->Guns);
          g_free(Play->Drugs);
       t@@ -1619,8 +1629,7 @@ void CopyNames(struct NAMES *dest, struct NAMES *src)
          AssignName(&dest->Guns, _(src->Guns));
          AssignName(&dest->Drug, _(src->Drug));
          AssignName(&dest->Drugs, _(src->Drugs));
       -  AssignName(&dest->Month, _(src->Month));
       -  AssignName(&dest->Year, _(src->Year));
       +  AssignName(&dest->Date, _(src->Date));
          AssignName(&dest->LoanSharkName, _(src->LoanSharkName));
          AssignName(&dest->BankName, _(src->BankName));
          AssignName(&dest->GunShopName, _(src->GunShopName));
       t@@ -2439,6 +2448,24 @@ void SetupParameters(void)
          }
        }
        
       +void GetDateString(GString *str, Player *Play)
       +{
       +  gchar buf[200], *turn, *pt;
       +
       +  turn = g_strdup_printf("%d", Play->Turn);
       +  g_string_assign(str, Names.Date);
       +  while ((pt = strstr(str->str, "%T")) != NULL) {
       +    int ind = pt - str->str;
       +
       +    g_string_erase(str, ind, 2);
       +    g_string_insert(str, ind, turn);
       +  }
       +
       +  g_date_strftime(buf, sizeof(buf), str->str, Play->date);
       +  g_string_assign(str, buf);
       +  g_free(turn);
       +}
       +
        static void PluginHelp(void)
        {
          gchar *plugins;
 (DIR) diff --git a/src/dopewars.h b/src/dopewars.h
       t@@ -68,6 +68,8 @@ typedef enum {
                                         * client sends the server a C_DONE message */
          A_UTF8,                       /* All strings are sent over the network using
                                         * UTF-8 (Unicode) encoding */
       +  A_DATE,                       /* We can understand "proper" dd-mm-yy dates
       +                                 * rather than just turn numbers */
          A_NUM                         /* N.B. Must be last */
        } AbilType;
        
       t@@ -82,7 +84,7 @@ typedef struct ABILITIES {
        
        struct NAMES {
          gchar *Bitch, *Bitches, *Gun, *Guns, *Drug, *Drugs;
       -  gchar *Month, *Year, *LoanSharkName, *BankName;
       +  gchar *Date, *LoanSharkName, *BankName;
          gchar *GunShopName, *RoughPubName;
        };
        
       t@@ -163,6 +165,11 @@ struct LOG {
          FILE *fp;
        };
        
       +struct DATE {
       +  int day, month, year;
       +};
       +
       +extern struct DATE StartDate;
        extern int ClientSock, ListenSock;
        extern gboolean Network, Client, Server, NotifyMetaServer, AIPlayer;
        extern unsigned Port;
       t@@ -287,6 +294,7 @@ typedef struct TDopeList DopeList;
        struct PLAYER_T {
          guint ID;
          int Turn;
       +  GDate *date;
          price_t Cash, Debt, Bank;
          int Health;
          int CoatSize;
       t@@ -427,6 +435,7 @@ gboolean SetConfigValue(int GlobalIndex, int StructIndex,
                                gboolean IndexGiven, GScanner *scanner);
        gboolean IsCop(Player *Play);
        void RestoreConfig(void);
       +void GetDateString(GString *str, Player *Play);
        void ScannerErrorHandler(GScanner *scanner, gchar *msg, gint error);
        gboolean IsConnectedPlayer(Player *play);
        void BackupConfig(void);
 (DIR) diff --git a/src/gui_client/gtk_client.c b/src/gui_client/gtk_client.c
       t@@ -1190,7 +1190,7 @@ void DisplayStats(Player *Play, struct StatusWidgets *Status)
                             Location[Play->IsAt].Name);
          gtk_label_set_text(GTK_LABEL(Status->Location), text->str);
        
       -  g_string_sprintf(text, "%s%02d%s", Names.Month, Play->Turn, Names.Year);
       +  GetDateString(text, Play);
          gtk_label_set_text(GTK_LABEL(Status->Date), text->str);
        
          g_string_sprintf(text, "%d", Play->CoatSize);
 (DIR) diff --git a/src/message.c b/src/message.c
       t@@ -256,6 +256,7 @@ void InitAbilities(Player *Play)
        #else
          Play->Abil.Local[A_UTF8] = FALSE;
        #endif
       +  Play->Abil.Local[A_DATE] = TRUE;
        
          if (!Network) {
            for (i = 0; i < A_NUM; i++) {
       t@@ -653,6 +654,10 @@ void SendSpyReport(Player *To, Player *SpiedOn)
          g_free(cashstr);
          g_free(debtstr);
          g_free(bankstr);
       +  if (HaveAbility(SpiedOn, A_DATE)) {
       +    g_string_sprintfa(text, "%d^%d^%d^", g_date_day(SpiedOn->date),
       +                      g_date_month(SpiedOn->date), g_date_year(SpiedOn->date));
       +  }
          for (i = 0; i < NumGun; i++) {
            g_string_sprintfa(text, "%d^", SpiedOn->Guns[i].Carried);
          }
       t@@ -674,13 +679,13 @@ void SendSpyReport(Player *To, Player *SpiedOn)
          g_string_free(text, TRUE);
        }
        
       -#define NUMNAMES 12
       +#define NUMNAMES 11
        
        void SendInitialData(Player *To)
        {
          gchar *LocalNames[NUMNAMES] = { Names.Bitch, Names.Bitches, Names.Gun,
            Names.Guns, Names.Drug, Names.Drugs,
       -    Names.Month, Names.Year, Names.LoanSharkName,
       +    Names.Date, Names.LoanSharkName,
            Names.BankName, Names.GunShopName,
            Names.RoughPubName
          };
       t@@ -696,15 +701,23 @@ void SendInitialData(Player *To)
          text = g_string_new("");
          g_string_sprintf(text, "%s^%d^%d^%d^", VERSION, NumLocation, NumGun,
                           NumDrug);
       -  for (i = 0; i < 8; i++) {
       +  for (i = 0; i < 6; i++) {
            g_string_append(text, LocalNames[i]);
            g_string_append_c(text, '^');
          }
       +
       +  if (HaveAbility(To, A_DATE)) {
       +    g_string_append(text, LocalNames[6]);
       +    g_string_append_c(text, '^');
       +  } else {
       +    g_string_sprintfa(text, "%d-^-%d^", StartDate.month, StartDate.year);
       +  }
       +
          if (HaveAbility(To, A_PLAYERID))
            g_string_sprintfa(text, "%d^", To->ID);
        
       -  /* Player ID is expected after the first 8 names, so send the rest now */
       -  for (i = 8; i < NUMNAMES; i++) {
       +  /* Player ID is expected after the first 7 names, so send the rest now */
       +  for (i = 7; i < NUMNAMES; i++) {
            g_string_append(text, LocalNames[i]);
            g_string_append_c(text, '^');
          }
       t@@ -739,8 +752,17 @@ void ReceiveInitialData(Player *Play, char *Data)
          AssignName(&Names.Guns, GetNextWord(&pt, ""));
          AssignName(&Names.Drug, GetNextWord(&pt, ""));
          AssignName(&Names.Drugs, GetNextWord(&pt, ""));
       -  AssignName(&Names.Month, GetNextWord(&pt, ""));
       -  AssignName(&Names.Year, GetNextWord(&pt, ""));
       +  if (HaveAbility(Play, A_DATE)) {
       +    AssignName(&Names.Date, GetNextWord(&pt, ""));
       +  } else {
       +    gchar *month, *year, *date;
       +    month = GetNextWord(&pt, "");
       +    year = GetNextWord(&pt, "");
       +
       +    date = g_strdup_printf("%s%%T%s", month, year);
       +    AssignName(&Names.Date, date);
       +    g_free(date);
       +  }
          if (HaveAbility(Play, A_PLAYERID))
            Play->ID = GetNextInt(&pt, 0);
        
       t@@ -880,6 +902,11 @@ void ReceivePlayerData(Player *Play, char *text, Player *From)
          From->IsAt = GetNextInt(&cp, 0);
          From->Turn = GetNextInt(&cp, 0);
          From->Flags = GetNextInt(&cp, 0);
       +  if (HaveAbility(Play, A_DATE)) {
       +    g_date_set_day(From->date, GetNextInt(&cp, 1));
       +    g_date_set_month(From->date, GetNextInt(&cp, 1));
       +    g_date_set_year(From->date, GetNextInt(&cp, 1980));
       +  }
          for (i = 0; i < NumGun; i++) {
            From->Guns[i].Carried = GetNextInt(&cp, 0);
          }
 (DIR) diff --git a/src/serverside.c b/src/serverside.c
       t@@ -525,6 +525,7 @@ void HandleServerMessage(gchar *buf, Player *Play)
                      GetPlayerName(Play), Location[i].Name);
              Play->IsAt = i;
              Play->Turn++;
       +      g_date_add_days(Play->date, 1);
              Play->Debt = Play->Debt * (DebtInterest + 100) / 100;
              Play->Debt = MAX(Play->Debt, 0);
              Play->Bank = Play->Bank * (BankInterest + 100) / 100;