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.
25 #include <sys/types.h>
33 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
34 static EventGenRec alarmGen = {
35 &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm
37 static EventGenRec *nextGen = &alarmGen;
39 static int myRandSeed = 1;
41 static long baseTimeval;
44 void AtExit(void (*handler)(void))
47 on_exit((void *)handler, NULL);
53 ///////////// HELP MESSAGES /////////////
58 "NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
59 " \t(c) 2002 Shiar <shiar@shiar.org>\n\n",
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 " -c, --connect <host>\tInitiate connection\n"
79 " -p, --port <port>\tSet port number (default is %d)\n"
81 " -t, --team <team>\tJoin a team (don't receive lines from your teammates)\n"
82 " -l, --level <lvl>\tBegin at a higher level (can be used as handicap)\n"
83 " -k, --keys <keys>\tRemap keys (default is \"%s\" for cursors)\n"
84 " -d, --dropmode\tDrops go into drop mode\n"
85 " -D, --instadrop\tInstant drop\n"
87 " -r, --robot <cmd>\tExecute program to control the game instead of keyboard\n"
88 " -F, --fair-robot\tUse fair robot interface\n"
89 "\n", DEFAULT_PORT, DEFAULT_KEYS
96 "This program is free software; you can redistribute it and/or modify\n"
97 "it under the terms of the GNU General Public License as published by\n"
98 "the Free Software Foundation; either version 2 of the License, or\n"
99 "(at your option) any later version.\n"
101 "This program is distributed in the hope that it will be useful,\n"
102 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
103 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
104 "GNU General Public License for more details.\n"
106 "You should have received a copy of the GNU General Public License\n"
107 "along with this program; if not, write to the Free Software\n"
108 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
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"
138 ///////////// RANDOM /////////////
141 * My really crappy random number generator follows
142 * Should be more than sufficient for our purposes though
144 void SRandom(int seed)
147 myRandSeed = seed % 31751 + 1;
150 int Random(int min, int max1)
151 { //return a random value
152 myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
153 return myRandSeed % (max1 - min) + min;
156 ///////////// I/O /////////////
158 int MyRead(int fd, void *data, int len)
164 result = read(fd, data, left);
166 data = ((char *)data) + result;
169 else if (errno != EINTR)
175 int MyWrite(int fd, void *data, int len)
181 result = write(fd, data, left);
183 data = ((char *)data) + result;
186 else if (errno != EINTR)
192 ///////////// TIME /////////////
194 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 void CatchAlarm(int sig)
207 signal(SIGALRM, CatchAlarm);
210 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
215 void SetTimeval(struct timeval *tv, long usec)
217 tv->tv_sec = usec / 1000000;
218 tv->tv_usec = usec % 1000000;
221 long GetTimeval(struct timeval *tv)
223 return tv->tv_sec * 1000000 + tv->tv_usec;
226 long AbsTimeval(void)
230 gettimeofday(&tv, NULL);
231 return GetTimeval(&tv);
234 void ResetBaseTime(void)
236 baseTimeval = AbsTimeval();
241 baseTimeval -= AbsTimeval();
244 void ResumeTime(void)
246 baseTimeval += AbsTimeval();
249 long CurTimeval(void)
253 gettimeofday(&tv, NULL);
254 return GetTimeval(&tv) - baseTimeval;
257 static long SetITimer1(long interval, long value)
259 struct itimerval it, old;
261 SetTimeval(&it.it_interval, interval);
262 SetTimeval(&it.it_value, value);
263 if (setitimer(ITIMER_REAL, &it, &old) < 0)
265 signal(SIGALRM, CatchAlarm);
266 return GetTimeval(&old.it_value);
269 long SetITimer(long interval, long value)
273 old = SetITimer1(0, 0);
275 SetITimer1(interval, value);
279 ///////////// ... /////////////
281 volatile void die(char *msg)
287 volatile void fatal(char *msg)
289 fprintf(stderr, "%s\n", msg);
293 void BlockSignals(MySigSet *saved, ...)
299 va_start(args, saved);
300 #ifdef HAS_SIGPROCMASK
305 while ((sig = va_arg(args, int))) {
306 #ifdef HAS_SIGPROCMASK
307 sigaddset(&set, sig);
312 #ifdef HAS_SIGPROCMASK
313 sigprocmask(SIG_BLOCK, &set, saved);
315 *saved = sigblock(set);
320 void RestoreSignals(MySigSet *saved, MySigSet *set)
322 #ifdef HAS_SIGPROCMASK
323 sigprocmask(SIG_SETMASK, set, saved);
326 *saved = sigsetmask(*set);
332 ///////////// EVENTS /////////////
334 void AddEventGen(EventGenRec *gen)
336 assert(gen->next == NULL);
337 gen->next = nextGen->next;
341 void RemoveEventGen(EventGenRec *gen)
343 // assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
345 while (nextGen->next != gen)
346 nextGen = nextGen->next;
347 nextGen->next = gen->next;
352 MyEventType WaitMyEvent(MyEvent *event, int mask)
357 int result, anyReady, anySet;
361 for (i = 0; i < FT_len; ++i)
363 anyReady = anySet = 0;
366 if (gen->mask & mask) {
370 FD_SET(gen->fd, &fds[gen->fdType]);
375 } while (gen != nextGen);
378 tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
379 result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
380 &fds[FT_except], anyReady ? &tv : NULL);
383 if (retry && !anyReady)
389 if ((gen->mask & mask) && (gen->ready || (
390 result > 0 && gen->fd >= 0
391 && FD_ISSET(gen->fd, &fds[gen->fdType])
394 event->type = gen->func(gen, event);
395 if (event->type != E_none) {
401 } while (gen != nextGen);