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>
33 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
35 static EventGenRec alarmGen =
36 { &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm };
37 static EventGenRec *nextGen = &alarmGen;
39 static sigjmp_buf close_env;
41 static int myRandSeed = 1;
43 static long baseTimeval;
45 ExtFunc void AtExit(void (*handler)(void))
48 on_exit((void *)handler, NULL);
54 ///////////// HELP MESSAGES /////////////
56 ExtFunc void Header(void)
59 "NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
60 " \t(c) 2002 Shiar <shiar@shiar.org>\n\n",
64 ExtFunc void Usage(void)
68 "Usage: netris <options>\n"
70 " -h, --help\t\tPrint this usage information\n"
71 " -H, --info\t\tShow distribution and warranty information\n"
72 " -R, --rules\t\tShow game rules\n"
74 " -S, --slowterm\tDisable inverse/bold/color for slow terminals\n"
75 " -a, --ascii\t\tUse ascii characters\n"
76 " -C, --color=0\t\tDisable color\n"
78 " -w, --wait\t\tWait for connection\n"
79 " -c, --connect <host>\tInitiate connection\n"
80 " -p, --port <port>\tSet port number (default is %d)\n"
82 " -s, --seed <seed>\tStart with given random seed\n"
83 " -i, --speed <sec>\tSet the initial step-down interval, in seconds\n"
84 " -l, --level <lvl>\tBegin at a higher level (can be used as handicap)\n"
85 " -k, --keys <keys>\tRemap keys (default is \"%s\" for cursors)\n"
86 " -d, --dropmode\tDrops go into drop mode\n"
87 " -D, --instadrop\tInstant drop\n"
89 " -r, --robot <cmd>\tExecute program to control the game instead of keyboard\n"
90 " -F, --fair-robot\tUse fair robot interface\n"
91 "\n", DEFAULT_PORT, DEFAULT_KEYS);
94 ExtFunc void DistInfo(void)
98 "This program is free software; you can redistribute it and/or modify\n"
99 "it under the terms of the GNU General Public License as published by\n"
100 "the Free Software Foundation; either version 2 of the License, or\n"
101 "(at your option) any later version.\n"
103 "This program is distributed in the hope that it will be useful,\n"
104 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
105 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
106 "GNU General Public License for more details.\n"
108 "You should have received a copy of the GNU General Public License\n"
109 "along with this program; if not, write to the Free Software\n"
110 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
114 ExtFunc void Rules(void)
120 "Good old Tetris. Scoring is like on the GameBoy version (so try to\n"
121 "remove as many lines at once as you can). After removing ten lines\n"
122 "you go to the next level, which will be faster thus making the game\n"
127 "It's just like normal T*tris except that when you clear more than\n"
128 "one row with a single piece, the other player receives penalty lines\n"
129 "For clearing 2, 3 or 4 rows, respectively 1, 2 or 4 junk rows will\n"
130 "be added to the bottom of your opponent's board respectively.\n"
131 "The junk rows have exactly one empty column, which will line up for\n"
134 "The longest surviving player wins the game.\n"
138 ///////////// RANDOM /////////////
140 ExtFunc void InitUtil(void)
146 if (sigsetjmp(close_env, 1)) exit(0);
147 signal(SIGINT, CatchInt);
152 * My really crappy random number generator follows
153 * Should be more than sufficient for our purposes though
155 ExtFunc void SRandom(int seed)
158 myRandSeed = seed % 31751 + 1;
161 ExtFunc int Random(int min, int max1)
163 myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
164 return myRandSeed % (max1 - min) + min;
167 ///////////// I/O /////////////
169 ExtFunc int MyRead(int fd, void *data, int len)
175 result = read(fd, data, left);
177 data = ((char *)data) + result;
180 else if (errno != EINTR)
186 ExtFunc int MyWrite(int fd, void *data, int len)
192 result = write(fd, data, left);
194 data = ((char *)data) + result;
197 else if (errno != EINTR)
203 ///////////// TIME /////////////
205 ExtFunc void NormalizeTime(struct timeval *tv)
207 tv->tv_sec += tv->tv_usec / 1000000;
208 tv->tv_usec %= 1000000;
209 if (tv->tv_usec < 0) {
210 tv->tv_usec += 1000000;
215 ExtFunc void CatchInt(int sig)
217 siglongjmp(close_env, 1);
220 ExtFunc void CatchAlarm(int sig)
223 signal(SIGALRM, CatchAlarm);
226 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
231 ExtFunc void SetTimeval(struct timeval *tv, long usec)
233 tv->tv_sec = usec / 1000000;
234 tv->tv_usec = usec % 1000000;
237 ExtFunc long GetTimeval(struct timeval *tv)
239 return tv->tv_sec * 1000000 + tv->tv_usec;
242 ExtFunc long AbsTimeval(void)
246 gettimeofday(&tv, NULL);
247 return GetTimeval(&tv);
250 ExtFunc void ResetBaseTime(void)
252 baseTimeval = AbsTimeval();
255 ExtFunc void PauseTime(void)
257 baseTimeval -= AbsTimeval();
260 ExtFunc void ResumeTime(void)
262 baseTimeval += AbsTimeval();
265 ExtFunc long CurTimeval(void)
269 gettimeofday(&tv, NULL);
270 return GetTimeval(&tv) - baseTimeval;
273 static long SetITimer1(long interval, long value)
275 struct itimerval it, old;
277 SetTimeval(&it.it_interval, interval);
278 SetTimeval(&it.it_value, value);
279 if (setitimer(ITIMER_REAL, &it, &old) < 0)
281 signal(SIGALRM, CatchAlarm);
282 return GetTimeval(&old.it_value);
285 ExtFunc long SetITimer(long interval, long value)
289 old = SetITimer1(0, 0);
291 SetITimer1(interval, value);
295 ///////////// ... /////////////
297 ExtFunc volatile void die(char *msg)
303 ExtFunc volatile void fatal(char *msg)
305 fprintf(stderr, "%s\n", msg);
309 ExtFunc void BlockSignals(MySigSet *saved, ...)
315 va_start(args, saved);
316 #ifdef HAS_SIGPROCMASK
321 while ((sig = va_arg(args, int))) {
322 #ifdef HAS_SIGPROCMASK
323 sigaddset(&set, sig);
328 #ifdef HAS_SIGPROCMASK
329 sigprocmask(SIG_BLOCK, &set, saved);
331 *saved = sigblock(set);
336 ExtFunc void RestoreSignals(MySigSet *saved, MySigSet *set)
338 #ifdef HAS_SIGPROCMASK
339 sigprocmask(SIG_SETMASK, set, saved);
342 *saved = sigsetmask(*set);
348 ///////////// EVENTS /////////////
350 ExtFunc void AddEventGen(EventGenRec *gen)
352 assert(gen->next == NULL);
353 gen->next = nextGen->next;
357 ExtFunc void RemoveEventGen(EventGenRec *gen)
359 // assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
361 while (nextGen->next != gen)
362 nextGen = nextGen->next;
363 nextGen->next = gen->next;
368 ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
373 int result, anyReady, anySet;
377 for (i = 0; i < FT_len; ++i)
379 anyReady = anySet = 0;
382 if (gen->mask & mask) {
386 FD_SET(gen->fd, &fds[gen->fdType]);
391 } while (gen != nextGen);
394 tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
395 result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
396 &fds[FT_except], anyReady ? &tv : NULL);
399 if (retry && !anyReady)
405 if ((gen->mask & mask)
406 && (gen->ready || (result > 0 && gen->fd >= 0
407 && FD_ISSET(gen->fd, &fds[gen->fdType])))) {
409 event->type = gen->func(gen, event);
410 if (event->type != E_none) {
416 } while (gen != nextGen);