2 * Netris -- A free networked version of T*tris
3 * Copyright (C) 1994,1995,1996 Mark H. Weaver <mhw@netris.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * $Id: util.c,v 1.29 1999/05/16 06:56:33 mhw Exp $
27 #include <sys/types.h>
32 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
34 static EventGenRec alarmGen =
35 { &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm };
36 static EventGenRec *nextGen = &alarmGen;
38 static myRandSeed = 1;
40 static struct timeval baseTimeval;
42 ExtFunc void InitUtil(void)
48 signal(SIGINT, CatchInt);
52 ExtFunc void ResetBaseTime(void)
54 gettimeofday(&baseTimeval, NULL);
57 ExtFunc void AtExit(void (*handler)(void))
60 on_exit((void *)handler, NULL);
66 ExtFunc void Usage(void)
69 "Netris version %s (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
70 "Usage: netris <options>\n"
71 " -h Print usage information\n"
72 " -w Wait for connection\n"
73 " -c <host> Initiate connection\n"
74 " -p <port> Set port number (default is %d)\n"
75 " -k <keys> Remap keys. The argument is a prefix of the string\n"
76 " containing the keys in order: left, rotate, right, drop,\n"
77 " down-faster, toggle-spying, pause, faster, redraw, new.\n"
78 " \"^\" prefixes controls. (default is \"%s\")\n"
79 " -i <sec> Set the step-down interval, in seconds\n"
80 " -r <robot> Execute <robot> (a command) as a robot controlling\n"
81 " the game instead of the keyboard\n"
82 " -F Use fair robot interface\n"
83 " -s <seed> Start with given random seed\n"
84 " -D Drops go into drop mode\n"
85 " This means that sliding off a cliff after a drop causes\n"
86 " another drop automatically\n"
87 " -S Disable inverse/bold/color for slow terminals\n"
89 " -H Show distribution and warranty information\n"
91 version_string, DEFAULT_PORT, DEFAULT_KEYS);
94 ExtFunc void DistInfo(void)
97 "Netris version %s (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
99 "This program is free software; you can redistribute it and/or modify\n"
100 "it under the terms of the GNU General Public License as published by\n"
101 "the Free Software Foundation; either version 2 of the License, or\n"
102 "(at your option) any later version.\n"
104 "This program is distributed in the hope that it will be useful,\n"
105 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
106 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
107 "GNU General Public License for more details.\n"
109 "You should have received a copy of the GNU General Public License\n"
110 "along with this program; if not, write to the Free Software\n"
111 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n",
115 ExtFunc void Rules(void)
118 "Netris version %s rules\n"
122 "It's just like normal T*tris except that when you clear more than\n"
123 "one row with a single piece, the other player's board is moved up\n"
124 "and junk rows are added to the bottom. If you clear 2, 3 or 4\n"
125 "rows, 1, 2 or 4 junk rows are added to your opponent's board,\n"
126 "respectively. The junk rows have exactly one empty column.\n"
127 "For each group of junk rows given, the empty columns will line\n"
128 "up. This is intentional.\n"
130 "The longest surviving player wins the game.\n"
134 "This mode is currently very boring, because there's no scoring\n"
135 "and it never gets any faster. This will be rectified at some point.\n"
136 "I'm not very motivated to do it right now because I'm sick of one\n"
137 "player T*tris. For now, use the \"f\" key (by default) to make the\n"
138 "game go faster. Speedups cannot be reversed for the remainder of\n"
144 * My really crappy random number generator follows
145 * Should be more than sufficient for our purposes though
147 ExtFunc void SRandom(int seed)
150 myRandSeed = seed % 31751 + 1;
153 ExtFunc int Random(int min, int max1)
155 myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
156 return myRandSeed % (max1 - min) + min;
159 ExtFunc int MyRead(int fd, void *data, int len)
165 result = read(fd, data, left);
167 data = ((char *)data) + result;
170 else if (errno != EINTR)
176 ExtFunc int MyWrite(int fd, void *data, int len)
182 result = write(fd, data, left);
184 data = ((char *)data) + result;
187 else if (errno != EINTR)
193 ExtFunc void NormalizeTime(struct timeval *tv)
195 tv->tv_sec += tv->tv_usec / 1000000;
196 tv->tv_usec %= 1000000;
197 if (tv->tv_usec < 0) {
198 tv->tv_usec += 1000000;
203 ExtFunc void CatchInt(int sig)
208 ExtFunc void CatchAlarm(int sig)
211 signal(SIGALRM, CatchAlarm);
214 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
219 ExtFunc long CurTimeval(void)
223 gettimeofday(&tv, NULL);
224 tv.tv_sec -= baseTimeval.tv_sec;
225 tv.tv_usec -= baseTimeval.tv_usec;
226 return GetTimeval(&tv);
229 ExtFunc void SetTimeval(struct timeval *tv, long usec)
231 tv->tv_sec = usec / 1000000;
232 tv->tv_usec = usec % 1000000;
235 ExtFunc long GetTimeval(struct timeval *tv)
237 return tv->tv_sec * 1000000 + tv->tv_usec;
240 static long SetITimer1(long interval, long value)
242 struct itimerval it, old;
244 SetTimeval(&it.it_interval, interval);
245 SetTimeval(&it.it_value, value);
246 if (setitimer(ITIMER_REAL, &it, &old) < 0)
248 signal(SIGALRM, CatchAlarm);
249 return GetTimeval(&old.it_value);
252 ExtFunc long SetITimer(long interval, long value)
256 old = SetITimer1(0, 0);
258 SetITimer1(interval, value);
262 ExtFunc volatile void die(char *msg)
268 ExtFunc volatile void fatal(char *msg)
271 fprintf(stderr, "%s\n", msg);
275 ExtFunc void BlockSignals(MySigSet *saved, ...)
281 va_start(args, saved);
282 #ifdef HAS_SIGPROCMASK
287 while ((sig = va_arg(args, int))) {
288 #ifdef HAS_SIGPROCMASK
289 sigaddset(&set, sig);
294 #ifdef HAS_SIGPROCMASK
295 sigprocmask(SIG_BLOCK, &set, saved);
297 *saved = sigblock(set);
302 ExtFunc void RestoreSignals(MySigSet *saved, MySigSet *set)
304 #ifdef HAS_SIGPROCMASK
305 sigprocmask(SIG_SETMASK, set, saved);
308 *saved = sigsetmask(*set);
314 ExtFunc void AddEventGen(EventGenRec *gen)
316 assert(gen->next == NULL);
317 gen->next = nextGen->next;
321 ExtFunc void RemoveEventGen(EventGenRec *gen)
323 /* assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
325 while (nextGen->next != gen)
326 nextGen = nextGen->next;
327 nextGen->next = gen->next;
332 ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
337 int result, anyReady, anySet;
340 /* XXX In certain circumstances, this routine does polling */
342 for (i = 0; i < FT_len; ++i)
344 anyReady = anySet = 0;
347 if (gen->mask & mask) {
351 FD_SET(gen->fd, &fds[gen->fdType]);
356 } while (gen != nextGen);
359 tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
360 result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
361 &fds[FT_except], anyReady ? &tv : NULL);
364 if (retry && !anyReady)
370 if ((gen->mask & mask)
371 && (gen->ready || (result > 0 && gen->fd >= 0
372 && FD_ISSET(gen->fd, &fds[gen->fdType])))) {
374 event->type = gen->func(gen, event);
375 if (event->type != E_none) {
381 } while (gen != nextGen);