1
2 /*
3 TetriNET Server for Linux V1.13.XX
4 *************************************************************************
5 What is TetriNET?
6 TetriNET is an addictive 6 player tetris game. Would someone please
7 fill this question in with something more interesting ;)
8
9
10 What does this program do?
11 I created this program originally because I wanted to run a TetriNET
12 server off my gateway machine, which ran RedHat Linux, and masqueraded
13 packets between my internal network and the Internet. And thats where
14 my total interest lies. If a new TetriNET comes out, I _may_ try to
15 update the linux server.
16 What this program does is set up a TetriNET server that ordinary
17 TetriNET clients can connect to. It attempts to fix some of the
18 "glaring" holes in the TetriNET protocol that I discovered, and which
19 I'm sure some people use as cheats, but I now see why it is nearly
20 impossible to fix ;), without a modification to the client.
21 I've kept the server as close to the same as the original TetriNET
22 server, but I've added some extras that I've often wanted, such as
23 the "/kick" and "/ban" keywords.
24 Please note, this server in no way encompasses the whole game. The clients
25 are the ones that do most of the work, with the server just passing suitable
26 packets between each client, and of course adding some of it's own.
27
28 Acknowledgements
29 Naturally I acknowledge the author of the brilliant game TetriNET,
30 St0rmcat. Let me just say that trying to find your homepage was definately
31 an experience (one of the three most hardest things on the internet)... and
32 so was reading it ;) I guess it must be interesting to be defining a "protocol"
33
34 I also acknowledge the author(s) of the "EggDrop" irc program, (see net.h).
35 The reason is that I borrowed some of their code (really, with minor
36 modifications, net.c is completely theirs). I didn't feel like recreating
37 the wheel, and I'd previously gone through that program line by line
38 anyway, and thought it to be one of the most brilliantly neatly written
39 programs I've seen yet.
40
41 Thanks to BlueCoder (see crack.h). His goals follow the same lines as mine,
42 and thus was a good source of information. Good luck on your program man,
43 and keep in touch with any of your additions to the protocol ;)
44
45 Thanks to those who quite unknowingly tested the Server when it went on live
46 trial, on the 14/9/98 and 15/9/98. I just wish I could remember your nicks ;)
47 One person I DO remember ;), is ^k1mc1^, good fun to play against, and has
48 an excellent team name :)
49
50 Who Am I
51 My name is Brendan Grieve, and I tend to program now and then on something
52 that interests me. I don't program for a living, but rather live for my
53 programming, if you get my meaning. Most of my code is generally open, since
54 if even one person learns something from it, GREAT. The best way to learn is
55 to look at other code, and to modify it even, to add something in.
56 Also, of course, any bugs can be traced right to the exact line, and patched
57 easily ;)
58
59 email: brg@cheerful.com
60
61 What can I do with your Source Code?
62 Learn from it if you want. Use it. If you want to improve it, go ahead, and
63 if you think your changes will be of use to others, then please do
64 email me the changes, and I'll add them to the main distribution.
65 Essentially all code, apart from bits (mentiotioned in their respective
66 header files), are completely public domain.
67
68 What I want at the moment is for this code to be portable to other
69 unices than just Linux. And for that, naturally I need someone who
70 has other types of unixes to try compile the program.
71
72 I now have a WISHLIST text file with all the excellent suggestions
73 sent in by various people. They all might one day be added, and if
74 you think of a good way, go right ahead ;), and if it's good, I'll add
75 it to the main distribution.
76
77
78 */
79
80
81
82
83
84 /*undef TETDEBUG*/ /* Every time I find I need a printf, I'll encase it as a debug */
85
86 #include "config.h" /* Generally about the only file */
87 /* that the user can safely change */
88 #include <signal.h>
89 #include <unistd.h>
90 #include "main.h"
91 #include "net.h"
92 #include "utils.h"
93 #include "crack.h"
94 #include "game.h"
95
96 #include "utils.c"
97 #include "net.c"
98 #include "crack.c"
99 #include "game.c"
100
101
102 /* remnet (channel, n) - Removes n from the channel list */
remnet(struct channel_t * chan,struct net_t * n)103 void remnet(struct channel_t *chan, struct net_t *n)
104 {
105 struct net_t *nsock,*osock;
106
107 nsock=chan->net;
108 osock=NULL;
109 while( (nsock!=NULL) && (nsock!= n))
110 {
111 osock=nsock;
112 nsock=nsock->next;
113 }
114 if (nsock!=NULL)
115 {
116 if (osock==NULL)
117 chan->net=nsock->next;
118 else
119 osock->next=nsock->next;
120 nsock->channel=NULL;
121 }
122 }
123
124 /* addnet (channel, n) - Adds n to the channel list */
addnet(struct channel_t * chan,struct net_t * n)125 void addnet(struct channel_t *chan, struct net_t *n)
126 {
127 n->next=chan->net;
128 chan->net=n;
129 n->channel=chan;
130 }
131
132 /* writepid() - Writes the current pid to game.pidfile */
writepid(void)133 void writepid(void)
134 {
135 FILE *file_out;
136
137 file_out = fopen(game.pidfile,"w");
138 if (file_out == NULL)
139 {
140 lvprintf(0,"ERROR: Could not write to PID file %s\n", game.pidfile);
141 }
142 else
143 {
144 fprintf(file_out,"%d", getpid());
145 fclose(file_out);
146 lvprintf(9,"Wrote PID to file %s\n", game.pidfile);
147 }
148 }
149
150 /* delpid() - Delete the pid file */
delpid(void)151 void delpid(void)
152 {
153 remove(game.pidfile);
154 lvprintf(9,"Removed PID file %s\n", game.pidfile);
155 }
156
157 /* int numallplayers(chan) - Returns ANY player that is connected in a channel */
numallplayers(struct channel_t * chan)158 int numallplayers(struct channel_t *chan)
159 {
160 int count;
161 struct net_t *n;
162
163 count=0;
164 n=chan->net;
165 while (n!=NULL)
166 {
167 count++;
168 n=n->next;
169 }
170 return(count);
171 }
172 /* int numplayers(chan) - Returns number of CONNECTED Players in a channel */
numplayers(struct channel_t * chan)173 int numplayers(struct channel_t *chan)
174 {
175 int count;
176 struct net_t *n;
177
178 count=0;
179 n=chan->net;
180 while (n!=NULL)
181 {
182 if( ((n->type==NET_CONNECTED) || (n->type==NET_WAITINGFORTEAM))) count++;
183 n=n->next;
184 }
185 return(count);
186 }
187
188 /* int numchannels() - Returns number of channels */
numchannels(void)189 int numchannels(void)
190 {
191 int count;
192 struct channel_t *chan;
193
194 chan=chanlist;
195 count=0;
196 while (chan!= NULL)
197 {
198 count++;
199 chan=chan->next;
200 }
201 return(count);
202
203 }
204
205
206
207 /* is_banned( net ) - Returns 1 if the IP of the player is banned */
is_banned(struct net_t * n)208 char is_banned(struct net_t *n)
209 { /* I should use regex, but I've not used it before, and it was late. Easier to write a quick one of my own */
210 FILE *file_in;
211 char n1[4], n2[4], n3[4], n4[4];
212 char ip1[4], ip2[4], ip3[4], ip4[4];
213 int i; int found;
214
215 file_in = fopen(FILE_BAN,"r");
216 if (file_in == NULL)
217 return(0);
218
219 sprintf(n1,"%lu", (unsigned long)(n->addr&0xff000000)/(unsigned long)0x1000000);
220 sprintf(n2,"%lu", (unsigned long)(n->addr&0x00ff0000)/(unsigned long)0x10000);
221 sprintf(n3,"%lu", (unsigned long)(n->addr&0x0000ff00)/(unsigned long)0x100);
222 sprintf(n4,"%lu", (unsigned long)n->addr&0x000000ff);
223
224 found = 0;
225 while (!found && !feof(file_in))
226 {
227 /* Read in line by line, and match regular expressions with the IP of sock_index */
228 i = fscanf(file_in," %4[0-9*] . %4[0-9*] . %4[0-9*] . %4[0-9*] \n", ip1, ip2, ip3, ip4);
229 if (i == 4)
230 {
231 if ( ((!strcmp(n1,ip1)) || (!strcmp(ip1,"*")))
232 && ((!strcmp(n2,ip2)) || (!strcmp(ip2,"*")))
233 && ((!strcmp(n3,ip3)) || (!strcmp(ip3,"*")))
234 && ((!strcmp(n4,ip4)) || (!strcmp(ip4,"*")))
235 )
236 {/* Matches! */
237 found=1;
238 }
239 }
240 }
241 fclose(file_in);
242 return(found);
243 }
244
245 /* is_op( net ) - Returns 1 if this player is the lowest gameslot, thus the chanop */
is_op(struct net_t * n)246 char is_op(struct net_t *n)
247 {
248 int found;
249 struct net_t *nt;
250 found = 0;
251
252 nt=n->channel->net;
253 while( nt!=NULL)
254 {
255 if ( ( (nt->type == NET_CONNECTED) || (nt->type == NET_WAITINGFORTEAM) ) && (nt->gameslot < n->gameslot))
256 found = 1;
257 nt=nt->next;
258 }
259 return(!found);
260 }
261
262 /* passed_level(net, level required to pass) - Returns 1 if the player's security */
263 /* level is equal to or higher than the level required to pass */
264 /* Passing is_op gives player a security level of at least 2*/
passed_level(struct net_t * n,int passlevel)265 char passed_level(struct net_t *n, int passlevel)
266 {
267 int currlevel;
268
269 currlevel=LEVEL_NORMAL; /* Normal Player */
270
271 if (is_op(n)) currlevel=LEVEL_OP; /* Op by position */
272
273 /* Player might already have a higher level... say they did a /op */
274 if (n->securitylevel > currlevel)
275 currlevel=n->securitylevel;
276
277 return( currlevel >= passlevel);
278 }
279
280 /* kick(net from, player to be kicked) - Disconnects player, and informs all others that they were kicked */
kick(struct net_t * n_from,int kick_gameslot)281 void kick(struct net_t *n_from, int kick_gameslot)
282 {
283 struct net_t *n;
284 struct net_t *n_to;
285
286 n=n_from->channel->net;
287 n_to=NULL;
288 while (n!=NULL)
289 {
290 if ( (n->gameslot == kick_gameslot) && ((n->type == NET_CONNECTED) || (n->type == NET_WAITINGFORTEAM)))
291 n_to = n;
292 n=n->next;
293 }
294 if ((n_to!=NULL) && (kick_gameslot>=1) && (kick_gameslot<=6))
295 {
296 lvprintf(4,"#%s-%s: Kicked %s from server\n",n_from->channel->name,n_from->nick,n_to->nick);
297 n=n_from->channel->net;
298 while (n!=NULL)
299 {
300 if ( ((n->type == NET_CONNECTED) || (n->type == NET_WAITINGFORTEAM)))
301 {
302 tprintf(n->sock,"kick %d\xff", kick_gameslot);
303 }
304 n=n->next;
305 }
306 killsock(n_to->sock); lostnet(n_to);
307 }
308 }
309
310 /* tet_checkversion( client version ) - Returns 0 if the server supports this */
311 /* client version. At the moment, ONLY support 1.13 client*/
tet_checkversion(char * buf)312 int tet_checkversion(char *buf)
313 { /* Returns -1 if versioncheck fails */
314 if (!strcmp(TETVERSION,buf))
315 return(0);
316 else
317 return(-1);
318 }
319
320 /* lvprintf( priority, same as printf ) - Logs to the log IF priority is smaller */
321 /* or equal to game.verbose */
lvprintf(int priority,char * format,...)322 void lvprintf(int priority, char *format, ...)
323 { /* No bounds checking. Be very careful what you log */
324 if (priority <= game.verbose) {
325 va_list va; static char SBUF2[768];
326 va_start(va, format);
327 vsnprintf(SBUF2, sizeof(SBUF2),format,va);
328 lprintf(SBUF2);
329 va_end(va);
330 }
331 }
332
333 /* lprintf( same as printf ) - Logs to the log. */
lprintf(char * format,...)334 void lprintf(char *format, ...)
335 { /* No bounds checking. Be very careful what you log */
336 va_list va; static char SBUF2[768];
337 FILE *file_out;
338 char *mytime;
339 char *P;
340 time_t cur_time;
341 va_start(va, format);
342 vsnprintf(SBUF2, sizeof(SBUF2),format,va);
343
344 file_out = fopen(FILE_LOG,"a");
345 if (file_out != NULL)
346 {
347 cur_time = time(NULL);
348 mytime=ctime(&cur_time);
349 P=mytime;
350 P+=4;
351 mytime[strlen(mytime)-6]=0;
352 fprintf(file_out,"%s %s", P, SBUF2);
353 fclose(file_out);
354 }
355 va_end(va);
356 }
357
358 /* Open a Listening Socket on the TetriNET port */
init_telnet_port()359 void init_telnet_port()
360 {
361 int i,j;
362 struct net_t *n;
363
364 /* find old entry if it exists */
365 n=gnet;
366 while ( (n!=NULL) && (n->type!=NET_TELNET))
367 n=n->next;
368
369 if (n==NULL) {
370 /* no existing entry */
371 n=gnet;
372 gnet=malloc(sizeof(struct net_t));
373 gnet->next=n;
374 n=gnet;
375 n->addr=getmyip();
376 n->type=NET_TELNET;
377 strcpy(n->nick,"(telnet)");
378 getmyhostname(n->host);
379 }
380 else {
381 /* already an entry */
382 killsock(n->sock);
383 }
384 j=TELNET_PORT;
385 i=open_listen_socket(&j,game.bindip);
386
387 if (i>=0) {
388 n->port=j;
389 n->sock=i;
390
391 lvprintf(3,"Listening at telnet port %d, on socket %d, bound to %s\n", j,i,game.bindip);
392 return;
393 }
394 printf("Couldn't find telnet port %d. (TetriNET already running?)\n",j);
395 lvprintf(0,"Couldn't find telnet port %d.\n", j);
396 exit(1);
397 }
398
399 /* Open a Listening Socket on the TetriNET query port */
init_query_port()400 void init_query_port()
401 {
402 int i,j;
403 struct net_t *n;
404
405 /* find old entry if it exists */
406 n=gnet;
407 while ( (n!=NULL) && (n->type!=NET_QUERY))
408 n=n->next;
409
410 if (n==NULL) {
411 /* no existing entry */
412 n=gnet;
413 gnet=malloc(sizeof(struct net_t));
414 gnet->next=n;
415 n=gnet;
416 n->addr=getmyip();
417 n->type=NET_QUERY;
418 strcpy(n->nick,"(telnet)");
419 getmyhostname(n->host);
420 }
421 else {
422 /* already an entry */
423 killsock(n->sock);
424 }
425 j=QUERY_PORT;
426 i=open_listen_socket(&j,game.bindip);
427
428 if (i>=0) {
429 n->port=j;
430 n->sock=i;
431
432 lvprintf(3,"Listening at query port %d, on socket %d, bound to %s\n", j,i,game.bindip);
433 return;
434 }
435 printf("Couldn't find telnet port %d. (TetriNET already running?)\n",j);
436 lvprintf(0,"Couldn't find telnet port %d.\n", j);
437 exit(1);
438 }
439
440
441
442
443 /* Main loop calls here when activity found on a net socket */
net_activity(int z,char * buf,int len)444 void net_activity(int z, char *buf, int len)
445 {
446 struct net_t *n;
447 struct channel_t *chan;
448
449 chan=chanlist;
450 n=NULL;
451 while ( (chan!=NULL) && (n==NULL) )
452 {
453 n=chan->net;
454 while( (n!=NULL) && (n->sock!=z) )
455 n=n->next;
456 chan=chan->next;
457 }
458
459 if (n==NULL)
460 { /* Try global list */
461 n=gnet;
462 while( (n!=NULL) && (n->sock!=z) )
463 n=n->next;
464 }
465
466
467 if (n==NULL) return;
468
469 /* Reset timeout on socket */
470 if (n->status == STAT_PLAYING)
471 n->timeout = game.timeout_ingame;
472 else
473 n->timeout = game.timeout_outgame;
474
475 switch (n->type)
476 {
477 case NET_TELNET: /* Recieved connection */
478 {
479 net_telnet(n,buf);
480 break;
481 }
482 case NET_QUERY: /* Recieved connection */
483 {
484 net_query(n,buf);
485 break;
486 }
487 case NET_TELNET_INIT: /* Received clients init sequence */
488 {
489 net_telnet_init(n,buf);
490 break;
491 }
492 case NET_QUERY_INIT: /* Received clients init sequence */
493 {
494 net_query_init(n,buf);
495 break;
496 }
497 case NET_WAITINGFORTEAM: /* Waiting for inital team */
498 {
499 net_waitingforteam(n,buf);
500 break;
501 }
502 case NET_CONNECTED: /* Recieved command from client */
503 {
504 net_connected(n,buf);
505 break;
506 }
507 default:
508 {
509 lvprintf(0,"Internal Error - Untrapped Network activity. (BIG ERROR)\n");
510 }
511 }
512 }
513
514 /* String length (minus colours) */
strclen(char * S)515 int strclen(char *S)
516 {
517 int i;int count;
518 if (S==NULL)
519 return 0;
520
521 i=0;count=0;
522 while(S[i]!=0)
523 {
524 if( (S[i] != BOLD)
525 && (S[i] != CYAN)
526 && (S[i] != BLACK)
527 && (S[i] != BLUE)
528 && (S[i] != DARKGRAY)
529 && (S[i] != MAGENTA)
530 && (S[i] != GREEN)
531 && (S[i] != NEON)
532 && (S[i] != SILVER)
533 && (S[i] != BROWN)
534 && (S[i] != NAVY)
535 && (S[i] != VIOLET)
536 && (S[i] != RED)
537 && (S[i] != ITALIC)
538 && (S[i] != TEAL)
539 && (S[i] != WHITE)
540 && (S[i] != YELLOW)
541 && (S[i] != UNDERLINE) )
542 count++;
543 i++;
544 }
545 return(i);
546 }
547
548 /* Connected, recieving commands */
net_connected(struct net_t * n,char * buf)549 void net_connected(struct net_t *n, char *buf)
550 {
551 char COMMAND[101]; char PARAM[601]; char MSG[601];
552 char STRG[513], STRG2[513];
553 int num; int num1; int num2; int num3; int num4; int s; int i,j,k,l,x,y;
554 int nn1,nn2,nn3,nn4,nn5,nn6,nn7,nn8,nn9;
555 int valid_param;
556 char *P=NULL;
557 struct channel_t *chan,*ochan,*c,*oc;
558 struct net_t *nsock=NULL;
559 struct net_t *ns1,*ns2;
560
561 COMMAND[0]=0;PARAM[0]=0;MSG[0]=0;
562 /* Ensure command is proper before passing it to other players */
563 sscanf(buf, "%100s %600[^\n\r]", COMMAND, PARAM);
564 valid_param = 0; /* 0 = invalid */
565 /* 1 = valid */
566 /* 2 = valid command, but failed some test */
567
568
569 /* Party Line Message - pline <playernumber> <message> */
570 if ( !strcasecmp(COMMAND, "pline") )
571 {
572 valid_param=2;
573 s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
574 if ( (s >= 2) && (num==n->gameslot))
575 {
576 if (MSG[0]=='/')
577 {
578 valid_param=1;
579 /* First parse to see if it's a server command */
580 if ( !strncasecmp(MSG, "/kick", 5) && (game.command_kick > 0))
581 {
582 valid_param=2;
583 if ( passed_level(n,game.command_kick) )
584 {
585 P=MSG+6;
586 while( (((*P)-'0') >= 1) && (((*P)-'0') <= 6) )
587 {
588
589 kick(n, (*P)-'0');
590 P++;
591 }
592 }
593 else
594 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
595
596 }
597
598 /* Set channel settings */
599 if ( !strncasecmp(MSG, "/set", 4) && (game.command_set>0))
600 {
601 valid_param=2;
602 if (passed_level(n,game.command_set)
603 || ((passed_level(n,LEVEL_AUTHOP)||(passed_level(n,LEVEL_OP)&&!n->channel->persistant))
604 && (game.command_set==4)
605 )
606 )
607 {
608 PARAM[0]=0;
609 STRG2[0]=0;
610 STRG[0]=0;
611 sscanf(MSG,"%s %s %1024[^\n]", STRG2,STRG,PARAM);
612
613
614 if ( !strcasecmp(STRG,"BLOCK") )
615 {
616 k=0;
617 k=sscanf(PARAM,"%d %d %d %d %d %d %d",&nn1,&nn2,&nn3,&nn4,&nn5,&nn6,&nn7);
618 if (k==7)
619 {
620 if ((abs(nn1)+abs(nn2)+abs(nn3)+abs(nn4)+abs(nn5)+abs(nn6)+abs(nn7)) == 100)
621 {
622 n->channel->block_leftl=abs(nn1);
623 n->channel->block_leftz=abs(nn2);
624 n->channel->block_square=abs(nn3);
625 n->channel->block_rightl=abs(nn4);
626 n->channel->block_rightz=abs(nn5);
627 n->channel->block_halfcross=abs(nn6);
628 n->channel->block_line=abs(nn7);
629 tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
630 }
631 else
632 {
633 tprintf(n->sock,"pline 0 %cAll Parameters must add up to 100%%\xff",NAVY);
634 }
635 }
636 else if (strlen(PARAM)==0)
637 {
638 tprintf(n->sock,"pline 0 %cBLOCK\xff",RED);
639 tprintf(n->sock,"pline 0 %cSet the percentage occurance of blocks in a game\xff",NAVY);
640 tprintf(n->sock,"pline 0 %cll\t%cPercent Left L shaped block\xff", BLUE,NAVY);
641 tprintf(n->sock,"pline 0 %clz\t%cPercent Left Z shaped block\xff", BLUE,NAVY);
642 tprintf(n->sock,"pline 0 %csq\t%cPercent Square shaped block\xff", BLUE,NAVY);
643 tprintf(n->sock,"pline 0 %crl\t%cPercent Right L shaped block\xff", BLUE,NAVY);
644 tprintf(n->sock,"pline 0 %crz\t%cPercent Right Z shaped block\xff", BLUE,NAVY);
645 tprintf(n->sock,"pline 0 %chc\t%cPercent HalfCross shaped block\xff", BLUE,NAVY);
646 tprintf(n->sock,"pline 0 %cln\t%cPercent Line shaped block\xff",BLUE,NAVY);
647 tprintf(n->sock,"pline 0 %cAll percentages add up to a total of 100%%\xff",NAVY);
648 tprintf(n->sock,"pline 0 %cIE: %c/set %cBLOCK %c14 14 15 14 14 14 15\xff",NAVY,BLUE,RED,BLUE);
649 tprintf(n->sock,"pline 0 Current Setting: %d %d %d %d %d %d %d\xff",
650 n->channel->block_leftl,
651 n->channel->block_leftz,
652 n->channel->block_square,
653 n->channel->block_rightl,
654 n->channel->block_rightz,
655 n->channel->block_halfcross,
656 n->channel->block_line);
657 }
658 else
659 tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cBLOCK\xff",NAVY,BLUE,RED);
660 }
661 else if ( !strcasecmp(STRG,"SPECIAL") )
662 {
663 k=0;
664 k=sscanf(PARAM,"%d %d %d %d %d %d %d %d %d",&nn1,&nn2,&nn3,&nn4,&nn5,&nn6,&nn7,&nn8,&nn9);
665 if (k==9)
666 {
667 if ( ((abs(nn1)+abs(nn2)+abs(nn3)+abs(nn4)+abs(nn5)+abs(nn6)+abs(nn7)+abs(nn8)+abs(nn9)) == 100)
668 )
669 {
670 n->channel->special_addline=abs(nn1);
671 n->channel->special_clearline=abs(nn2);
672 n->channel->special_nukefield=abs(nn3);
673 n->channel->special_randomclear=abs(nn4);
674 n->channel->special_switchfield=abs(nn5);
675 n->channel->special_clearspecial=abs(nn6);
676 n->channel->special_gravity=abs(nn7);
677 n->channel->special_quakefield=abs(nn8);
678 n->channel->special_blockbomb=abs(nn9);
679 tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
680 }
681 else
682 tprintf(n->sock,"pline 0 %cAll Parameters must add up to 100%%\xff",NAVY);
683 }
684 else if (strlen(PARAM)==0)
685 {
686 tprintf(n->sock,"pline 0 %cSPECIAL\xff",RED);
687 tprintf(n->sock,"pline 0 %cSet the percentage occurance of special blocks in a game\xff",NAVY);
688 tprintf(n->sock,"pline 0 %cA\t%cPercent ADDLINE block\xff",BLUE,NAVY);
689 tprintf(n->sock,"pline 0 %cC\t%cPercent CLEARLINE block\xff",BLUE,NAVY);
690 tprintf(n->sock,"pline 0 %cN\t%cPercent NUKEFIELD block\xff",BLUE,NAVY);
691 tprintf(n->sock,"pline 0 %cR\t%cPercent RANDOMCLEAR block\xff",BLUE,NAVY);
692 tprintf(n->sock,"pline 0 %cS\t%cPercent SWITCHFIELD block\xff",BLUE,NAVY);
693 tprintf(n->sock,"pline 0 %cB\t%cPercent CLEARSPECIAL block\xff",BLUE,NAVY);
694 tprintf(n->sock,"pline 0 %cG\t%cPercent GRAVITY block\xff",BLUE,NAVY);
695 tprintf(n->sock,"pline 0 %cQ\t%cPercent QUAKEFIELD block\xff",BLUE,NAVY);
696 tprintf(n->sock,"pline 0 %cO\t%cPercent BLOCKBOMB block\xff",BLUE,NAVY);
697 tprintf(n->sock,"pline 0 %cAll percentages add up to a total of 100%%\xff",NAVY);
698 tprintf(n->sock,"pline 0 %cIE: %c/set %cSPECIAL %c32 18 1 11 3 14 1 6 14\xff",NAVY,BLUE,RED,BLUE);
699 tprintf(n->sock,"pline 0 Current Setting: %d %d %d %d %d %d %d %d %d\xff",
700 n->channel->special_addline,
701 n->channel->special_clearline,
702 n->channel->special_nukefield,
703 n->channel->special_randomclear,
704 n->channel->special_switchfield,
705 n->channel->special_clearspecial,
706 n->channel->special_gravity,
707 n->channel->special_quakefield,
708 n->channel->special_blockbomb);
709 }
710 else
711 tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cSPECIAL\xff",NAVY,BLUE,RED);
712 }
713 else if ( !strcasecmp(STRG,"SUDDENDEATH") )
714 {
715 k=0;
716 k=sscanf(PARAM,"%d %d %d",&nn1,&nn2,&nn3);
717 if (k==3)
718 {
719 if ( (nn1 >= 0) && (nn2 >= 0) && (nn3 > 0) )
720 {
721 n->channel->sd_timeout=nn1;
722 n->channel->sd_lines_per_add=nn2;
723 n->channel->sd_secs_between_lines=nn3;
724 tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
725 }
726 else
727 tprintf(n->sock,"pline 0 %cInvalid Parameters\xff",NAVY);
728 }
729 else if (strlen(PARAM)==0)
730 {
731 tprintf(n->sock,"pline 0 %cSUDDENDEATH\xff",RED);
732 tprintf(n->sock,"pline 0 %cSet the configuration for SUDDENDEATH mode\xff",NAVY);
733 tprintf(n->sock,"pline 0 %cto\t%cNumber of Seconds till SuddenDeath Mode\xff",BLUE,NAVY);
734 tprintf(n->sock,"pline 0 %cla\t%cNumber of Lines to add each time\xff",BLUE,NAVY);
735 tprintf(n->sock,"pline 0 %csl\t%cNumber of Seconds between each add line\xff",BLUE,NAVY);
736 tprintf(n->sock,"pline 0 %cIE: %c/set %cSUDDENDEATH %c180 1 30\xff",NAVY,BLUE,RED,BLUE);
737 tprintf(n->sock,"pline 0 Current Setting: %d %d %d\xff",
738 n->channel->sd_timeout,
739 n->channel->sd_lines_per_add,
740 n->channel->sd_secs_between_lines);
741 }
742 else
743 tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cSUDDENDEATH\xff",NAVY,BLUE,RED);
744 }
745 else if ( !strcasecmp(STRG,"SUDDENDEATHMSG") )
746 {
747 k=0;
748 k=sscanf(PARAM,"%512[^\n]",STRG2);
749 if (k==1)
750 {
751 strncpy(n->channel->sd_message,STRG2,SDMSGLEN);n->channel->sd_message[SDMSGLEN-1]=0;
752 tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
753 }
754 else if (strlen(PARAM)==0)
755 {
756 tprintf(n->sock,"pline 0 %cSUDDENDEATHMSG\xff",RED);
757 tprintf(n->sock,"pline 0 %cSet the Message sent to players when SuddenDeath mode arrives\xff",NAVY);
758 tprintf(n->sock,"pline 0 %cmsg\t%cMessage to send to players\xff",BLUE,NAVY);
759 tprintf(n->sock,"pline 0 %cIE: %c/set %cSUDDENDEATHMSG %cTime's up! It's SUDDEN DEATH MODE!\xff",NAVY,BLUE,RED,BLUE);
760 tprintf(n->sock,"pline 0 Current Setting: %s\xff",n->channel->sd_message);
761 }
762 else
763 tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cSUDDENDEATHMSG\xff",NAVY,BLUE,RED);
764 }
765 else if ( !strcasecmp(STRG,"RULES") )
766 {
767 k=0;
768 k=sscanf(PARAM,"%d %d %d %d %d %d %d %d",&nn1,&nn2,&nn3,&nn4,&nn5,&nn6,&nn7,&nn8);
769 if (k==8)
770 {
771 if ( (nn1>=0)&&(nn1<100)&&(nn2>0)&&(nn3>0)&&(nn4>0)&&(nn5>=0)&&(nn6>0)&&(nn6<=18)&&(nn7>=0)&&(nn7<=1)&&(nn8>=0)&&(nn8<=1))
772 {
773 n->channel->starting_level=nn1;
774 n->channel->lines_per_level=nn2;
775 n->channel->level_increase=nn3;
776 n->channel->lines_per_special=nn4;
777 n->channel->special_added=nn5;
778 n->channel->special_capacity=nn6;
779 n->channel->classic_rules=nn7;
780 n->channel->average_levels=nn8;
781 tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
782 }
783 else
784 tprintf(n->sock,"pline 0 %cInvalid parameters\xff",NAVY);
785 }
786 else if (strlen(PARAM)==0)
787 {
788 tprintf(n->sock,"pline 0 %cRULES\xff",RED);
789 tprintf(n->sock,"pline 0 %cSet the Channel Rules in the game\xff",NAVY);
790 tprintf(n->sock,"pline 0 %csl\t%cStarting Level of all players\xff",BLUE,NAVY);
791 tprintf(n->sock,"pline 0 %cll\t%cLines per level\xff",BLUE,NAVY);
792 tprintf(n->sock,"pline 0 %cli\t%cAmount level increases each time\xff",BLUE,NAVY);
793 tprintf(n->sock,"pline 0 %cls\t%cLines per special\xff",BLUE,NAVY);
794 tprintf(n->sock,"pline 0 %csa\t%cNumber of specials added each time\xff",BLUE,NAVY);
795 tprintf(n->sock,"pline 0 %csc\t%cSpecial Capacity of players\xff",BLUE,NAVY);
796 tprintf(n->sock,"pline 0 %ccr\t%cPlay with classic rules?\xff",BLUE,NAVY);
797 tprintf(n->sock,"pline 0 %cal\t%cAverage all players levels?\xff",BLUE,NAVY);
798 tprintf(n->sock,"pline 0 %cIE: %c/set %cRULES %c1 2 1 1 1 18 1 1\xff",NAVY,BLUE,RED,BLUE);
799 tprintf(n->sock,"pline 0 Current Setting: %d %d %d %d %d %d %d %d\xff",
800 n->channel->starting_level,
801 n->channel->lines_per_level,
802 n->channel->level_increase,
803 n->channel->lines_per_special,
804 n->channel->special_added,
805 n->channel->special_capacity,
806 n->channel->classic_rules,
807 n->channel->average_levels);
808 }
809 else
810 tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cRULES\xff",NAVY,BLUE,RED);
811 }
812 else if ( !strcasecmp(STRG,"MISC") )
813 {
814 k=0;
815 k=sscanf(PARAM,"%d %d %d",&nn1,&nn2,&nn3);
816 if (k==3)
817 {
818 if ( (nn1>=0)&&(nn1<=1)&&(nn2>=0)&&(nn2<=1)&&(nn3>=0)&&(nn3<=1))
819 {
820 n->channel->stripcolour=nn1;
821 n->channel->serverannounce=nn2;
822 n->channel->pingintercept=nn3;
823 tprintf(n->sock,"pline 0 %cSettings Updated!\xff",NAVY);
824 }
825 else
826 tprintf(n->sock,"pline 0 %cInvalid parameters\xff",NAVY);
827 }
828 else if (strlen(PARAM)==0)
829 {
830 tprintf(n->sock,"pline 0 %cMISC\xff",RED);
831 tprintf(n->sock,"pline 0 %cSet Misc options\xff",NAVY);
832 tprintf(n->sock,"pline 0 %csc\t%cStrip Colour from GameMessages?\xff",BLUE,NAVY);
833 tprintf(n->sock,"pline 0 %csa\t%cServer Announces winner?\xff",BLUE,NAVY);
834 tprintf(n->sock,"pline 0 %cpi\t%cIntercept \"t\" in a Gamemessage as PING?\xff",BLUE,NAVY);
835 tprintf(n->sock,"pline 0 %cIE: %c/set %cMISC %c 1 1 1\xff",NAVY,BLUE,RED,BLUE);
836 tprintf(n->sock,"pline 0 Current Setting: %d %d %d\xff",
837 n->channel->stripcolour,
838 n->channel->serverannounce,
839 n->channel->pingintercept);
840 }
841 else
842 tprintf(n->sock,"pline 0 %cNot enough parameters. Try %c/set %cMISC\xff",NAVY,BLUE,RED);
843 }
844 else
845 {
846 tprintf(n->sock,"pline 0 %cSET %ccommands - Set channel attributes\xff",TEAL, NAVY);
847 tprintf(n->sock,"pline 0 %cCommands are of the general form: %c/set %c<command>%c[%cvalue [..value]%c]\xff",NAVY,BLUE,RED,BLACK,BLUE,BLACK);
848 tprintf(n->sock,"pline 0 %cWhen given without a value, the current value is returned.\xff",NAVY);
849 tprintf(n->sock,"pline 0 %c/set %cBLOCK %cll lz sq rl rz hc ln %cSet Block Configuration\xff", BLUE,RED,BLUE,NAVY);
850 tprintf(n->sock,"pline 0 %c/set %cSPECIAL %cA C N R S B G Q O %cSet Special Configuration\xff",BLUE,RED,BLUE,NAVY);
851 tprintf(n->sock,"pline 0 %c/set %cSUDDENDEATH %cto la sl %cSet SuddenDeath Configuration\xff",BLUE,RED,BLUE,NAVY);
852 tprintf(n->sock,"pline 0 %c/set %cSUDDENDEATHMSG %cmsg %cSet SuddenDeath Message\xff",BLUE,RED,BLUE,NAVY);
853 tprintf(n->sock,"pline 0 %c/set %cRULES %csl ll li ls sa sc cr al %cSet Rules Configuration\xff",BLUE,RED,BLUE,NAVY);
854 tprintf(n->sock,"pline 0 %c/set %cMISC %csc sa pi %cSet Misc Configuration\xff",BLUE,RED,BLUE,NAVY);
855 /*tprintf(n->sock,"pline 0 %c/set %cCONFIG %cconfignum %cSet ALL config options in one shot\xff",BLUE,RED,BLUE,NAVY);*/
856 tprintf(n->sock,"pline 0 %cType %c/set %ccommandname %cto find out what the parameters mean.\xff",NAVY,BLUE,RED,NAVY);
857 }
858 }
859 else
860 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
861 }
862
863 /* Set channel topic */
864 if ( !strncasecmp(MSG, "/topic", 6) && (game.command_topic>0))
865 {
866 valid_param=2;
867 if ( passed_level(n,game.command_topic) )
868 {
869 P=MSG+7;
870 if (strlen(MSG)>=7)
871 {
872 strncpy(n->channel->description, P, DESCRIPTIONLEN-1); n->channel->description[DESCRIPTIONLEN-1]=0;
873 lvprintf(4,"#%s-%s changed channel topic to %s\n",n->channel->name,n->nick,n->channel->description);
874 nsock=n->channel->net;
875 while (nsock!=NULL)
876 {
877 if ((nsock->type==NET_CONNECTED))
878 {
879 tprintf(nsock->sock,"pline 0 %c%s%c%c changes the channel topic to %s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->description);
880 }
881 nsock=nsock->next;
882 }
883 }
884 }
885 else
886 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
887 }
888
889 /* Who is online */
890 if ( !strncasecmp(MSG, "/who", 4) && (game.command_who>0))
891 {
892 valid_param=2;
893 if ( passed_level(n,game.command_who) )
894 {
895 if (passed_level(n,LEVEL_AUTHOP))
896 tprintf(n->sock,"pline 0 %cNickname\tTeam \tChannel\tIP\xff", NAVY);
897 else
898 tprintf(n->sock,"pline 0 %cNickname\tTeam \tChannel\xff", NAVY);
899 l=1;
900 chan=chanlist;
901 while(chan!=NULL)
902 {
903 nsock=chan->net;
904 while (nsock!=NULL)
905 {
906 if (nsock->type==NET_CONNECTED)
907 {
908 STRG[0]=0;
909 STRG2[0]=0;
910 strcpy(STRG,nsock->nick);
911 j=strclen(STRG);
912 k=strlen(STRG);
913 while(j<15)
914 {
915 STRG[k]=' ';
916 k++;
917 j++;
918 }
919 STRG[k]=0;
920
921 strcpy(STRG2,nsock->team);
922 j=strclen(STRG2);
923 k=strlen(STRG2);
924 while(j<17)
925 {
926 STRG2[k]=' ';
927 k++;
928 j++;
929 }
930 STRG2[k]=0;
931
932 if (nsock==n)
933 j=RED;
934 else
935 j=DARKGRAY;
936
937 if (passed_level(n,LEVEL_AUTHOP))
938 tprintf(n->sock,"pline 0 %c(%c%d%c) %c%s\t%c%s\t%c#%s\t%s\xff", NAVY,j,l,NAVY, j, STRG,TEAL,STRG2,BLUE,nsock->channel->name,nsock->host);
939 else
940 tprintf(n->sock,"pline 0 %c(%c%d%c) %c%s\t%c%s\t%c#%s\xff", NAVY,j,l,NAVY, j, STRG,TEAL,STRG2,BLUE,nsock->channel->name);
941 l++;
942 }
943 nsock=nsock->next;
944 }
945 chan=chan->next;
946 }
947 }
948 else
949 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
950 }
951
952 /* Set channel priority */
953 if ( !strncasecmp(MSG, "/priority", 9) && (game.command_priority>0))
954 {
955 valid_param=2;
956 if ( passed_level(n,game.command_priority) )
957 {
958 P=MSG+10;
959 if ( (atoi(P) >= 0) && (atoi(P) < 100) )
960 {
961 n->channel->priority=atoi(P);
962 lvprintf(4,"#%s-%s changed channel priority to %d\n",n->channel->name,n->nick,n->channel->priority);
963 nsock=n->channel->net;
964 while (nsock!=NULL)
965 {
966 if ((nsock->type==NET_CONNECTED) )
967 {
968 tprintf(nsock->sock,"pline 0 %c%s%c%c changes the channel priority to %d\xff", GREEN,n->nick,BLACK,GREEN,n->channel->priority);
969 }
970 nsock=nsock->next;
971 }
972 }
973 else
974 {
975 tprintf(n->sock,"pline 0 %cChannel priority should lie in the range of 0 to 99. 0 prevents people from automatically joining.\xff",NAVY);
976 }
977 }
978 else
979 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
980 }
981
982 /* List Channels */
983 if ( !strncasecmp(MSG, "/list", 5) && (game.command_list>0))
984 {
985 valid_param=2;
986 if ( passed_level(n,game.command_list) )
987 {
988 if (chanlist != NULL)
989 {
990 tprintf(n->sock,"pline 0 %cTetriNET Channel Lister - (Type %c/join %c#channelname%c)\xff",NAVY,RED,BLUE,NAVY);
991 chan=chanlist;
992 i=1;
993 while (chan != NULL)
994 {
995 if (n->channel==chan)
996 j=RED;
997 else
998 j=BLUE;
999
1000 if (chan->status==STATE_INGAME)
1001 {
1002 sprintf(STRG,"%c{INGAME}%c", DARKGRAY,NAVY);
1003 }
1004 else
1005 {
1006 sprintf(STRG," ");
1007 }
1008 if (numplayers(chan) >= chan->maxplayers)
1009 tprintf(n->sock,"pline 0 %c(%c%d%c) %c#%-6s\t%c[%cFULL%c] %s (%d) %c%s\xff", NAVY, j, i, NAVY, BLUE, chan->name, NAVY,RED,NAVY,STRG, chan->priority,BLACK,chan->description);
1010 else
1011 {
1012 tprintf(n->sock,"pline 0 %c(%c%d%c) %c#%-6s\t%c[%cOPEN%c-%d/%d%c] %s (%d) %c%s\xff", NAVY, j, i, NAVY, BLUE, chan->name, NAVY,TEAL,BLUE,numplayers(chan),chan->maxplayers,NAVY,STRG, chan->priority,BLACK,chan->description);
1013 }
1014 i++;
1015 chan=chan->next;
1016 }
1017 }
1018 }
1019 else
1020 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1021 }
1022
1023 /* Join Channel */
1024 if ( !strncasecmp(MSG, "/j", 2) && (game.command_join>0))
1025 {
1026 valid_param=2;
1027 if ( passed_level(n,game.command_join) || (game.command_join==4))
1028 {
1029 if ( !strncasecmp(MSG,"/join", 5) )
1030 P=MSG+6;
1031 else
1032 P=MSG+3;
1033 STRG[0]=0;
1034 k = sscanf(P,"%512s", STRG);
1035 if ((k != 0) )
1036 {
1037 /* First, is it a #channel or channel number? */
1038 j=atoi(STRG);
1039 chan=NULL;
1040 ochan=NULL;
1041 if (j>0)
1042 { /* Position */
1043 chan=chanlist;
1044 j--;
1045 while( (j>0) && (chan!=NULL) )
1046 {
1047 chan=chan->next;
1048 j--;
1049 }
1050 }
1051 else if (STRG[0]=='#')
1052 { /* Name */
1053 sscanf(P,"#%512s", STRG);
1054
1055 chan = chanlist;
1056 while ( (chan != NULL) && (strcasecmp(STRG,chan->name)) )
1057 chan=chan->next;
1058 j=0;
1059 }
1060 else
1061 {
1062 j=-1;
1063 tprintf(n->sock,"pline 0 %cFormat: %c/join %c<#channel|channel number>\xff", NAVY,RED,BLUE);
1064 }
1065 ochan=n->channel;
1066 if ( (chan!=NULL) && (numplayers(chan)>=chan->maxplayers))
1067 { /* A Full channel */
1068 tprintf(n->sock,"pline 0 %cThat channel is %cFULL%c!\xff", NAVY, RED,BLACK);
1069 }
1070 else if ( (chan==NULL) && (j>=0) && (numchannels() >= game.maxchannels))
1071 { /* Too many channels */
1072 tprintf(n->sock,"pline 0 %cCannot create any more channels!\xff",RED);
1073 }
1074 else if ( (chan==NULL) && (j>=0) && (game.command_join==4) && (n->securitylevel!=LEVEL_AUTHOP))
1075 { /* Can't create a NEW channel */
1076 tprintf(n->sock,"pline 0 %cCannot create new channel\xff",RED);
1077 }
1078 else if (j>=0)
1079 {
1080 if (chan == NULL)
1081 { /* New channel */
1082 chan=chanlist;
1083 while ((chan!= NULL) && (chan->next!=NULL)) chan=chan->next;
1084
1085 if (chan==NULL)
1086 {
1087 chanlist=malloc(sizeof(struct channel_t));
1088 chan=chanlist;
1089 }
1090 else
1091 {
1092 chan->next=malloc(sizeof(struct channel_t));
1093 chan=chan->next;
1094 }
1095
1096 chan->next=NULL;
1097 chan->net=NULL;
1098 strncpy(chan->name, STRG, CHANLEN-1); chan->name[CHANLEN-1]=0;
1099 chan->maxplayers=DEFAULTMAXPLAYERS;
1100 chan->status=STATE_ONLINE;
1101 chan->description[0]=0;
1102 chan->priority=DEFAULTPRIORITY;
1103 chan->sd_mode=SD_NONE;
1104 chan->persistant=0;
1105
1106 /* Copy default settings */
1107 chan->starting_level=game.starting_level;
1108 chan->lines_per_level=game.lines_per_level;
1109 chan->level_increase=game.level_increase;
1110 chan->lines_per_special=game.lines_per_special;
1111 chan->special_added=game.special_added;
1112 chan->special_capacity=game.special_capacity;
1113 chan->classic_rules=game.classic_rules;
1114 chan->average_levels=game.average_levels;
1115 chan->sd_timeout=game.sd_timeout;
1116 chan->sd_lines_per_add=game.sd_lines_per_add;
1117 chan->sd_secs_between_lines=game.sd_secs_between_lines;
1118 strcpy(chan->sd_message,game.sd_message);
1119 chan->block_leftl=game.block_leftl;
1120 chan->block_leftz=game.block_leftz;
1121 chan->block_square=game.block_square;
1122 chan->block_rightl=game.block_rightl;
1123 chan->block_rightz=game.block_rightz;
1124 chan->block_halfcross=game.block_halfcross;
1125 chan->block_line=game.block_line;
1126 chan->special_addline=game.special_addline;
1127 chan->special_clearline=game.special_clearline;
1128 chan->special_nukefield=game.special_nukefield;
1129 chan->special_randomclear=game.special_randomclear;
1130 chan->special_switchfield=game.special_switchfield;
1131 chan->special_clearspecial=game.special_clearspecial;
1132 chan->special_gravity=game.special_gravity;
1133 chan->special_quakefield=game.special_quakefield;
1134 chan->special_blockbomb=game.special_blockbomb;
1135 chan->stripcolour=game.stripcolour;
1136 chan->serverannounce=game.serverannounce;
1137 chan->pingintercept=game.pingintercept;
1138
1139 /* Remove ourselves from old channel list */
1140 n->channel=chan;
1141
1142 lvprintf(4,"#%s-%s created new channel\n", n->channel->name,n->nick);
1143 tprintf(n->sock,"pline 0 %cCreated new Channel - %c#%s%c\xff", GREEN, BLUE, chan->name, BLACK);
1144 }
1145
1146 else
1147 { /* An already existing channel */
1148 n->channel = chan;
1149 lvprintf(4,"#%s-%s joined channel\n", n->channel->name,n->nick);
1150
1151 tprintf(n->sock,"pline 0 %cJoined existing Channel - %c#%s%c\xff", GREEN, BLUE, chan->name, BLACK);
1152 }
1153 remnet(ochan,n);
1154 addnet(chan,n);
1155
1156 /* Send to old channel, this player join message */
1157 nsock=ochan->net;
1158 while (nsock!=NULL)
1159 {
1160 if ( (nsock->type==NET_CONNECTED) )
1161 {
1162 /* Tell them we've joined this channel */
1163 tprintf(nsock->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", DARKGRAY,n->nick,BLACK,DARKGRAY,n->channel->name);
1164 }
1165 nsock=nsock->next;
1166 }
1167
1168 if ((ochan->status == STATE_INGAME) || (ochan->status ==STATE_PAUSED))
1169 {
1170 n->status = STAT_NOTPLAYING;
1171 tprintf(n->sock,"endgame\xff");
1172 }
1173
1174 /* Cleartheir Field */
1175 for(y=0;y<FIELD_MAXY;y++)
1176 for(x=0;x<FIELD_MAXX;x++)
1177 n->field[x][y]=0; /* Nothing */
1178
1179 /* Work out gameslot */
1180 num1=n->gameslot;
1181 num2=0; num3=1;
1182 while ( (num2 < n->channel->maxplayers) && (num3) )
1183 {
1184 num2++;
1185 num3=0;
1186 nsock=n->channel->net;
1187 while (nsock!=NULL)
1188 {
1189 if( (nsock!=n) && ( (nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock->gameslot==num2) ) num3=1;
1190 nsock=nsock->next;
1191 }
1192 }
1193 if (num3==1)
1194 {
1195 lvprintf(0,"#%s-%s Ran out of places in channel (FATAL)\n",n->channel->name,n->nick);
1196 killsock(n->sock);lostnet(n);
1197 return;
1198 }
1199
1200 /* Clear our spot */
1201 tprintf(n->sock,"playerleave %d\xff",n->gameslot);
1202 n->gameslot=num2;
1203
1204 /* Now, send playerleft to all on old channel AND to player */
1205 num3=0;
1206 num4=0;
1207 STRG2[0]=0;
1208 nsock=ochan->net;
1209 while (nsock!=NULL)
1210 {
1211 if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
1212 {
1213 tprintf(nsock->sock,"playerleave %d\xff", num1);
1214 tprintf(n->sock,"playerleave %d\xff", nsock->gameslot);
1215 if (strcasecmp(STRG2,nsock->team))
1216 {/* Different team, so add player */
1217 num3++;
1218 if (nsock->status==STAT_PLAYING) num4++;
1219 strcpy(STRG2,nsock->team);
1220 }
1221 else if (STRG2[0]==0)
1222 {
1223 num3++;
1224 if (nsock->status==STAT_PLAYING) num4++;
1225 }
1226 }
1227 nsock=nsock->next;
1228 }
1229
1230 /* Now send to new channel, this player joined, AND to player */
1231 nsock=n->channel->net;
1232 while (nsock!=NULL)
1233 {
1234 if ( (nsock!=n) && (nsock->type==NET_CONNECTED))
1235 {
1236 /* Send each other player and their team anme */
1237 tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff",nsock->gameslot, nsock->nick, nsock->gameslot, nsock->team);
1238 /* Send to the other player, this player and their team */
1239 tprintf(nsock->sock, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team);
1240 /* Tell them we've joined this channel */
1241 tprintf(nsock->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->name);
1242 }
1243 nsock=nsock->next;
1244 }
1245
1246 /* Set our playernumber */
1247 tprintf(n->sock, "playernum %d\xff",n->gameslot);
1248
1249 /* If game is in progress, send all other players fields */
1250 if( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
1251 {
1252 nsock=n->channel->net;
1253 while (nsock!=NULL)
1254 {
1255 if( (nsock->type==NET_CONNECTED) &&(nsock!=n))
1256 {
1257 /* Each player who has lost, send player_lost */
1258 if (nsock->status != STAT_PLAYING)
1259 {
1260 tprintf(n->sock,"playerlost %d\xff", nsock->gameslot);
1261 }
1262 sendfield(n, nsock); /* Send to player, this players field */
1263 }
1264 nsock=nsock->next;
1265 }
1266 }
1267
1268 /* If we are ingame, then tell this person that we are! */
1269 if ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
1270 tprintf(n->sock,"ingame\xff");
1271
1272 /* If we are currently paused, kindly let them know that fact to */
1273 if ( n->channel->status == STATE_PAUSED )
1274 tprintf(n->sock,"pause 1\xff");
1275
1276 /* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */
1277 if ( (num4 <= 1) && (ochan->status == STATE_INGAME) && (n->status == STAT_PLAYING) )
1278 {
1279 nsock=ochan->net;
1280 while (nsock!=NULL)
1281 {
1282 if ( (nsock=n) && (nsock->type == NET_CONNECTED))
1283 {
1284 tprintf(nsock->sock,"endgame\xff");
1285 nsock->status=STAT_NOTPLAYING;
1286 nsock->timeout=game.timeout_outgame;
1287 }
1288 nsock=nsock->next;
1289 }
1290 ochan->status = STATE_ONLINE;
1291 }
1292
1293 /* If no players, then we delete the channel IF it's not persistant*/
1294 if ( (numallplayers(ochan) == 0) && (ochan!=n->channel) && (!ochan->persistant) )
1295 {
1296 c=chanlist;
1297 oc=NULL;
1298 while ( (c != ochan) && (c != NULL) )
1299 {
1300 oc=c;
1301 c=c->next;
1302 }
1303 if (c != NULL)
1304 {
1305 if (oc != NULL)
1306 oc->next=c->next;
1307 else
1308 chanlist=c->next;
1309 free(c);
1310 }
1311 }
1312
1313 n->timeout=game.timeout_outgame;
1314 if (n->channel->status == STATE_ONLINE)
1315 {
1316 n->status=STAT_NOTPLAYING;
1317 }
1318 else
1319 {
1320 n->status=STAT_LOST;
1321 }
1322 }
1323 }
1324 }
1325 else
1326 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1327 }
1328
1329 /* Clear Winlist - Suggestion by n|ck */
1330 if ( !strncasecmp(MSG, "/clear", 6) && (game.command_clear>0))
1331 {
1332 valid_param=2;
1333 if ( passed_level(n,game.command_clear) )
1334 {
1335 lvprintf(4,"#%s-%s cleared the winlist\n",n->channel->name,n->nick);
1336 init_winlist();
1337 writewinlist();
1338 sendwinlist(n->channel,NULL);
1339 }
1340 else
1341 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1342 }
1343
1344 /* Persistant Channel */
1345 if ( !strncasecmp(MSG, "/persistant", 11) && (game.command_persistant>0))
1346 {
1347 valid_param=2;
1348 if ( passed_level(n,game.command_persistant) )
1349 {
1350 P=MSG+12;
1351 if (*P=='0')
1352 {
1353 n->channel->persistant=0;
1354 tprintf(n->sock,"pline 0 %cChannel will be deleted when last player leaves\xff",NAVY);
1355 }
1356 else
1357 {
1358 n->channel->persistant=1;
1359 tprintf(n->sock,"pline 0 %cChannel is now persistant, and will not be deleted\xff",NAVY);
1360 }
1361 }
1362 else
1363 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1364 }
1365
1366 /* Save Config */
1367 if ( !strncasecmp(MSG, "/save", 5) && (game.command_save>0))
1368 {
1369 valid_param=2;
1370 if ( passed_level(n,game.command_save) )
1371 {
1372 gamewrite();
1373 tprintf(n->sock,"pline 0 %cGame configuration and Persistant Channel info saved\xff",NAVY);
1374 }
1375 else
1376 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1377 }
1378
1379 /* Reset/Load Config */
1380 if ( !strncasecmp(MSG, "/reset", 6) && (game.command_reset>0))
1381 {
1382 valid_param=2;
1383 if ( passed_level(n,game.command_reset) )
1384 {
1385 gameread();
1386 tprintf(n->sock,"pline 0 %cGame configuration and Persistant Channel info loaded\xff",NAVY);
1387 }
1388 else
1389 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1390 }
1391
1392 /* Private msg to a person - Suggestion by crazor */
1393 if ( !strncasecmp(MSG, "/msg", 4) && (game.command_msg>0))
1394 {
1395 valid_param=2;
1396 if ( passed_level(n,game.command_msg) )
1397 {
1398 P=MSG+5;
1399 sscanf(P,"%512s %512[^\n\r ]", STRG, STRG2);
1400
1401 P=STRG;
1402 while( (((*P)-'0') >= 1) && (((*P)-'0') <= 6) )
1403 {
1404 j=(*P)-'0';
1405 nsock=n->channel->net;
1406 while (nsock!=NULL)
1407 {
1408 if ( (nsock->type == NET_CONNECTED) && (nsock->gameslot == j))
1409 {
1410 lvprintf(5,"#%s-(%s to %s): %s\n", n->channel->name,n->nick,nsock->nick,STRG2);
1411 tprintf(nsock->sock,"pline %d %c(msg)%c %s\xff", n->gameslot, NAVY, BLACK, STRG2);
1412 }
1413 nsock=nsock->next;
1414 }
1415 P++;
1416 }
1417 }
1418 else
1419 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1420 }
1421
1422 /* Move a player to another gamespot */
1423 if ( !strncasecmp(MSG, "/move", 5) && (game.command_move>0))
1424 {
1425 valid_param=2;
1426 if ( passed_level(n,game.command_move) && (n->channel->status == STATE_ONLINE) )
1427 {
1428 P=MSG+6;
1429 k=0;l=0;
1430 sscanf(P," %d %d", &k, &l);
1431
1432 if ( (k>0) && (k<=6) && (l>0) && (l<=6) && (k!=l) )
1433 {
1434 /* Ok, this is NOT supposed to work, but it does ;) */
1435
1436 /* Give player l, player k's number */
1437 /* Give player k, player l's number */
1438 /* Send to all others, as if they've rejoined */
1439
1440 /* Find sock_index... for k */
1441 ns1=n->channel->net;
1442 while ( (ns1!=NULL) && !( ((ns1->type == NET_CONNECTED) && (ns1->gameslot==k) )))
1443 ns1=ns1->next;
1444
1445 ns2=n->channel->net;
1446 while( (ns2!=NULL) && !((ns2->type == NET_CONNECTED) && (ns2->gameslot==l) ))
1447 ns2=ns2->next;
1448
1449 if ( (ns1!=NULL) )
1450 {
1451 tprintf(ns1->sock,"playernum %d\xff", l);
1452 ns1->gameslot = l;
1453
1454 if (ns2!=NULL)
1455 { /* This player existed... */
1456 lvprintf(4,"#%s-%s swaps player %s(%d) with %s(%d)\n", n->channel->name,n->nick,ns1->nick,k,ns2->nick,l);
1457 tprintf(ns2->sock,"playernum %d\xff", k);
1458 ns2->gameslot=k;
1459 tprintf(ns1->sock,"playerjoin %d %s\xff", ns2->gameslot, ns2->nick);
1460 tprintf(ns2->sock,"playerjoin %d %s\xff", ns1->gameslot, ns1->nick);
1461 }
1462 else
1463 {
1464 lvprintf(4,"#%s-%s moves player %s(%d) to %s(%d)\n", n->channel->name,n->nick,ns1->nick,k,ns1->nick,l);
1465 tprintf(ns1->sock,"playerleave %d\xff", k);
1466 }
1467
1468 /* Now tell everyone else */
1469 nsock=n->channel->net;
1470 while (nsock!=NULL)
1471 {
1472 if ( (nsock->type == NET_CONNECTED) && (nsock!=ns1) && (nsock!=ns2) )
1473 {
1474 tprintf(nsock->sock,"playerjoin %d %s\xff", ns1->gameslot, ns1->nick);
1475 if (ns2!=NULL)
1476 { /* Player existed */
1477 tprintf(nsock->sock,"playerjoin %d %s\xff", ns2->gameslot,ns2->nick);
1478 }
1479 else
1480 {
1481 tprintf(nsock->sock,"playerleave %d\xff", k);
1482 }
1483 }
1484 nsock=nsock->next;
1485 }
1486 }
1487 }
1488 else
1489 tprintf(n->sock,"pline 0 %c/move %c<playernumber> <newplayernumber>\xff", RED, BLUE);
1490
1491 }
1492 else
1493 {
1494 if (n->channel->status != STATE_ONLINE)
1495 tprintf(n->sock,"pline 0 %cCommand unavailable while a game is in progress. Stop it first.\xff",RED);
1496 else
1497 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1498 }
1499 }
1500
1501
1502 /* Take "ops" - Suggestion by (jawfx@hotmail.com 21/9/98) */
1503 if ( !strncasecmp(MSG, "/op", 3) && (game.command_op>0))
1504 {
1505 valid_param=2;
1506 P=MSG+4;
1507 if (securityread() < 0)
1508 securitywrite();
1509
1510 if ( (strlen(security.op_password) > 0) && !strcmp(P, security.op_password) )
1511 { /* Passed, this player is OP */
1512 n->securitylevel =LEVEL_AUTHOP;
1513 tprintf(n->sock,"pline 0 %cYour security level is now: %cAUTHENTICATED OP\xff", GREEN, RED);
1514 lvprintf(4,"#%s-%s authenticated successfully for op status\n", n->channel->name,n->nick);
1515 }
1516 else
1517 {
1518 tprintf(n->sock,"pline 0 Invalid Password! (Attempt logged)\xff");
1519 lvprintf(1,"#%s-%s Failed attempt to gain OP status\n", n->channel->name, n->nick);
1520 }
1521 }
1522
1523 /* Winlist. Display the top X people - Suggestion by crazor */
1524 if ( !strncasecmp(MSG, "/winlist", 8) && (game.command_winlist>0) )
1525 {
1526 valid_param=2;
1527 if (passed_level(n,game.command_winlist))
1528 {
1529 P=MSG+9;
1530 if (strlen(MSG) == 8)
1531 j=10;
1532 else
1533 j=atoi(P);
1534 if ( (j >= 1) && (j <= MAXWINLIST) )
1535 {
1536 i=0;
1537 tprintf(n->sock,"pline 0 %cTop %d Winlist\xff", BLUE, j);
1538 while ( (i < j) && (winlist[i].inuse) )
1539 {
1540 if (winlist[i].status == 't')
1541 {
1542 if (!strcmp(n->team, winlist[i].name))
1543 k = RED;
1544 else
1545 k = BLACK;
1546 tprintf(n->sock,"pline 0 %c%d. %4d - Team %s\xff", k, i+1, winlist[i].score, winlist[i].name);
1547 }
1548 else
1549 {
1550 if (!strcmp(n->nick, winlist[i].name))
1551 k = RED;
1552 else
1553 k = BLACK;
1554 tprintf(n->sock,"pline 0 %c%d. %4d - Player %s\xff", k, i+1, winlist[i].score, winlist[i].name);
1555 }
1556 i++;
1557 }
1558 }
1559 }
1560 else
1561 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1562 }
1563
1564 if ( !strncasecmp(MSG, "/help", 5) && (game.command_help>0) )
1565 {
1566 valid_param=2;
1567 if (passed_level(n,game.command_help))
1568 {
1569 tprintf(n->sock,"pline 0 V%s.%s - Built in server commands %c(*) %crequires 'op', %c(!) %crequires '/op'\xff", TETVERSION, SERVERBUILD, TEAL, BLACK, RED, BLACK);
1570 if (game.command_clear>0)
1571 {
1572 STRG[0]=0;
1573 switch(game.command_clear)
1574 {
1575 case 2: /* Requires OP */
1576 {
1577 sprintf(STRG,"%c(*)", TEAL);
1578 break;
1579 }
1580 case 3: /* Requires /OP */
1581 {
1582 sprintf(STRG,"%c(!)", RED);
1583 break;
1584 }
1585 }
1586 tprintf(n->sock,"pline 0 %c/clear\xff", RED);
1587 tprintf(n->sock,"pline 0 %-4s %cClears the winlist\xff", STRG, BLACK);
1588 }
1589 if (game.command_join)
1590 {
1591 STRG[0]=0;
1592 switch(game.command_join)
1593 {
1594 case 2: /* Requires OP */
1595 {
1596 sprintf(STRG,"%c(*)", TEAL);
1597 break;
1598 }
1599 case 3: /* Requires /OP */
1600 {
1601 sprintf(STRG,"%c(!)", RED);
1602 break;
1603 }
1604 }
1605 tprintf(n->sock,"pline 0 %c/join %c<#channel|channel number>\xff", RED, BLUE);
1606 tprintf(n->sock,"pline 0 %-4s %cJoins or creates a virtual tetrinet channel\xff", STRG, BLACK);
1607 }
1608 if (game.command_kick)
1609 {
1610 STRG[0]=0;
1611 switch(game.command_kick)
1612 {
1613 case 2: /* Requires OP */
1614 {
1615 sprintf(STRG,"%c(*)", TEAL);
1616 break;
1617 }
1618 case 3: /* Requires /OP */
1619 {
1620 sprintf(STRG,"%c(!)", RED);
1621 break;
1622 }
1623 }
1624 tprintf(n->sock,"pline 0 %c/kick %c<playernumber(s)>\xff", RED, BLUE);
1625 tprintf(n->sock,"pline 0 %-4s %cKicks player(s) from the server\xff", STRG, BLACK);
1626 }
1627 if (game.command_list)
1628 {
1629 STRG[0]=0;
1630 switch(game.command_list)
1631 {
1632 case 2: /* Requires OP */
1633 {
1634 sprintf(STRG,"%c(*)", TEAL);
1635 break;
1636 }
1637 case 3: /* Requires /OP */
1638 {
1639 sprintf(STRG,"%c(!)", RED);
1640 break;
1641 }
1642 }
1643 tprintf(n->sock,"pline 0 %c/list\xff", RED);
1644 tprintf(n->sock,"pline 0 %-4s %cLists available virtual TetriNET channels\xff", STRG, BLACK);
1645 }
1646 tprintf(n->sock,"pline 0 %c/me %c<action>\xff", RED, BLUE);
1647 tprintf(n->sock,"pline 0 Performs an action\xff");
1648 if (game.command_move)
1649 {
1650 STRG[0]=0;
1651 switch(game.command_move)
1652 {
1653 case 2: /* Requires OP */
1654 {
1655 sprintf(STRG,"%c(*)", TEAL);
1656 break;
1657 }
1658 case 3: /* Requires /OP */
1659 {
1660 sprintf(STRG,"%c(!)", RED);
1661 break;
1662 }
1663 }
1664 tprintf(n->sock,"pline 0 %c/move %c<playernumber> <new playernumber>\xff", RED, BLUE);
1665 tprintf(n->sock,"pline 0 %-4s %cMoves a player to a new playernumber\xff", STRG,BLACK);
1666 }
1667
1668 if (game.command_msg)
1669 {
1670 STRG[0]=0;
1671 switch(game.command_msg)
1672 {
1673 case 2: /* Requires OP */
1674 {
1675 sprintf(STRG,"%c(*)", TEAL);
1676 break;
1677 }
1678 case 3: /* Requires /OP */
1679 {
1680 sprintf(STRG,"%c(!)", RED);
1681 break;
1682 }
1683 }
1684 tprintf(n->sock,"pline 0 %c/msg %c<playernumber(s)> <msg>\xff", RED, BLUE);
1685 tprintf(n->sock,"pline 0 %-4s %cPrivately messages player(s)\xff", STRG,BLACK);
1686 }
1687 if (game.command_op)
1688 {
1689 tprintf(n->sock,"pline 0 %c/op %c<op_password>\xff", RED, BLUE);
1690 tprintf(n->sock,"pline 0 Gain AUTHENTICATED OP status\xff");
1691 }
1692 if (game.command_persistant)
1693 {
1694 STRG[0]=0;
1695 switch(game.command_persistant)
1696 {
1697 case 2: /* Requires OP */
1698 {
1699 sprintf(STRG,"%c(*)", TEAL);
1700 break;
1701 }
1702 case 3: /* Requires /OP */
1703 {
1704 sprintf(STRG,"%c(!)", RED);
1705 break;
1706 }
1707 }
1708 tprintf(n->sock,"pline 0 %c/persistant %c<0/1>\xff", RED, BLUE);
1709 tprintf(n->sock,"pline 0 %-4s %cPersistant channels are not deleted when the last person leaves\xff", STRG, BLACK);
1710 }
1711 if (game.command_priority)
1712 {
1713 STRG[0]=0;
1714 switch(game.command_priority)
1715 {
1716 case 2: /* Requires OP */
1717 {
1718 sprintf(STRG,"%c(*)", TEAL);
1719 break;
1720 }
1721 case 3: /* Requires /OP */
1722 {
1723 sprintf(STRG,"%c(!)", RED);
1724 break;
1725 }
1726 }
1727 tprintf(n->sock,"pline 0 %c/priority %c<channel priority(1-99)>\xff", RED, BLUE);
1728 tprintf(n->sock,"pline 0 %-4s %cNew players join the highest priority channel\xff", STRG, BLACK);
1729 }
1730 if (game.command_reset)
1731 {
1732 STRG[0]=0;
1733 switch(game.command_reset)
1734 {
1735 case 2: /* Requires OP */
1736 {
1737 sprintf(STRG,"%c(*)", TEAL);
1738 break;
1739 }
1740 case 3: /* Requires /OP */
1741 {
1742 sprintf(STRG,"%c(!)", RED);
1743 break;
1744 }
1745 }
1746 tprintf(n->sock,"pline 0 %c/reset\xff", RED);
1747 tprintf(n->sock,"pline 0 %-4s %cReload saved game configuration AND persistant channel config\xff", STRG, BLACK);
1748 }
1749 if (game.command_save)
1750 {
1751 STRG[0]=0;
1752 switch(game.command_save)
1753 {
1754 case 2: /* Requires OP */
1755 {
1756 sprintf(STRG,"%c(*)", TEAL);
1757 break;
1758 }
1759 case 3: /* Requires /OP */
1760 {
1761 sprintf(STRG,"%c(!)", RED);
1762 break;
1763 }
1764 }
1765 tprintf(n->sock,"pline 0 %c/save\xff", RED);
1766 tprintf(n->sock,"pline 0 %-4s %cAll game configuration AND persistant channel info is saved\xff", STRG, BLACK);
1767 }
1768 if (game.command_set)
1769 {
1770 STRG[0]=0;
1771 switch(game.command_set)
1772 {
1773 case 2: /* Requires OP */
1774 {
1775 sprintf(STRG,"%c(*)", TEAL);
1776 break;
1777 }
1778 case 3: /* Requires /OP */
1779 {
1780 sprintf(STRG,"%c(!)", RED);
1781 break;
1782 }
1783 }
1784 tprintf(n->sock,"pline 0 %c/set\xff", RED);
1785 tprintf(n->sock,"pline 0 %-4s %cSet Channel Config. Type %c/set %cHELP\xff", STRG, BLACK,BLUE,RED);
1786 }
1787 if (game.command_topic)
1788 {
1789 STRG[0]=0;
1790 switch(game.command_topic)
1791 {
1792 case 2: /* Requires OP */
1793 {
1794 sprintf(STRG,"%c(*)", TEAL);
1795 break;
1796 }
1797 case 3: /* Requires /OP */
1798 {
1799 sprintf(STRG,"%c(!)", RED);
1800 break;
1801 }
1802 }
1803 tprintf(n->sock,"pline 0 %c/topic %c<channel topic>\xff", RED, BLUE);
1804 tprintf(n->sock,"pline 0 %-4s %cChanges the topic of the virtual TetriNET channel\xff", STRG, BLACK);
1805 }
1806 if (game.command_who)
1807 {
1808 STRG[0]=0;
1809 switch(game.command_who)
1810 {
1811 case 2: /* Requires OP */
1812 {
1813 sprintf(STRG,"%c(*)", TEAL);
1814 break;
1815 }
1816 case 3: /* Requires /OP */
1817 {
1818 sprintf(STRG,"%c(!)", RED);
1819 break;
1820 }
1821 }
1822 tprintf(n->sock,"pline 0 %c/who\xff", RED);
1823 tprintf(n->sock,"pline 0 %-4s %cLists all logged in players, and what channel they're on\xff", STRG, BLACK);
1824 }
1825
1826 if (game.command_winlist)
1827 {
1828 STRG[0]=0;
1829 switch(game.command_winlist)
1830 {
1831 case 2: /* Requires OP */
1832 {
1833 sprintf(STRG,"%c(*)", TEAL);
1834 break;
1835 }
1836 case 3: /* Requires /OP */
1837 {
1838 sprintf(STRG,"%c(!)", RED);
1839 break;
1840 }
1841 }
1842 tprintf(n->sock,"pline 0 %c/winlist %c[n]\xff", RED, BLUE);
1843 tprintf(n->sock,"pline 0 %-4s %cDisplays the top n players\xff",STRG,BLACK);
1844 }
1845 }
1846 else
1847 tprintf(n->sock,"pline 0 %cYou do NOT have access to that command!\xff",RED);
1848 }
1849 if (valid_param==1)
1850 {
1851 tprintf(n->sock,"pline 0 %cInvalid /COMMAND!\xff",RED);
1852 }
1853 }
1854 else
1855 {
1856 lvprintf(5,"#%s-%s: %s\n", n->channel->name,n->nick,MSG);
1857 nsock=n->channel->net;
1858 while (nsock!=NULL)
1859 {
1860 if ( (nsock!=n) && (nsock->type == NET_CONNECTED) )
1861 { /* Write line, after first resetting it to black (incase colour still exists from nick) */
1862 tprintf(nsock->sock,"pline %d %c%s\xff", n->gameslot, BLACK, MSG);
1863 }
1864 nsock=nsock->next;
1865 }
1866 }
1867 valid_param=1;
1868 }
1869 }
1870
1871 /* Party Line Act - plineact <playernumber> <message> */
1872 if ( !strcasecmp(COMMAND, "plineact") )
1873 {
1874 valid_param=2;
1875 s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
1876 if ( (s >= 2) && (num==n->gameslot))
1877 {
1878 valid_param=1;
1879 lvprintf(5,"#%s-%s acts: %s\n",n->channel->name,n->nick,MSG);
1880 nsock=n->channel->net;
1881 while (nsock!=NULL)
1882 {
1883 if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
1884 { /* Write out action, after first resetting colors */
1885 tprintf(nsock->sock,"plineact %d %s\xff", n->gameslot, MSG);
1886 }
1887 nsock=nsock->next;
1888 }
1889 }
1890 }
1891
1892
1893 /* Change Team - team <playernumber> <teamname> */
1894 if ( !strcasecmp(COMMAND, "team") )
1895 {
1896 valid_param=2;
1897 s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
1898 if ( (s >= 1) && (num==n->gameslot) && (n->status == STAT_NOTPLAYING))
1899 {
1900 valid_param=1;
1901 strncpy(n->team, MSG, TEAMLEN); n->team[TEAMLEN]=0;
1902 lvprintf(5,"#%s-%s changes team to %s\n",n->channel->name,n->nick,n->team);
1903 nsock=n->channel->net;
1904 while (nsock!=NULL)
1905 {
1906 if ( (n!=nsock) && (nsock->type == NET_CONNECTED) )
1907 tprintf(nsock->sock,"team %d %s\xff", n->gameslot, MSG);
1908 nsock=nsock->next;
1909 }
1910 }
1911 }
1912
1913 /* Pause Game - pause <0|1> <playernumber> */
1914 if ( !strcasecmp(COMMAND, "pause") )
1915 {
1916 valid_param=2;
1917 s = sscanf(PARAM, "%d %d", &num, &num2);
1918 if ( (s >= 2) && is_op(n) && (n->channel->status == STATE_INGAME) && (num2==n->gameslot) && ( (num==0)||(num==1)) )
1919 {
1920 if (num==1)
1921 lvprintf(4,"#%s-%s pauses game\n",n->channel->name,n->nick);
1922 else
1923 lvprintf(5,"#%2-%s unpauses game\n",n->channel->name,n->nick);
1924
1925
1926 valid_param=1;
1927 nsock=n->channel->net;
1928 while(nsock!=NULL)
1929 {
1930 if ( (nsock->type == NET_CONNECTED) && (nsock->channel==n->channel))
1931 tprintf(nsock->sock,"pause %d\xff", num);
1932 nsock=nsock->next;
1933 }
1934 if (num==0)
1935 n->channel->status=STATE_PAUSED;
1936 else
1937 n->channel->status=STATE_INGAME;
1938 }
1939 }
1940
1941 /* Game message - gmsg <message> */
1942 if ( !strcasecmp(COMMAND, "gmsg") )
1943 {
1944 valid_param=1;
1945 /* If it's just "t", then reply PONG to player only*/
1946 sprintf(MSG,"<%s> t", n->nick);
1947 if ( !strcasecmp(MSG, PARAM) && n->channel->pingintercept)
1948 {
1949 tprintf(n->sock,"gmsg * PONG\xff");
1950 }
1951 else
1952 {
1953 /* FIRST, get the NICK, and strip out color codes. Else it looks horrible */
1954 sprintf(MSG,"<%s>", n->nick);
1955 j=0;
1956 if ( PARAM[0] == '<' )
1957 { /* Yep, its a message. So save nick stripped of colour codes in MSG */
1958 j=strlen(MSG);
1959 MSG[0]=0;
1960 P=MSG;
1961 for(i=0;i<j;i++)
1962 {
1963 if ( n->channel->stripcolour
1964 && (PARAM[i] != BOLD)
1965 && (PARAM[i] != CYAN)
1966 && (PARAM[i] != BLACK)
1967 && (PARAM[i] != BLUE)
1968 && (PARAM[i] != DARKGRAY)
1969 && (PARAM[i] != MAGENTA)
1970 && (PARAM[i] != GREEN)
1971 && (PARAM[i] != NEON)
1972 && (PARAM[i] != SILVER)
1973 && (PARAM[i] != BROWN)
1974 && (PARAM[i] != NAVY)
1975 && (PARAM[i] != VIOLET)
1976 && (PARAM[i] != RED)
1977 && (PARAM[i] != ITALIC)
1978 && (PARAM[i] != TEAL)
1979 && (PARAM[i] != WHITE)
1980 && (PARAM[i] != YELLOW)
1981 && (PARAM[i] != UNDERLINE) )
1982 {
1983 *P = PARAM[i];
1984 P++;
1985 }
1986 }
1987 *P='\0';
1988 P=PARAM+j+1;
1989 j=1;
1990 }
1991 lvprintf(5,"#%s-%s: %s\n", n->channel->name,n->nick,PARAM);
1992 nsock=n->channel->net;
1993 while (nsock!=NULL)
1994 {
1995 if ( (nsock->type == NET_CONNECTED) )
1996 {
1997 if (j)
1998 tprintf(nsock->sock,"gmsg %s %s\xff", MSG, P);
1999 else
2000 tprintf(nsock->sock,"gmsg %s\xff", PARAM);
2001 }
2002 nsock=nsock->next;
2003 }
2004 }
2005 }
2006
2007 /* Player Lost - playerlost <playernumber> */
2008 if ( !strcasecmp(COMMAND, "playerlost") )
2009 {
2010 valid_param=2;
2011 s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
2012 if ( (s >= 1) && ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) ) && (num==n->gameslot) )
2013 {
2014 valid_param=1;
2015 /* Now, is this player actually playing? If not, we just ignore them */
2016 if (n->status == STAT_PLAYING)
2017 {
2018 /* Set player to be "Lost" */
2019 n->status = STAT_LOST;
2020 n->timeout = game.timeout_outgame;
2021 lvprintf(6,"#%s-%s lost\n",n->channel->name,n->nick);
2022
2023 num2=0; /* Assume no-one left playing */
2024 num3=0; /* Player who is still in */
2025 MSG[0]=0; /* Store playing team name here */
2026 /* Check if game is finished, and tell each person this player has lost */
2027 nsock=n->channel->net;
2028 ns1=NULL;
2029 while (nsock!=NULL)
2030 {
2031 if ( (nsock!=n) && (nsock->type == NET_CONNECTED) && (nsock->status == STAT_PLAYING))
2032 {
2033 tprintf(nsock->sock,"playerlost %d\xff",num);
2034 if (strcasecmp(MSG,nsock->team))
2035 { /* Different team, so add player */
2036 num2++;
2037 ns1=nsock;
2038 strcpy(MSG,nsock->team);
2039 }
2040 else if (MSG[0]==0)
2041 {
2042 num2++;
2043 ns1=nsock;
2044 }
2045 }
2046 nsock=nsock->next;
2047 }
2048 if ( (num2 <= 1) && (ns1!=NULL) )
2049 { /* 1 or less different teams playing. Stop the game, and take score */
2050 if (ns1->type == NET_CONNECTED)
2051 {
2052 if (strlen(ns1->team) > 0)
2053 { /* Team won, so add score to team */
2054 updatewinlist(ns1->team,'t',3);
2055 }
2056 else
2057 { /* Player won, so add score to player name */
2058 updatewinlist(ns1->nick,'p',3);
2059 }
2060 }
2061 n->channel->status=STATE_ONLINE;
2062 nsock=n->channel->net;
2063 while (nsock!=NULL)
2064 {
2065 if ( (nsock->type == NET_CONNECTED))
2066 {
2067 tprintf(nsock->sock,"endgame\xff");
2068 tprintf(nsock->sock,"playerwon %d\xff", ns1->gameslot);
2069 nsock->status=STAT_NOTPLAYING;
2070 nsock->timeout=game.timeout_outgame;
2071 /* Send every playing field */
2072
2073 ns2=n->channel->net;
2074 while (ns2!=NULL)
2075 {
2076 if ( (ns2!=nsock) && (ns2->type == NET_CONNECTED))
2077 sendfield(nsock,ns2);
2078 ns2=ns2->next;
2079 }
2080
2081 /*!!! ADD-IN: Server anounces winner */
2082 if ( (ns1->type == NET_CONNECTED) && n->channel->serverannounce)
2083 {
2084 if ( strlen(ns1->team) > 0)
2085 { /* a team won */
2086 tprintf(nsock->sock,"pline 0 ---- Team %s%c WON ----\xff", ns1->team, BLACK);
2087 }
2088 else
2089 { /* a player won */
2090 tprintf(nsock->sock,"pline 0 ---- Player %s%c WON ----\xff", ns1->nick, BLACK);
2091 }
2092 }
2093 }
2094 nsock=nsock->next;
2095 }
2096 writewinlist();
2097 sendwinlist(n->channel,NULL); /* Send to all */
2098
2099 }
2100
2101 }
2102
2103 }
2104 }
2105
2106 /* Field Update - f <field codes> */
2107 if ( !strcasecmp(COMMAND, "f") )
2108 {
2109 valid_param=2;
2110 s = sscanf(PARAM, "%d %600[^\n\r]", &num, MSG);
2111 if ( (s >= 1) && (num==n->gameslot))
2112 {
2113 valid_param=1;
2114 /* First, transmit these changes as is to all other players */
2115 nsock=n->channel->net;
2116 while (nsock!=NULL)
2117 {
2118 if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
2119 tprintf(nsock->sock,"f %d %s\xff", n->gameslot, MSG);
2120 nsock=nsock->next;
2121 }
2122
2123 /* Now parse it ourselves, and update our internal knowledge of players field */
2124 parsefield(n, MSG);
2125 }
2126 }
2127
2128 /* Level - lvl <playernumber> <current level> */
2129 if ( !strcasecmp(COMMAND, "lvl") )
2130 {
2131 valid_param=2;
2132 s = sscanf(PARAM, "%d %d", &num, &num2);
2133 if ( (n->channel->status==STATE_INGAME) && (num==n->gameslot) && (n->status == STAT_PLAYING) )
2134 {
2135 valid_param=1;
2136 nsock=n->channel->net;
2137 while (nsock!=NULL)
2138 {
2139 if ( (nsock->type == NET_CONNECTED))
2140 tprintf(nsock->sock,"lvl %d %d\xff", n->gameslot,num2);
2141 nsock=nsock->next;
2142 }
2143 }
2144 }
2145
2146 /* Special Block Use - sb <to use on,0=all> <special block> <playernum> */
2147 if ( !strcasecmp(COMMAND, "sb") )
2148 {
2149 valid_param=2;
2150 s = sscanf(PARAM, "%d %s %d", &num, MSG, &num2);
2151 if ( (s >= 3) && (n->channel->status == STATE_INGAME) && (num2==n->gameslot) && (n->status == STAT_PLAYING))
2152 {
2153 valid_param=1;
2154 nsock=n->channel->net;
2155 while (nsock!=NULL)
2156 {
2157 if ( (nsock!=n) && (nsock->type == NET_CONNECTED) )
2158 {
2159 tprintf(nsock->sock,"sb %d %s %d\xff", num, MSG, n->gameslot);
2160 }
2161 nsock=nsock->next;
2162 }
2163 }
2164 }
2165
2166 /* Start/Stop Game - startgame <0/1, 0=stopgame> <playernumber> */
2167 if ( !strcasecmp(COMMAND, "startgame") )
2168 {
2169 valid_param=2;
2170 s = sscanf(PARAM, "%d %d %600[^\n\r]", &num, &num2, MSG);
2171 if ( (s >= 2) && is_op(n) && ( ((num==1) && (n->channel->status == STATE_ONLINE)) || ((num==0) && (n->channel->status == STATE_INGAME)) ) && (num2==n->gameslot) && ( (num == 1) || (num == 0)) )
2172 {
2173 valid_param=1;
2174 if (num==1)
2175 {
2176 n->channel->status = STATE_INGAME;
2177 lvprintf(4,"#%s-%s started the game\n", n->channel->name,n->nick);
2178 }
2179 else
2180 {
2181 n->channel->status = STATE_ONLINE;
2182 lvprintf(4,"#%s-%s stopped the game\n", n->channel->name,n->nick);
2183 n->channel->sd_mode=SD_NONE;
2184 }
2185
2186 /* Read in Game config and winlist, in case they were changed */
2187 /* gameread();*/
2188 readwinlist();
2189
2190 /* Set the SuddenDeath timeout, if any */
2191 if (n->channel->sd_timeout>0)
2192 {
2193 n->channel->sd_mode=SD_INIT;
2194 n->channel->sd_timeleft=n->channel->sd_timeout;
2195 }
2196 nsock=n->channel->net;
2197 while (nsock!=NULL)
2198 {/* Send to every player the game parameters */
2199 if ( (nsock->type == NET_CONNECTED))
2200 {
2201 if (num == 1) /* Start game */
2202 {
2203
2204 tprintf(nsock->sock,"newgame 0 ");
2205 tprintf(nsock->sock,"%d %d %d %d %d %d ",
2206 n->channel->starting_level, n->channel->lines_per_level,
2207 n->channel->level_increase, n->channel->lines_per_special,
2208 n->channel->special_added, n->channel->special_capacity);
2209 for(j=0;j<n->channel->block_leftl;j++) tprintf(nsock->sock,"3");
2210 for(j=0;j<n->channel->block_leftz;j++) tprintf(nsock->sock,"5");
2211 for(j=0;j<n->channel->block_square;j++)tprintf(nsock->sock,"2");
2212 for(j=0;j<n->channel->block_rightl;j++)tprintf(nsock->sock,"4");
2213 for(j=0;j<n->channel->block_rightz;j++)tprintf(nsock->sock,"6");
2214 for(j=0;j<n->channel->block_halfcross;j++) tprintf(nsock->sock,"7");
2215 for(j=0;j<n->channel->block_line;j++) tprintf(nsock->sock,"1");
2216 tprintf(nsock->sock," ");
2217 for(j=0;j<n->channel->special_addline;j++) tprintf(nsock->sock,"1");
2218 for(j=0;j<n->channel->special_clearline;j++) tprintf(nsock->sock,"2");
2219 for(j=0;j<n->channel->special_nukefield;j++) tprintf(nsock->sock,"3");
2220 for(j=0;j<n->channel->special_randomclear;j++) tprintf(nsock->sock,"4");
2221 for(j=0;j<n->channel->special_switchfield;j++) tprintf(nsock->sock,"5");
2222 for(j=0;j<n->channel->special_clearspecial;j++) tprintf(nsock->sock,"6");
2223 for(j=0;j<n->channel->special_gravity;j++) tprintf(nsock->sock,"7");
2224 for(j=0;j<n->channel->special_quakefield;j++) tprintf(nsock->sock,"8");
2225 for(j=0;j<n->channel->special_blockbomb;j++) tprintf(nsock->sock,"9");
2226 tprintf(nsock->sock," %d %d\xff", n->channel->average_levels, n->channel->classic_rules);
2227
2228 /* And set them to be playing */
2229 nsock->status = STAT_PLAYING;
2230
2231 /* Give them new timeouts */
2232 nsock->timeout = game.timeout_ingame;
2233
2234 /* BLANK *ALL* the fields and send them to each player */
2235 /* Clear their Field */
2236 for(y=0;y<FIELD_MAXY;y++)
2237 for(x=0;x<FIELD_MAXX;x++)
2238 nsock->field[x][y]=0; /* Nothing */
2239
2240 /* Send to every other player */
2241 ns1=n->channel->net;
2242 while (ns1!=NULL)
2243 {
2244 if ( (ns1!=nsock) && (ns1->type==NET_CONNECTED) )
2245 {
2246 sendfield(ns1,nsock);
2247 }
2248 ns1=ns1->next;
2249 }
2250 }
2251 else /* End Game */
2252 {
2253 tprintf(nsock->sock,"endgame\xff");
2254 /* And set them to not be playing */
2255 nsock->status = STAT_NOTPLAYING;
2256 nsock->timeout = game.timeout_outgame;
2257 }
2258 }
2259 nsock=nsock->next;
2260 }
2261 }
2262 }
2263
2264
2265
2266 /* Log invalid params */
2267 if (valid_param==0)
2268 lvprintf(1,"#%s-%s - Invalid Command - %s\n", n->channel->name,n->nick, buf);
2269 }
2270
2271 /* The player has sent their inital team name, well they should have anyway */
net_waitingforteam(struct net_t * n,char * buf)2272 void net_waitingforteam(struct net_t *n, char *buf)
2273 {
2274 FILE *file_in;
2275 char strg[1024];
2276 char *P;
2277 struct net_t *nsock;
2278
2279 sprintf(strg,"team %d ",n->gameslot);
2280 if (strncmp(buf,strg,strlen(strg)))
2281 { /* Incorrect, Kill this player, they never existed ;) */
2282 lvprintf(1,"Incorrect TEAM statement - %s!\n",buf);
2283 killsock(n->sock); lostnet(n);
2284 return;
2285 }
2286
2287 P=buf+strlen(strg);
2288 n->type=NET_CONNECTED;
2289 n->status=STAT_NOTPLAYING;
2290 strncpy(n->team, P, TEAMLEN); n->team[TEAMLEN]='\0';
2291
2292 nsock=n->channel->net;
2293 while (nsock!=NULL)
2294 {
2295 if ( (nsock != n) && (nsock->type==NET_CONNECTED))
2296 {
2297 /* Send each other player and their team to this player */
2298 tprintf(n->sock, "playerjoin %d %s\xffteam %d %s\xff", nsock->gameslot, nsock->nick, nsock->gameslot, nsock->team);
2299
2300 /* Send to the other player, this player and their team */
2301 tprintf(nsock->sock, "playerjoin %d %s\xffteam %d %s\xff", n->gameslot, n->nick, n->gameslot, n->team);
2302 }
2303 nsock=nsock->next;
2304 }
2305
2306 /* Now for the game.motd if it exists. */
2307 file_in = fopen(FILE_MOTD,"r");
2308 if (file_in != NULL)
2309 {/* Exists, so send it to the player */
2310 while (!feof(file_in))
2311 {
2312 fscanf(file_in,"%1023[^\n]\n", strg);
2313 tprintf(n->sock,"pline 0 %s\xff", strg);
2314 }
2315 fclose(file_in);
2316 }
2317
2318 /* If game is in progress, send all other players fields */
2319 /* Tell each other player that we are lost... no really :P */
2320 if( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
2321 {
2322 nsock=n->channel->net;
2323 while (nsock!=NULL)
2324 {
2325 if( (nsock->type==NET_CONNECTED) &&(nsock!=n) )
2326 {
2327 /* Each player who has lost, send player_lost */
2328 if (nsock->status != STAT_PLAYING)
2329 {
2330 tprintf(n->sock,"playerlost %d\xff", nsock->gameslot);
2331 }
2332 sendfield(n, nsock); /* Send to player, this players field */
2333
2334 /* And tell this player that the newjoined player has lost */
2335 tprintf(nsock->sock,"playerlost %d\xff", n->gameslot);
2336 }
2337 nsock=nsock->next;
2338 }
2339 }
2340
2341 /* If we are ingame, then tell this person that we are! */
2342 if ( (n->channel->status == STATE_INGAME) || (n->channel->status == STATE_PAUSED) )
2343 tprintf(n->sock,"ingame\xff");
2344
2345 /* If we are currently paused, kindly let them know that fact to */
2346 if ( n->channel->status == STATE_PAUSED )
2347 tprintf(n->sock,"pause 1\xff");
2348
2349 /* And tell them their channel */
2350 tprintf(n->sock,"pline 0 %c%s%c %chas joined channel #%s\xff", GREEN,n->nick,BLACK,GREEN,n->channel->name);
2351
2352 lvprintf(2,"#%s-%s New connection\n", n->channel->name,n->nick);
2353 }
2354
2355 /* Recieving Query commands */
net_query_init(struct net_t * n,char * buf)2356 void net_query_init(struct net_t *n, char *buf)
2357 {
2358 killsock(n->sock);lostnet(n);
2359 return;
2360 }
2361
2362 /* The person has sent their init string */
net_telnet_init(struct net_t * n,char * buf)2363 void net_telnet_init(struct net_t *n, char *buf)
2364 {
2365 int gameslot,found,i;
2366 int tet_err;
2367 char *dec;
2368 struct channel_t *chan;
2369 struct net_t *nsock;
2370
2371 /* Work out game slot */
2372 gameslot=0; found=1;
2373 while ( (gameslot < n->channel->maxplayers) && (found) )
2374 {
2375 gameslot++;
2376 found=0;
2377 nsock=n->channel->net;
2378 while (nsock!=NULL)
2379 {
2380 if( ( (nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock->gameslot==gameslot) ) found=1;
2381 nsock=nsock->next;
2382 }
2383 }
2384
2385 if (found)
2386 { /* No free Gameslots, so tell that the server is full!! */
2387 tprintf(n->sock,"noconnecting Server is Full!\xff");
2388 lvprintf(9,"%s: Disconnected because of FULL server.\n",n->host);
2389 killsock(n->sock); lostnet(n); return;
2390 }
2391
2392 /* Set Game Socket */
2393 n->gameslot = gameslot;
2394
2395 lvprintf(10,"INIT: %s\n", buf);
2396
2397 /* If init string is in fact "playerquery", return number of logged in players, and kill them */
2398 if (!strcasecmp(buf, "playerquery"))
2399 {
2400 lvprintf(9,"%s: Playerquery request\n",n->host);
2401 tprintf(n->sock, "Number of players logged in: %d\n", numplayers(n->channel));
2402 return;
2403 }
2404
2405 /* Version - Return Full version of server */
2406 if (!strcasecmp(buf, "version"))
2407 {
2408 lvprintf(9,"%s: Version request\n",n->host);
2409 tprintf(n->sock,"%s.%s\n+OK\n", TETVERSION, SERVERBUILD);
2410 return;
2411 }
2412
2413 /* ListChan - List of all channels */
2414 if (!strcasecmp(buf, "listchan"))
2415 {
2416 lvprintf(9,"%s: ListChan request\n",n->host);
2417 chan=chanlist;
2418 while(chan!=NULL)
2419 {
2420 tprintf(n->sock,"\"%s\" \"%s\" %d %d %d %d\n",chan->name, chan->description, numplayers(chan), chan->maxplayers, chan->priority, chan->status);
2421 chan=chan->next;
2422 }
2423 tprintf(n->sock,"+OK\n");
2424 return;
2425 }
2426
2427 /* Listuser - List of all users */
2428 if (!strcasecmp(buf,"listuser"))
2429 {
2430 lvprintf(9,"%s: ListUser request\n",n->host);
2431 chan=chanlist;
2432 while (chan!=NULL)
2433 {
2434 nsock=chan->net;
2435 while (nsock!=NULL)
2436 {
2437 if(nsock->type==NET_CONNECTED)
2438 {
2439 tprintf(n->sock,"\"%s\" \"%s\" \"%s\" %d %d %d \"%s\"\n",nsock->nick, nsock->team, nsock->version,nsock->gameslot,nsock->status,nsock->securitylevel,nsock->channel->name);
2440 }
2441 nsock=nsock->next;
2442 }
2443 chan=chan->next;
2444 }
2445 tprintf(n->sock,"+OK\n");
2446 return;
2447 }
2448
2449 /* Winlist - Returns Winlist */
2450 if (!strcasecmp(buf,"getwinlist"))
2451 {
2452 lprintf("%s: GetWinlist request\n",n->host);
2453 for(i=0;i<MAXWINLIST;i++)
2454 {
2455 if(winlist[i].inuse)
2456 {
2457 tprintf(n->sock,"\"%s\" %c %lu\n", winlist[i].name,winlist[i].status,winlist[i].score);
2458 }
2459 }
2460 tprintf(n->sock,"+OK\n");
2461 return;
2462 }
2463
2464 if (strlen(buf) < 7)
2465 {/* Invalid... quit */
2466 lvprintf(9,"%s: Disconnected due to invalid command (This can be normal)\n",n->host);
2467 killsock(n->sock);lostnet(n);
2468 return;
2469
2470 }
2471
2472
2473
2474 tet_err = tet_decrypt(buf);
2475 if (tet_err != 0)
2476 { /* Error */
2477 lvprintf(9,"%s: Disconnected due to failed decryption: %s\n",n->host,buf);
2478 killsock(n->sock); lostnet(n);
2479 return;
2480 }
2481
2482 dec = tet_dec2str(buf);
2483
2484 lvprintf(10,"DECR: %s\n", dec);
2485
2486 /* OK, so dec should now hold "tetrisstart <nickname> <version number> */
2487 i = sscanf(dec,"tetrisstart %30[^\x20] %10s", n->nick, n->version);
2488
2489
2490 if (i < 2)
2491 {/* To few conversions - Player dies*/
2492 lvprintf(9,"%s: Disconnected due to invalid tetrisstart: %s\n",n->host,dec);
2493 killsock(n->sock); lostnet(n);
2494 }
2495
2496 /* Ensure a valid nickname */
2497 if (!strcasecmp(n->nick,"server"))
2498 {
2499 lvprintf(9,"%s Disconnected due to invalid nickname: %s\n",n->host,n->nick);
2500 tprintf(n->sock, "noconnecting Nickname %s not allowed!\xff", n->nick);
2501 killsock(n->sock); lostnet(n);
2502 }
2503
2504 /* Ensure that Version is OK */
2505 if (tet_checkversion(n->version) == -1)
2506 {
2507 tprintf(n->sock, "noconnecting TetriNET version (%s) does not match Server's (%s)!\xff", n->version, TETVERSION);
2508 lvprintf(9,"%s: Client version (%s) not allowed!\n", n->nick, n->version);
2509 killsock(n->sock); lostnet(n);
2510 return;
2511 }
2512
2513 /* Ensure that no-one else has this nick */
2514 found=0;
2515 chan=chanlist;
2516 while( (chan!=NULL) && !found)
2517 {
2518 nsock=chan->net;
2519 while ((nsock!=NULL) && !found)
2520 {
2521 if( ((nsock->type==NET_CONNECTED) || (nsock->type==NET_WAITINGFORTEAM) )&&(nsock!=n)&&(!strcasecmp(nsock->nick, n->nick)) ) found=1;
2522 nsock=nsock->next;
2523 }
2524 chan=chan->next;
2525 }
2526 if (found)
2527 {
2528 tprintf(n->sock, "noconnecting Nickname already exists on server!\xff");
2529 lvprintf(9,"%s: Disconnected since nickname already exists on server: %s\n",n->host,n->nick);
2530 killsock(n->sock); lostnet(n);
2531 return;
2532 }
2533
2534 n->team[0] = 0; /* Clear Team */
2535
2536 /* Now waiting for team */
2537 n->type = NET_WAITINGFORTEAM;
2538
2539 /* Send Winlist to this new arrival */
2540 sendwinlist(n->channel,n);
2541
2542 /* Send them their player number */
2543 tprintf(n->sock, "playernum %d\xff",gameslot);
2544
2545
2546 }
2547
2548 /* Someone has just connected. So lets answer them */
net_telnet(struct net_t * n,char * buf)2549 void net_telnet(struct net_t *n, char *buf)
2550 {
2551 unsigned long ip; int k,l; char s[121]; char strg[121];
2552 char n1[4], n2[4], n3[4], n4[4];
2553 struct channel_t *chan, *ochan;
2554 struct net_t *net;
2555 int x,y;
2556
2557
2558 net=malloc(sizeof(struct net_t));
2559 net->next=NULL;
2560
2561 net->sock=answer(n->sock,s,&ip,0);
2562
2563 while ((net->sock==(-1)) && (errno==EAGAIN))
2564 net->sock=answer(n->sock,s,&ip,0);
2565 /* Find a channel */
2566 chan = chanlist;
2567 ochan = NULL;
2568 while ( chan != NULL )
2569 {
2570 if ( ((ochan == NULL) || (chan->priority > ochan->priority)) && (numplayers(chan) < chan->maxplayers) && (chan->priority!=0))
2571 ochan=chan; /* Found a likely channel */
2572 chan=chan->next;
2573 }
2574
2575
2576 /* Save the port stuff */
2577 net->addr=ip;
2578 net->port=n->port;
2579 net->timeout=game.timeout_outgame;
2580 net->securitylevel=LEVEL_NORMAL;
2581 net->status=STAT_NOTPLAYING;
2582 sprintf(net->host,"%s", s);
2583 if (strlen(s) == 0)
2584 { /* No resolved host... copy IP */
2585 sprintf(n1,"%lu", (unsigned long)(n->addr&0xff000000)/(unsigned long)0x1000000);
2586 sprintf(n2,"%lu", (unsigned long)(n->addr&0x00ff0000)/(unsigned long)0x10000);
2587 sprintf(n3,"%lu", (unsigned long)(n->addr&0x0000ff00)/(unsigned long)0x100);
2588 sprintf(n4,"%lu", (unsigned long)n->addr&0x000000ff);
2589 sprintf(net->host,"%s.%s.%s.%s",n1,n2,n3,n4);
2590 }
2591
2592
2593
2594 if(net->sock <0)
2595 {
2596 lvprintf(4,"Failed TELNET incoming connection from %s", s);
2597 killsock(net->sock);
2598 free(net);
2599 return;
2600 }
2601
2602 /* Is this person banned? */
2603 if (is_banned(net))
2604 {
2605 tprintf(net->sock,"noconnecting You are banned from server!\xff");
2606 killsock(net->sock);
2607 free(net);
2608 return;
2609 }
2610
2611 if (ochan == NULL)
2612 { /* No channels found, so create a new one :P */
2613 if (numchannels() < game.maxchannels)
2614 {
2615 chan=chanlist;
2616 while ( (chan!=NULL) && (chan->next!=NULL) ) chan=chan->next;
2617
2618
2619 if (chan==NULL)
2620 {
2621 chanlist = malloc(sizeof(struct channel_t));
2622 chan=chanlist;
2623 }
2624 else
2625 {
2626 chan->next = malloc(sizeof(struct channel_t));
2627 chan=chan->next;
2628 }
2629
2630 chan->next=NULL;
2631 chan->net=NULL;
2632
2633
2634
2635 chan->maxplayers=DEFAULTMAXPLAYERS;
2636 chan->status=STATE_ONLINE;
2637 chan->description[0]=0;
2638 chan->priority=DEFAULTPRIORITY;
2639 chan->sd_mode=SD_NONE;
2640 chan->persistant=0;
2641
2642 /* Copy default settings */
2643 chan->starting_level=game.starting_level;
2644 chan->lines_per_level=game.lines_per_level;
2645 chan->level_increase=game.level_increase;
2646 chan->lines_per_special=game.lines_per_special;
2647 chan->special_added=game.special_added;
2648 chan->special_capacity=game.special_capacity;
2649 chan->classic_rules=game.classic_rules;
2650 chan->average_levels=game.average_levels;
2651 chan->sd_timeout=game.sd_timeout;
2652 chan->sd_lines_per_add=game.sd_lines_per_add;
2653 chan->sd_secs_between_lines=game.sd_secs_between_lines;
2654 strcpy(chan->sd_message,game.sd_message);
2655 chan->block_leftl=game.block_leftl;
2656 chan->block_leftz=game.block_leftz;
2657 chan->block_square=game.block_square;
2658 chan->block_rightl=game.block_rightl;
2659 chan->block_rightz=game.block_rightz;
2660 chan->block_halfcross=game.block_halfcross;
2661 chan->block_line=game.block_line;
2662 chan->special_addline=game.special_addline;
2663 chan->special_clearline=game.special_clearline;
2664 chan->special_nukefield=game.special_nukefield;
2665 chan->special_randomclear=game.special_randomclear;
2666 chan->special_switchfield=game.special_switchfield;
2667 chan->special_clearspecial=game.special_clearspecial;
2668 chan->special_gravity=game.special_gravity;
2669 chan->special_quakefield=game.special_quakefield;
2670 chan->special_blockbomb=game.special_blockbomb;
2671 chan->stripcolour=game.stripcolour;
2672 chan->serverannounce=game.serverannounce;
2673 chan->pingintercept=game.pingintercept;
2674
2675
2676 k=0;l=1;
2677 while (l)
2678 {
2679 k++;
2680 ochan=chanlist;
2681 if (k==1)
2682 {
2683 sprintf(strg,"%s", DEFAULTCHANNEL);
2684 strncpy(chan->name,strg,CHANLEN-1); chan->name[CHANLEN-1]=0;
2685 }
2686 else
2687 {
2688 sprintf(strg,"%s%d", DEFAULTCHANNEL,k);
2689 strncpy(chan->name,strg,CHANLEN-1); chan->name[CHANLEN-1]=0;
2690 }
2691 l=0;
2692 while( (ochan != NULL) && (!l) )
2693 {
2694 if ( (!strcasecmp(chan->name,ochan->name)) && (chan!=ochan))
2695 l=1;
2696 else
2697 ochan=ochan->next;
2698 }
2699 }
2700
2701 }
2702 else
2703 {
2704 lvprintf(4,"Server FULL - Denying\n");
2705 tprintf(net->sock,"noconnecting Server is Full!\xff");
2706 killsock(net->sock);
2707 free(net);
2708 return;
2709 }
2710 }
2711 else
2712 {
2713 chan=ochan; /* Found a channel */
2714 }
2715 net->channel = chan;
2716 addnet(chan,net);
2717
2718 net->type=NET_TELNET_INIT;
2719 strcpy(net->nick,"???");
2720
2721 /* Clear their Field */
2722 for(y=0;y<FIELD_MAXY;y++)
2723 for(x=0;x<FIELD_MAXX;x++)
2724 net->field[x][y]=0; /* Nothing */
2725
2726 lvprintf(9,"Incoming Telnet connection: %s\n", net->host);
2727 /* Now we wait for the client init string */
2728 }
2729
2730
2731
2732 /* Someone has just connected. So lets answer them */
net_query(struct net_t * n,char * buf)2733 void net_query(struct net_t *n, char *buf)
2734 {
2735 }
2736
lostnet(struct net_t * n)2737 void lostnet(struct net_t *n)
2738 {
2739 int found,playing;
2740 char MSG[TEAMLEN+4];
2741 struct net_t *nsock;
2742
2743 struct channel_t *chan,*ochan;
2744
2745 /* Log the lost connection */
2746 if (n->type == NET_CONNECTED)
2747 {
2748
2749 lvprintf(4,"#%s-%s Lost telnet connection from %s\n", n->channel->name, n->nick, n->host);
2750 }
2751 /* Inform all other active players this one has left iff this one was connected "properly"! */
2752 if ( n->type == NET_CONNECTED )
2753 {
2754 playing=0;
2755 found=0;/* Number of different teams/players playing */
2756 MSG[0]=0; /* Store playing team name here */
2757 nsock=n->channel->net;
2758 while (nsock!=NULL)
2759 {
2760 if ( (nsock!=n) && (nsock->type == NET_CONNECTED) )
2761 { /* Different player, connected, in same channel */
2762 tprintf(nsock->sock,"playerleave %d\xff", n->gameslot);
2763
2764 if (strcasecmp(MSG,nsock->team))
2765 {/* Different team, so add player */
2766 found++;
2767 if (nsock->status == STAT_PLAYING) playing++;
2768 strcpy(MSG,nsock->team);
2769 }
2770 else if (MSG[0]==0)
2771 {
2772 found++;
2773 if (nsock->status == STAT_PLAYING) playing++;
2774 }
2775 }
2776 nsock=nsock->next;
2777 }
2778
2779 /* If 1 or less players/teams now are playing, AND the player that quit WAS playing, STOPIT */
2780 if ( (playing <= 1) && (n->channel->status == STATE_INGAME) && (n->status == STAT_PLAYING) )
2781 {
2782 nsock=n->channel->net;
2783 while (nsock!=NULL)
2784 {
2785 if ( (nsock!=n) && (nsock->type == NET_CONNECTED))
2786 {
2787 tprintf(nsock->sock,"endgame\xff");
2788 nsock->status=STAT_NOTPLAYING;
2789 nsock->timeout=game.timeout_outgame;
2790 }
2791 nsock=nsock->next;
2792 }
2793 n->channel->status = STATE_ONLINE;
2794 }
2795 }
2796
2797 /* If we're the only numplayers players, then we delete the channel */
2798 if ( (numallplayers(n->channel)==1) && (!n->channel->persistant) )
2799 {
2800 chan=chanlist;
2801 ochan=NULL;
2802 while ( (chan != n->channel) && (chan != NULL) )
2803 {
2804 ochan=chan;
2805 chan=chan->next;
2806 }
2807 if (chan != NULL)
2808 {
2809 if (ochan != NULL)
2810 ochan->next=chan->next;
2811 else
2812 chanlist=chan->next;
2813 free(chan);
2814 }
2815 }
2816 else
2817 remnet(n->channel,n);
2818
2819 free(n);
2820 }
2821
net_eof(int z)2822 void net_eof(int z)
2823 {
2824 struct channel_t *chan;
2825 struct net_t *nsock;
2826
2827 nsock=NULL;
2828 chan=chanlist;
2829 while ( (chan!=NULL) && (nsock==NULL))
2830 {
2831 nsock=chan->net;
2832 while ((nsock!=NULL) && (nsock->sock!=z))
2833 {
2834 nsock=nsock->next;
2835 }
2836 chan=chan->next;
2837 }
2838 if (nsock==NULL)
2839 {
2840 lvprintf(3,"Socket(%d): EOF on unknown socket\n",z);
2841 close(z); killsock(z);
2842 return;
2843 }
2844
2845
2846 killsock(z); lostnet(nsock);
2847 }
2848
got_term(int z)2849 void got_term(int z)
2850 {
2851 struct net_t *nsock;
2852 struct channel_t *chan;
2853
2854 lvprintf(1,"Got TERM Signal - Quitting\n");
2855 /* Kill all our socks */
2856 nsock=NULL;
2857 chan=chanlist;
2858 while (chan!=NULL)
2859 {
2860 nsock=chan->net;
2861 while (nsock!=NULL)
2862 {
2863 if (nsock->type != NET_FREE)
2864 {
2865 killsock(nsock->sock);
2866 lostnet(nsock);
2867 }
2868 nsock=nsock->next;
2869 }
2870 chan=chan->next;
2871 }
2872
2873 /* Write winlist etc... */
2874 writewinlist();
2875
2876 /* Remove PID */
2877 delpid();
2878
2879 /* Done */
2880 exit(0);
2881 }
2882
init_main(void)2883 void init_main(void)
2884 {
2885 struct sigaction sv;
2886
2887 lvprintf(0,"\nTetriNET for Linux V%s.%s\n---------------------------------\n", TETVERSION, SERVERBUILD);
2888
2889
2890 gnet=NULL;
2891 chanlist=NULL;
2892
2893 /* set up error traps: We DON'T want Broken pipes!!! In fact, what the hell ARE broken pipes anyway. */
2894 sv.sa_handler=SIG_IGN; sigaction(SIGPIPE,&sv,NULL);
2895
2896 /* We want to shut down cleanly */
2897 sv.sa_handler=got_term; sigaction(SIGTERM,&sv,NULL);
2898
2899
2900
2901 }
2902
check_timeouts(void)2903 void check_timeouts(void)
2904 {
2905 struct net_t *n;
2906 struct channel_t *chan;
2907 int found,i;
2908
2909
2910 found=0;
2911 chan=chanlist;
2912 while ( (chan!=NULL) )
2913 {
2914 n=chan->net;
2915 while ( (n!=NULL) && !found)
2916 {
2917 if (n->timeout > 0) n->timeout--;
2918 if (!n->timeout)
2919 { /* Timeout has occurred */
2920
2921 switch (n->type)
2922 {
2923 case NET_TELNET_INIT:
2924 case NET_WAITINGFORTEAM:
2925 case NET_CONNECTED:
2926 case NET_QUERY_INIT:
2927 {
2928 lvprintf(4,"#%s-%s: Timed out!\n", n->channel->name,n->nick);
2929 tprintf(n->sock,"pline 0 %cYou have timed out! Disconnecting!\xff",RED);
2930 killsock(n->sock);
2931 lostnet(n);
2932 found=1;
2933 break;
2934 }
2935 }
2936 }
2937 if (!found) n=n->next;
2938 }
2939 if (!found)
2940 chan=chan->next;
2941 else
2942 {
2943 chan=chanlist;
2944 found=0;
2945 }
2946 }
2947
2948 /* Sudden Death Timeouts */
2949 chan=chanlist;
2950 while (chan!=NULL)
2951 {
2952 if ( (chan->status==STATE_INGAME) && (chan->sd_mode!=SD_NONE) )
2953 {
2954 chan->sd_timeleft--;
2955 if(chan->sd_timeleft <=0)
2956 {/* Timeout */
2957 n=chan->net;
2958 while(n!=NULL)
2959 {
2960 if ((n->type==NET_CONNECTED) )
2961 {
2962 if (chan->sd_mode==SD_INIT)
2963 {
2964 tprintf(n->sock,"gmsg %s\xff",n->channel->sd_message);
2965 }
2966 else
2967 {
2968 for(i=0;i<n->channel->sd_lines_per_add;i++)
2969 tprintf(n->sock,"sb 0 a 0\xff");
2970 }
2971 }
2972 n=n->next;
2973 }
2974 chan->sd_timeleft=chan->sd_secs_between_lines;
2975 chan->sd_mode=SD_WAIT;
2976 }
2977 }
2978 chan=chan->next;
2979 }
2980 }
2981
2982
2983
main(int argc,char * argv[])2984 int main(int argc, char *argv[])
2985 {
2986 int xx;
2987 char buf[1050];
2988 int buf_len;
2989 int forknum;
2990 long int timeticks, otimeticks;
2991
2992
2993 /* Initialise */
2994 init_main();
2995 init_game();
2996 init_net();
2997 init_telnet_port();
2998 /*init_query_port();*/
2999 init_winlist();
3000 init_security();
3001 readwinlist();
3002
3003 if (securityread() < 0)
3004 securitywrite();
3005
3006 /* Now fork out, and start a new process group */
3007 /* Fork. If we are the parent, quit, if child, continue */
3008 if ((forknum=fork()) == -1)
3009 {
3010 printf("Error: Unable to fork new process\n");
3011 exit(5);
3012 }
3013 if (forknum > 0)
3014 {
3015 exit(0);
3016 }
3017 setsid();
3018
3019 /* Close all stdio */
3020 close(0);
3021 close(1);
3022 close(2);
3023
3024 /* Write out PID */
3025 writepid();
3026
3027 /* Reset time */
3028 timeticks = time(NULL);
3029 otimeticks = timeticks;
3030
3031 while (1)
3032 {
3033
3034 timeticks=time(NULL);
3035 if ((timeticks-otimeticks) > CYCLE)
3036 { /* Check timeouts */
3037 check_timeouts();
3038 }
3039
3040 /* flush sockets */
3041 dequeue_sockets();
3042
3043 /* Read data from a currently waiting socket */
3044 xx=sockgets(buf, &buf_len);
3045 if (xx>=0) /* Non-error */
3046 {
3047 net_activity(xx, buf, buf_len);
3048 }
3049 else if (xx==-1) /* EOF from someone */
3050 {
3051 lvprintf(9,"Close Socket\n");
3052 net_eof(buf_len); /* Close this socket */
3053 }
3054 else if (xx==-2) /* Select() error */
3055 {
3056 lvprintf(4,"Select error - Whatever the hell that is supposed to be..\n");
3057 }
3058
3059
3060 }
3061 }
3062