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>
35 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
36 static EventGenRec alarmGen = {
37 &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm
39 static EventGenRec *nextGen = &alarmGen;
41 static int myRandSeed = 1;
43 static long baseTimeval;
46 void AtExit(void (*handler)(void))
49 on_exit((void *)handler, NULL);
55 ///////////// HELP MESSAGES /////////////
60 "NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
61 " \t(c) 2002 Shiar <shiar@shiar.org>\n\n",
70 "Usage: netris <options>\n"
72 " -h, --help\t\tPrint this usage information\n"
73 " -H, --info\t\tShow distribution and warranty information\n"
74 " -R, --rules\t\tShow game rules\n"
76 " -S, --slowterm\tDisable inverse/bold/color for slow terminals\n"
77 " -a, --ascii\t\tUse ascii characters\n"
78 " -C, --color=0\t\tDisable color\n"
80 " -c, --connect <host>\tInitiate connection\n"
81 " -p, --port <port>\tSet port number (default is %d)\n"
83 " -t, --team <team>\tJoin a team (don't receive lines from your teammates)\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
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"
121 "Good old Tetris. Scoring is like on the GameBoy version (so try to\n"
122 "remove as many lines at once as you can). After removing ten lines\n"
123 "you go to the next level, which will be faster thus making the game\n"
128 "It's just like normal T*tris except that when you clear more than\n"
129 "one row with a single piece, the other player receives penalty lines\n"
130 "For clearing 2, 3 or 4 rows, respectively 1, 2 or 4 junk rows will\n"
131 "be added to the bottom of your opponent's board respectively.\n"
132 "The junk rows have exactly one empty column, which will line up for\n"
135 "The longest surviving player wins the game.\n"
140 ///////////// RANDOM /////////////
143 * My really crappy random number generator follows
144 * Should be more than sufficient for our purposes though
146 void SRandom(int seed)
149 myRandSeed = seed % 31751 + 1;
152 int Random(int min, int max1)
153 { //return a random value
154 myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
155 return myRandSeed % (max1 - min) + min;
158 ///////////// I/O /////////////
160 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 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 ///////////// TIME /////////////
196 void NormalizeTime(struct timeval *tv)
198 tv->tv_sec += tv->tv_usec / 1000000;
199 tv->tv_usec %= 1000000;
200 if (tv->tv_usec < 0) {
201 tv->tv_usec += 1000000;
206 void CatchAlarm(int sig)
209 signal(SIGALRM, CatchAlarm);
212 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
217 void SetTimeval(struct timeval *tv, long usec)
219 tv->tv_sec = usec / 1000000;
220 tv->tv_usec = usec % 1000000;
223 long GetTimeval(struct timeval *tv)
225 return tv->tv_sec * 1000000 + tv->tv_usec;
228 long AbsTimeval(void)
232 gettimeofday(&tv, NULL);
233 return GetTimeval(&tv);
236 void ResetBaseTime(void)
238 baseTimeval = AbsTimeval();
243 baseTimeval -= AbsTimeval();
246 void ResumeTime(void)
248 baseTimeval += AbsTimeval();
251 long CurTimeval(void)
255 gettimeofday(&tv, NULL);
256 return GetTimeval(&tv) - baseTimeval;
259 static long SetITimer1(long interval, long value)
261 struct itimerval it, old;
263 SetTimeval(&it.it_interval, interval);
264 SetTimeval(&it.it_value, value);
265 if (setitimer(ITIMER_REAL, &it, &old) < 0)
267 signal(SIGALRM, CatchAlarm);
268 return GetTimeval(&old.it_value);
271 long SetITimer(long interval, long value)
275 old = SetITimer1(0, 0);
277 SetITimer1(interval, value);
281 ///////////// ... /////////////
283 volatile void die(char *msg)
289 volatile void fatal(char *msg)
291 fprintf(stderr, "%s\n", msg);
295 void BlockSignals(MySigSet *saved, ...)
301 va_start(args, saved);
302 #ifdef HAS_SIGPROCMASK
307 while ((sig = va_arg(args, int))) {
308 #ifdef HAS_SIGPROCMASK
309 sigaddset(&set, sig);
314 #ifdef HAS_SIGPROCMASK
315 sigprocmask(SIG_BLOCK, &set, saved);
317 *saved = sigblock(set);
322 void RestoreSignals(MySigSet *saved, MySigSet *set)
324 #ifdef HAS_SIGPROCMASK
325 sigprocmask(SIG_SETMASK, set, saved);
328 *saved = sigsetmask(*set);
334 ///////////// EVENTS /////////////
336 void AddEventGen(EventGenRec *gen)
338 assert(gen->next == NULL);
339 gen->next = nextGen->next;
343 void RemoveEventGen(EventGenRec *gen)
345 // assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
347 while (nextGen->next != gen)
348 nextGen = nextGen->next;
349 nextGen->next = gen->next;
354 MyEventType WaitMyEvent(MyEvent *event, int mask)
359 int result, anyReady, anySet;
363 for (i = 0; i < FT_len; ++i)
365 anyReady = anySet = 0;
368 if (gen->mask & mask) {
372 FD_SET(gen->fd, &fds[gen->fdType]);
377 } while (gen != nextGen);
380 tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
381 result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
382 &fds[FT_except], anyReady ? &tv : NULL);
385 if (retry && !anyReady)
391 if ((gen->mask & mask) && (gen->ready || (
392 result > 0 && gen->fd >= 0
393 && FD_ISSET(gen->fd, &fds[gen->fdType])
396 event->type = gen->func(gen, event);
397 if (event->type != E_none) {
403 } while (gen != nextGen);