unofficial version 0.6: first major updates
[netris.git] / util.c
diff --git a/util.c b/util.c
index 3bbd704c43b3c47d135ce764b43b394168b5ce20..f93b8c857881b39b15b206c11fda7391cf12b1c2 100644 (file)
--- a/util.c
+++ b/util.c
@@ -28,6 +28,7 @@
 #include <sys/time.h>
 #include <netdb.h>
 #include <errno.h>
+#include <setjmp.h>
 
 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
 
@@ -35,24 +36,11 @@ static EventGenRec alarmGen =
                { &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm };
 static EventGenRec *nextGen = &alarmGen;
 
-static myRandSeed = 1;
+static sigjmp_buf close_env;
 
-static struct timeval baseTimeval;
+static int myRandSeed = 1;
 
-ExtFunc void InitUtil(void)
-{
-       if (initSeed)
-               SRandom(initSeed);
-       else
-               SRandom(time(0));
-       signal(SIGINT, CatchInt);
-       ResetBaseTime();
-}
-
-ExtFunc void ResetBaseTime(void)
-{
-       gettimeofday(&baseTimeval, NULL);
-}
+static long baseTimeval;
 
 ExtFunc void AtExit(void (*handler)(void))
 {
@@ -63,40 +51,50 @@ ExtFunc void AtExit(void (*handler)(void))
 #endif
 }
 
