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 " -i, --speed <sec>\tSet the initial step-down interval, in seconds\n"
83 " -l, --level <lvl>\tBegin at a higher level (can be used as handicap)\n"
84 " -k, --keys <keys>\tRemap keys (default is \"%s\" for cursors)\n"
85 " -d, --dropmode\tDrops go into drop mode\n"
86 " -D, --instadrop\tInstant drop\n"
88 " -r, --robot <cmd>\tExecute program to control the game instead of keyboard\n"
89 " -F, --fair-robot\tUse fair robot interface\n"
90 "\n", DEFAULT_PORT, DEFAULT_KEYS);
93 ExtFunc void DistInfo(void)
97 "This program is free software; you can redistribute it and/or modify\n"
98 "it under the terms of the GNU General Public License as published by\n"
99 "the Free Software Foundation; either version 2 of the License, or\n"
100 "(at your option) any later version.\n"
102 "This program is distributed in the hope that it will be useful,\n"
103 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
104 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
105 "GNU General Public License for more details.\n"
107 "You should have received a copy of the GNU General Public License\n"
108 "along with this program; if not, write to the Free Software\n"
109 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
113 ExtFunc void Rules(void)
119 "Good old Tetris. Scoring is like on the GameBoy version (so try to\n"
120 "remove as many lines at once as you can). After removing ten lines\n"
121 "you go to the next level, which will be faster thus making the game\n"
126 "It's just like normal T*tris except that when you clear more than\n"
127 "one row with a single piece, the other player receives penalty lines\n"
128 "For clearing 2, 3 or 4 rows, respectively 1, 2 or 4 junk rows will\n"
129 "be added to the bottom of your opponent's board respectively.\n"
130 "The junk rows have exactly one empty column, which will line up for\n"
133 "The longest surviving player wins the game.\n"
137 ///////////// RANDOM /////////////
139 ExtFunc void InitUtil(void)
142 if (sigsetjmp(close_env, 1)) exit(0);
143 signal(SIGINT, CatchInt);
148 * My really crappy random number generator follows
149 * Should be more than sufficient for our purposes though
151 ExtFunc void SRandom(int seed)
154 myRandSeed = seed % 31751 + 1;
157 ExtFunc int Random(int min, int max1)
158 { //return a random value
159 myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
160 return myRandSeed % (max1 - min) + min;
163 ///////////// I/O /////////////
165 ExtFunc int MyRead(int fd, void *data, int len)
171 result = read(fd, data, left);
173 data = ((char *)data) + result;
176 else if (errno != EINTR)
182 ExtFunc int MyWrite(int fd, void *data, int len)
188 result = write(fd, data, left);
190 data = ((char *)data) + result;
193 else if (errno != EINTR)
199 ///////////// TIME /////////////
201 ExtFunc void NormalizeTime(struct timeval *tv)
203 tv->tv_sec += tv->tv_usec / 1000000;
204 tv->tv_usec %= 1000000;
205 if (tv->tv_usec < 0) {
206 tv->tv_usec += 1000000;
211 ExtFunc void CatchInt(int sig)
213 siglongjmp(close_env, 1);
216 ExtFunc void CatchAlarm(int sig)
219 signal(SIGALRM, CatchAlarm);
222 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
227 ExtFunc void SetTimeval(struct timeval *tv, long usec)
229 tv->tv_sec = usec / 1000000;
230 tv->tv_usec = usec % 1000000;
233 ExtFunc long GetTimeval(struct timeval *tv)
235 return tv->tv_sec * 1000000 + tv->tv_usec;
238 ExtFunc long AbsTimeval(void)
242 gettimeofday(&tv, NULL);
243 return GetTimeval(&tv);
246 ExtFunc void ResetBaseTime(void)
248 baseTimeval = AbsTimeval();
251 ExtFunc void PauseTime(void)
253 baseTimeval -= AbsTimeval();
256 ExtFunc void ResumeTime(void)
258 baseTimeval += AbsTimeval();
261 ExtFunc long CurTimeval(void)
265 gettimeofday(&tv, NULL);
266 return GetTimeval(&tv) - baseTimeval;
269 static long SetITimer1(long interval, long value)
271 struct itimerval it, old;
273 SetTimeval(&it.it_interval, interval);
274 SetTimeval(&it.it_value, value);
275 if (setitimer(ITIMER_REAL, &it, &old) < 0)
277 signal(SIGALRM, CatchAlarm);
278 return GetTimeval(&old.it_value);
281 ExtFunc long SetITimer(long interval, long value)
285 old = SetITimer1(0, 0);
287 SetITimer1(interval, value);
291 ///////////// ... /////////////
293 ExtFunc volatile void die(char *msg)
299 ExtFunc volatile void fatal(char *msg)
301 fprintf(stderr, "%s\n", msg);
305 ExtFunc void BlockSignals(MySigSet *saved, ...)
311 va_start(args, saved);
312 #ifdef HAS_SIGPROCMASK
317 while ((sig = va_arg(args, int))) {
318 #ifdef HAS_SIGPROCMASK
319 sigaddset(&set, sig);
324 #ifdef HAS_SIGPROCMASK
325 sigprocmask(SIG_BLOCK, &set, saved);
327 *saved = sigblock(set);
332 ExtFunc void RestoreSignals(MySigSet *saved, MySigSet *set)
334 #ifdef HAS_SIGPROCMASK
335 sigprocmask(SIG_SETMASK, set, saved);
338 *saved = sigsetmask(*set);
344 ///////////// EVENTS /////////////
346 ExtFunc void AddEventGen(EventGenRec *gen)
348 assert(gen->next == NULL);
349 gen->next = nextGen->next;
353 ExtFunc void RemoveEventGen(EventGenRec *gen)
355 // assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
357 while (nextGen->next != gen)
358 nextGen = nextGen->next;
359 nextGen->next = gen->next;
364 ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
369 int result, anyReady, anySet;
373 for (i = 0; i < FT_len; ++i)
375 anyReady = anySet = 0;
378 if (gen->mask & mask) {
382 FD_SET(gen->fd, &fds[gen->fdType]);
387 } while (gen != nextGen);
390 tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
391 result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
392 &fds[FT_except], anyReady ? &tv : NULL);
395 if (retry && !anyReady)
401 if ((gen->mask & mask)
402 && (gen->ready || (result > 0 && gen->fd >= 0
403 && FD_ISSET(gen->fd, &fds[gen->fdType])))) {
405 event->type = gen->func(gen, event);
406 if (event->type != E_none) {
412 } while (gen != nextGen);