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.\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"
88 " -S Disable inverse/bold/color for slow terminals\n"
90 " -H Show distribution and warranty information\n"
92 version_string, DEFAULT_PORT, DEFAULT_KEYS);
95 ExtFunc void DistInfo(void)
98 "Netris version %s (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
100 "This program is free software; you can redistribute it and/or modify\n"
101 "it under the terms of the GNU General Public License as published by\n"
102 "the Free Software Foundation; either version 2 of the License, or\n"
103 "(at your option) any later version.\n"
105 "This program is distributed in the hope that it will be useful,\n"
106 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
107 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
108 "GNU General Public License for more details.\n"
110 "You should have received a copy of the GNU General Public License\n"
111 "along with this program; if not, write to the Free Software\n"
112 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n",
116 ExtFunc void Rules(void)
119 "Netris version %s rules\n"
123 "It's just like normal T*tris except that when you clear more than\n"
124 "one row with a single piece, the other player's board is moved up\n"
125 "and junk rows are added to the bottom. If you clear 2, 3 or 4\n"
126 "rows, 1, 2 or 4 junk rows are added to your opponent's board,\n"
127 "respectively. The junk rows have exactly one empty column.\n"
128 "For each group of junk rows given, the empty columns will line\n"
129 "up. This is intentional.\n"
131 "The longest surviving player wins the game.\n"
135 "This mode is currently very boring, because there's no scoring\n"
136 "and it never gets any faster. This will be rectified at some point.\n"
137 "I'm not very motivated to do it right now because I'm sick of one\n"
138 "player T*tris. For now, use the \"f\" key (by default) to make the\n"
139 "game go faster. Speedups cannot be reversed for the remainder of\n"
145 * My really crappy random number generator follows
146 * Should be more than sufficient for our purposes though
148 ExtFunc void SRandom(int seed)
151 myRandSeed = seed % 31751 + 1;
154 ExtFunc int Random(int min, int max1)
156 myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
157 return myRandSeed % (max1 - min) + min;
160 ExtFunc int MyRead(int fd, void *data, int len)
166 result = read(fd, data, left);
168 data = ((char *)data) + result;
171 else if (errno != EINTR)
177 ExtFunc int MyWrite(int fd, void *data, int len)
183 result = write(fd, data, left);
185 data = ((char *)data) + result;
188 else if (errno != EINTR)
194 ExtFunc void NormalizeTime(struct timeval *tv)
196 tv->tv_sec += tv->tv_usec / 1000000;
197 tv->tv_usec %= 1000000;
198 if (tv->tv_usec < 0) {
199 tv->tv_usec += 1000000;
204 ExtFunc void CatchInt(int sig)
209 ExtFunc void CatchAlarm(int sig)
212 signal(SIGALRM, CatchAlarm);
215 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
220 ExtFunc long CurTimeval(void)
224 gettimeofday(&tv, NULL);
225 tv.tv_sec -= baseTimeval.tv_sec;
226 tv.tv_usec -= baseTimeval.tv_usec;
227 return GetTimeval(&tv);
230 ExtFunc void SetTimeval(struct timeval *tv, long usec)
232 tv->tv_sec = usec / 1000000;
233 tv->tv_usec = usec % 1000000;
236 ExtFunc long GetTimeval(struct timeval *tv)
238 return tv->tv_sec * 1000000 + tv->tv_usec;
241 static long SetITimer1(long interval, long value)
243 struct itimerval it, old;
245 SetTimeval(&it.it_interval, interval);
246 SetTimeval(&it.it_value, value);
247 if (setitimer(ITIMER_REAL, &it, &old) < 0)
249 signal(SIGALRM, CatchAlarm);
250 return GetTimeval(&old.it_value);
253 ExtFunc long SetITimer(long interval, long value)
257 old = SetITimer1(0, 0);
259 SetITimer1(interval, value);
263 ExtFunc volatile void die(char *msg)
269 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);