+///////////// HELP MESSAGES /////////////
+
+ExtFunc void Header(void)
+{
+       fprintf(stderr,
+         "NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
+         "          \t(c) 2002 Shiar <shiar@shiar.org>\n\n",
+         version_string);
+} //Header
+
 ExtFunc void Usage(void)
 {
+       Header();
        fprintf(stderr,
-         "Netris version %s (C) 1994-1996,1999  Mark H. Weaver <mhw@netris.org>\n"
          "Usage: netris <options>\n"
-         "  -h         Print usage information\n"
-         "  -w         Wait for connection\n"
-         "  -c <host>  Initiate connection\n"
-         "  -p <port>  Set port number (default is %d)\n"
-         "  -k <keys>  Remap keys.  The argument is a prefix of the string\n"
-         "               containing the keys in order: left, rotate, right, drop,\n"
-         "               down-faster, toggle-spying, pause, faster, redraw.\n"
-         "               \"^\" prefixes controls.  (default is \"%s\")\n"
-         "  -i <sec>   Set the step-down interval, in seconds\n"
-         "  -r <robot> Execute <robot> (a command) as a robot controlling\n"
-         "               the game instead of the keyboard\n"
-         "  -F         Use fair robot interface\n"
-         "  -s <seed>  Start with given random seed\n"
-         "  -d         Drops go into drop mode\n"
-         "               This means that sliding off a cliff after a drop causes\n"
-         "               another drop automatically\n"
-         "  -D         Instant drop\n"
-         "  -S         Disable inverse/bold/color for slow terminals\n"
-         "  -C         Disable color\n"
-         "  -H         Show distribution and warranty information\n"
-         "  -R         Show rules\n",
-         version_string, DEFAULT_PORT, DEFAULT_KEYS);
+         "\n"
+         "  -h, --help\t\tPrint this usage information\n"
+         "  -H, --info\t\tShow distribution and warranty information\n"
+         "  -R, --rules\t\tShow game rules\n"
+         "\n"
+         "  -S, --slowterm\tDisable inverse/bold/color for slow terminals\n"
+         "  -a, --ascii\t\tUse ascii characters\n"
+         "  -C, --color=0\t\tDisable color\n"
+         "\n"
+         "  -w, --wait\t\tWait for connection\n"
+         "  -c, --connect <host>\tInitiate connection\n"
+         "  -p, --port <port>\tSet port number (default is %d)\n"
+         "\n"
+         "  -s, --seed <seed>\tStart with given random seed\n"
+         "  -i, --speed <sec>\tSet the initial step-down interval, in seconds\n"
+         "  -l, --level <lvl>\tBegin at a higher level (can be used as handicap)\n"
+         "  -k, --keys <keys>\tRemap keys (default is \"%s\" for cursors)\n"
+         "  -d, --dropmode\tDrops go into drop mode\n"
+         "  -D, --instadrop\tInstant drop\n"
+         "\n"
+         "  -r, --robot <cmd>\tExecute program to control the game instead of keyboard\n"
+         "  -F, --fair-robot\tUse fair robot interface\n"
+         "\n", DEFAULT_PORT, DEFAULT_KEYS);
 }
 
 ExtFunc void DistInfo(void)
 {
+       Header();
        fprintf(stderr,
-         "Netris version %s (C) 1994-1996,1999  Mark H. Weaver <mhw@netris.org>\n"
-         "\n"
          "This program is free software; you can redistribute it and/or modify\n"
          "it under the terms of the GNU General Public License as published by\n"
          "the Free Software Foundation; either version 2 of the License, or\n"
@@ -109,37 +107,46 @@ ExtFunc void DistInfo(void)
          "\n"
          "You should have received a copy of the GNU General Public License\n"
          "along with this program; if not, write to the Free Software\n"
-         "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n",
-         version_string);
-}
+         "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
+         "\n");
+} //DistInfo
 
 ExtFunc void Rules(void)
 {
+       Header();
        fprintf(stderr,
-         "Netris version %s rules\n"
+         "One player mode\n"
+         "---------------\n"
+         "Good old Tetris. Scoring is like on the GameBoy version (so try to\n"
+         "remove as many lines at once as you can). After removing ten lines\n"
+         "you go to the next level, which will be faster thus making the game\n"
+         "harder to play.\n"
          "\n"
          "Two player mode\n"
          "---------------\n"
          "It's just like normal T*tris except that when you clear more than\n"
-         "one row with a single piece, the other player's board is moved up\n"
-         "and junk rows are added to the bottom.  If you clear 2, 3 or 4\n"
-         "rows, 1, 2 or 4 junk rows are added to your opponent's board,\n"
-         "respectively.  The junk rows have exactly one empty column.\n"
-         "For each group of junk rows given, the empty columns will line\n"
-         "up.  This is intentional.\n"
+         "one row with a single piece, the other player receives penalty lines\n"
+         "For clearing 2, 3 or 4 rows, respectively 1, 2 or 4 junk rows will\n"
+         "be added to the bottom of your opponent's board respectively.\n"
+         "The junk rows have exactly one empty column, which will line up for\n"
+         "multiple rows.\n"
          "\n"
          "The longest surviving player wins the game.\n"
-         "\n"
-         "One player mode\n"
-         "---------------\n"
-         "This mode is currently very boring, because there's no scoring\n"
-         "and it never gets any faster.  This will be rectified at some point.\n"
-         "I'm not very motivated to do it right now because I'm sick of one\n"
-         "player T*tris.  For now, use the \"f\" key (by default) to make the\n"
-         "game go faster.  Speedups cannot be reversed for the remainder of\n"
-         "the game.\n",
-         version_string);
-}
+         "\n");
+} //Rules
+
+///////////// RANDOM /////////////
+
+ExtFunc void InitUtil(void)
+{
+       if (Game.seed)
+               SRandom(Game.seed);
+       else
+               SRandom(time(0));
+       if (sigsetjmp(close_env, 1)) exit(0);
+       signal(SIGINT, CatchInt);
+       ResetBaseTime();
+} //InitUtil
 
 /*
  * My really crappy random number generator follows
@@ -147,15 +154,17 @@ ExtFunc void Rules(void)
  */
 ExtFunc void SRandom(int seed)
 {
-       initSeed = seed;
+       Game.seed = seed;
        myRandSeed = seed % 31751 + 1;
-}
+} //SRandom
 
 ExtFunc int Random(int min, int max1)
 {
        myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
        return myRandSeed % (max1 - min) + min;
-}
+} //Random
+
+///////////// I/O /////////////
 
 ExtFunc int MyRead(int fd, void *data, int len)
 {
@@ -172,7 +181,7 @@ ExtFunc int MyRead(int fd, void *data, int len)
                        return result;
        }
        return len;
