1 #ifndef WIN32
2 #include "config.h"
3 #endif
4
5 #include <stdio.h>
6 #include <sys/types.h>
7
8 #if (!defined(WIN32))
9 #ifdef TIME_WITH_SYS_TIME
10 #include <sys/time.h>
11 #include <time.h>
12 #else
13 #ifdef TM_IN_SYS_TIME
14 #include <sys/time.h>
15 #else
16 #include <time.h>
17 #endif
18 #endif
19 #include <sys/socket.h>
20 #else
21 #include <time.h>
22 #include <winsock.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <signal.h>
27 #include <math.h>
28 #include <errno.h>
29 #ifdef HAVE_FLOAT_H
30 #include <float.h>
31 #endif
32 #ifndef __USE_GNU
33 #define __USE_GNU
34 #endif
35 #include <string.h>
36
37 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h>
39 #endif
40
41 #ifdef __EMX__
42 #define INCL_DOS
43 #include <os2.h>
44 #endif
45
46 #include "data.h"
47 #include "server.h"
48 #include "net.h"
49 #include "cfg.h"
50 #include "hash.h"
51 #include "time.h"
52 #include "getopt.h"
53 #include "math.h"
54 #include "error.h"
55
56
57 unsigned short port=DEFAULT_PORT; /* game port (not a gameport ;-) )*/
58 int level_number=0; /* line number in the LEVEL_FILE */
59 int fd; /* socket */
60 int n_players; /* highest ID of player */
61 int active_players=0; /* # of players in the game */
62 unsigned int id=0; /* my ID */
63 unsigned long_long game_start; /* time of game start */
64 /* important sprites */
65 int grenade_sprite,bullet_sprite,slug_sprite,shell_sprite,shotgun_shell_sprite,mess1_sprite,mess2_sprite,mess3_sprite,mess4_sprite,noise_sprite;
66 int shrapnel_sprite[N_SHRAPNELS];
67 int nonquitable=0; /* 1=clients can't abort game pressing F12 (request is ignored) */
68 unsigned long_long last_tick;
69 unsigned long_long last_player_left=0,last_packet_came=0;
70
71 unsigned char *level_checksum=0; /* MD5 sum of the level */
72
73 unsigned char weapons_order[ARMS]={4,0,3,1,2};
74
75 struct birthplace_type
76 {
77 int x,y;
78 }*birthplace=DUMMY;
79
80 int n_birthplaces=0;
81
82 /* list of players */
83 struct player_list
84 {
85 struct player_list *next,*prev;
86 struct player member;
87 }players;
88
89
90 /* time queue of respawning objects */
91 struct queue_list
92 {
93 struct queue_list* next;
94 unsigned long_long time;
95 struct it member;
96 }time_queue;
97
98
99 /* list of objects */
100 struct object_list objects;
101
102 struct player_list *last_player;
103 struct object_list *last_obj;
104
105
106 #ifdef WIN32
107 #define random rand
108 #define srandom srand
109
110 #define SERVICE_NAME "0verkill_015"
111 #define SERVICE_DISP_NAME "0verkill Server 0.15"
112 int consoleApp=0; /* 0 kdyz to bezi jako server na pozadi */
113
114 /***************************************************/
115 /* WINDOWS NT SERVICE INSTALLATION/RUNNING/REMOVAL */
116
117 #include <winsvc.h>
118
119 int server(void);
120
121 SERVICE_STATUS ssStatus;
122 SERVICE_STATUS_HANDLE sshStatusHandle;
123 DWORD globErr=ERROR_SUCCESS;
124 TCHAR szErr[2048];
125 int hServerExitEvent=0; /* close server flag */
126
GetLastErrorText(LPTSTR lpszBuf,DWORD dwSize)127 LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize) {
128 DWORD dwRet;
129 LPTSTR lpszTemp=NULL;
130 globErr=GetLastError();
131 dwRet=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL,
132 globErr, LANG_NEUTRAL, (LPTSTR)&lpszTemp, 0, NULL);
133 /* supplied buffer is not long enough */
134 if (( !dwRet )||( (long)dwSize < (long)dwRet+14 ))
135 sprintf(lpszBuf, ": %u", globErr);
136 else {
137 lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');
138 CharToOem(lpszTemp, lpszTemp);
139 sprintf(lpszBuf, ": %u: %s", globErr, lpszTemp);
140 }
141 if ( lpszTemp )
142 LocalFree((HLOCAL)lpszTemp);
143 return lpszBuf;
144 }
145
CmdInstallService(LPCTSTR pszUserName,LPCTSTR pszUserPassword,LPCTSTR pszDependencies)146 void CmdInstallService(LPCTSTR pszUserName, LPCTSTR pszUserPassword, LPCTSTR pszDependencies) {
147 SC_HANDLE schService;
148 SC_HANDLE schSCManager;
149 TCHAR szPath[2048];
150 printf("Installing %s as ", SERVICE_NAME);
151 if ( pszUserName==NULL )
152 printf("LOCAL_SYSTEM");
153 else {
154 printf("\"%s\"", pszUserName);
155 if ( pszUserPassword )
156 printf("/\"%s\"", pszUserPassword);
157 };
158 printf("...\r\n");
159 if ( GetModuleFileName(NULL, szPath, 2046)==0 ) {
160 printf("Unable to install %s%s\r\n", SERVICE_NAME, GetLastErrorText(szErr, 2046));
161 return;
162 };
163 schSCManager=OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
164 if ( schSCManager ) {
165 schService=CreateService(
166 schSCManager, /* SCManager database */
167 SERVICE_NAME, /* name of service */
168 SERVICE_DISP_NAME, /* name to display */
169 SERVICE_ALL_ACCESS, /* desired access */
170 SERVICE_WIN32_OWN_PROCESS, /* service type */
171 SERVICE_DEMAND_START, /* start type */
172 SERVICE_ERROR_NORMAL, /* error control type */
173 szPath, /* service's binary */
174 NULL, /* no load ordering group */
175 NULL, /* no tag identifier */
176 pszDependencies, /* dependencies */
177 pszUserName, /* account */
178 pszUserPassword); /* password */
179 if ( schService ) {
180 printf("%s was installed successfully.\r\n", SERVICE_NAME);
181 globErr=ERROR_SUCCESS;
182 CloseServiceHandle(schService);
183 }
184 else
185 printf("CreateService failed%s\r\n", GetLastErrorText(szErr, 2046));
186 CloseServiceHandle(schSCManager);
187 }
188 else
189 printf("OpenSCManager failed%s\r\n", GetLastErrorText(szErr, 2046));
190 }
191
CmdRemoveService()192 void CmdRemoveService() {
193 SC_HANDLE schService,
194 schSCManager;
195 schSCManager=OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
196 if ( schSCManager ) {
197 schService=OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
198 if ( schService ) {
199 if ( ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus) ) {
200 printf("Stopping %s...\r\n", SERVICE_NAME);
201 Sleep(500);
202 while( QueryServiceStatus(schService, &ssStatus) ) {
203 if ( ssStatus.dwCurrentState==SERVICE_STOP_PENDING ) {
204 printf(".");
205 Sleep(500);
206 }
207 else
208 break;
209 };
210 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
211 printf("\r\n%s stopped successfully.\r\n", SERVICE_NAME);
212 else
213 printf("\r\n%s failed to stop.\r\n", SERVICE_NAME);
214 }
215 else
216 printf("ControlService failed%s\r\n", GetLastErrorText(szErr, 2046));
217 if ( DeleteService(schService) ) {
218 globErr=ERROR_SUCCESS;
219 printf("%s removed.\r\n", SERVICE_NAME);
220 }
221 else
222 printf("DeleteService failed%s\r\n", GetLastErrorText(szErr, 2046));
223 CloseServiceHandle(schService);
224 }
225 else
226 printf("OpenService failed%s\r\n", GetLastErrorText(szErr, 2046));
227 CloseServiceHandle(schSCManager);
228 }
229 else
230 printf("OpenSCManager failed%s\r\n", GetLastErrorText(szErr, 2046));
231 }
232
AddToMessageLog(LPTSTR lpszMsg,int infoOnly)233 void AddToMessageLog(LPTSTR lpszMsg, int infoOnly) {
234 TCHAR szMsg[2048];
235 HANDLE hEventSource;
236 LPTSTR lpszStrings[2];
237
238 hEventSource=RegisterEventSource(NULL, SERVICE_NAME);
239
240 sprintf(szMsg, infoOnly ? "%s notification:" : "%s error: %u", SERVICE_NAME, globErr);
241 lpszStrings[0]=szMsg;
242 lpszStrings[1]=lpszMsg;
243
244 if ( hEventSource!=INVALID_HANDLE_VALUE ) {
245 ReportEvent(hEventSource, infoOnly ? EVENTLOG_INFORMATION_TYPE : EVENTLOG_ERROR_TYPE, 0, 0, NULL, 2, 0, (LPCTSTR*)lpszStrings, NULL);
246 DeregisterEventSource(hEventSource);
247 };
248 };
249
ReportStatusToSCMgr(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint)250 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) {
251 static DWORD dwCheckPoint=1;
252 BOOL fResult=TRUE;
253
254 if ( dwCurrentState==SERVICE_START_PENDING )
255 ssStatus.dwControlsAccepted=0;
256 else
257 ssStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;
258
259 ssStatus.dwCurrentState=dwCurrentState;
260 ssStatus.dwWin32ExitCode=dwWin32ExitCode;
261 ssStatus.dwWaitHint=dwWaitHint;
262
263 if (( dwCurrentState==SERVICE_RUNNING )||
264 ( dwCurrentState==SERVICE_STOPPED ))
265 ssStatus.dwCheckPoint=0;
266 else
267 ssStatus.dwCheckPoint=dwCheckPoint++;
268 if ( !(fResult=SetServiceStatus(sshStatusHandle, &ssStatus)) ) {
269 globErr=GetLastError();
270 AddToMessageLog("SetServiceStatus failed", 0);
271 }
272 return fResult;
273 }
274
ServiceStop()275 void ServiceStop() {
276 hServerExitEvent=1;
277 raise(SIGINT);
278 }
279
ServiceCtrl(DWORD dwCtrlCode)280 void WINAPI ServiceCtrl(DWORD dwCtrlCode) {
281 switch( dwCtrlCode ) {
282 case SERVICE_CONTROL_STOP:
283 ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
284 ServiceStop();
285 return;
286 };
287 if ( hServerExitEvent )
288 ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
289 else
290 ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
291 }
292
293
ServiceStart(DWORD dwArgc,LPTSTR * lpszArgv)294 void ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv) {
295 if ( dwArgc>1 )
296 SetCurrentDirectory(lpszArgv[1]);
297 else {
298 char path[1024],
299 *p2;
300 GetModuleFileName(NULL, path, sizeof(path));
301 p2=path+strlen(path);
302 while(( p2>=path )&&( *p2!='\\' )&&( *p2!='/' ))
303 p2--;
304 *p2=0;
305 SetCurrentDirectory(path);
306 }
307 server();
308 }
309
ServiceMain(DWORD dwArgc,LPTSTR * lpszArgv)310 void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
311 if ( !(sshStatusHandle=RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrl)) )
312 return;
313
314 ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
315 ssStatus.dwServiceSpecificExitCode=0;
316 if ( !ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
317 goto Cleanup;
318
319 nonquitable=1;
320 ServiceStart(dwArgc, lpszArgv);
321
322 Cleanup:
323 ReportStatusToSCMgr(SERVICE_STOPPED, globErr, 0);
324 return;
325 };
326 /* WINDOWS NT SERVICE INSTALLATION/REMOVAL */
327 /*******************************************/
328 #endif
329
330
331 /* load dynamic data */
load_dynamic(unsigned char * filename)332 void load_dynamic(unsigned char * filename)
333 {
334 FILE * stream;
335 static unsigned char line[1024];
336 char *p,*q,*name;
337 int n,x,y,t;
338
339 if (!(stream=fopen(filename,"rb"))){unsigned char msg[256];snprintf(msg,256,"Can't open file \"%s\"!\n",filename);ERROR(msg);EXIT(1);}
340 while(fgets(line,1024,stream))
341 {
342 p=line;
343 _skip_ws(&p);
344 for (name=p;(*p)!=' '&&(*p)!=9&&(*p)!=10&&(*p);p++);
345 if (!(*p))continue;
346 *p=0;p++;
347 _skip_ws(&p);
348 if ((t=_convert_type(*p))<0){unsigned char msg[256];snprintf(msg,256,"Unknown object type '%c'.\n",*p);ERROR(msg);EXIT(1);}
349 p++;
350 _skip_ws(&p);
351 x=strtol(p,&q,0);
352 _skip_ws(&q);
353 y=strtol(q,&p,0);
354 if (t==TYPE_BIRTHPLACE) /* birthplace */
355 {
356 n_birthplaces++;
357 birthplace=mem_realloc(birthplace,sizeof(struct birthplace_type)*n_birthplaces);
358 if (!birthplace){ERROR("Error: Not enough memory.\n");EXIT(1);}
359 birthplace[n_birthplaces-1].x=x;
360 birthplace[n_birthplaces-1].y=y;
361 continue;
362 }
363 if (find_sprite(name,&n)){unsigned char msg[256];snprintf(msg,256,"Unknown bitmap name \"%s\"!\n",name);ERROR(msg);EXIT(1);}
364 new_obj(id,t,0,n,0,0,int2double(x),int2double(y),0,0,0);
365 id++;
366 }
367 fclose(stream);
368 if (!n_birthplaces){ERROR("Error: No birthplaces.\n");EXIT(1);}
369 }
370
371
print_ip(unsigned char * txt,struct in_addr ip)372 void print_ip(unsigned char * txt,struct in_addr ip)
373 {
374 unsigned int a;
375
376 sprintf(txt,"%d",*((unsigned char *)&ip));
377 for (a=1;a<sizeof(ip);a++)
378 sprintf(txt+strlen(txt),".%d",((unsigned char *)&ip)[a]);
379 }
380
381
382 /* write a message to stdout or stderr */
message(unsigned char * msg,int output)383 void message(unsigned char *msg,int output)
384 {
385 time_t t;
386 struct tm tm;
387 static unsigned char timestamp[64];
388
389 #ifdef WIN32
390 if ( !consoleApp )
391 return;
392 #endif
393
394 t=time(0);
395 tm=*(localtime(&t));
396
397 /* time stamp is in format day.month.year hour:minute:second */
398 snprintf(timestamp,64,"%2d.%2d.%d %02d:%02d:%02d ",tm.tm_mday,tm.tm_mon+1,tm.tm_year+1900,tm.tm_hour,tm.tm_min,tm.tm_sec);
399 switch (output)
400 {
401 case 1:
402 printf("%s%s",timestamp,msg);
403 fflush(stdout);
404 break;
405
406 case 2:
407 fprintf(stderr,"%s%s",timestamp,msg);
408 fflush(stderr);
409 break;
410 }
411 }
412
413
414 /* switch weapon to the player's best one */
select_best_weapon(struct player * p)415 int select_best_weapon(struct player* p)
416 {
417 unsigned char t[ARMS]={4,0,1,3,2};
418 int a;
419
420 for (a=ARMS-1;a>=0;a--)
421 if ((p->weapons&(1<<t[a]))&&p->ammo[t[a]])return t[a];
422
423 return p->current_weapon;
424 }
425
426
427 /* Bakta modify - better weapon selection routines */
428 /* test if weapon is better than the one he wields */
is_weapon_better(struct player * p,int weapon)429 int is_weapon_better(struct player* p, int weapon)
430 {
431 int i;
432 int cur=0, test=0;
433
434 for(i=ARMS-1;i>=0;i--)
435 {
436 if(weapons_order[i]==p->current_weapon)
437 cur = i;
438 if(weapons_order[i]==weapon)
439 test = i;
440 }
441 return cur<test;
442 }
443
444
445 /* test if player p has weapon and can use it (has ammo for it) */
is_weapon_usable(struct player * p,int weapon)446 int is_weapon_usable(struct player* p, int weapon)
447 {
448 return !!((p->weapons&(1<<weapon))&&p->ammo[weapon]);
449 }
450
451
452 /* test if player p has weapon and has no ammo for it */
is_weapon_empty(struct player * p,int weapon)453 int is_weapon_empty(struct player* p, int weapon)
454 {
455 return !!((p->weapons&(1<<weapon))&&!p->ammo[weapon]);
456 }
457
458
459 /* initialize socket */
init_socket(void)460 void init_socket(void)
461 {
462 struct sockaddr_in server;
463 fd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
464 if (fd<0)
465 {
466 ERROR("Error: Can't create socket!\n");
467 EXIT(1);
468 }
469
470 server.sin_family=AF_INET;
471 server.sin_port=htons(port);
472 server.sin_addr.s_addr=INADDR_ANY;
473
474 if (bind(fd,(struct sockaddr*)&server,sizeof(server)))
475 {
476 unsigned char msg[256];
477 snprintf(msg,256,"Error: Can't bind socket to port %d!\n",port);
478 ERROR(msg);
479 EXIT(1);
480 }
481 }
482
483
484 /* selects random birthplace and returns */
find_birthplace(int * x,int * y)485 void find_birthplace(int *x,int *y)
486 {
487 int a=random()%n_birthplaces;
488
489 *x=birthplace[a].x;
490 *y=birthplace[a].y;
491 }
492
493
494 /* return index of hero with color num in sprites field */
495 /* if there's not such color, returns -1 */
select_hero(int num)496 int select_hero(int num)
497 {
498 static unsigned char txt[32];
499 int a;
500
501 sprintf(txt,"hero%d",num);
502 if (find_sprite(txt,&a))return -1;
503 return a;
504 }
505
506
507 /* initialize player */
init_player(struct player * p,my_double x,my_double y)508 void init_player(struct player* p,my_double x,my_double y)
509 {
510 int a;
511
512 p->health=100;
513 p->armor=0;
514 p->current_weapon=0;
515 p->weapons=17; /* he has only gun and grenades */
516 p->invisibility_counter=0;
517 for (a=0;a<ARMS;a++)
518 p->ammo[a]=0;
519 p->ammo[0]=weapon[0].basic_ammo;
520 p->obj->xspeed=0;
521 p->obj->yspeed=0;
522 p->obj->status=0;
523 p->obj->ttl=0;
524 p->obj->anim_pos=0;
525 p->obj->x=x;
526 p->obj->y=y;
527 }
528
529
530 /* completely add player to server's database */
531 /* player starts on x,y coordinates */
add_player(unsigned char color,unsigned char * name,struct sockaddr_in * address,int x,int y)532 int add_player(unsigned char color, unsigned char *name,struct sockaddr_in *address,int x, int y)
533 {
534 int h;
535 #define cp last_player->next
536
537 cp=last_player->next;
538
539 /* alloc memory for new player */
540 cp=mem_alloc(sizeof(struct player_list));
541 if (!cp)
542 {message("Not enough memory.\n",2);return 1;}
543 cp->member.name=mem_alloc(strlen(name)+1);
544 if (!cp->member.name)
545 {mem_free(cp);message("Not enough memory.\n",2);return 1;}
546
547 /* fill in the structure */
548 cp->member.color=color;
549 cp->member.frags=0;
550 cp->member.deaths=0;
551 cp->member.keyboard_status.left=0;
552 cp->member.keyboard_status.right=0;
553 cp->member.keyboard_status.speed=0;
554 cp->member.keyboard_status.fire=0;
555 cp->member.keyboard_status.creep=0;
556 cp->member.keyboard_status.down_ladder=0;
557 cp->member.keyboard_status.weapon=0;
558 cp->member.id=n_players+1; /* player numbering starts from 1, 0 is server's ID */
559 cp->member.last_update=get_time();
560 memcpy(cp->member.name,name,strlen(name)+1);
561 cp->member.address=*address;
562 cp->member.packet_pos=0;
563 cp->member.current_level=-1;
564 /* create new object "player" */
565 h=select_hero(cp->member.color);
566 if (h<0)
567 {mem_free(cp->member.name);mem_free(cp);message ("No such color.\n",1);return 1;}
568 cp->member.obj=new_obj(id,T_PLAYER,0,h,0,0,int2double(x),int2double(y),0,0,(&(cp->member)));
569 if (!cp->member.obj)
570 {mem_free(cp->member.name);mem_free(cp);message("Can't create object.\n",1);return 1;}
571 id++;
572 init_player(&(cp->member),int2double(x),int2double(y));
573
574 /* that's all */
575 cp->prev=last_player;
576 cp->next=0;
577 last_player=cp;
578 #undef cp
579 return 0;
580 }
581
582
send_chunk_to_player(struct player * player)583 void send_chunk_to_player(struct player *player)
584 {
585 static unsigned char p[MAX_PACKET_LENGTH];
586
587 if (!(player->packet_pos))return;
588 if (player->packet_pos>MAX_PACKET_LENGTH-1)return;
589 p[0]=P_CHUNK;
590 memcpy(p+1,player->packet,player->packet_pos);
591 send_packet(p,(player->packet_pos)+1,(struct sockaddr*)(&(player->address)),0,player->id);
592 player->packet_pos=0;
593 }
594
595
send_chunk_packet_to_player(unsigned char * packet,int len,struct player * player)596 void send_chunk_packet_to_player(unsigned char *packet, int len, struct player *player)
597 {
598 if (len>MAX_PACKET_LENGTH-1)return;
599 if ((player->packet_pos)+len>MAX_PACKET_LENGTH-1)send_chunk_to_player(player);
600 memcpy((player->packet)+(player->packet_pos),packet,len);
601 player->packet_pos+=len;
602 }
603
604
send_chunks(void)605 void send_chunks(void)
606 {
607 struct player_list* p;
608
609 for (p=&players;p->next;p=p->next)
610 send_chunk_to_player(&(p->next->member));
611 }
612
613
614 /* send a packet to all players except one */
615 /* if not_this_player is null, sends to all players */
sendall(unsigned char * packet,int len,struct player * not_this_player)616 void sendall(unsigned char *packet,int len, struct player * not_this_player)
617 {
618 struct player_list* p;
619
620 if (!not_this_player)
621 for (p=&players;p->next;p=p->next)
622 send_packet(packet,len,(struct sockaddr*)(&(p->next->member.address)),0,p->next->member.id);
623 else
624 for (p=&players;p->next;p=p->next)
625 if ((&(p->next->member))!=not_this_player)
626 send_packet(packet,len,(struct sockaddr*)(&(p->next->member.address)),0,p->next->member.id);
627 }
628
629
630 /* send a packet to all players except one */
631 /* if not_this_player is null, sends to all players */
sendall_chunked(unsigned char * packet,int len,struct player * not_this_player)632 void sendall_chunked(unsigned char *packet,int len, struct player * not_this_player)
633 {
634 struct player_list* p;
635
636 if (!not_this_player)
637 for (p=&players;p->next;p=p->next)
638 send_chunk_packet_to_player(packet,len,&(p->next->member));
639 else
640 for (p=&players;p->next;p=p->next)
641 if ((&(p->next->member))!=not_this_player)
642 send_chunk_packet_to_player(packet,len,&(p->next->member));
643 }
644
645
which_update(struct it * obj,my_double old_x,my_double old_y,my_double old_x_speed,my_double old_y_speed,unsigned int old_status,int old_ttl)646 int which_update(struct it *obj,my_double old_x,my_double old_y,my_double old_x_speed,my_double old_y_speed,unsigned int old_status,int old_ttl)
647 {
648 int a=0;
649
650 if (old_ttl==obj->ttl)
651 {
652 if (old_x_speed==obj->xspeed&&old_y_speed==obj->yspeed)a=5; /* update pos and status */
653 if (old_x==obj->x&&old_y==obj->y)a=4; /* update speed and status */
654 }
655
656 if (old_status==obj->status&&old_ttl==obj->ttl)
657 {
658 a=1; /* update speed+coords */
659
660 if (old_x_speed==obj->xspeed&&old_y_speed==obj->yspeed)a=3; /* update pos */
661 if (old_x==obj->x&&old_y==obj->y)
662 {
663 if(a==3)return -1; /* nothing to update */
664 a=2; /* update speed */
665 }
666 }
667 return a;
668 }
669
670 /* send a packet to all players except one */
671 /* if not_this_player is null, sends to all players */
672 /* type is:
673 0=full update
674 1=update speed+coordinates
675 2=update speed
676 3=update coordinates
677 4=update speed + status
678 5=update coordinates + status
679 6=update speed + status + ttl
680 7=update coordinates + status + ttl
681 */
sendall_update_object(struct it * obj,struct player * not_this_player,int type)682 void sendall_update_object(struct it* obj, struct player * not_this_player,int type)
683 {
684 struct player_list* p;
685 int l;
686 static unsigned char packet[32];
687
688 switch (type)
689 {
690 case 0: /* all */
691 packet[0]=P_UPDATE_OBJECT;
692 put_int(packet+1,obj->id);
693 packet[5]=obj->update_counter;
694 put_float(packet+6,obj->x);
695 put_float(packet+10,obj->y);
696 put_float(packet+14,obj->xspeed);
697 put_float(packet+18,obj->yspeed);
698 put_int16(packet+22,obj->status);
699 put_int16(packet+24,obj->ttl);
700 l=26;
701 break;
702
703 case 1: /* coordinates and speed */
704 packet[0]=P_UPDATE_OBJECT_POS;
705 put_int(packet+1,obj->id);
706 packet[5]=obj->update_counter;
707 put_float(packet+6,obj->x);
708 put_float(packet+10,obj->y);
709 put_float(packet+14,obj->xspeed);
710 put_float(packet+18,obj->yspeed);
711 l=22;
712 break;
713
714 case 2: /* speed */
715 packet[0]=P_UPDATE_OBJECT_SPEED;
716 put_int(packet+1,obj->id);
717 packet[5]=obj->update_counter;
718 put_float(packet+6,obj->xspeed);
719 put_float(packet+10,obj->yspeed);
720 l=14;
721 break;
722
723 case 3: /* coordinates */
724 packet[0]=P_UPDATE_OBJECT_COORDS;
725 put_int(packet+1,obj->id);
726 packet[5]=obj->update_counter;
727 put_float(packet+6,obj->x);
728 put_float(packet+10,obj->y);
729 l=14;
730 break;
731
732 case 4: /* speed and status */
733 packet[0]=P_UPDATE_OBJECT_SPEED_STATUS;
734 put_int(packet+1,obj->id);
735 packet[5]=obj->update_counter;
736 put_float(packet+6,obj->xspeed);
737 put_float(packet+10,obj->yspeed);
738 put_int16(packet+14,obj->status);
739 l=16;
740 break;
741
742 case 5: /* coordinates and status */
743 packet[0]=P_UPDATE_OBJECT_COORDS_STATUS;
744 put_int(packet+1,obj->id);
745 packet[5]=obj->update_counter;
746 put_float(packet+6,obj->x);
747 put_float(packet+10,obj->y);
748 put_int16(packet+14,obj->status);
749 l=16;
750 break;
751
752 case 6: /* speed and status and ttl */
753 packet[0]=P_UPDATE_OBJECT_SPEED_STATUS_TTL;
754 put_int(packet+1,obj->id);
755 packet[5]=obj->update_counter;
756 put_float(packet+6,obj->xspeed);
757 put_float(packet+10,obj->yspeed);
758 put_int16(packet+14,obj->status);
759 put_int16(packet+16,obj->ttl);
760 l=18;
761 break;
762
763 case 7: /* coordinates and status and ttl */
764 packet[0]=P_UPDATE_OBJECT_COORDS_STATUS_TTL;
765 put_int(packet+1,obj->id);
766 packet[5]=obj->update_counter;
767 put_float(packet+6,obj->x);
768 put_float(packet+10,obj->y);
769 put_int16(packet+14,obj->status);
770 put_int16(packet+16,obj->ttl);
771 l=18;
772 break;
773
774 default: /* don't update */
775 return;
776
777 }
778
779 obj->update_counter++;
780
781 if (!not_this_player)
782 for (p=&players;p->next;p=p->next)
783 send_chunk_packet_to_player(packet,l,&(p->next->member));
784 else
785 for (p=&players;p->next;p=p->next)
786 if ((&(p->next->member))!=not_this_player)
787 send_chunk_packet_to_player(packet,l,&(p->next->member));
788 }
789
790
791 /* send update status packet to all players (except not_this_player if this is !NULL)*/
sendall_update_status(struct it * obj,struct player * not_this_player)792 void sendall_update_status(struct it* obj, struct player * not_this_player)
793 {
794 struct player_list* p;
795 static unsigned char packet[8];
796
797 packet[0]=P_UPDATE_STATUS;
798 put_int(packet+1,obj->id);
799 put_int16(packet+5,obj->status);
800
801 if (!not_this_player)
802 for (p=&players;p->next;p=p->next)
803 send_chunk_packet_to_player(packet,7,&(p->next->member));
804 else
805 for (p=&players;p->next;p=p->next)
806 if ((&(p->next->member))!=not_this_player)
807 send_chunk_packet_to_player(packet,7,&(p->next->member));
808 }
809
810
811 /* send hit packet to all players except not_this player (if !NULL)*/
sendall_hit(unsigned long id,unsigned char direction,unsigned char xoffs,unsigned char yoffs,struct player * not_this_player)812 void sendall_hit(unsigned long id,unsigned char direction,unsigned char xoffs,unsigned char yoffs,struct player* not_this_player)
813 {
814 struct player_list* p;
815 static unsigned char packet[8];
816
817 packet[0]=P_HIT;
818 put_int(packet+1,id);
819 packet[5]=direction;
820 packet[6]=xoffs;
821 packet[7]=yoffs;
822
823 if (!not_this_player)
824 for (p=&players;p->next;p=p->next)
825 send_chunk_packet_to_player(packet,8,&(p->next->member));
826 else
827 for (p=&players;p->next;p=p->next)
828 if ((&(p->next->member))!=not_this_player)
829 send_chunk_packet_to_player(packet,8,&(p->next->member));
830 }
831
832
833 /* sort players according to frags */
_qsort_cmp(const void * a,const void * b)834 int _qsort_cmp(const void *a,const void *b)
835 {
836 int fa,fb,da,db;
837 fa=(*((struct player**)a))->frags;
838 fb=(*((struct player**)b))->frags;
839 da=(*((struct player**)a))->deaths;
840 db=(*((struct player**)b))->deaths;
841
842 if (fa>fb)return -1;
843 if (fa==fb)
844 {
845 if (da<db)return -1;
846 if (da>db)return 1;
847 return 0;
848 }
849 return 1;
850 }
851
852
853 /* send info how many players are in the game and top score */
854 /* id=recipient's id */
855 /* if addr is NULL info is sent to all */
send_info(struct sockaddr * addr,int id)856 void send_info(struct sockaddr *addr,int id)
857 {
858 unsigned char *packet;
859 int p=active_players>TOP_PLAYERS_N?TOP_PLAYERS_N:active_players;
860 int a,n,l;
861 struct player **t; /* table for qsort */
862 struct player_list *q;
863
864 /* alloc memory */
865 t=mem_alloc(active_players*sizeof(struct player*));
866 if (!t)return;
867 packet=mem_alloc(1+4+1+p*(MAX_NAME_LEN+4+4));
868 if (!packet)return;
869
870 /* fill table for quicksort */
871 for (a=0,q=(&players);q->next;a++,q=q->next)
872 t[a]=&(q->next->member);
873
874 /* sort players */
875 qsort(t,active_players,sizeof(struct player*),_qsort_cmp);
876
877 /* create packet header */
878 packet[0]=P_INFO;
879 put_int(packet+1,active_players);
880 packet[5]=p;
881 n=6;
882
883 /* put players into packet */
884 for (a=0;a<p;a++)
885 {
886 put_int(packet+n,(t[a])->frags);
887 put_int(packet+n+4,(t[a])->deaths);
888 packet[n+8]=t[a]->color;
889 l=strlen((t[a])->name)+1;
890 memcpy(packet+n+9,(t[a])->name,l);
891 n+=l+9;
892 }
893 if (!addr)sendall(packet,n,0);
894 else send_packet(packet,n,addr,0,id);
895
896 mem_free(packet);
897 mem_free(t);
898 }
899
900 /* send message to a player */
901 /* name is name of player who sent the message (chat), NULL means it's from server */
send_message(struct player * player,unsigned char * name,unsigned char * msg)902 void send_message(struct player* player,unsigned char *name,unsigned char *msg)
903 {
904 static unsigned char packet[256];
905 int len;
906
907 packet[0]=P_MESSAGE;
908 if (!name){snprintf(packet+1,256,"%s",msg);len=strlen(msg)+1+1;}
909 else {snprintf(packet+1,256,"%s> %s",name,msg);len=strlen(name)+strlen(msg)+1+3;}
910 if (len > 255)
911 len = 255;
912 send_chunk_packet_to_player(packet,len,player);
913 }
914
915
916 /* similar to send_message but sends to all except one or two players */
sendall_message(unsigned char * name,unsigned char * msg,struct player * not1,struct player * not2)917 void sendall_message(unsigned char *name,unsigned char *msg,struct player *not1,struct player* not2)
918 {
919 static unsigned char packet[256];
920 int len;
921 struct player_list* p;
922
923 packet[0]=P_MESSAGE;
924 if (!name){snprintf(packet+1,255,"%s",msg);len=strlen(msg)+1+1;}
925 else {snprintf(packet+1,255,"%s> %s",name,msg);len=strlen(name)+strlen(msg)+1+3;}
926 if (len > 255)
927 len = 255;
928 for (p=&players;p->next;p=p->next)
929 if ((!not1||(&(p->next->member))!=not1)&&(!not2||(&(p->next->member))!=not2))
930 send_chunk_packet_to_player(packet,len,&(p->next->member));
931 }
932
933
sendall_bell(void)934 void sendall_bell(void)
935 {
936 static unsigned char packet;
937 struct player_list* p;
938
939 packet=P_BELL;
940 for (p=&players;p->next;p=p->next)
941 send_chunk_packet_to_player(&packet,1,&(p->next->member));
942
943 }
944
945
946 /* send new object information to given address */
send_new_obj(struct sockaddr * address,struct it * obj,int id)947 void send_new_obj(struct sockaddr* address, struct it* obj,int id)
948 {
949 static unsigned char packet[32];
950
951 packet[0]=P_NEW_OBJ;
952 put_int(packet+1,obj->id);
953 put_int16(packet+5,obj->sprite);
954 put_float(packet+7,obj->x);
955 put_float(packet+11,obj->y);
956 put_float(packet+15,obj->xspeed);
957 put_float(packet+19,obj->yspeed);
958 put_int16(packet+23,obj->status);
959 packet[25]=obj->type;
960 put_int16(packet+26,obj->ttl);
961 send_packet(packet,28,address,0,id);
962 }
963
964
965 /* send new object information to given address */
send_new_obj_chunked(struct player * player,struct it * obj)966 void send_new_obj_chunked(struct player* player, struct it* obj)
967 {
968 static unsigned char packet[32];
969
970 packet[0]=P_NEW_OBJ;
971 put_int(packet+1,obj->id);
972 put_int16(packet+5,obj->sprite);
973 put_float(packet+7,obj->x);
974 put_float(packet+11,obj->y);
975 put_float(packet+15,obj->xspeed);
976 put_float(packet+19,obj->yspeed);
977 put_int16(packet+23,obj->status);
978 packet[25]=obj->type;
979 put_int16(packet+26,obj->ttl);
980 send_chunk_packet_to_player(packet,28,player);
981 }
982
983
984 /* send player update to given player */
send_update_player(struct player * p)985 void send_update_player(struct player* p)
986 {
987 static unsigned char packet[32];
988 int a;
989
990 packet[0]=P_UPDATE_PLAYER;
991 packet[1]=p->health;
992 packet[2]=p->armor;
993 for (a=0;a<ARMS;a++)
994 put_int16(packet+3+(a<<1),p->ammo[a]);
995 put_int(packet+3+2*ARMS,p->frags);
996 put_int(packet+7+2*ARMS,p->deaths);
997 packet[11+2*ARMS]=p->current_weapon;
998 packet[12+2*ARMS]=p->weapons;
999 send_chunk_packet_to_player(packet,13+2*ARMS,p);
1000 }
1001
1002 /* send a packet to all players except one */
1003 /* if not_this_player is null, sends to all players */
sendall_new_object(struct it * obj,struct player * not_this_player)1004 void sendall_new_object(struct it* obj, struct player * not_this_player)
1005 {
1006 struct player_list* p;
1007
1008 if (!not_this_player)
1009 for (p=&players;p->next;p=p->next)
1010 send_new_obj_chunked(&(p->next->member),obj);
1011 else
1012 for (p=&players;p->next;p=p->next)
1013 if ((&(p->next->member))!=not_this_player)
1014 send_new_obj_chunked(&(p->next->member),obj);
1015 }
1016
1017
1018
1019 /* send all objects except one to specified player */
1020 /* if not_this_object is null, sends all objects */
send_objects(struct player * player,struct it * not_this_object)1021 void send_objects(struct player* player,struct it* not_this_object)
1022 {
1023 struct object_list *p;
1024
1025 if (!not_this_object)
1026 for(p=&objects;p->next;p=p->next)
1027 send_new_obj_chunked(player,&(p->next->member));
1028 else
1029 for(p=&objects;p->next;p=p->next)
1030 if((&p->next->member)!=not_this_object)
1031 send_new_obj_chunked(player,&(p->next->member));
1032 }
1033
1034
1035 /* send all objects except one to specified player */
1036 /* if not_this_object is null, sends all objects */
send_change_level(struct player * player)1037 void send_change_level(struct player* player)
1038 {
1039 unsigned char packet[64];
1040
1041 packet[0]=P_CHANGE_LEVEL;
1042 put_int(packet+1,level_number);
1043 memcpy(packet+5,level_checksum,33);
1044 send_packet(packet,38,(struct sockaddr*)(&(player->address)),0,player->id);
1045 }
1046
1047
1048 /* send all objects in time queue to given player */
send_timeq_objects(struct player * player)1049 void send_timeq_objects(struct player *player)
1050 {
1051 struct queue_list *p;
1052
1053 for (p=&time_queue;p->next;p=p->next)
1054 send_new_obj_chunked(player,&(p->next->member));
1055 }
1056
1057
1058 /* remove player from server's list */
1059 /* delete player's hero and send message */
delete_player(struct player_list * q)1060 void delete_player(struct player_list *q)
1061 {
1062 unsigned char packet[5];
1063
1064 /* delete object player's hero */
1065 packet[0]=P_DELETE_OBJECT;
1066 put_int(packet+1,q->member.obj->id);
1067 sendall_chunked(packet,5,&(q->member));
1068 delete_obj(q->member.obj->id);
1069
1070 mem_free (q->member.name);
1071 q->prev->next=q->next;
1072 if (!q->next)last_player=q->prev; /* we're deleting last player of the list */
1073 else q->next->prev=q->prev;
1074 mem_free(q);
1075 active_players--;
1076 if (!active_players)last_player_left=get_time();
1077 }
1078
1079
1080 /* create a new object and fill with data and adds to hash table */
add_to_timeq(unsigned int id,unsigned char type,int ttl,int sprite,unsigned char pos,int status,my_double x,my_double y,my_double xspeed,my_double yspeed,void * data,unsigned long_long t)1081 struct it * add_to_timeq(
1082 unsigned int id,
1083 unsigned char type,
1084 int ttl,
1085 int sprite,
1086 unsigned char pos,
1087 int status,
1088 my_double x,
1089 my_double y,
1090 my_double xspeed,
1091 my_double yspeed,
1092 void * data,unsigned long_long t)
1093 {
1094 struct queue_list *p;
1095 struct queue_list *q;
1096
1097 t+=get_time();
1098 for (p=&time_queue;p->next&&p->next->member.last_updated<t;p=p->next);
1099
1100 q=p->next;
1101
1102 p->next=mem_alloc(sizeof(struct queue_list));
1103 if (!p->next){p->next=q;return 0;}
1104 p=p->next;
1105 p->next=q;
1106 p->member.x=x;
1107 p->member.y=y;
1108 p->member.xspeed=xspeed;
1109 p->member.yspeed=yspeed;
1110 p->member.type=type;
1111 p->member.ttl=ttl;
1112 p->member.id=id;
1113 p->member.sprite=sprite;
1114 p->member.anim_pos=pos;
1115 p->member.data=data;
1116 p->member.status=status|64;
1117 p->member.last_updated=t;
1118 return &(p->member);
1119 }
1120
1121
1122 /* update time queue (respawning objects) */
1123 /* add objects timed out to the game */
update_timeq(void)1124 void update_timeq(void)
1125 {
1126 unsigned long_long t=get_time();
1127 struct queue_list *p,*q;
1128 struct it *o;
1129
1130 #define N p->next->member
1131 for (p=&time_queue;p->next&&p->next->member.last_updated<=t;)
1132 {
1133 N.status&=~64;
1134 o=new_obj(N.id,N.type,N.ttl,N.sprite,N.anim_pos,N.status,N.x,N.y,N.xspeed,N.yspeed,N.data);
1135 sendall_update_status(o,0);
1136 q=p->next->next;
1137 mem_free(p->next);
1138 p->next=q;
1139 }
1140 #undef N
1141 }
1142
1143
1144 /* find player with given address */
1145 /* on unsuccess return 0 */
find_player(struct sockaddr_in * address,int id)1146 struct player_list* find_player(struct sockaddr_in *address,int id)
1147 {
1148 struct player_list *p;
1149
1150 if (!address)
1151 {
1152 for(p=&players;p->next;p=p->next)
1153 if (p->next->member.id==id)
1154 return p->next;
1155 return 0;
1156 }
1157 for(p=&players;p->next;p=p->next)
1158 if (((p->next->member.address.sin_addr.s_addr)==(address->sin_addr.s_addr)&&(p->next->member.address.sin_port)==(address->sin_port))&&
1159 (p->next->member.id==id))
1160 return p->next;
1161 return 0;
1162 }
1163
1164
1165
1166 /* create noise on given position */
create_noise(int x,int y,struct player * p)1167 void create_noise(int x,int y,struct player *p)
1168 {
1169 struct it *o;
1170
1171 p->obj->status|=4096;
1172 o=new_obj(id,T_NOISE,NOISE_TTL,noise_sprite,0,0,int2double(x),int2double(y),0,0,(void *)(p->id));
1173 if (!o)return;
1174 id++;
1175 sendall_new_object(o,0);
1176 }
1177
1178
1179
1180 /* read packet from socket */
read_data(void)1181 void read_data(void)
1182 {
1183 unsigned char txt[256];
1184 unsigned char txt1[256];
1185 fd_set rfds;
1186 struct timeval tv;
1187 struct sockaddr_in client;
1188 int a=sizeof(client);
1189 static unsigned char packet[280];
1190 struct player *p;
1191 struct player_list *q;
1192 unsigned char min,maj;
1193 int s,x,y,l;
1194
1195 packet[279]=0;
1196
1197 tv.tv_sec=0;
1198 tv.tv_usec=0;
1199 FD_ZERO(&rfds);
1200 FD_SET(fd,&rfds);
1201 while (select(fd+1,&rfds,0,0,&tv))
1202 {
1203 if ((l=recv_packet(packet,256,(struct sockaddr*)(&client),&a,0,0,&s))==-1)
1204 return;
1205
1206 last_packet_came=get_time();
1207
1208 switch(*packet)
1209 {
1210 case P_NEW_PLAYER:
1211 if (l<6)break; /* invalid packet */
1212 {
1213 unsigned long_long t;
1214 if (packet[1]) /* this byte must be always 0 - version authentification, old versions transmitted color byte here */
1215 {
1216 message("Incompatible client version.\n",2);
1217 packet[0]=P_PLAYER_REFUSED;
1218 packet[1]=E_PLAYER_REFUSED;
1219 send_packet(packet,2,(struct sockaddr*)(&client),0,last_player->member.id);
1220 break;
1221 }
1222 maj=packet[2];
1223 min=packet[3];
1224 print_ip(txt1,client.sin_addr);
1225 snprintf(txt,256,"Request for player #%d (client version %d.%d) from %s.\n",n_players,maj,min,txt1);
1226 message(txt,2);
1227 if (maj!=VERSION_MAJOR||min<MIN_CLIENT_VERSION_MINOR)
1228 {
1229 message("Incompatible client version. Player refused.\n",2);
1230 packet[0]=P_PLAYER_REFUSED;
1231 packet[1]=E_INCOMPATIBLE_VERSION;
1232 send_packet(packet,2,(struct sockaddr*)(&client),0,last_player->member.id);
1233 break;
1234 }
1235 if (strlen(packet+5) > MAX_NAME_LEN)
1236 {
1237 snprintf(txt,256,"Name too long, shortening it to %i characters\n",MAX_NAME_LEN);
1238 message(txt,2);
1239 packet[5+MAX_NAME_LEN]='\0';
1240 }
1241 find_birthplace(&x,&y);
1242 if (add_player(packet[4],packet+5,&client,x,y)) /* failed to add player */
1243 {
1244 message("Player refused.\n",2);
1245 packet[0]=P_PLAYER_REFUSED;
1246 packet[1]=E_PLAYER_REFUSED;
1247 send_packet(packet,2,(struct sockaddr*)(&client),0,last_player->member.id);
1248 break;
1249 }
1250 snprintf(txt,256,"Player #%d accepted, name \"%s\", address %s.\n",n_players,packet+5,txt1);
1251 message(txt,2);
1252 snprintf(txt,256,"%s entered the game.",packet+5);
1253 active_players++;
1254 n_players++;
1255 packet[0]=P_PLAYER_ACCEPTED;
1256 last_player->member.obj->status|=1024;
1257 put_int(packet+1,last_player->member.obj->id);
1258 put_int16(packet+5,last_player->member.obj->sprite);
1259 put_float(packet+7,last_player->member.obj->x);
1260 put_float(packet+11,last_player->member.obj->y);
1261 put_float(packet+15,last_player->member.obj->xspeed);
1262 put_float(packet+19,last_player->member.obj->yspeed);
1263 put_int16(packet+23,last_player->member.obj->status);
1264 t=get_time();
1265 put_long_long(packet+25,t-game_start);
1266 put_int(packet+33,last_player->member.id);
1267 packet[37]=VERSION_MAJOR;
1268 packet[38]=VERSION_MINOR;
1269 send_packet(packet,39,(struct sockaddr*)(&client),0,0);
1270 send_change_level(&(last_player->member));
1271 sendall_bell();
1272 sendall_message(0,txt,0,0);
1273 snprintf(txt,256,"There'%s %d %s in the game.",active_players==1?"s":"re",active_players,active_players==1?"player":"players");
1274 sendall_message(0,txt,0,0);
1275 send_info(0,0);
1276 }
1277 break;
1278
1279 case P_LEVEL_ACCEPTED:
1280 q=find_player(&client,s);
1281 if (!q)break;
1282 if (q->member.current_level>=0)break;
1283
1284 q->member.current_level=level_number;
1285 sendall_new_object(q->member.obj,&(q->member));
1286 create_noise(double2int(q->member.obj->x),double2int(q->member.obj->y),&(q->member));
1287 /* send all objects in the game */
1288 send_objects(&(q->member),q->member.obj);
1289 /* send all objects waiting for respawn */
1290 send_timeq_objects(&(q->member));
1291 break;
1292
1293 case P_INFO:
1294 q=find_player(&client,s);
1295 if (!q) send_info((struct sockaddr*)(&client),0);
1296 else send_info((struct sockaddr*)(&client),q->member.id);
1297 break;
1298
1299 case P_REENTER_GAME:
1300 q=find_player(&client,s);
1301 if (!q)break;
1302 if (!(q->member.obj->status&1024)||(q->member.obj->status&4096))break;
1303 find_birthplace(&x,&y);
1304 create_noise(x,y,&(q->member));
1305 q->member.obj->x=int2double(x);
1306 q->member.obj->y=int2double(y);
1307 sendall_update_object(q->member.obj,0,3); /* update coordinates */
1308 break;
1309
1310 case P_END:
1311 if (nonquitable)break;
1312 q=find_player(&client,s);
1313 if (!q)break;
1314 p=&(q->member);
1315 packet[0]=P_END;
1316 memcpy(packet+1,p->name,strlen(p->name)+1);
1317 sendall(packet,2+strlen(p->name),0);
1318 snprintf(txt,256,"Game terminated by player \"%s\".\n",p->name);
1319 message(txt,2);
1320 exit(0);
1321
1322 case P_QUIT_REQUEST:
1323 q=find_player(&client,s);
1324 if (!q) /* this player has been deleted, but due to network inconsistency he doesn't know it */
1325 {
1326 packet[0]=P_PLAYER_DELETED;
1327 send_packet(packet,1,(struct sockaddr*)(&client),0,last_player->member.id);
1328 break;
1329 }
1330 snprintf(txt,256,"%s left the game.\n",q->member.name);
1331 message(txt,2);
1332 packet[0]=P_PLAYER_DELETED;
1333 send_packet(packet,1,(struct sockaddr*)(&client),0,last_player->member.id);
1334 snprintf(txt,256,"%s left the game.",q->member.name);
1335 sendall_message(0,txt,0,0);
1336 delete_player(q);
1337 send_info(0,0);
1338 break;
1339
1340 case P_KEYBOARD:
1341 if (l<3)break; /* invalid packet */
1342 q=find_player(&client,s);
1343 if (!q)break;
1344 q->member.last_update=get_time();
1345 q->member.keyboard_status.right=(packet[1])&1;
1346 q->member.keyboard_status.left=((packet[1])>>1)&1;
1347 q->member.keyboard_status.jump=((packet[1])>>2)&1;
1348 q->member.keyboard_status.creep=((packet[1])>>3)&1;
1349 q->member.keyboard_status.speed=((packet[1])>>4)&1;
1350 q->member.keyboard_status.fire=((packet[1])>>5)&1;
1351 q->member.keyboard_status.down_ladder=((packet[1])>>6)&1;
1352 q->member.keyboard_status.weapon=packet[2];
1353 break;
1354
1355 case P_MESSAGE:
1356 if (l<2)break; /* invalid packet */
1357 q=find_player(&client,s);
1358 if (!q)break;
1359 sendall_message(q->member.name,packet+1,0,0);
1360 snprintf(txt,256,"%s> %s\n",q->member.name,packet+1);
1361 message(txt,1);
1362 break;
1363
1364 default:
1365 snprintf(txt,256,"Unknown packet: head=%d\n",*packet);
1366 message(txt,2);
1367 break;
1368 }
1369 }
1370 }
1371
1372
1373 /* compute collision of two objects */
1374 /* return value: 0=nothing */
1375 /* 1=collision */
collision(int x1,int y1,int t1,int s1,struct pos * p1,int x2,int y2,int t2,int s2,struct pos * p2)1376 int collision(int x1,int y1,int t1,int s1,struct pos* p1,int x2,int y2,int t2,int s2,struct pos *p2)
1377 {
1378 int w1,w2,h1,h2;
1379 unsigned char h=0,v=0;
1380
1381 get_dimensions(t1,s1,p1,&w1,&h1);
1382 get_dimensions(t2,s2,p2,&w2,&h2);
1383
1384 if ((x2>=x1&&x2<=x1+w1-1)||(x2+w2-1>=x1&&x2+w2-1<=x1+w1-1))h=1;
1385 if ((x1>=x2&&x1<=x2+w2-1)||(x1+w1-1>=x2&&x1+w1-1<=x2+w2-1))h=1;
1386 if (!h)return 0;
1387
1388 if ((y2>=y1&&y2<=y1+h1-1)||(y2+h2-1>=y1&&y2+h2-1<=y1+h1-1))v=1;
1389 if ((y1>=y2&&y1<=y2+h2-1)||(y1+h1-1>=y2&&y1+h1-1<=y2+h2-1))v=1;
1390 if (!v)return 0;
1391 return 1;
1392 }
1393
1394
1395 /* create corpse on given position and with color num */
1396 /* num is number of dead player */
create_corpse(int x,int y,int num)1397 void create_corpse(int x,int y,int num)
1398 {
1399 struct it *o;
1400 static unsigned char txt[32];
1401 int a;
1402 int xoffs=num>15?-15:-5;
1403 int yoffs=num>15?-1:0;
1404
1405 sprintf(txt,"corpse%d",num);
1406 if (find_sprite(txt,&a))return;
1407
1408 o=new_obj(id,T_CORPSE,CORPSE_TTL,a,0,0,int2double(x+xoffs),int2double(y+yoffs),0,0,0);
1409 if (!o)return;
1410 id++;
1411 sendall_new_object(o,0);
1412 }
1413
1414
1415 /* create mess on given position */
1416 /* y1=y coordinate of the mess */
1417 /* y2=y coordinate of the player (place where blood gushes and guts fly from */
create_mess(int x,int y1,int y2)1418 void create_mess(int x,int y1,int y2)
1419 {
1420 struct it *o;
1421
1422 o=new_obj(id,T_CORPSE,CORPSE_TTL,mess1_sprite,0,0,int2double(x),int2double(y1),0,0,0);
1423 if (!o)return;
1424 id++;
1425 sendall_new_object(o,0);
1426
1427 o=new_obj(id,T_MESS,MESS_TTL,mess2_sprite,0,0,int2double(x),int2double(y2),-float2double(2*36),-float2double((double)1.4*36),0);
1428 if (!o)return;
1429 id++;
1430 sendall_new_object(o,0);
1431
1432 o=new_obj(id,T_MESS,MESS_TTL,mess2_sprite,0,0,int2double(x),int2double(y2),float2double((double)2.8*36),-float2double(1*36),0);
1433 if (!o)return;
1434 id++;
1435 sendall_new_object(o,0);
1436
1437 o=new_obj(id,T_MESS,MESS_TTL,mess2_sprite,0,0,int2double(x),int2double(y2),float2double(3*36),float2double((double).5*36),0);
1438 if (!o)return;
1439 id++;
1440 sendall_new_object(o,0);
1441
1442 o=new_obj(id,T_MESS,MESS_TTL,mess3_sprite,0,0,int2double(x),int2double(y2),-float2double((double)2.5*36),float2double((double).3*36),0);
1443 if (!o)return;
1444 id++;
1445 sendall_new_object(o,0);
1446
1447 o=new_obj(id,T_MESS,MESS_TTL,mess4_sprite,0,0,int2double(x),int2double(y2),-float2double((double)3.3*36),-float2double((double)2.1*36),0);
1448 if (!o)return;
1449 id++;
1450 sendall_new_object(o,0);
1451
1452 o=new_obj(id,T_MESS,MESS_TTL,mess4_sprite,0,0,int2double(x),int2double(y2),float2double((double)2.9*36),-float2double((double)1.7*36),0);
1453 if (!o)return;
1454 id++;
1455 sendall_new_object(o,0);
1456
1457 o=new_obj(id,T_MESS,MESS_TTL,mess4_sprite,0,0,int2double(x),int2double(y2),-float2double((double)1.3*36),float2double((double).8*36),0);
1458 if (!o)return;
1459 id++;
1460 sendall_new_object(o,0);
1461
1462 o=new_obj(id,T_MESS,MESS_TTL,mess3_sprite,0,0,int2double(x),int2double(y2),float2double((double).7*36),-float2double((double)1.2*36),0);
1463 if (!o)return;
1464 id++;
1465 sendall_new_object(o,0);
1466 }
1467
1468
1469 /* compute collision of given object with the others */
1470 /* return value: 1=delete this object */
1471 /* 0=don't delete */
1472 /* 2= delete this object but don't send delete packet */
dynamic_collision(struct it * obj)1473 int dynamic_collision(struct it *obj)
1474 {
1475 struct it *p;
1476 struct player_list *pl;
1477 unsigned char txt[256];
1478 struct it *o;
1479 my_double b;
1480 int a,c,s;
1481 int px,py,h;
1482
1483 #define OX (double2int(obj->x))
1484 #define OY (double2int(obj->y))
1485 #define PX (double2int(p->x))
1486 #define PY (double2int(p->y))
1487 #define A ((struct player*)(p->data))->armor
1488 #define H ((struct player*)(p->data))->health
1489 #define P ((struct player*)(p->data))
1490 #define MAX_AMMO(x) (weapon[x].max_ammo)
1491
1492
1493 for (pl=&players;pl->next;pl=pl->next)
1494 {
1495 p=pl->next->member.obj;
1496 if (p->type==T_PLAYER&&(p->status&1024))continue; /* dead player */
1497 if (collision(OX,OY,obj->type,obj->status,sprites[obj->sprite].positions,PX,PY,p->type,p->status,sprites[p->sprite].positions))
1498 switch(obj->type)
1499 {
1500 case T_AMMO_GRENADE:
1501 {
1502 unsigned char txt[256];
1503 if (p->type!=T_PLAYER)break;
1504 if (((struct player*)(p->data))->ammo[WEAPON_GRENADE]==MAX_AMMO(WEAPON_GRENADE))break;
1505 ((struct player*)(p->data))->ammo[WEAPON_GRENADE]+=weapon[WEAPON_GRENADE].add_ammo;
1506 if (((struct player*)(p->data))->ammo[WEAPON_GRENADE]>MAX_AMMO(WEAPON_GRENADE))
1507 ((struct player*)(p->data))->ammo[WEAPON_GRENADE]=MAX_AMMO(WEAPON_GRENADE);
1508 /* P->current_weapon=select_best_weapon(P); */
1509 send_update_player((struct player*)(p->data));
1510 send_message((struct player*)(p->data),0,"You got grenades");
1511 snprintf(txt,256,"%s got grenades.\n",((struct player*)(p->data))->name);
1512 message(txt,1);
1513 obj->status|=64;
1514 add_to_timeq(obj->id,T_AMMO_GRENADE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1515 sendall_update_status(obj,0);
1516 }
1517 return 2;
1518
1519 case T_AMMO_GUN:
1520 {
1521 unsigned char txt[256];
1522 if (p->type!=T_PLAYER)break;
1523 if (((struct player*)(p->data))->ammo[0]==MAX_AMMO(0))break;
1524
1525 if(is_weapon_better((struct player*)(p->data), 0)
1526 && is_weapon_empty((struct player*)(p->data), 0))
1527 P->current_weapon = 0;
1528
1529 ((struct player*)(p->data))->ammo[0]+=weapon[0].add_ammo;
1530 if (((struct player*)(p->data))->ammo[0]>MAX_AMMO(0))
1531 ((struct player*)(p->data))->ammo[0]=MAX_AMMO(0);
1532 /* P->current_weapon=select_best_weapon(P); */
1533 send_update_player((struct player*)(p->data));
1534 send_message((struct player*)(p->data),0,"You got a magazine");
1535 snprintf(txt,256,"%s got a magazine.\n",((struct player*)(p->data))->name);
1536 message(txt,1);
1537 obj->status|=64;
1538 add_to_timeq(obj->id,T_AMMO_GUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1539 sendall_update_status(obj,0);
1540 }
1541 return 2;
1542
1543 case T_AMMO_SHOTGUN:
1544 {
1545 unsigned char txt[256];
1546 if (p->type!=T_PLAYER)break;
1547 if (((struct player*)(p->data))->ammo[1]==MAX_AMMO(1))break;
1548
1549 if(is_weapon_better((struct player*)(p->data), 1)
1550 && is_weapon_empty((struct player*)(p->data), 1))
1551 P->current_weapon = 1;
1552
1553 ((struct player*)(p->data))->ammo[1]+=weapon[1].add_ammo;
1554 if (((struct player*)(p->data))->ammo[1]>MAX_AMMO(1))
1555 ((struct player*)(p->data))->ammo[1]=MAX_AMMO(1);
1556 /* P->current_weapon=select_best_weapon(P); */
1557 send_update_player((struct player*)(p->data));
1558 send_message((struct player*)(p->data),0,"You got shotgun shells");
1559 snprintf(txt,256,"%s got shotgun shells.\n",((struct player*)(p->data))->name);
1560 message(txt,1);
1561 obj->status|=64;
1562 add_to_timeq(obj->id,T_AMMO_SHOTGUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1563 sendall_update_status(obj,0);
1564 }
1565 return 2;
1566
1567 case T_AMMO_RIFLE:
1568 {
1569 unsigned char txt[256];
1570 if (p->type!=T_PLAYER)break;
1571 if (((struct player*)(p->data))->ammo[3]==MAX_AMMO(3))break;
1572
1573 if(is_weapon_better((struct player*)(p->data), 3)
1574 && is_weapon_empty((struct player*)(p->data), 3))
1575 P->current_weapon = 3;
1576
1577 ((struct player*)(p->data))->ammo[3]+=weapon[3].add_ammo;
1578 if (((struct player*)(p->data))->ammo[3]>MAX_AMMO(3))
1579 ((struct player*)(p->data))->ammo[3]=MAX_AMMO(3);
1580 /* P->current_weapon=select_best_weapon(P); */
1581 send_update_player((struct player*)(p->data));
1582 send_message((struct player*)(p->data),0,"You got cartridges");
1583 snprintf(txt,256,"%s got cartridges.\n",((struct player*)(p->data))->name);
1584 message(txt,1);
1585 obj->status|=64;
1586 add_to_timeq(obj->id,T_AMMO_RIFLE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1587 sendall_update_status(obj,0);
1588 }
1589 return 2;
1590
1591 case T_AMMO_UZI:
1592 {
1593 unsigned char txt[256];
1594 if (p->type!=T_PLAYER)break;
1595 if (((struct player*)(p->data))->ammo[2]==MAX_AMMO(2))break;
1596
1597 if(is_weapon_better((struct player*)(p->data), 2)
1598 && is_weapon_empty((struct player*)(p->data), 2))
1599 P->current_weapon = 2;
1600
1601 ((struct player*)(p->data))->ammo[2]+=weapon[2].add_ammo;
1602 if (((struct player*)(p->data))->ammo[2]>MAX_AMMO(2))
1603 ((struct player*)(p->data))->ammo[2]=MAX_AMMO(2);
1604 /* P->current_weapon=select_best_weapon(P); */
1605 send_update_player((struct player*)(p->data));
1606 send_message((struct player*)(p->data),0,"You got ammo for Uzi");
1607 snprintf(txt,256,"%s got Uzi ammo.\n",((struct player*)(p->data))->name);
1608 message(txt,1);
1609 obj->status|=64;
1610 add_to_timeq(obj->id,T_AMMO_UZI,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1611 sendall_update_status(obj,0);
1612 }
1613 return 2;
1614
1615 case T_UZI:
1616 {
1617 unsigned char txt[256];
1618 if (p->type!=T_PLAYER)break;
1619 if ((((struct player*)(p->data))->ammo[2]==MAX_AMMO(2))&&((((struct player *)(p->data))->weapons)&4))break;
1620
1621 if(is_weapon_better((struct player*)(p->data), 2)
1622 && !is_weapon_usable((struct player*)(p->data), 2))
1623 P->current_weapon = 2;
1624
1625 ((struct player*)(p->data))->weapons|=4;
1626 ((struct player*)(p->data))->ammo[2]+=weapon[2].basic_ammo;
1627 if (((struct player*)(p->data))->ammo[2]>MAX_AMMO(2))
1628 ((struct player*)(p->data))->ammo[2]=MAX_AMMO(2);
1629 // P->current_weapon=select_best_weapon(P);
1630 send_update_player((struct player*)(p->data));
1631 send_message((struct player*)(p->data),0,"You got Uzi");
1632 snprintf(txt,256,"%s got Uzi.\n",((struct player*)(p->data))->name);
1633 message(txt,1);
1634 obj->status|=64;
1635 add_to_timeq(obj->id,T_UZI,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1636 sendall_update_status(obj,0);
1637 }
1638 return 2;
1639
1640 case T_RIFLE:
1641 {
1642 unsigned char txt[256];
1643 if (p->type!=T_PLAYER)break;
1644 if ((((struct player*)(p->data))->ammo[3]==MAX_AMMO(3))&&((((struct player *)(p->data))->weapons)&8))break;
1645
1646 if(is_weapon_better((struct player*)(p->data), 3)
1647 && !is_weapon_usable((struct player*)(p->data), 3))
1648 P->current_weapon = 3;
1649
1650 ((struct player*)(p->data))->weapons|=8;
1651 ((struct player*)(p->data))->ammo[3]+=weapon[3].basic_ammo;
1652 if (((struct player*)(p->data))->ammo[3]>MAX_AMMO(3))
1653 ((struct player*)(p->data))->ammo[3]=MAX_AMMO(3);
1654 // P->current_weapon=select_best_weapon(P);
1655 send_update_player((struct player*)(p->data));
1656 send_message((struct player*)(p->data),0,"You got sniper rifle");
1657 snprintf(txt,256,"%s got sniper rifle.\n",((struct player*)(p->data))->name);
1658 message(txt,1);
1659 obj->status|=64;
1660 add_to_timeq(obj->id,T_RIFLE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1661 sendall_update_status(obj,0);
1662 }
1663 return 2;
1664
1665 case T_SHOTGUN:
1666 {
1667 unsigned char txt[256];
1668 if (p->type!=T_PLAYER)break;
1669 if ((((struct player*)(p->data))->ammo[1]==MAX_AMMO(1))&&((((struct player *)(p->data))->weapons)&2))break;
1670
1671 if(is_weapon_better((struct player*)(p->data), 1)
1672 && !is_weapon_usable((struct player*)(p->data), 1))
1673 P->current_weapon = 1;
1674
1675 ((struct player*)(p->data))->weapons|=2;
1676 ((struct player*)(p->data))->ammo[1]+=weapon[1].basic_ammo;
1677 if (((struct player*)(p->data))->ammo[1]>MAX_AMMO(1))
1678 ((struct player*)(p->data))->ammo[1]=MAX_AMMO(1);
1679 // P->current_weapon=select_best_weapon(P);
1680 send_update_player((struct player*)(p->data));
1681 send_message((struct player*)(p->data),0,"You got a shotgun");
1682 snprintf(txt,256,"%s got a shotgun.\n",((struct player*)(p->data))->name);
1683 message(txt,1);
1684 obj->status|=64;
1685 add_to_timeq(obj->id,T_SHOTGUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1686 sendall_update_status(obj,0);
1687 }
1688 return 2;
1689
1690 case T_INVISIBILITY:
1691 {
1692 unsigned char txt[256];
1693 if (p->type!=T_PLAYER)break;
1694
1695 ((struct player*)(p->data))->invisibility_counter=INVISIBILITY_DURATION;
1696 p->status|=64; /* hide player */
1697 sendall_update_status(p,0);
1698 send_message((struct player*)(p->data),0,"You got invisibility dope");
1699 snprintf(txt,256,"%s got invisibility.\n",((struct player*)(p->data))->name);
1700 message(txt,1);
1701 obj->status|=64;
1702 add_to_timeq(obj->id,T_INVISIBILITY,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,INVISIBILITY_RESPAWN_TIME);
1703 sendall_update_status(obj,0);
1704 }
1705 return 2;
1706
1707 case T_ARMOR:
1708 {
1709 unsigned char txt[256];
1710 if (p->type!=T_PLAYER)break;
1711 if (((struct player*)(p->data))->armor>=100)break; /* he has 100% armor */
1712 ((struct player*)(p->data))->armor+=ARMOR_ADD;
1713 if (((struct player*)(p->data))->armor>100)((struct player*)(p->data))->armor=100;
1714 send_update_player((struct player*)(p->data));
1715 send_message((struct player*)(p->data),0,"You got armor");
1716 snprintf(txt,256,"%s got armor.\n",((struct player*)(p->data))->name);
1717 message(txt,1);
1718 obj->status|=64;
1719 add_to_timeq(obj->id,T_ARMOR,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,ARMOR_RESPAWN_TIME);
1720 sendall_update_status(obj,0);
1721 }
1722 return 2;
1723
1724 case T_MEDIKIT:
1725 {
1726 unsigned char txt[256];
1727 if (p->type!=T_PLAYER)break;
1728 if (((struct player*)(p->data))->health>=100)break; /* he's healthy */
1729 ((struct player*)(p->data))->health+=MEDIKIT_HEALTH_ADD;
1730 if (((struct player*)(p->data))->health>100)((struct player*)(p->data))->health=100;
1731 send_update_player((struct player*)(p->data));
1732 send_message((struct player*)(p->data),0,"You picked up a medikit");
1733 snprintf(txt,256,"%s picked up a medikit.\n",((struct player*)(p->data))->name);
1734 message(txt,1);
1735 obj->status|=64;
1736 add_to_timeq(obj->id,T_MEDIKIT,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,MEDIKIT_RESPAWN_TIME);
1737 sendall_update_status(obj,0);
1738 }
1739 return 2;
1740
1741 case T_KILL:
1742 if (p->type!=T_PLAYER)break;
1743 a=(1-(double)A/100)*KILL_LETHALNESS;
1744 c=KILL_ARMOR_DAMAGE;
1745 if (a>=H) /* player died */
1746 {
1747 ((struct player*)(p->data))->deaths++;
1748 send_message((struct player*)(p->data),0,"You killed yourself");
1749 snprintf(txt,256,"%s suicides",((struct player*)(p->data))->name);
1750 sendall_message(0,txt,(struct player*)(p->data),0);
1751 snprintf(txt,256,"%s suicides.\n",((struct player*)(p->data))->name);
1752 message(txt,2);
1753
1754 s=p->status;
1755 px=PX;
1756 py=PY;
1757 h=H;
1758 H=0;
1759 p->xspeed=0;
1760 p->yspeed=0;
1761 p->status|=1024; /* dead flag */
1762 sendall_update_object(p,0,0); /* update everything */
1763 send_update_player((struct player*)(p->data)); /* dead player */
1764 send_info(0,0);
1765 if (a-h>=OVERKILL)
1766 create_mess(px,py+((s&256)?CREEP_HEIGHT:PLAYER_HEIGHT)-MESS_HEIGHT,py);
1767 else
1768 create_corpse(px,py+((s&256)?CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->data))->color);
1769 }
1770 else
1771 {
1772 H-=a; /* health */
1773 A=(c>=A)?0:(A-c); /* armor */
1774 send_update_player((struct player*)(p->data));
1775 }
1776 return 0;
1777
1778 case T_SHRAPNEL:
1779 if (p->type==T_CORPSE)
1780 {
1781 unsigned char packet[5];
1782 px=PX;
1783 py=PY;
1784 packet[0]=P_DELETE_OBJECT;
1785 put_int(packet+1,p->id);
1786 sendall_chunked(packet,5,0);
1787 delete_obj(p->id);
1788 create_mess(px,py,py);
1789 return 1;
1790 }
1791 case T_BULLET:
1792 if (p->type!=T_PLAYER)break;
1793 b=(obj->type==T_BULLET?FIRE_IMPACT:SHRAPNEL_IMPACT);
1794 p->status|=128;
1795 p->xspeed+=obj->xspeed>0?b:-b;
1796 sendall_update_object(p,0,4); /* update speed + status */
1797 p->status&=~128;
1798 a=(1-(double)A/100)*weapon[obj->status].lethalness*(2-double2int(obj->y-p->y)/(double)PLAYER_HEIGHT)*obj->ttl/weapon[obj->status].ttl;
1799 c=weapon[obj->status].armor_damage*(2-double2int(obj->y-p->y)/(double)PLAYER_HEIGHT)*obj->ttl/weapon[obj->status].ttl;
1800 if (a>=H) /* player was slain */
1801 {
1802 o=&((find_in_table((int)(obj->data)))->member); /* owner of the bullet */
1803 ((struct player*)(p->data))->deaths++;
1804 if (o->data==p->data) /* suicide */
1805 {
1806 ((struct player*)(o->data))->frags-=!!(((struct player*)(o->data))->frags);
1807 send_message((struct player*)(o->data),0,"You killed yourself");
1808 snprintf(txt,256,"%s suicides",((struct player*)(o->data))->name);
1809 sendall_message(0,txt,(struct player*)(o->data),0);
1810 snprintf(txt,256,"%s suicides.\n",((struct player*)(o->data))->name);
1811 message(txt,2);
1812 }
1813 else
1814 {
1815 ((struct player*)(o->data))->frags++;
1816 snprintf(txt,256,"%s killed %s.",((struct player*)(o->data))->name,((struct player*)(p->data))->name);
1817 sendall_message(0,txt,(struct player*)(o->data),(struct player*)(p->data));
1818 snprintf(txt,256,"%s killed you",((struct player*)(o->data))->name);
1819 send_message((struct player*)(p->data),0,txt); /* the dead */
1820 snprintf(txt,256,"You killed %s",((struct player*)(p->data))->name);
1821 send_message((struct player*)(o->data),0,txt); /* the dead */
1822 snprintf(txt,256,"%s killed %s.\n",((struct player*)(o->data))->name,((struct player*)(p->data))->name);
1823 message(txt,2);
1824 }
1825 s=p->status;
1826 px=PX;
1827 py=PY;
1828 h=H;
1829 H=0;
1830 p->xspeed=0;
1831 p->yspeed=0;
1832 p->status|=1024; /* dead flag */
1833 sendall_update_object(p,0,0); /* update everything */
1834 send_update_player((struct player*)(p->data)); /* dead player */
1835 send_update_player((struct player*)(o->data)); /* owner of bullet/shrapnel */
1836 send_info(0,0);
1837 if (a-h>=OVERKILL)
1838 create_mess(px,py+((s&256)?CREEP_HEIGHT:PLAYER_HEIGHT)-MESS_HEIGHT,py);
1839 else
1840 create_corpse(px,py+((s&256)?CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->data))->color);
1841 }
1842 else
1843 {
1844 H-=a; /* health */
1845 A=(c>=A)?0:(A-c); /* armor */
1846 sendall_hit(p->id,obj->xspeed<0,OX-PX,OY-PY,0);
1847 send_update_player((struct player*)(p->data));
1848 }
1849 return 1;
1850 }
1851 }
1852 return 0;
1853
1854 #undef MAX_AMMO
1855 #undef P
1856 #undef H
1857 #undef A
1858 #undef OX
1859 #undef OY
1860 #undef PX
1861 #undef PY
1862 }
1863
1864
1865 /* recompute objects positions */
update_game(void)1866 void update_game(void)
1867 {
1868 static unsigned char packet[64];
1869 struct object_list *p;
1870 struct player_list *q;
1871 int w,h,b,a;
1872 unsigned char stop_x,stop_y;
1873 my_double x,y,xs,ys;
1874 my_double x1,y1;
1875 unsigned char sy;
1876 struct it *s; /* for grenades throwing */
1877 int status;
1878 my_double DELTA_TIME;
1879 unsigned long_long t;
1880 unsigned int old_status;
1881 int old_ttl;
1882 my_double old_x,old_y,old_x_speed,old_y_speed;
1883
1884 for(p=&objects;p->next;p=p->next)
1885 {
1886 if (p->next->member.type==T_NOTHING)continue;
1887 if (p->next->member.type==T_PLAYER&&(p->next->member.status&1024))continue; /* dead player */
1888 if (p->next->member.type==T_PLAYER&&(((struct player*)(p->next->member.data))->current_level)<0) /* player hasn't entered the level yet */
1889 {
1890 send_change_level((struct player*)p->next->member.data);
1891 continue;
1892 }
1893
1894 old_status=p->next->member.status;
1895 old_ttl=p->next->member.ttl;
1896 old_x=p->next->member.x;
1897 old_y=p->next->member.y;
1898 old_x_speed=p->next->member.xspeed;
1899 old_y_speed=p->next->member.yspeed;
1900
1901 x=p->next->member.x;
1902 y=p->next->member.y;
1903 xs=p->next->member.xspeed;
1904 ys=p->next->member.yspeed;
1905 status=p->next->member.status;
1906
1907 /* decrease invisibility counter of invisible player */
1908 if ((p->next->member.type==T_PLAYER)&&(((struct player*)(p->next->member.data))->invisibility_counter))
1909 {
1910 ((struct player*)(p->next->member.data))->invisibility_counter--;
1911 if (!(((struct player*)(p->next->member.data))->invisibility_counter))
1912 {
1913 p->next->member.status&=~64;
1914 sendall_update_status(&(p->next->member),0);
1915 }
1916 }
1917
1918
1919 /* decrement time to live */
1920 if (p->next->member.ttl>0)
1921 {
1922 p->next->member.ttl--;
1923 /* create player */
1924 if (p->next->member.type==T_NOISE&&p->next->member.ttl==(NOISE_TTL>>1))
1925 {
1926 /* find player */
1927 q=find_player(0,(int)(p->next->member.data));
1928 if (q) /* player is still in the game */
1929 {
1930 init_player(&(q->member),q->member.obj->x,q->member.obj->y);
1931 q->member.obj->status&=~1024;
1932 q->member.obj->status&=~4096;
1933 sendall_update_object(q->member.obj,0,0); /* update everything */
1934 send_update_player(&(q->member));
1935 }
1936
1937 goto cont_cycle; /* that's all for T_NOISE at this moment */
1938 }
1939 /* grenades must be created after locking off */
1940 /* not when shoot request comes */
1941 if (p->next->member.type==T_PLAYER&&p->next->member.ttl==GRENADE_DELAY+HOLD_GUN_AFTER_SHOOT&&((struct player*)(p->next->member.data))->current_weapon==WEAPON_GRENADE)
1942 {
1943 s=new_obj(
1944 id,
1945 T_GRENADE,
1946 weapon[WEAPON_GRENADE].ttl,
1947 grenade_sprite,
1948 0,
1949 WEAPON_GRENADE,
1950 add_int(p->next->member.x,p->next->member.status&2?2:PLAYER_WIDTH-2),
1951 p->next->member.y+GRENADE_FIRE_YOFFSET,
1952 p->next->member.xspeed+(p->next->member.status&2?-weapon[WEAPON_GRENADE].shell_xspeed:weapon[WEAPON_GRENADE].shell_xspeed),
1953 p->next->member.yspeed+weapon[WEAPON_GRENADE].shell_yspeed,
1954 (void *)(p->next->member.id));
1955 id++;
1956 sendall_new_object(s,0);
1957 }
1958 /* if ttl is 0, delete this object */
1959 if (p->next->member.ttl<=0)
1960 {
1961 /* player's ttl means how long he holds the gun */
1962 switch(p->next->member.type)
1963 {
1964 case T_PLAYER:
1965 p->next->member.status&=~16;
1966 break;
1967
1968 case T_GRENADE:
1969 packet[0]=P_EXPLODE_GRENADE;
1970 put_int(packet+1,id);
1971 put_int(packet+5,p->next->member.id);
1972 sendall_chunked(packet,9,0);
1973
1974 for (b=0;b<N_SHRAPNELS_EXPLODE;b++)
1975 {
1976 double angle=(double)b*2*M_PI/N_SHRAPNELS_EXPLODE;
1977 my_double spd=add_int(mul_int(my_and(mul_int(weapon[WEAPON_GRENADE].speed,b+1),15),16),100);
1978
1979 new_obj(
1980 id,
1981 T_SHRAPNEL,
1982 SHRAPNEL_TTL,
1983 shrapnel_sprite[random()%N_SHRAPNELS],
1984 0,
1985 WEAPON_GRENADE,
1986 p->next->member.x,
1987 p->next->member.y,
1988 p->next->member.xspeed+mul(spd,float2double(cos(angle))),
1989 p->next->member.yspeed+mul(spd,float2double(sin(angle))),
1990 p->next->member.data);
1991 id++;
1992 }
1993 delete_obj(p->next->member.id);
1994 if (!(p->next))return;
1995 goto cont_cycle;
1996
1997 default:
1998 packet[0]=P_DELETE_OBJECT;
1999 put_int(packet+1,p->next->member.id);
2000 sendall_chunked(packet,5,0);
2001 delete_obj(p->next->member.id);
2002 if (!(p->next))return;
2003 goto cont_cycle;
2004 }
2005 }
2006 }
2007 /* maintain only objects that you are allowed to maintain */
2008 if (!obj_attr[p->next->member.type].maintainer)goto dc;
2009 if (!(obj_attr[p->next->member.type].maintainer&2))continue;
2010
2011
2012 /* when not falling, slow down x motion */
2013 if (!(p->next->member.status&8))p->next->member.xspeed=mul(p->next->member.xspeed,obj_attr[p->next->member.type].slow_down_x);
2014
2015 /* fall */
2016 if (obj_attr[p->next->member.type].fall)
2017 {
2018 if (p->next->member.type!=T_SHRAPNEL)p->next->member.status|=8;
2019 p->next->member.yspeed+=FALL_ACCEL;
2020 /* but not too fast */
2021 if (p->next->member.yspeed>MAX_Y_SPEED)p->next->member.yspeed=MAX_Y_SPEED;
2022 }
2023
2024 t=get_time();
2025 get_dimensions(p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions,&w,&h);
2026 DELTA_TIME=float2double(((double)((long_long)(t-p->next->member.last_updated)))/MICROSECONDS);
2027 update_position(
2028 &(p->next->member),
2029 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
2030 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
2031 w,h,&stop_x,&stop_y);
2032 p->next->member.last_updated=t;
2033
2034 /* walk up the stairs */
2035 if (stop_x&&p->next->member.type==T_PLAYER&&!(p->next->member.status&256))
2036 {
2037 x1=p->next->member.x;
2038 y1=p->next->member.y;
2039 p->next->member.x=x;
2040 p->next->member.y=y-int2double(1);
2041 update_position(
2042 &(p->next->member),
2043 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
2044 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
2045 w,h,0,&sy);
2046 if ((p->next->member.xspeed>0&&p->next->member.x<=x1)||(p->next->member.xspeed<0&&p->next->member.x>=x1)) /* restore original values */
2047 {
2048 p->next->member.x=x1;
2049 p->next->member.y=y1;
2050 }
2051 else
2052 {
2053 stop_y=sy;
2054 stop_x=0;
2055 }
2056 }
2057
2058 if (stop_x)p->next->member.xspeed=-mul(p->next->member.xspeed,obj_attr[p->next->member.type].bounce_x);
2059 if (my_abs(p->next->member.xspeed)<MIN_X_SPEED)
2060 {
2061 p->next->member.xspeed=0;
2062 p->next->member.status&=~1;
2063 }
2064
2065
2066 if (stop_y)
2067 {
2068 p->next->member.yspeed=mul(p->next->member.yspeed,obj_attr[p->next->member.type].bounce_y);
2069 p->next->member.yspeed=-p->next->member.yspeed;
2070 if (my_abs(p->next->member.yspeed)<MIN_Y_SPEED)
2071 {
2072 p->next->member.yspeed=0;
2073 if (stop_y==1)p->next->member.status&=~8;
2074 }
2075 }
2076
2077 if ((p->next->member.type==T_SHRAPNEL||p->next->member.type==T_BULLET)&&(stop_x||stop_y)) /* bullet and shrapnel die crashing into wall */
2078 {
2079 packet[0]=P_DELETE_OBJECT;
2080 put_int(packet+1,p->next->member.id);
2081 sendall_chunked(packet,5,0);
2082 delete_obj(p->next->member.id);
2083 if (!(p->next))break;
2084 continue;
2085 }
2086 dc:
2087 /* compute collision with other objects */
2088 a=dynamic_collision(&(p->next->member));
2089 switch (a)
2090 {
2091 case 1: /* object dies */
2092 packet[0]=P_DELETE_OBJECT;
2093 put_int(packet+1,p->next->member.id);
2094 sendall_chunked(packet,5,0);
2095
2096 case 2:
2097 delete_obj(p->next->member.id);
2098 if (!(p->next))return;
2099 goto cont_cycle;
2100
2101 case 0: /* object still lives */
2102 if ( /* send update but only when something's changed and client doesn't maintain the object */
2103 (obj_attr[p->next->member.type].maintainer&4)&& /* server sends update */
2104 (x!=p->next->member.x|| /* something's changed */
2105 y!=p->next->member.y||
2106 xs!=p->next->member.xspeed||
2107 ys!=p->next->member.yspeed||
2108 status!=p->next->member.status))
2109 {
2110 a=which_update(&(p->next->member),old_x,old_y,old_x_speed,old_y_speed,old_status,old_ttl);
2111 sendall_update_object(&(p->next->member),0,a);
2112 }
2113 break;
2114 }
2115 cont_cycle:;
2116 }
2117 }
2118
free_all_memory(void)2119 void free_all_memory(void)
2120 {
2121 struct queue_list *t;
2122 struct player_list *p;
2123
2124 /* delete players */
2125 for (p=&players;p->next;)
2126 delete_player(p->next);
2127 /* delete objects */
2128 while (last_obj!=(&objects))delete_obj(last_obj->member.id);
2129
2130 for (t=&time_queue;t->next;)
2131 {
2132 struct queue_list *q;
2133
2134 q=t->next->next;
2135 mem_free(t->next);
2136 t->next=q;
2137 }
2138
2139 /* delete birthplaces */
2140 if (n_birthplaces)mem_free(birthplace);
2141
2142 /* delete sprites */
2143 free_sprites(0);
2144
2145 free_area();
2146 if (level_checksum)mem_free(level_checksum);
2147 }
2148
2149 /* fatal signal handler (sigsegv, sigabrt, ... ) */
signal_handler(int sig_num)2150 void signal_handler(int sig_num)
2151 {
2152 unsigned char packet[16];
2153 unsigned char txt[256];
2154
2155 packet[0]=P_END;
2156 memcpy(packet+1,"server",7);
2157
2158 sendall(packet,8,0);
2159 sendall(packet,8,0);
2160 sendall(packet,8,0);
2161 sendall(packet,8,0);
2162 sendall(packet,8,0);
2163 sendall(packet,8,0);
2164 sendall(packet,8,0);
2165 sendall(packet,8,0);
2166 /* 800 % redundancy should be enough ;-) */
2167
2168 snprintf(txt,256,"Signal %d caught.\n",sig_num);
2169 message(txt,2);
2170 free_all_memory();
2171 check_memory_leaks();
2172 #ifdef WIN32
2173 hServerExitEvent=1;
2174 #else
2175 signal(sig_num,SIG_DFL);
2176 raise(sig_num);
2177 #endif
2178 }
2179
2180
2181 /* walk with given player */
walk_player(struct player * q,int direction,int speed,int creep)2182 void walk_player(struct player *q,int direction, int speed, int creep)
2183 {
2184 int a;
2185
2186 unsigned int old_status=q->obj->status;
2187 int old_ttl=q->obj->ttl;
2188 my_double old_x=q->obj->x,
2189 old_y=q->obj->y,
2190 old_x_speed=q->obj->xspeed,
2191 old_y_speed=q->obj->yspeed;
2192
2193
2194 if ((q->obj->status&(512+16))==(512+16))return; /* when throwing grenade can't walk */
2195 if (creep) /* creep */
2196 {
2197 a=MAX_SPEED_CREEP;
2198 if (!(q->obj->status&256))q->obj->y+=CREEP_YOFFSET;
2199 q->obj->status|=256;
2200
2201 }
2202 else
2203 {
2204 a=speed?MAX_SPEED_WALK_FAST:MAX_X_SPEED;
2205 if (q->obj->status&256)q->obj->y-=CREEP_YOFFSET;
2206 q->obj->status&=~256;
2207 }
2208 switch (direction)
2209 {
2210 case 0: /* stop */
2211 q->obj->status&=~1;
2212 q->obj->xspeed=0;
2213 break;
2214
2215 case 1: /* left */
2216 q->obj->status|=1;
2217 q->obj->xspeed-=WALK_ACCEL;
2218 if (q->obj->xspeed<-a)q->obj->xspeed=-a;
2219 break;
2220
2221 case 2: /* right */
2222 q->obj->status|=1;
2223 q->obj->xspeed+=WALK_ACCEL;
2224 if (q->obj->xspeed>a)q->obj->xspeed=a;
2225 break;
2226 }
2227
2228 a=which_update(q->obj,old_x,old_y,old_x_speed,old_y_speed,old_status,old_ttl);
2229
2230 sendall_update_object(q->obj,0,a);
2231 }
2232
2233
2234 /* jump with given player */
jump_player(struct player * p)2235 void jump_player(struct player *p)
2236 {
2237 if (p->obj->status&8||p->obj->status&256)return;
2238 p->obj->status|=8;
2239 p->obj->yspeed=-SPEED_JUMP;
2240 sendall_update_object(p->obj,0,4); /* update speed + status */
2241 }
2242
2243
2244 /* change weapon of given player (w=new weapon) */
change_weapon_player(struct player * q,int w)2245 void change_weapon_player(struct player *q,int w)
2246 {
2247 unsigned char txt[256];
2248
2249 if (!w)return;
2250 w--;
2251 if (q->current_weapon==w)return;
2252 if (!(q->weapons&(1<<w)))
2253 {send_message(q,0,"No weapon.");return;}
2254 if (!(q->ammo[w]))
2255 {send_message(q,0,"Not enough ammo.");return;}
2256 q->current_weapon=w;
2257 snprintf(txt,256,"%s takes %s.\n",q->name,weapon[w].name);
2258 message(txt,1);
2259 send_update_player(q);
2260 }
2261
2262
2263 /* shoot with given player */
2264 /* direction: 0=right, 1=left */
fire_player(struct player * q,int direction)2265 void fire_player(struct player *q,int direction)
2266 {
2267 int a;
2268 struct it *s;
2269
2270 if (!(q->obj->status&6)||(q->obj->status&256)||((q->obj->status&16)&&(q->obj->ttl>HOLD_GUN_AFTER_SHOOT)))return;
2271 if (!q->ammo[q->current_weapon])
2272 {
2273 a=select_best_weapon(q);
2274 if (a==q->current_weapon) return;
2275 q->current_weapon=a;
2276 }
2277 q->ammo[q->current_weapon]--;
2278 send_update_player(q);
2279 q->obj->status&=~512;
2280 if (q->current_weapon==WEAPON_SHOTGUN) /* shotgun */
2281 {
2282 s=new_obj( /* SHELL */
2283 id,
2284 T_SHELL,
2285 SHELL_TTL,
2286 shotgun_shell_sprite,
2287 0,
2288 0,
2289 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2290 q->obj->y+FIRE_YOFFSET,
2291 q->obj->xspeed+(direction==1?-weapon[1].shell_xspeed:weapon[1].shell_xspeed),
2292 weapon[1].shell_yspeed,
2293 (void *)(q->obj->id));
2294 id++;
2295 sendall_new_object(s,0);
2296 s=new_obj( /* straight */
2297 id,
2298 T_BULLET,
2299 weapon[q->current_weapon].ttl,
2300 slug_sprite,
2301 0,
2302 q->current_weapon,
2303 add_int(q->obj->x,direction==1?-2:PLAYER_WIDTH+2),
2304 q->obj->y+FIRE_YOFFSET,
2305 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2306 0,
2307 (void *)(q->obj->id));
2308 id++;
2309 sendall_new_object(s,0);
2310 s=new_obj( /* straight */
2311 id,
2312 T_BULLET,
2313 weapon[q->current_weapon].ttl,
2314 slug_sprite,
2315 0,
2316 q->current_weapon,
2317 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2318 q->obj->y+FIRE_YOFFSET+int2double(1),
2319 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2320 0,
2321 (void *)(q->obj->id));
2322 id++;
2323 sendall_new_object(s,0);
2324 s=new_obj( /* one up */
2325 id,
2326 T_BULLET,
2327 weapon[q->current_weapon].ttl,
2328 slug_sprite,
2329 0,
2330 q->current_weapon,
2331 add_int(q->obj->x,direction==1?-1:PLAYER_WIDTH+1),
2332 q->obj->y+FIRE_YOFFSET,
2333 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2334 float2double((double).1*36),
2335 (void *)(q->obj->id));
2336 id++;
2337 sendall_new_object(s,0);
2338 s=new_obj( /* two up */
2339 id,
2340 T_BULLET,
2341 weapon[q->current_weapon].ttl,
2342 slug_sprite,
2343 0,
2344 q->current_weapon,
2345 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2346 q->obj->y+FIRE_YOFFSET-int2double(1),
2347 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2348 float2double((double).15*36),
2349 (void *)(q->obj->id));
2350 id++;
2351 sendall_new_object(s,0);
2352 s=new_obj( /* one down */
2353 id,
2354 T_BULLET,
2355 weapon[q->current_weapon].ttl,
2356 slug_sprite,
2357 0,
2358 q->current_weapon,
2359 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2360 q->obj->y+FIRE_YOFFSET+int2double(1),
2361 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2362 -float2double((double).1*36),
2363 (void *)(q->obj->id));
2364 id++;
2365 sendall_new_object(s,0);
2366 s=new_obj( /* two down */
2367 id,
2368 T_BULLET,
2369 weapon[q->current_weapon].ttl,
2370 slug_sprite,
2371 0,
2372 q->current_weapon,
2373 add_int(q->obj->x,direction==1?-1:PLAYER_WIDTH+1),
2374 q->obj->y+FIRE_YOFFSET,
2375 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2376 -float2double((double).15*36),
2377 (void *)(q->obj->id));
2378 id++;
2379 sendall_new_object(s,0);
2380 }
2381 else
2382 {
2383 if (q->current_weapon!=WEAPON_GRENADE) /* not grenades */
2384 {
2385 s=new_obj( /* SHELL */
2386 id,
2387 T_SHELL,
2388 SHELL_TTL,
2389 shell_sprite,
2390 0,
2391 0,
2392 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2393 q->obj->y+FIRE_YOFFSET,
2394 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].shell_xspeed:weapon[q->current_weapon].shell_xspeed),
2395 weapon[q->current_weapon].shell_yspeed,
2396 (void *)(q->obj->id));
2397 id++;
2398 sendall_new_object(s,0);
2399 s=new_obj(
2400 id,
2401 T_BULLET,
2402 weapon[q->current_weapon].ttl,
2403 bullet_sprite,
2404 0,
2405 q->current_weapon,
2406 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2407 q->obj->y+FIRE_YOFFSET,
2408 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2409 0,
2410 (void *)(q->obj->id));
2411 id++;
2412 sendall_new_object(s,0);
2413 }
2414 else /* grenades */
2415 {
2416 q->obj->status|=512;
2417 q->obj->status&=~1;
2418 }
2419 }
2420 q->obj->xspeed+=(direction==1)?weapon[q->current_weapon].impact:-weapon[q->current_weapon].impact;
2421 q->obj->status|=16;
2422 q->obj->status|=32;
2423 q->obj->ttl=weapon[q->current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
2424 sendall_update_object(q->obj,0,6); /* update speed and status and ttl */
2425 q->obj->status&=~32;
2426 }
2427
2428
2429 /* update given player (jump, shoot, creep, change weapon) */
move_player(struct player * p)2430 void move_player(struct player *p)
2431 {
2432 int a;
2433
2434 if (p->obj->status&1024)return; /* dead player */
2435
2436 if (p->keyboard_status.down_ladder) /* climb down a ladder */
2437 p->obj->status|=2048;
2438 else
2439 p->obj->status&=~2048;
2440
2441 if (p->keyboard_status.jump)
2442 jump_player(p);
2443 if (p->keyboard_status.right)
2444 {
2445 if ((p->obj->status&6)==4) /* walk right */
2446 walk_player(p,2,p->keyboard_status.speed,p->keyboard_status.creep);
2447 else
2448 {
2449 if ((p->obj->status)&1)
2450 walk_player(p,0,p->keyboard_status.speed,p->keyboard_status.creep); /* stop */
2451 else
2452 {
2453 a=(p->obj->status&6)>>1;
2454 p->obj->status&=~6;
2455 p->obj->status|=(a==1)?0:4;
2456 sendall_update_status(p->obj,0);
2457 }
2458 }
2459 }
2460
2461 if (p->keyboard_status.left)
2462 {
2463 if ((p->obj->status&6)==2) /* walk right */
2464 walk_player(p,1,p->keyboard_status.speed,p->keyboard_status.creep);
2465 else
2466 {
2467 if ((p->obj->status)&1)
2468 walk_player(p,0,p->keyboard_status.speed,p->keyboard_status.creep); /* stop */
2469 else
2470 {
2471 a=(p->obj->status&6)>>1;
2472 p->obj->status&=~6;
2473 p->obj->status|=(a==2)?0:2;
2474 sendall_update_status(p->obj,0);
2475 }
2476 }
2477 }
2478 change_weapon_player(p,p->keyboard_status.weapon);
2479 if (p->keyboard_status.fire)
2480 fire_player(p,(p->obj->status&6)>>1);
2481 }
2482
2483
2484 /* update players, kick out not responding players */
update_players(void)2485 void update_players(void)
2486 {
2487 struct player_list *p;
2488 unsigned char txt[256];
2489 unsigned char packet;
2490 unsigned long_long t=get_time();
2491
2492 for (p=&players;p->next;p=p->next)
2493 {
2494 /* this player is dead - delete him */
2495 if (t-(p->next->member).last_update>=MAX_DUMB_TIME)
2496 {
2497 snprintf(txt,256,"%s not responding. Kicked out of the game.\n",p->next->member.name);
2498 message(txt,2);
2499 packet=P_PLAYER_DELETED;
2500 send_packet(&packet,1,(struct sockaddr*)(&(p->next->member.address)),0,last_player->member.id);
2501 snprintf(txt,256,"%s was kicked out of the game.",p->next->member.name);
2502 sendall_message(0,txt,0,0);
2503 delete_player(p->next);
2504 if (!(p->next))break;
2505 }
2506 else
2507 move_player(&(p->next->member));
2508 }
2509 }
2510
2511
2512 /* write help message to stdout */
print_help(void)2513 void print_help(void)
2514 {
2515 #ifdef WIN32
2516 printf( "0verkill server.\n"
2517 "(c)2000 Brainsoft\n"
2518 "Portions (c) 2000 by Filip Konvicka\n"
2519 "Usage: server [-nh] [-l <level_number>] [-p <port number>] [-i username[/password]] [-I] [-r]\n"
2520 "-i Installs as a service\n"
2521 "-I Installs with the LOCAL_SYSTEM account.\n"
2522 "-r Stops and removes the service\n"
2523 "-n Server can't be ended by client\n"
2524 "You must be an administrator in order to install/remove a service.\n");
2525 #else
2526 printf( "0verkill server.\n"
2527 "(c)2000 Brainsoft\n"
2528 #ifdef __EMX__
2529 "Portions (c) 2000 by Mikulas Patocka\n"
2530 #endif
2531 "Usage: server [-nh] [-l <level number>] [-p <port number>]\n"
2532 "-n Server can't be ended by client\n"
2533 );
2534 #endif
2535 }
2536
2537
parse_command_line(int argc,char ** argv)2538 void parse_command_line(int argc,char **argv)
2539 {
2540 int a;
2541 char *c;
2542
2543 while(1)
2544 {
2545 #ifdef WIN32
2546 a=getopt(argc,argv,"hl:np:ri:Ic");
2547 #else
2548 a=getopt(argc,argv,"hl:np:");
2549 #endif
2550 switch(a)
2551 {
2552 case EOF:
2553 return;
2554
2555 case '?':
2556 case ':':
2557 EXIT(1);
2558
2559 #ifdef WIN32
2560 case 'c':
2561 break; /* run as console app */
2562 case 'r': /* remove service */
2563 CmdRemoveService();
2564 EXIT(1);
2565 case 'i': { /* install service */
2566 char username[80],
2567 password[80],
2568 *user=NULL,
2569 *pass=NULL;
2570 if ( optarg ) {
2571 username[sizeof(username)-1]=0;
2572 user=username;
2573 if ( (pass=strchr(optarg, '/'))==NULL ) {
2574 strcpy(username, optarg);
2575 memcpy(username, optarg, sizeof(username)-1);
2576 password[0]=0;
2577 }
2578 else {
2579 int size=pass-optarg;
2580 if ( size>sizeof(username)-1 )
2581 size=sizeof(username)-1;
2582 memcpy(username, optarg, size);
2583 username[size]=0;
2584 pass++;
2585 size=strlen(pass);
2586 if ( size>sizeof(password)-1 )
2587 size=sizeof(password)-1;
2588 memcpy(password, pass, size);
2589 }
2590 }
2591 CmdInstallService(user, pass, NULL);
2592 EXIT(1);
2593 }
2594 case 'I': { /* install service */
2595 CmdInstallService(NULL, NULL, NULL);
2596 EXIT(1);
2597 }
2598 #endif
2599
2600 case 'h':
2601 print_help();
2602 EXIT(0);
2603
2604 case 'p':
2605 port=strtoul(optarg,&c,10);
2606 if (*c){ERROR("Error: Not a number.\n");EXIT(1);}
2607 if (errno==ERANGE)
2608 {
2609 if (!port){ERROR("Error: Number underflow.\n");EXIT(1);}
2610 else {ERROR("Error: Number overflow.\n");EXIT(1);}
2611 }
2612 break;
2613
2614 case 'l':
2615 level_number=strtoul(optarg,&c,10);
2616 if (*c){ERROR("Error: Not a number.\n");EXIT(1);}
2617 if (errno==ERANGE)
2618 {
2619 if (!level_number){ERROR("Error: Number underflow.\n");EXIT(1);}
2620 else {ERROR("Error: Number overflow.\n");EXIT(1);}
2621 }
2622 break;
2623
2624 case 'n':
2625 nonquitable=1;
2626 break;
2627 }
2628 }
2629 }
2630
2631
2632 /*-----------------------------------------------------------------------------------*/
server(void)2633 int server(void)
2634 {
2635 int a;
2636 unsigned char txt[256];
2637 unsigned long_long last_time;
2638 unsigned char *LEVEL;
2639
2640 last_player=&players;
2641 last_obj=&objects;
2642
2643 snprintf(txt,256,"Running 0verkill server version %d.%d\n",VERSION_MAJOR,VERSION_MINOR);
2644 message(txt,2);
2645 #ifdef WIN32
2646 snprintf(txt,256,"This is 0verkill server for Win32, build #%u\n",VERSION_PORT);
2647 message(txt,2);
2648 #endif
2649 message("Initialization.\n",2);
2650 #ifdef WIN32
2651 message("Starting Windows Sockets\n",2);
2652 {
2653 WSADATA wd;
2654 WSAStartup(0x101, &wd);
2655 snprintf(txt,256,"Started WinSock version %X.%02X\n", wd.wVersion/0x100, wd.wVersion&0xFF);
2656 message(txt, 2);
2657 }
2658 #endif
2659 init_area(); /* initialize playing area */
2660 hash_table_init();
2661
2662 #ifdef WIN32
2663 if ( !consoleApp )
2664 ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 2000);
2665 #endif
2666
2667 message("Loading sprites.\n",2);
2668 load_sprites(DATA_PATH GAME_SPRITES_FILE); /* players, corpses, bullets, ... */
2669 if (find_sprite("bullet",&bullet_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"bullet\".\n");ERROR(msg);EXIT(1);}
2670 if (find_sprite("slug",&slug_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"slug\".\n");ERROR(msg);EXIT(1);}
2671 if (find_sprite("shell",&shell_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"shell\".\n");ERROR(msg);EXIT(1);}
2672 if (find_sprite("sshell",&shotgun_shell_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"sshell\".\n");ERROR(msg);EXIT(1);}
2673 if (find_sprite("grenade",&grenade_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"grenade\".\n");ERROR(msg);EXIT(1);}
2674 if (find_sprite("mess1",&mess1_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"mess1\".\n");ERROR(msg);EXIT(1);}
2675 if (find_sprite("mess2",&mess2_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"mess2\".\n");ERROR(msg);EXIT(1);}
2676 if (find_sprite("mess3",&mess3_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"mess3\".\n");ERROR(msg);EXIT(1);}
2677 if (find_sprite("mess4",&mess4_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"mess4\".\n");ERROR(msg);EXIT(1);}
2678 if (find_sprite("noise",&noise_sprite)){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"noise\".\n");ERROR(msg);EXIT(1);}
2679 for (a=0;a<N_SHRAPNELS;a++)
2680 {
2681 sprintf(txt,"shrapnel%d",a+1);
2682 if (find_sprite(txt,&shrapnel_sprite[a])){unsigned char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
2683 }
2684
2685 LEVEL=load_level(level_number);
2686 level_checksum=md5_level(level_number);
2687 if (!LEVEL){char txt[256];snprintf(txt,256,"Can't load level number %d\n",level_number);ERROR(txt);EXIT(1);}
2688 snprintf(txt,256,"Loading level \"%s\"....\n",LEVEL);
2689 message(txt,2);
2690 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,LEVEL_SPRITES_SUFFIX);
2691 message("Loading level graphics.\n",2);
2692 load_sprites(txt);
2693 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
2694 message("Loading level map.\n",2);
2695 load_data(txt);
2696 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,DYNAMIC_DATA_SUFFIX);
2697 message("Loading level objects.\n",2);
2698 mem_free(LEVEL);
2699 load_dynamic(txt);
2700
2701 message("Initializing socket.\n",2);
2702 init_socket(); /* initialize socket */
2703
2704 message("Installing signal handlers.\n",2);
2705 signal(SIGINT,signal_handler);
2706 signal(SIGTERM,signal_handler);
2707 signal(SIGFPE,signal_handler);
2708 signal(SIGILL,signal_handler);
2709 signal(SIGABRT,signal_handler);
2710 #ifndef WIN32
2711 signal(SIGBUS,signal_handler);
2712 signal(SIGQUIT,signal_handler);
2713 #endif
2714 message("Game started.\n",2);
2715
2716 #ifdef __EMX__
2717 DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 1, 0);
2718 #endif
2719
2720 game_start=get_time();
2721 srandom(game_start);
2722
2723 #ifdef WIN32
2724 if ( !consoleApp )
2725 ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
2726 #endif
2727
2728 last_time=get_time();
2729 again:
2730 last_time+=PERIOD_USEC;
2731 if (get_time()-last_time>PERIOD_USEC*100)last_time=get_time();
2732 read_data();
2733 update_timeq();
2734 update_game();
2735 update_players(); /* MUST come after update_game otherwise when player shoots he hit himself */
2736 send_chunks();
2737 last_tick=get_time();
2738 if (!active_players&&(last_tick-last_player_left)>DELAY_BEFORE_SLEEP_USEC&&(last_tick-last_packet_came)>DELAY_BEFORE_SLEEP_USEC)
2739 {
2740 #ifndef WIN32
2741 message("Sleep\n",2);
2742 {
2743 fd_set fds;
2744 FD_ZERO(&fds);
2745 FD_SET(fd,&fds);
2746 select(fd+1,&fds,0,0,0);
2747 }
2748 message("Wakeup\n",2);
2749 #else
2750 WaitForSingleObject(fd, 500); /* wait max. 0.5 seconds, then we must test hServerExitEvent */
2751 #endif
2752 }
2753 #ifdef WIN32
2754 /* we must return so that the service can be properly stopped */
2755 if ( hServerExitEvent )
2756 return 0;
2757 #endif
2758 sleep_until(last_time+PERIOD_USEC);
2759 goto again;
2760
2761 return 0;
2762 }
2763
2764
main(int argc,char ** argv)2765 int main(int argc, char **argv)
2766 {
2767 int a;
2768
2769 #ifdef WIN32
2770 SERVICE_TABLE_ENTRY dispatchTable[]={{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain}, {NULL, NULL}};
2771 if ( argc==1 ) {
2772 if ( !StartServiceCtrlDispatcher(dispatchTable) ) {
2773 globErr=GetLastError();
2774 /*LPTSTR pszError=CErrorContext::LoadWin32ErrorString(globErr);
2775 ::CharToOem(pszError, pszError);
2776 _tprintf(_T("StartServiceCtrlDispatcher failed: %u"), globErr);
2777 if ( pszError!=NULL ) {
2778 _tprintf(_T(": %s\r\n"), pszError);
2779 ::LocalFree(pszError);
2780 }
2781 else
2782 _tprintf(_T("\r\n"));*/
2783 AddToMessageLog("StartServiceCtrlDispatcher failed", 0);
2784 }
2785 }
2786 consoleApp=1;
2787 #endif
2788 parse_command_line(argc,argv);
2789
2790 a=server();
2791 free_all_memory();
2792 check_memory_leaks();
2793 return a;
2794 }
2795