-}
+} //MyRead
 
 ExtFunc int MyWrite(int fd, void *data, int len)
 {
@@ -189,7 +198,9 @@ ExtFunc int MyWrite(int fd, void *data, int len)
                        return result;
        }
        return len;
-}
+} //MyWrite
+
+///////////// TIME /////////////
 
 ExtFunc void NormalizeTime(struct timeval *tv)
 {
@@ -203,7 +214,7 @@ ExtFunc void NormalizeTime(struct timeval *tv)
 
 ExtFunc void CatchInt(int sig)
 {
-       exit(0);
+       siglongjmp(close_env, 1);
 }
 
 ExtFunc void CatchAlarm(int sig)
@@ -217,26 +228,47 @@ static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
        return E_alarm;
 }
 
-ExtFunc long CurTimeval(void)
+ExtFunc void SetTimeval(struct timeval *tv, long usec)
+{
+       tv->tv_sec = usec / 1000000;
+       tv->tv_usec = usec % 1000000;
+} //SetTimeval
+
+ExtFunc long GetTimeval(struct timeval *tv)
+{
+       return tv->tv_sec * 1000000 + tv->tv_usec;
+} //GetTimeval
+
+ExtFunc long AbsTimeval(void)
 {
        struct timeval tv;
 
        gettimeofday(&tv, NULL);
-       tv.tv_sec -= baseTimeval.tv_sec;
-       tv.tv_usec -= baseTimeval.tv_usec;
        return GetTimeval(&tv);
-}
+} //CurTimeval
 
-ExtFunc void SetTimeval(struct timeval *tv, long usec)
+ExtFunc void ResetBaseTime(void)
 {
-       tv->tv_sec = usec / 1000000;
-       tv->tv_usec = usec % 1000000;
-}
+       baseTimeval = AbsTimeval();
+} //ResetBaseTime
 
-ExtFunc long GetTimeval(struct timeval *tv)
+ExtFunc void PauseTime(void)
 {
-       return tv->tv_sec * 1000000 + tv->tv_usec;
-}
+       baseTimeval -= AbsTimeval();
+} //PauseTime
+
+ExtFunc void ResumeTime(void)
+{
+       baseTimeval += AbsTimeval();
+} //ResumeTime
+
+ExtFunc long CurTimeval(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       return GetTimeval(&tv) - baseTimeval;
+} //CurTimeval
 
 static long SetITimer1(long interval, long value)
 {
@@ -260,6 +292,8 @@ ExtFunc long SetITimer(long interval, long value)
        return old;
 }
 
+///////////// ... /////////////
+
 ExtFunc volatile void die(char *msg)
 {
        perror(msg);
@@ -311,33 +345,34 @@ ExtFunc void RestoreSignals(MySigSet *saved, MySigSet *set)
 #endif
 }
 
+///////////// EVENTS /////////////
+
 ExtFunc void AddEventGen(EventGenRec *gen)
 {
        assert(gen->next == NULL);
        gen->next = nextGen->next;
        nextGen->next = gen;
-}
+} //AddEventGen
 
 ExtFunc void RemoveEventGen(EventGenRec *gen)
 {
-       /* assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
+       // assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
        if (gen->next) {
                while (nextGen->next != gen)
                        nextGen = nextGen->next;
                nextGen->next = gen->next;
                gen->next = NULL;
        }
-}
+} //RemoveEventGen
 
 ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
-{
+{ //poll
        int i, retry = 0;
        fd_set fds[FT_len];
        EventGenRec *gen;
        int result, anyReady, anySet;
        struct timeval tv;
 
-       /* XXX In certain circumstances, this routine does polling */
        for (;;) {
                for (i = 0; i < FT_len; ++i)
                        FD_ZERO(&fds[i]);
@@ -381,7 +416,7 @@ ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
                } while (gen != nextGen);
                retry = 1;
        }
-}
+} //WaitMyEvent
 
 /*
  * vi: ts=4 ai