improve .gitignore
[0verkill.git] / server.c
blobea2af61441cba564c7dd1919204b03d7577d5b28
1 #ifndef WIN32
2 #include "config.h"
3 #endif
5 #include <stdio.h>
6 #include <sys/types.h>
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 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #else
23 #include <time.h>
24 #include <winsock.h>
25 #endif
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <math.h>
30 #include <errno.h>
31 #ifdef HAVE_FLOAT_H
32 #include <float.h>
33 #endif
34 #ifndef __USE_GNU
35 #define __USE_GNU
36 #endif
37 #include <string.h>
39 #ifdef HAVE_SYS_SELECT_H
40 #include <sys/select.h>
41 #endif
43 #ifdef __EMX__
44 #define INCL_DOS
45 #include <os2.h>
46 #endif
48 #include "data.h"
49 #include "server.h"
50 #include "net.h"
51 #include "cfg.h"
52 #include "hash.h"
53 #include "time.h"
54 #include "getopt.h"
55 #include "math.h"
56 #include "error.h"
59 unsigned short port=DEFAULT_PORT; /* game port (not a gameport ;-) )*/
60 int level_number=0; /* line number in the LEVEL_FILE */
61 int fd; /* socket */
62 int n_players; /* highest ID of player */
63 int active_players=0; /* # of players in the game */
64 unsigned int id=0; /* my ID */
65 unsigned long_long game_start; /* time of game start */
66 /* important sprites */
67 int grenade_sprite,bullet_sprite,slug_sprite,shell_sprite,shotgun_shell_sprite,
68 mess1_sprite,mess2_sprite,mess3_sprite,mess4_sprite,noise_sprite,
69 bfgcell_sprite;
70 int shrapnel_sprite[N_SHRAPNELS],bfgbit_sprite[N_SHRAPNELS],bloodrain_sprite[N_SHRAPNELS],jetfire_sprite;
71 int nonquitable=0; /* 1=clients can't abort game pressing F12 (request is ignored) */
72 unsigned long_long last_tick;
73 unsigned long_long last_player_left=0,last_packet_came=0;
75 char *level_checksum=0; /* MD5 sum of the level */
76 short meatcounter=0;
77 unsigned short weapons_order[ARMS]={4,0,3,1,2,5};
79 struct birthplace_type
81 int x,y;
82 }*birthplace=DUMMY;
84 int n_birthplaces=0;
86 /* list of players */
87 struct player_list
89 struct player_list *next,*prev;
90 struct player member;
91 }players;
94 /* time queue of respawning objects */
95 struct queue_list
97 struct queue_list* next;
98 unsigned long_long time;
99 struct it member;
100 }time_queue;
103 /* list of objects */
104 struct object_list objects;
106 struct player_list *last_player;
107 struct object_list *last_obj;
110 #ifdef WIN32
111 #define SERVICE_NAME "0verkill_017"
112 #define SERVICE_DISP_NAME "0verkill Server 0.17"
113 int consoleApp=0; /* 0 kdyz to bezi jako server na pozadi */
115 /***************************************************/
116 /* WINDOWS NT SERVICE INSTALLATION/RUNNING/REMOVAL */
118 #include <winsvc.h>
120 int server(void);
122 SERVICE_STATUS ssStatus;
123 SERVICE_STATUS_HANDLE sshStatusHandle;
124 DWORD globErr=ERROR_SUCCESS;
125 TCHAR szErr[2048];
126 int hServerExitEvent=0; /* close server flag */
128 LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize) {
129 DWORD dwRet;
130 LPTSTR lpszTemp=NULL;
131 globErr=GetLastError();
132 dwRet=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL,
133 globErr, LANG_NEUTRAL, (LPTSTR)&lpszTemp, 0, NULL);
134 /* supplied buffer is not long enough */
135 if (( !dwRet )||( (long)dwSize < (long)dwRet+14 ))
136 snprintf(lpszBuf, sizeof(lpszBuf), ": %u", globErr);
137 else {
138 lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');
139 CharToOem(lpszTemp, lpszTemp);
140 snprintf(lpszBuf, sizeof(lpszBuf), ": %u: %s", globErr, lpszTemp);
142 if ( lpszTemp )
143 LocalFree((HLOCAL)lpszTemp);
144 return lpszBuf;
147 void CmdInstallService(LPCTSTR pszUserName, LPCTSTR pszUserPassword, LPCTSTR pszDependencies) {
148 SC_HANDLE schService;
149 SC_HANDLE schSCManager;
150 TCHAR szPath[2048];
151 printf("Installing %s as ", SERVICE_NAME);
152 if ( pszUserName==NULL )
153 printf("LOCAL_SYSTEM");
154 else {
155 printf("\"%s\"", pszUserName);
156 if ( pszUserPassword )
157 printf("/\"%s\"", pszUserPassword);
159 printf("...\r\n");
160 if ( GetModuleFileName(NULL, szPath, 2046)==0 ) {
161 printf("Unable to install %s%s\r\n", SERVICE_NAME, GetLastErrorText(szErr, 2046));
162 return;
164 schSCManager=OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
165 if ( schSCManager ) {
166 schService=CreateService(
167 schSCManager, /* SCManager database */
168 SERVICE_NAME, /* name of service */
169 SERVICE_DISP_NAME, /* name to display */
170 SERVICE_ALL_ACCESS, /* desired access */
171 SERVICE_WIN32_OWN_PROCESS, /* service type */
172 SERVICE_DEMAND_START, /* start type */
173 SERVICE_ERROR_NORMAL, /* error control type */
174 szPath, /* service's binary */
175 NULL, /* no load ordering group */
176 NULL, /* no tag identifier */
177 pszDependencies, /* dependencies */
178 pszUserName, /* account */
179 pszUserPassword); /* password */
180 if ( schService ) {
181 printf("%s was installed successfully.\r\n", SERVICE_NAME);
182 globErr=ERROR_SUCCESS;
183 CloseServiceHandle(schService);
185 else
186 printf("CreateService failed%s\r\n", GetLastErrorText(szErr, 2046));
187 CloseServiceHandle(schSCManager);
189 else
190 printf("OpenSCManager failed%s\r\n", GetLastErrorText(szErr, 2046));
193 void CmdRemoveService() {
194 SC_HANDLE schService,
195 schSCManager;
196 schSCManager=OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
197 if ( schSCManager ) {
198 schService=OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
199 if ( schService ) {
200 if ( ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus) ) {
201 printf("Stopping %s...\r\n", SERVICE_NAME);
202 Sleep(500);
203 while( QueryServiceStatus(schService, &ssStatus) ) {
204 if ( ssStatus.dwCurrentState==SERVICE_STOP_PENDING ) {
205 printf(".");
206 Sleep(500);
208 else
209 break;
211 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
212 printf("\r\n%s stopped successfully.\r\n", SERVICE_NAME);
213 else
214 printf("\r\n%s failed to stop.\r\n", SERVICE_NAME);
216 else
217 printf("ControlService failed%s\r\n", GetLastErrorText(szErr, 2046));
218 if ( DeleteService(schService) ) {
219 globErr=ERROR_SUCCESS;
220 printf("%s removed.\r\n", SERVICE_NAME);
222 else
223 printf("DeleteService failed%s\r\n", GetLastErrorText(szErr, 2046));
224 CloseServiceHandle(schService);
226 else
227 printf("OpenService failed%s\r\n", GetLastErrorText(szErr, 2046));
228 CloseServiceHandle(schSCManager);
230 else
231 printf("OpenSCManager failed%s\r\n", GetLastErrorText(szErr, 2046));
234 void AddToMessageLog(LPTSTR lpszMsg, int infoOnly) {
235 TCHAR szMsg[2048];
236 HANDLE hEventSource;
237 LPTSTR lpszStrings[2];
239 hEventSource=RegisterEventSource(NULL, SERVICE_NAME);
241 snprintf(szMsg, sizeof(szMsg), infoOnly ? "%s notification:" : "%s error: %u", SERVICE_NAME, globErr);
242 lpszStrings[0]=szMsg;
243 lpszStrings[1]=lpszMsg;
245 if ( hEventSource!=INVALID_HANDLE_VALUE ) {
246 ReportEvent(hEventSource, infoOnly ? EVENTLOG_INFORMATION_TYPE : EVENTLOG_ERROR_TYPE, 0, 0, NULL, 2, 0, (LPCTSTR*)lpszStrings, NULL);
247 DeregisterEventSource(hEventSource);
251 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) {
252 static DWORD dwCheckPoint=1;
253 BOOL fResult=TRUE;
255 if ( dwCurrentState==SERVICE_START_PENDING )
256 ssStatus.dwControlsAccepted=0;
257 else
258 ssStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;
260 ssStatus.dwCurrentState=dwCurrentState;
261 ssStatus.dwWin32ExitCode=dwWin32ExitCode;
262 ssStatus.dwWaitHint=dwWaitHint;
264 if (( dwCurrentState==SERVICE_RUNNING )||
265 ( dwCurrentState==SERVICE_STOPPED ))
266 ssStatus.dwCheckPoint=0;
267 else
268 ssStatus.dwCheckPoint=dwCheckPoint++;
269 if ( !(fResult=SetServiceStatus(sshStatusHandle, &ssStatus)) ) {
270 globErr=GetLastError();
271 AddToMessageLog("SetServiceStatus failed", 0);
273 return fResult;
276 void ServiceStop() {
277 hServerExitEvent=1;
278 raise(SIGINT);
281 void WINAPI ServiceCtrl(DWORD dwCtrlCode) {
282 switch( dwCtrlCode ) {
283 case SERVICE_CONTROL_STOP:
284 ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
285 ServiceStop();
286 return;
288 if ( hServerExitEvent )
289 ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
290 else
291 ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
295 void ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv) {
296 if ( dwArgc>1 )
297 SetCurrentDirectory(lpszArgv[1]);
298 else {
299 char path[1024],
300 *p2;
301 GetModuleFileName(NULL, path, sizeof(path));
302 p2=path+strlen(path);
303 while(( p2>=path )&&( *p2!='\\' )&&( *p2!='/' ))
304 p2--;
305 *p2=0;
306 SetCurrentDirectory(path);
308 server();
311 void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
312 if ( !(sshStatusHandle=RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrl)) )
313 return;
315 ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
316 ssStatus.dwServiceSpecificExitCode=0;
317 if ( !ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
318 goto Cleanup;
320 nonquitable=1;
321 ServiceStart(dwArgc, lpszArgv);
323 Cleanup:
324 ReportStatusToSCMgr(SERVICE_STOPPED, globErr, 0);
325 return;
327 /* WINDOWS NT SERVICE INSTALLATION/REMOVAL */
328 /*******************************************/
329 #endif
332 /* load dynamic data */
333 static void load_dynamic(char * filename)
335 FILE * stream;
336 static char line[1024];
337 char *p,*q,*name;
338 int n,x,y,t;
340 #ifndef WIN32
341 if (!(stream=fopen(filename,"rb")))
342 #else
343 if (!fopen_s(&stream, filename, "rb"))
344 #endif
346 char msg[256];
347 snprintf(msg,256,"Can't open file \"%s\"!\n",filename);
348 ERROR(msg);
349 EXIT(1);
351 while(fgets(line,1024,stream))
353 p=line;
354 _skip_ws(&p);
355 for (name=p;(*p)!=' '&&(*p)!=9&&(*p)!=10&&(*p);p++);
356 if (!(*p))continue;
357 *p=0;p++;
358 _skip_ws(&p);
359 if ((t=_convert_type(*p))<0){char msg[256];snprintf(msg,256,"Unknown object type '%c'.\n",*p);ERROR(msg);EXIT(1);}
360 p++;
361 _skip_ws(&p);
362 x=strtol(p,&q,0);
363 _skip_ws(&q);
364 y=strtol(q,&p,0);
365 if (t==TYPE_BIRTHPLACE) /* birthplace */
367 n_birthplaces++;
368 birthplace=mem_realloc(birthplace,sizeof(struct birthplace_type)*n_birthplaces);
369 if (!birthplace){ERROR("Error: Not enough memory.\n");EXIT(1);}
370 birthplace[n_birthplaces-1].x=x;
371 birthplace[n_birthplaces-1].y=y;
372 continue;
374 if (find_sprite(name,&n)){char msg[256];snprintf(msg,256,"Unknown bitmap name \"%s\"!\n",name);ERROR(msg);EXIT(1);}
375 new_obj(id,t,0,n,0,0,int2double(x),int2double(y),0,0,0);
376 id++;
378 fclose(stream);
379 if (!n_birthplaces){ERROR("Error: No birthplaces.\n");EXIT(1);}
382 /* write a message to stdout or stderr */
383 static void message(char *msg,int output)
385 time_t t;
386 struct tm tm;
387 static char timestamp[64];
389 #ifdef WIN32
390 if ( !consoleApp )
391 return;
392 #endif
394 t=time(0);
395 #ifndef WIN32
396 tm=*(localtime(&t));
397 #else
398 localtime_s(&tm, &t);
399 #endif
401 /* time stamp is in format day.month.year hour:minute:second */
402 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);
403 switch (output)
405 case 1:
406 printf("%s%s",timestamp,msg);
407 fflush(stdout);
408 break;
410 case 2:
411 fprintf(stderr,"%s%s",timestamp,msg);
412 fflush(stderr);
413 break;
418 /* switch weapon to the player's best one */
419 static int select_best_weapon(struct player* p)
421 unsigned short t[ARMS]={4,0,1,3,2,5};
422 int a;
424 for (a=ARMS-1;a>=0;a--)
425 if ((p->weapons&(1<<t[a]))&&p->ammo[t[a]])return t[a];
427 return p->current_weapon;
431 /* Bakta modify - better weapon selection routines */
432 /* test if weapon is better than the one he wields */
433 static int is_weapon_better(struct player* p, int weapon)
435 int i;
436 int cur=0, test=0;
438 for(i=ARMS-1;i>=0;i--)
440 if(weapons_order[i]==p->current_weapon)
441 cur = i;
442 if(weapons_order[i]==weapon)
443 test = i;
445 return cur<test;
449 /* test if player p has weapon and can use it (has ammo for it) */
450 static int is_weapon_usable(struct player* p, int weapon)
452 return !!((p->weapons&(1<<weapon))&&p->ammo[weapon]);
456 /* test if player p has weapon and has no ammo for it */
457 static int is_weapon_empty(struct player* p, int weapon)
459 return !!((p->weapons&(1<<weapon))&&!p->ammo[weapon]);
463 /* initialize socket */
464 static void init_socket(void)
466 struct sockaddr_in server;
467 fd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
468 if (fd<0)
470 ERROR("Error: Can't create socket!\n");
471 EXIT(1);
474 server.sin_family=AF_INET;
475 server.sin_port=htons(port);
476 server.sin_addr.s_addr=INADDR_ANY;
478 if (bind(fd,(struct sockaddr*)&server,sizeof(server)))
480 char msg[256];
481 snprintf(msg,256,"Error: Can't bind socket to port %d!\n",port);
482 ERROR(msg);
483 EXIT(1);
488 /* selects random birthplace and returns */
489 static void find_birthplace(int *x,int *y)
491 int a=random()%n_birthplaces;
493 *x=birthplace[a].x;
494 *y=birthplace[a].y;
498 /* return index of hero with color num in sprites field */
499 /* if there's not such color, returns -1 */
500 static int select_hero(int num)
502 static char txt[32];
503 int a;
505 snprintf(txt, sizeof(txt), "hero%d",num);
506 if (find_sprite(txt,&a))return -1;
507 return a;
511 /* initialize player */
512 static void init_player(struct player* p,int x,int y)
514 int a;
516 p->health=100;
517 p->health_ep=ILLNESS_SPEED;
518 p->armor=0;
519 p->current_weapon=0;
520 p->weapons= WEAPON_MASK_GUN |
521 WEAPON_MASK_GRENADE |
522 WEAPON_MASK_CHAINSAW |
523 WEAPON_MASK_BLOODRAIN; /* he has only gun, grenades, chainsaw and bloodrain */
524 p->invisibility_counter=0;
525 for (a=0;a<ARMS;a++)
526 p->ammo[a]=0;
527 p->ammo[WEAPON_GUN]=weapon[WEAPON_GUN].basic_ammo;
528 p->ammo[WEAPON_CHAINSAW]=weapon[WEAPON_CHAINSAW].basic_ammo;
529 p->obj->xspeed=0;
530 p->obj->yspeed=0;
531 p->obj->status=0;
532 p->obj->ttl=0;
533 p->obj->anim_pos=0;
534 p->obj->x=x;
535 p->obj->y=y;
539 /* completely add player to server's database */
540 /* player starts on x,y coordinates */
541 static int add_player(unsigned char color, char *name,struct sockaddr_in *address,int x, int y)
543 int h;
544 struct player_list *cp;
546 /* alloc memory for new player */
547 cp=mem_alloc(sizeof(struct player_list));
548 if (!cp)
549 {message("Not enough memory.\n",2);return 1;}
550 cp->member.name=mem_alloc(strlen(name)+1);
551 if (!cp->member.name)
552 {mem_free(cp);message("Not enough memory.\n",2);return 1;}
554 /* fill in the structure */
555 cp->member.color=color;
556 cp->member.frags=0;
557 cp->member.deaths=0;
558 cp->member.keyboard_status.status=0;
559 cp->member.keyboard_status.weapon=0;
560 cp->member.id=n_players+1; /* player numbering starts from 1, 0 is server's ID */
561 cp->member.last_update=get_time();
562 memcpy(cp->member.name,name,strlen(name)+1);
563 cp->member.address=*address;
564 cp->member.packet_pos=0;
565 cp->member.current_level=-1;
566 /* create new object "player" */
567 h=select_hero(cp->member.color);
568 if (h<0)
569 {mem_free(cp->member.name);mem_free(cp);message ("No such color.\n",1);return 1;}
570 cp->member.obj=new_obj(id,T_PLAYER,0,h,0,0,int2double(x),int2double(y),0,0,(&(cp->member)));
571 if (!cp->member.obj)
572 {mem_free(cp->member.name);mem_free(cp);message("Can't create object.\n",1);return 1;}
573 id++;
574 init_player(&(cp->member),int2double(x),int2double(y));
576 /* that's all */
577 cp->prev=last_player;
578 cp->next=0;
579 last_player->next=cp;
580 last_player=cp;
581 return 0;
585 static void send_chunk_to_player(struct player *player)
587 static char p[MAX_PACKET_LENGTH];
589 if (!(player->packet_pos))return;
590 if (player->packet_pos>MAX_PACKET_LENGTH-1)return;
591 p[0]=P_CHUNK;
592 memcpy(p+1,player->packet,player->packet_pos);
593 send_packet(p,(player->packet_pos)+1,(struct sockaddr*)(&(player->address)),0,player->id);
594 player->packet_pos=0;
598 static void send_chunk_packet_to_player(char *packet, int len, struct player *player)
600 if (len>MAX_PACKET_LENGTH-1)return;
601 if ((player->packet_pos)+len>MAX_PACKET_LENGTH-1)send_chunk_to_player(player);
602 memcpy((player->packet)+(player->packet_pos),packet,len);
603 player->packet_pos+=len;
607 static void send_chunks(void)
609 struct player_list* p;
611 for (p=&players;p->next;p=p->next)
612 send_chunk_to_player(&(p->next->member));
616 /* send a packet to all players except one */
617 /* if not_this_player is null, sends to all players */
618 static void sendall(char *packet,int len, struct player * not_this_player)
620 struct player_list* p;
622 if (!not_this_player)
623 for (p=&players;p->next;p=p->next)
624 send_packet(packet,len,(struct sockaddr*)(&(p->next->member.address)),0,p->next->member.id);
625 else
626 for (p=&players;p->next;p=p->next)
627 if ((&(p->next->member))!=not_this_player)
628 send_packet(packet,len,(struct sockaddr*)(&(p->next->member.address)),0,p->next->member.id);
632 /* send a packet to all players except one */
633 /* if not_this_player is null, sends to all players */
634 static void sendall_chunked(char *packet,int len, struct player * not_this_player)
636 struct player_list* p;
638 if (!not_this_player)
639 for (p=&players;p->next;p=p->next)
640 send_chunk_packet_to_player(packet,len,&(p->next->member));
641 else
642 for (p=&players;p->next;p=p->next)
643 if ((&(p->next->member))!=not_this_player)
644 send_chunk_packet_to_player(packet,len,&(p->next->member));
648 static int which_update(struct it *obj,int old_x,int old_y,int old_x_speed,int old_y_speed,unsigned int old_status,int old_ttl)
650 int a=0;
652 if (old_ttl==obj->ttl)
654 if (old_x_speed==obj->xspeed&&old_y_speed==obj->yspeed)a=5; /* update pos and status */
655 if (old_x==obj->x&&old_y==obj->y)a=4; /* update speed and status */
658 if (old_status==obj->status&&old_ttl==obj->ttl)
660 a=1; /* update speed+coords */
662 if (old_x_speed==obj->xspeed&&old_y_speed==obj->yspeed)a=3; /* update pos */
663 if (old_x==obj->x&&old_y==obj->y)
665 if(a==3)return -1; /* nothing to update */
666 a=2; /* update speed */
669 return a;
672 /* send a packet to all players except one */
673 /* if not_this_player is null, sends to all players */
674 /* type is:
675 0=full update
676 1=update speed+coordinates
677 2=update speed
678 3=update coordinates
679 4=update speed + status
680 5=update coordinates + status
681 6=update speed + status + ttl
682 7=update coordinates + status + ttl
684 static void sendall_update_object(struct it* obj, struct player * not_this_player,int type)
686 struct player_list* p;
687 static char packet[32];
688 int offset = 0;
690 switch (type)
692 case 0: /* all */
693 packet[offset++]=P_UPDATE_OBJECT;
694 put_int(packet,obj->id,&offset);
695 packet[offset++]=obj->update_counter;
696 put_int(packet,obj->x,&offset);
697 put_int(packet,obj->y,&offset);
698 put_int(packet,obj->xspeed,&offset);
699 put_int(packet,obj->yspeed,&offset);
700 put_int(packet,obj->status,&offset);
701 put_int16(packet,obj->ttl,&offset);
702 break;
704 case 1: /* coordinates and speed */
705 packet[offset++]=P_UPDATE_OBJECT_POS;
706 put_int(packet,obj->id,&offset);
707 packet[offset++]=obj->update_counter;
708 put_int(packet,obj->x,&offset);
709 put_int(packet,obj->y,&offset);
710 put_int(packet,obj->xspeed,&offset);
711 put_int(packet,obj->yspeed,&offset);
712 break;
714 case 2: /* speed */
715 packet[offset++]=P_UPDATE_OBJECT_SPEED;
716 put_int(packet,obj->id,&offset);
717 packet[offset++]=obj->update_counter;
718 put_int(packet,obj->xspeed,&offset);
719 put_int(packet,obj->yspeed,&offset);
720 break;
722 case 3: /* coordinates */
723 packet[offset++]=P_UPDATE_OBJECT_COORDS;
724 put_int(packet,obj->id,&offset);
725 packet[offset++]=obj->update_counter;
726 put_int(packet,obj->x,&offset);
727 put_int(packet,obj->y,&offset);
728 break;
730 case 4: /* speed and status */
731 packet[offset++]=P_UPDATE_OBJECT_SPEED_STATUS;
732 put_int(packet,obj->id,&offset);
733 packet[offset++]=obj->update_counter;
734 put_int(packet,obj->xspeed,&offset);
735 put_int(packet,obj->yspeed,&offset);
736 put_int(packet,obj->status,&offset);
737 break;
739 case 5: /* coordinates and status */
740 packet[offset++]=P_UPDATE_OBJECT_COORDS_STATUS;
741 put_int(packet,obj->id,&offset);
742 packet[offset++]=obj->update_counter;
743 put_int(packet,obj->x,&offset);
744 put_int(packet,obj->y,&offset);
745 put_int(packet,obj->status,&offset);
746 break;
748 case 6: /* speed and status and ttl */
749 packet[offset++]=P_UPDATE_OBJECT_SPEED_STATUS_TTL;
750 put_int(packet,obj->id,&offset);
751 packet[offset++]=obj->update_counter;
752 put_int(packet,obj->xspeed,&offset);
753 put_int(packet,obj->yspeed,&offset);
754 put_int(packet,obj->status,&offset);
755 put_int16(packet,obj->ttl,&offset);
756 break;
758 case 7: /* coordinates and status and ttl */
759 packet[offset++]=P_UPDATE_OBJECT_COORDS_STATUS_TTL;
760 put_int(packet,obj->id,&offset);
761 packet[offset++]=obj->update_counter;
762 put_int(packet,obj->x,&offset);
763 put_int(packet,obj->y,&offset);
764 put_int16(packet,obj->status,&offset);
765 put_int16(packet,obj->ttl,&offset);
766 break;
768 default: /* don't update */
769 return;
772 obj->update_counter++;
774 if (!not_this_player)
775 for (p=&players;p->next;p=p->next)
776 send_chunk_packet_to_player(packet,offset,&(p->next->member));
777 else
778 for (p=&players;p->next;p=p->next)
779 if ((&(p->next->member))!=not_this_player)
780 send_chunk_packet_to_player(packet,offset,&(p->next->member));
784 /* send update status packet to all players (except not_this_player if this is !NULL)*/
785 static void sendall_update_status(struct it* obj, struct player * not_this_player)
787 struct player_list* p;
788 static char packet[32];
789 int offset = 0;
791 packet[offset++]=P_UPDATE_STATUS;
792 put_int(packet,obj->id,&offset);
793 put_int(packet,obj->status,&offset);
795 if (!not_this_player)
796 for (p=&players;p->next;p=p->next)
797 send_chunk_packet_to_player(packet,offset,&(p->next->member));
798 else
799 for (p=&players;p->next;p=p->next)
800 if ((&(p->next->member))!=not_this_player)
801 send_chunk_packet_to_player(packet,offset,&(p->next->member));
805 /* send hit packet to all players except not_this player (if !NULL)*/
806 static void sendall_hit(unsigned long id,unsigned char direction,unsigned char xoffs,unsigned char yoffs,struct player* not_this_player)
808 struct player_list* p;
809 static char packet[8];
810 int offset = 0;
812 packet[offset++]=P_HIT;
813 put_int(packet,id,&offset);
814 packet[offset++]=direction;
815 packet[offset++]=xoffs;
816 packet[offset++]=yoffs;
818 if (!not_this_player)
819 for (p=&players;p->next;p=p->next)
820 send_chunk_packet_to_player(packet,offset,&(p->next->member));
821 else
822 for (p=&players;p->next;p=p->next)
823 if ((&(p->next->member))!=not_this_player)
824 send_chunk_packet_to_player(packet,offset,&(p->next->member));
828 /* sort players according to frags */
829 static int _qsort_cmp(const void *a,const void *b)
831 int fa,fb,da,db;
832 fa=(*((struct player**)a))->frags;
833 fb=(*((struct player**)b))->frags;
834 da=(*((struct player**)a))->deaths;
835 db=(*((struct player**)b))->deaths;
837 if (fa>fb)return -1;
838 if (fa==fb)
840 if (da<db)return -1;
841 if (da>db)return 1;
842 return 0;
844 return 1;
848 /* send info how many players are in the game and top score */
849 /* id=recipient's id */
850 /* if addr is NULL info is sent to all */
851 static void send_info(struct sockaddr *addr,int id)
853 char *packet;
854 int p=active_players>TOP_PLAYERS_N?TOP_PLAYERS_N:active_players;
855 int a,offset = 0,l;
856 struct player **t; /* table for qsort */
857 struct player_list *q;
859 /* alloc memory */
860 t=mem_alloc(active_players*sizeof(struct player*));
861 if (!t)return;
862 packet=mem_alloc(1+4+1+p*(MAX_NAME_LEN+4+4));
863 if (!packet)return;
865 /* fill table for quicksort */
866 for (a=0,q=(&players);q->next;a++,q=q->next)
867 t[a]=&(q->next->member);
869 /* sort players */
870 qsort(t,active_players,sizeof(struct player*),_qsort_cmp);
872 /* create packet header */
873 packet[offset++]=P_INFO;
874 put_int(packet,active_players,&offset);
875 packet[offset++]=p;
877 /* put players into packet */
878 for (a=0;a<p;a++)
880 put_int(packet,(t[a])->frags,&offset);
881 put_int(packet,(t[a])->deaths,&offset);
882 packet[offset++]=t[a]->color;
883 memcpy(packet+offset,(t[a])->name,l=strlen((t[a])->name)+1);
884 offset+=l;
886 if (!addr)
887 sendall(packet,offset,0);
888 else send_packet(packet,offset,addr,0,id);
890 mem_free(packet);
891 mem_free(t);
894 /* returns the actual length of the packet to be sent */
895 static int build_message_packet(char packet[], int maxlen, char *name, char *msg, char flags)
897 int n, len = 0;
899 /* assert(maxlen > 2); */
900 packet[0] = P_MESSAGE;
901 packet[1] = flags;
902 len += 2;
904 if (!name)
905 n = snprintf(packet + len, maxlen - len, "%s", msg);
906 else
907 n = snprintf(packet + len, maxlen - len, "%s> %s", name, msg);
908 /* account for the space the text consumed in the packet; could have been truncated */
909 len += min(n + 1, maxlen - len);
911 return len;
914 /* send message to a player */
915 /* name is name of player who sent the message (chat), NULL means it's from server */
916 static void send_message(struct player* player, char *name, char *msg, char flags)
918 static char packet[256];
919 int len;
921 len = build_message_packet(packet, sizeof(packet), name, msg, flags);
922 send_chunk_packet_to_player(packet, len, player);
926 /* similar to send_message but sends to all except one or two players */
927 static void sendall_message(char *name, char *msg,struct player *not1,struct player* not2, char flags)
929 static char packet[256];
930 int len;
931 struct player_list* p;
933 len = build_message_packet(packet, sizeof(packet), name, msg, flags);
934 for (p=&players;p->next;p=p->next)
935 if ((!not1||(&(p->next->member))!=not1)&&(!not2||(&(p->next->member))!=not2))
936 send_chunk_packet_to_player(packet, len, &(p->next->member));
940 static void sendall_bell(void)
942 static char packet;
943 struct player_list* p;
945 packet=P_BELL;
946 for (p=&players;p->next;p=p->next)
947 send_chunk_packet_to_player(&packet,1,&(p->next->member));
952 #if 0
953 /* send new object information to given address */
954 static void send_new_obj(struct sockaddr* address, struct it* obj,int id)
956 static char packet[32];
957 int offset = 0;
959 packet[offset++]=P_NEW_OBJ;
960 put_int(packet,obj->id,&offset);
961 put_int16(packet,obj->sprite,&offset);
962 put_int(packet,obj->x,&offset);
963 put_int(packet,obj->y,&offset);
964 put_int(packet,obj->xspeed,&offset);
965 put_int(packet,obj->yspeed,&offset);
966 put_int(packet,obj->status,&offset);
967 packet[offset++]=obj->type;
968 put_int16(packet,obj->ttl,&offset);
969 send_packet(packet,offset,address,0,id);
971 #endif
973 /* send new object information to given address */
974 static void send_new_obj_chunked(struct player* player, struct it* obj)
976 static char packet[32];
977 int offset = 0;
979 packet[offset++]=P_NEW_OBJ;
980 put_int(packet,obj->id,&offset);
981 put_int16(packet,obj->sprite,&offset);
982 put_int(packet,obj->x,&offset);
983 put_int(packet,obj->y,&offset);
984 put_int(packet,obj->xspeed,&offset);
985 put_int(packet,obj->yspeed,&offset);
986 put_int(packet,obj->status,&offset);
987 packet[offset++]=obj->type;
988 put_int16(packet,obj->ttl,&offset);
989 send_chunk_packet_to_player(packet,offset,player);
993 /* send player update to given player */
994 static void send_update_player(struct player* p)
996 static char packet[32];
997 int a,offset = 0;
999 packet[offset++]=P_UPDATE_PLAYER;
1000 packet[offset++]=p->health;
1001 packet[offset++]=p->armor;
1002 for (a=0;a<ARMS;a++)
1003 put_int16(packet,p->ammo[a],&offset);
1004 put_int(packet,p->frags,&offset);
1005 put_int(packet,p->deaths,&offset);
1006 put_int16(packet,p->current_weapon,&offset);
1007 put_int16(packet,p->weapons,&offset);
1008 send_chunk_packet_to_player(packet,offset,p);
1011 /* send a packet to all players except one */
1012 /* if not_this_player is null, sends to all players */
1013 static void sendall_new_object(struct it* obj, struct player * not_this_player)
1015 struct player_list* p;
1017 if (!not_this_player)
1018 for (p=&players;p->next;p=p->next)
1019 send_new_obj_chunked(&(p->next->member),obj);
1020 else
1021 for (p=&players;p->next;p=p->next)
1022 if ((&(p->next->member))!=not_this_player)
1023 send_new_obj_chunked(&(p->next->member),obj);
1028 /* send all objects except one to specified player */
1029 /* if not_this_object is null, sends all objects */
1030 static void send_objects(struct player* player,struct it* not_this_object)
1032 struct object_list *p;
1034 if (!not_this_object)
1035 for(p=&objects;p->next;p=p->next)
1036 send_new_obj_chunked(player,&(p->next->member));
1037 else
1038 for(p=&objects;p->next;p=p->next)
1039 if((&p->next->member)!=not_this_object)
1040 send_new_obj_chunked(player,&(p->next->member));
1044 /* send all objects except one to specified player */
1045 /* if not_this_object is null, sends all objects */
1046 #define CHKSUM_SZ 32
1047 static void send_change_level(struct player* player)
1049 char packet[64];
1050 int offset = 0;
1052 packet[offset++]=P_CHANGE_LEVEL;
1053 put_int(packet,level_number,&offset);
1054 memcpy(packet+offset,level_checksum,CHKSUM_SZ+1);
1055 offset+=CHKSUM_SZ+1;
1056 send_packet(packet,offset,(struct sockaddr*)(&(player->address)),0,player->id);
1060 /* send all objects in time queue to given player */
1061 static void send_timeq_objects(struct player *player)
1063 struct queue_list *p;
1065 for (p=&time_queue;p->next;p=p->next)
1066 send_new_obj_chunked(player,&(p->next->member));
1070 /* remove player from server's list */
1071 /* delete player's hero and send message */
1072 static void delete_player(struct player_list *q)
1074 char packet[5];
1075 int offset = 0;
1077 /* delete object player's hero */
1078 packet[offset++]=P_DELETE_OBJECT;
1079 put_int(packet,q->member.obj->id,&offset);
1080 sendall_chunked(packet,5,&(q->member));
1081 delete_obj(q->member.obj->id);
1083 mem_free (q->member.name);
1084 q->prev->next=q->next;
1085 if (!q->next)last_player=q->prev; /* we're deleting last player of the list */
1086 else q->next->prev=q->prev;
1087 mem_free(q);
1088 active_players--;
1089 if (!active_players)last_player_left=get_time();
1093 /* create a new object and fill with data and adds to hash table */
1094 static struct it * add_to_timeq(
1095 unsigned int id,
1096 unsigned char type,
1097 int ttl,
1098 int sprite,
1099 unsigned char pos,
1100 int status,
1101 int x,
1102 int y,
1103 int xspeed,
1104 int yspeed,
1105 void * data,unsigned long_long t)
1107 struct queue_list *p;
1108 struct queue_list *q;
1110 t+=get_time();
1111 for (p=&time_queue;p->next&&p->next->member.last_updated<t;p=p->next);
1113 q=p->next;
1115 p->next=mem_alloc(sizeof(struct queue_list));
1116 if (!p->next){p->next=q;return 0;}
1117 p=p->next;
1118 p->next=q;
1119 p->member.x=x;
1120 p->member.y=y;
1121 p->member.xspeed=xspeed;
1122 p->member.yspeed=yspeed;
1123 p->member.type=type;
1124 p->member.ttl=ttl;
1125 p->member.id=id;
1126 p->member.sprite=sprite;
1127 p->member.anim_pos=pos;
1128 p->member.data=data;
1129 p->member.status=status | S_INVISIBLE;
1130 p->member.last_updated=t;
1131 return &(p->member);
1135 /* update time queue (respawning objects) */
1136 /* add objects timed out to the game */
1137 static void update_timeq(void)
1139 unsigned long_long t=get_time();
1140 struct queue_list *p,*q;
1141 struct it *o;
1143 #define N p->next->member
1144 for (p=&time_queue;p->next&&p->next->member.last_updated<=t;)
1146 N.status &= ~S_INVISIBLE;
1147 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);
1148 sendall_update_status(o,0);
1149 q=p->next->next;
1150 mem_free(p->next);
1151 p->next=q;
1153 #undef N
1157 /* find player with given address */
1158 /* on unsuccess return 0 */
1159 static struct player_list* find_player(struct sockaddr_in *address,int id)
1161 struct player_list *p;
1163 if (!address)
1165 for(p=&players;p->next;p=p->next)
1166 if (p->next->member.id==id)
1167 return p->next;
1168 return 0;
1170 for(p=&players;p->next;p=p->next)
1171 if (((p->next->member.address.sin_addr.s_addr)==(address->sin_addr.s_addr)&&(p->next->member.address.sin_port)==(address->sin_port))&&
1172 (p->next->member.id==id))
1173 return p->next;
1174 return 0;
1179 /* create noise on given position */
1180 static void create_noise(int x,int y,struct player *p)
1182 struct it *o;
1184 p->obj->status |= S_NOISE;
1185 o=new_obj(id,T_NOISE,NOISE_TTL,noise_sprite,0,0,int2double(x),int2double(y),0,0,(void *)(long)(p->id));
1186 if (!o)return;
1187 id++;
1188 sendall_new_object(o,0);
1192 static int is_playername_in_use(const char *name)
1194 struct player_list *pl;
1196 for (pl=&players;pl->next;pl=pl->next) {
1197 if (!strcmp(pl->next->member.name, name))
1198 return 1;
1200 return 0;
1204 /* read packet from socket */
1205 static void read_data(void)
1207 char txt[256];
1208 char txt1[256];
1209 fd_set rfds;
1210 struct timeval tv;
1211 struct sockaddr_in client;
1212 int a=sizeof(client);
1213 static char packet[280];
1214 struct player *p;
1215 struct player_list *q;
1216 unsigned char min,maj;
1217 int s,x,y,l,offset = 0;
1219 packet[279]=0;
1221 tv.tv_sec=0;
1222 tv.tv_usec=0;
1223 FD_ZERO(&rfds);
1224 FD_SET(fd,&rfds);
1225 while (select(fd+1,&rfds,0,0,&tv))
1227 if ((l=recv_packet(packet,256,(struct sockaddr*)(&client),&a,0,0,&s))==-1)
1228 return;
1230 last_packet_came=get_time();
1232 switch(*packet)
1234 case P_NEW_PLAYER:
1235 if (l<6)break; /* invalid packet */
1237 unsigned long_long t;
1238 if (packet[1]) /* this byte must be always 0 - version authentification, old versions transmitted color byte here */
1240 message("Incompatible client version.\n",2);
1241 packet[0]=P_PLAYER_REFUSED;
1242 packet[1]=E_PLAYER_REFUSED;
1243 send_packet(packet,2,(struct sockaddr*)(&client),0,last_player->member.id);
1244 break;
1246 maj=packet[2];
1247 min=packet[3];
1248 snprintf(txt1, sizeof(txt1), "%s", inet_ntoa(client.sin_addr));
1249 snprintf(txt,256,"Request for player #%d (client version %d.%d) from %s.\n",n_players,maj,min,txt1);
1250 message(txt,2);
1251 if (maj!=VERSION_MAJOR||min<MIN_CLIENT_VERSION_MINOR)
1253 message("Incompatible client version. Player refused.\n",2);
1254 packet[0]=P_PLAYER_REFUSED;
1255 packet[1]=E_INCOMPATIBLE_VERSION;
1256 send_packet(packet,2,(struct sockaddr*)(&client),0,last_player->member.id);
1257 break;
1259 if (is_playername_in_use(packet+5))
1261 snprintf(txt,256,"Name \"%s\" already in use. Player refused.\n",packet+5);
1262 message(txt,2);
1263 packet[0]=P_PLAYER_REFUSED;
1264 packet[1]=E_NAME_IN_USE;
1265 send_packet(packet,2,(struct sockaddr*)(&client),0,last_player->member.id);
1267 break;
1269 find_birthplace(&x,&y);
1270 if (add_player(packet[4],packet+5,&client,x,y)) /* failed to add player */
1272 message("Player refused.\n",2);
1273 packet[0]=P_PLAYER_REFUSED;
1274 packet[1]=E_PLAYER_REFUSED;
1275 send_packet(packet,2,(struct sockaddr*)(&client),0,last_player->member.id);
1276 break;
1278 snprintf(txt,256,"Player #%d accepted, name \"%s\", address %s.\n",n_players,packet+5,txt1);
1279 message(txt,2);
1280 snprintf(txt,256,"%s entered the game.",packet+5);
1281 active_players++;
1282 n_players++;
1283 packet[offset++]=P_PLAYER_ACCEPTED;
1284 last_player->member.obj->status |= S_DEAD;
1285 put_int(packet,last_player->member.obj->id,&offset);
1286 put_int16(packet,last_player->member.obj->sprite,&offset);
1287 put_int(packet,last_player->member.obj->x,&offset);
1288 put_int(packet,last_player->member.obj->y,&offset);
1289 put_int(packet,last_player->member.obj->xspeed,&offset);
1290 put_int(packet,last_player->member.obj->yspeed,&offset);
1291 put_int(packet,last_player->member.obj->status,&offset);
1292 t=get_time();
1293 put_long_long(packet,t-game_start,&offset);
1294 put_int(packet,last_player->member.id,&offset);
1295 packet[offset++]=VERSION_MAJOR;
1296 packet[offset++]=VERSION_MINOR;
1297 send_packet(packet,offset,(struct sockaddr*)(&client),0,0);
1298 send_change_level(&(last_player->member));
1299 sendall_bell();
1300 sendall_message(0,txt,0,0, M_ENTER);
1301 snprintf(txt,256,"There'%s %d %s in the game.",active_players==1?"s":"re",active_players,active_players==1?"player":"players");
1302 sendall_message(0,txt,0,0, M_INFO);
1303 send_info(0,0);
1305 break;
1307 case P_LEVEL_ACCEPTED:
1308 q=find_player(&client,s);
1309 if (!q)break;
1310 if (q->member.current_level>=0)break;
1312 q->member.current_level=level_number;
1313 sendall_new_object(q->member.obj,&(q->member));
1314 create_noise(double2int(q->member.obj->x),double2int(q->member.obj->y),&(q->member));
1315 /* send all objects in the game */
1316 send_objects(&(q->member),q->member.obj);
1317 /* send all objects waiting for respawn */
1318 send_timeq_objects(&(q->member));
1319 break;
1321 case P_INFO:
1322 q=find_player(&client,s);
1323 if (!q) send_info((struct sockaddr*)(&client),0);
1324 else send_info((struct sockaddr*)(&client),q->member.id);
1325 break;
1327 case P_REENTER_GAME:
1328 q=find_player(&client,s);
1329 if (!q)break;
1330 if (!(q->member.obj->status & S_DEAD) || (q->member.obj->status & S_NOISE))
1331 break;
1332 find_birthplace(&x,&y);
1333 create_noise(x,y,&(q->member));
1334 q->member.obj->x=int2double(x);
1335 q->member.obj->y=int2double(y);
1336 sendall_update_object(q->member.obj,0,3); /* update coordinates */
1337 break;
1339 case P_END:
1340 if (nonquitable)break;
1341 q=find_player(&client,s);
1342 if (!q)break;
1343 p=&(q->member);
1344 packet[0]=P_END;
1345 memcpy(packet+1,p->name,strlen(p->name)+1);
1346 sendall(packet,2+strlen(p->name),0);
1347 snprintf(txt,256,"Game terminated by player \"%s\".\n",p->name);
1348 message(txt,2);
1349 exit(0);
1351 case P_QUIT_REQUEST:
1352 q=find_player(&client,s);
1353 if (!q) /* this player has been deleted, but due to network inconsistency he doesn't know it */
1355 packet[0]=P_PLAYER_DELETED;
1356 send_packet(packet,1,(struct sockaddr*)(&client),0,last_player->member.id);
1357 break;
1359 snprintf(txt,256,"%s left the game.\n",q->member.name);
1360 message(txt,2);
1361 packet[0]=P_PLAYER_DELETED;
1362 send_packet((char *)packet,1,(struct sockaddr*)(&client),0,last_player->member.id);
1363 snprintf(txt,256,"%s left the game.",q->member.name);
1364 sendall_message(0,txt,0,0, M_LEAVE);
1365 delete_player(q);
1366 send_info(0,0);
1367 break;
1369 case P_KEYBOARD:
1370 if (l<3)break; /* invalid packet */
1371 q=find_player(&client,s);
1372 if (!q)break;
1373 q->member.last_update=get_time();
1374 q->member.keyboard_status.status=packet[1];
1375 q->member.keyboard_status.weapon=packet[2];
1376 break;
1378 case P_MESSAGE:
1379 if (l < 3)
1380 break; /* invalid packet */
1381 q = find_player(&client, s);
1382 if (!q)
1383 break;
1384 sendall_message(q->member.name, packet + 2, 0, 0, M_CHAT);
1385 snprintf(txt, 256, "%s> %s\n", q->member.name, packet + 2);
1386 message(txt, 1);
1387 break;
1389 default:
1390 snprintf(txt,256,"Unknown packet: head=%d\n",*packet);
1391 message(txt,2);
1392 break;
1398 /* compute collision of two objects */
1399 /* return value: 0=nothing */
1400 /* 1=collision */
1401 static int collision(int x1,int y1,int t1,int s1,struct pos* p1,int x2,int y2,int t2,int s2,struct pos *p2)
1403 int w1,w2,h1,h2;
1404 unsigned char h=0,v=0;
1406 get_dimensions(t1,s1,p1,&w1,&h1);
1407 get_dimensions(t2,s2,p2,&w2,&h2);
1409 if ((x2>=x1&&x2<=x1+w1-1)||(x2+w2-1>=x1&&x2+w2-1<=x1+w1-1))h=1;
1410 if ((x1>=x2&&x1<=x2+w2-1)||(x1+w1-1>=x2&&x1+w1-1<=x2+w2-1))h=1;
1411 if (!h)return 0;
1413 if ((y2>=y1&&y2<=y1+h1-1)||(y2+h2-1>=y1&&y2+h2-1<=y1+h1-1))v=1;
1414 if ((y1>=y2&&y1<=y2+h2-1)||(y1+h1-1>=y2&&y1+h1-1<=y2+h2-1))v=1;
1415 if (!v)return 0;
1416 return 1;
1420 /* create corpse on given position and with color num */
1421 /* num is number of dead player */
1422 static void create_corpse(int x,int y,int num, int status)
1424 struct it *o;
1425 static char txt[32];
1426 int a;
1427 int xoffs=num>15?-15:-5;
1428 int yoffs=num>15?-1:0;
1430 snprintf(txt, sizeof(txt), "corpse%d",num);
1431 if (find_sprite(txt,&a))return;
1433 o=new_obj(id,T_CORPSE,CORPSE_TTL,a,0,status,int2double(x+xoffs),int2double(y+yoffs),0,0,0);
1434 if (!o)return;
1435 id++;
1436 sendall_new_object(o,0);
1440 /* create mess on given position */
1441 /* y1=y coordinate of the mess */
1442 /* y2=y coordinate of the player (place where blood gushes and guts fly from */
1443 static void create_mess(int x,int y1,int y2)
1445 struct it *o;
1447 o=new_obj(id,T_CORPSE,CORPSE_TTL,mess1_sprite,0,0,int2double(x),int2double(y1),0,0,0);
1448 if (!o)return;
1449 id++;
1450 sendall_new_object(o,0);
1452 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);
1453 if (!o)return;
1454 id++;
1455 sendall_new_object(o,0);
1457 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);
1458 if (!o)return;
1459 id++;
1460 sendall_new_object(o,0);
1462 o=new_obj(id,T_MESS,MESS_TTL,mess2_sprite,0,0,int2double(x),int2double(y2),float2double(3*36),float2double((double).5*36),0);
1463 if (!o)return;
1464 id++;
1465 sendall_new_object(o,0);
1467 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);
1468 if (!o)return;
1469 id++;
1470 sendall_new_object(o,0);
1472 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);
1473 if (!o)return;
1474 id++;
1475 sendall_new_object(o,0);
1477 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);
1478 if (!o)return;
1479 id++;
1480 sendall_new_object(o,0);
1482 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);
1483 if (!o)return;
1484 id++;
1485 sendall_new_object(o,0);
1487 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);
1488 if (!o)return;
1489 id++;
1490 sendall_new_object(o,0);
1494 /* compute collision of given object with the others */
1495 /* return value: 1=delete this object */
1496 /* 0=don't delete */
1497 /* 2= delete this object but don't send delete packet */
1498 static int dynamic_collision(struct it *obj)
1500 struct it *p;
1501 struct player_list *pl;
1502 struct object_list *ol;
1503 char txt[256];
1504 struct it *o;
1505 int b;
1506 int a,c,s;
1507 int px,py,h;
1509 #define OX (double2int(obj->x))
1510 #define OY (double2int(obj->y))
1511 #define PX (double2int(p->x))
1512 #define PY (double2int(p->y))
1513 #define A ((struct player*)(p->data))->armor
1514 #define H ((struct player*)(p->data))->health
1515 #define P ((struct player*)(p->data))
1516 #define MAX_AMMO(x) (weapon[x].max_ammo)
1519 for (pl=&players;pl->next;pl=pl->next)
1521 p=pl->next->member.obj;
1522 if (p->type==T_PLAYER&&(p->status & S_DEAD))
1523 continue; /* dead player */
1524 if (collision(OX,OY,obj->type,obj->status,sprites[obj->sprite].positions,PX,PY,p->type,p->status,sprites[p->sprite].positions))
1525 switch(obj->type)
1527 case T_AMMO_GRENADE:
1529 char txt[256];
1530 if (p->type!=T_PLAYER)break;
1531 if (((struct player*)(p->data))->ammo[WEAPON_GRENADE]==MAX_AMMO(WEAPON_GRENADE))break;
1532 ((struct player*)(p->data))->ammo[WEAPON_GRENADE]+=weapon[WEAPON_GRENADE].add_ammo;
1533 if (((struct player*)(p->data))->ammo[WEAPON_GRENADE]>MAX_AMMO(WEAPON_GRENADE))
1534 ((struct player*)(p->data))->ammo[WEAPON_GRENADE]=MAX_AMMO(WEAPON_GRENADE);
1535 /* P->current_weapon=select_best_weapon(P); */
1536 send_update_player((struct player*)(p->data));
1537 send_message((struct player*)(p->data),0,"You got grenades", M_AMMO);
1538 snprintf(txt,256,"%s got grenades.\n",((struct player*)(p->data))->name);
1539 message(txt,1);
1540 obj->status |= S_INVISIBLE;
1541 add_to_timeq(obj->id,T_AMMO_GRENADE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1542 sendall_update_status(obj,0);
1544 return 2;
1546 case T_AMMO_GUN:
1548 char txt[256];
1549 if (p->type!=T_PLAYER)break;
1550 if (((struct player*)(p->data))->ammo[WEAPON_GUN]==MAX_AMMO(WEAPON_GUN))break;
1552 if(is_weapon_better((struct player*)(p->data), WEAPON_GUN)
1553 && is_weapon_empty((struct player*)(p->data), WEAPON_GUN))
1554 P->current_weapon = WEAPON_GUN;
1556 ((struct player*)(p->data))->ammo[WEAPON_GUN]+=weapon[WEAPON_GUN].add_ammo;
1557 if (((struct player*)(p->data))->ammo[WEAPON_GUN]>MAX_AMMO(WEAPON_GUN))
1558 ((struct player*)(p->data))->ammo[WEAPON_GUN]=MAX_AMMO(WEAPON_GUN);
1559 /* P->current_weapon=select_best_weapon(P); */
1560 send_update_player((struct player*)(p->data));
1561 send_message((struct player*)(p->data),0,"You got a magazine", M_AMMO);
1562 snprintf(txt,256,"%s got a magazine.\n",((struct player*)(p->data))->name);
1563 message(txt,1);
1564 obj->status |= S_INVISIBLE;
1565 add_to_timeq(obj->id,T_AMMO_GUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1566 sendall_update_status(obj,0);
1568 return 2;
1570 case T_AMMO_SHOTGUN:
1572 char txt[256];
1573 if (p->type!=T_PLAYER)break;
1574 if (((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]==MAX_AMMO(WEAPON_SHOTGUN))break;
1576 if(is_weapon_better((struct player*)(p->data), WEAPON_SHOTGUN)
1577 && is_weapon_empty((struct player*)(p->data), WEAPON_SHOTGUN))
1578 P->current_weapon = WEAPON_SHOTGUN;
1580 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]+=weapon[WEAPON_SHOTGUN].add_ammo;
1581 if (((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]>MAX_AMMO(WEAPON_SHOTGUN))
1582 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]=MAX_AMMO(WEAPON_SHOTGUN);
1583 /* P->current_weapon=select_best_weapon(P); */
1584 send_update_player((struct player*)(p->data));
1585 send_message((struct player*)(p->data),0,"You got shotgun shells", M_AMMO);
1586 snprintf(txt,256,"%s got shotgun shells.\n",((struct player*)(p->data))->name);
1587 message(txt,1);
1588 obj->status |= S_INVISIBLE;
1589 add_to_timeq(obj->id,T_AMMO_SHOTGUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1590 sendall_update_status(obj,0);
1592 return 2;
1594 case T_AMMO_RIFLE:
1596 char txt[256];
1597 if (p->type!=T_PLAYER)break;
1598 if (((struct player*)(p->data))->ammo[WEAPON_RIFLE]==MAX_AMMO(WEAPON_RIFLE))break;
1600 if(is_weapon_better((struct player*)(p->data), WEAPON_RIFLE)
1601 && is_weapon_empty((struct player*)(p->data), WEAPON_RIFLE))
1602 P->current_weapon = WEAPON_RIFLE;
1604 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]+=weapon[WEAPON_RIFLE].add_ammo;
1605 if (((struct player*)(p->data))->ammo[WEAPON_RIFLE]>MAX_AMMO(WEAPON_RIFLE))
1606 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]=MAX_AMMO(WEAPON_RIFLE);
1607 /* P->current_weapon=select_best_weapon(P); */
1608 send_update_player((struct player*)(p->data));
1609 send_message((struct player*)(p->data),0,"You got cartridges", M_AMMO);
1610 snprintf(txt,256,"%s got cartridges.\n",((struct player*)(p->data))->name);
1611 message(txt,1);
1612 obj->status |= S_INVISIBLE;
1613 add_to_timeq(obj->id,T_AMMO_RIFLE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1614 sendall_update_status(obj,0);
1616 return 2;
1618 case T_AMMO_UZI:
1620 char txt[256];
1621 if (p->type!=T_PLAYER)break;
1622 if (((struct player*)(p->data))->ammo[WEAPON_UZI]==MAX_AMMO(WEAPON_UZI))break;
1624 if(is_weapon_better((struct player*)(p->data), WEAPON_UZI)
1625 && is_weapon_empty((struct player*)(p->data), WEAPON_UZI))
1626 P->current_weapon = WEAPON_UZI;
1628 ((struct player*)(p->data))->ammo[WEAPON_UZI]+=weapon[WEAPON_UZI].add_ammo;
1629 if (((struct player*)(p->data))->ammo[WEAPON_UZI]>MAX_AMMO(WEAPON_UZI))
1630 ((struct player*)(p->data))->ammo[WEAPON_UZI]=MAX_AMMO(WEAPON_UZI);
1631 /* P->current_weapon=select_best_weapon(P); */
1632 send_update_player((struct player*)(p->data));
1633 send_message((struct player*)(p->data),0,"You got ammo for Uzi", M_AMMO);
1634 snprintf(txt,256,"%s got Uzi ammo.\n",((struct player*)(p->data))->name);
1635 message(txt,1);
1636 obj->status |= S_INVISIBLE;
1637 add_to_timeq(obj->id,T_AMMO_UZI,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1638 sendall_update_status(obj,0);
1640 return 2;
1642 case T_UZI:
1644 char txt[256];
1645 if (p->type!=T_PLAYER)break;
1646 if ((((struct player*)(p->data))->ammo[WEAPON_UZI]==MAX_AMMO(WEAPON_UZI))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_UZI))break;
1648 if(is_weapon_better((struct player*)(p->data), WEAPON_UZI)
1649 && !is_weapon_usable((struct player*)(p->data), WEAPON_UZI))
1650 P->current_weapon = WEAPON_UZI;
1652 ((struct player*)(p->data))->weapons|=WEAPON_MASK_UZI;
1653 ((struct player*)(p->data))->ammo[WEAPON_UZI]+=weapon[WEAPON_UZI].basic_ammo;
1654 if (((struct player*)(p->data))->ammo[WEAPON_UZI]>MAX_AMMO(WEAPON_UZI))
1655 ((struct player*)(p->data))->ammo[WEAPON_UZI]=MAX_AMMO(WEAPON_UZI);
1656 // P->current_weapon=select_best_weapon(P);
1657 send_update_player((struct player*)(p->data));
1658 send_message((struct player*)(p->data),0,"You got Uzi", M_WEAPON);
1659 snprintf(txt,256,"%s got Uzi.\n",((struct player*)(p->data))->name);
1660 message(txt,1);
1661 obj->status |= S_INVISIBLE;
1662 add_to_timeq(obj->id,T_UZI,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1663 sendall_update_status(obj,0);
1665 return 2;
1667 case T_RIFLE:
1669 char txt[256];
1670 if (p->type!=T_PLAYER)break;
1671 if ((((struct player*)(p->data))->ammo[WEAPON_RIFLE]==MAX_AMMO(WEAPON_RIFLE))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_RIFLE))break;
1673 if(is_weapon_better((struct player*)(p->data), WEAPON_RIFLE)
1674 && !is_weapon_usable((struct player*)(p->data), WEAPON_RIFLE))
1675 P->current_weapon = WEAPON_RIFLE;
1677 ((struct player*)(p->data))->weapons|=WEAPON_MASK_RIFLE;
1678 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]+=weapon[WEAPON_RIFLE].basic_ammo;
1679 if (((struct player*)(p->data))->ammo[WEAPON_RIFLE]>MAX_AMMO(WEAPON_RIFLE))
1680 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]=MAX_AMMO(WEAPON_RIFLE);
1681 // P->current_weapon=select_best_weapon(P);
1682 send_update_player((struct player*)(p->data));
1683 send_message((struct player*)(p->data),0,"You got sniper rifle", M_WEAPON);
1684 snprintf(txt,256,"%s got sniper rifle.\n",((struct player*)(p->data))->name);
1685 message(txt,1);
1686 obj->status |= S_INVISIBLE;
1687 add_to_timeq(obj->id,T_RIFLE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1688 sendall_update_status(obj,0);
1690 return 2;
1692 case T_SHOTGUN:
1694 char txt[256];
1695 if (p->type!=T_PLAYER)break;
1696 if ((((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]==MAX_AMMO(WEAPON_SHOTGUN))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_SHOTGUN))break;
1698 if(is_weapon_better((struct player*)(p->data), WEAPON_SHOTGUN)
1699 && !is_weapon_usable((struct player*)(p->data), WEAPON_SHOTGUN))
1700 P->current_weapon = WEAPON_SHOTGUN;
1702 ((struct player*)(p->data))->weapons|=WEAPON_MASK_SHOTGUN;
1703 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]+=weapon[WEAPON_SHOTGUN].basic_ammo;
1704 if (((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]>MAX_AMMO(WEAPON_SHOTGUN))
1705 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]=MAX_AMMO(WEAPON_SHOTGUN);
1706 // P->current_weapon=select_best_weapon(P);
1707 send_update_player((struct player*)(p->data));
1708 send_message((struct player*)(p->data),0,"You got a shotgun", M_WEAPON);
1709 snprintf(txt,256,"%s got a shotgun.\n",((struct player*)(p->data))->name);
1710 message(txt,1);
1711 obj->status |= S_INVISIBLE;
1712 add_to_timeq(obj->id,T_SHOTGUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1713 sendall_update_status(obj,0);
1715 return 2;
1717 case T_BFG:
1719 char txt[256];
1720 if (p->type!=T_PLAYER)break;
1721 if ((((struct player*)(p->data))->ammo[WEAPON_BFG]==MAX_AMMO(WEAPON_BFG))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_BFG))break;
1723 if(is_weapon_better((struct player*)(p->data), WEAPON_BFG)
1724 && !is_weapon_usable((struct player*)(p->data), WEAPON_BFG))
1725 P->current_weapon = WEAPON_BFG;
1727 ((struct player*)(p->data))->weapons|=WEAPON_MASK_BFG;
1728 ((struct player*)(p->data))->ammo[WEAPON_BFG]+=weapon[WEAPON_BFG].basic_ammo;
1729 if (((struct player*)(p->data))->ammo[WEAPON_BFG]>MAX_AMMO(WEAPON_BFG))
1730 ((struct player*)(p->data))->ammo[WEAPON_BFG]=MAX_AMMO(WEAPON_BFG);
1731 // P->current_weapon=select_best_weapon(P);
1732 send_update_player((struct player*)(p->data));
1733 send_message((struct player*)(p->data),0,"You got a BFG", M_WEAPON);
1734 snprintf(txt,256,"%s got a BFG.\n",((struct player*)(p->data))->name);
1735 message(txt,1);
1736 obj->status |= S_INVISIBLE;
1737 add_to_timeq(obj->id,T_BFG,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1738 sendall_update_status(obj,0);
1740 return 2;
1742 case T_BLOODRAIN:
1744 char txt[256];
1745 if (p->type!=T_PLAYER)break;
1746 if ((((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]==MAX_AMMO(WEAPON_BLOODRAIN))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_BLOODRAIN))break;
1748 if(is_weapon_better((struct player*)(p->data), WEAPON_BLOODRAIN)
1749 && !is_weapon_usable((struct player*)(p->data), WEAPON_BLOODRAIN))
1750 P->current_weapon = WEAPON_BLOODRAIN;
1752 ((struct player*)(p->data))->weapons|=WEAPON_MASK_BLOODRAIN;
1753 ((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]+=weapon[WEAPON_BLOODRAIN].basic_ammo;
1754 if (((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]>MAX_AMMO(WEAPON_BLOODRAIN))
1755 ((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]=MAX_AMMO(WEAPON_BLOODRAIN);
1756 // P->current_weapon=select_best_weapon(P);
1757 send_update_player((struct player*)(p->data));
1758 send_message((struct player*)(p->data),0,"You charged your Bloodrain", M_WEAPON);
1759 snprintf(txt,256,"%s charged his Bloodrain.\n",((struct player*)(p->data))->name);
1760 message(txt,1);
1761 obj->status |= S_INVISIBLE;
1762 add_to_timeq(obj->id,T_BLOODRAIN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1763 sendall_update_status(obj,0);
1765 return 2;
1767 case T_INVISIBILITY:
1769 char txt[256];
1770 if (p->type!=T_PLAYER)break;
1772 ((struct player*)(p->data))->invisibility_counter=INVISIBILITY_DURATION;
1773 p->status |= S_INVISIBLE; /* hide player */
1774 sendall_update_status(p,0);
1775 send_message((struct player*)(p->data),0,"You got invisibility dope", M_ITEM);
1776 snprintf(txt,256,"%s got invisibility.\n",((struct player*)(p->data))->name);
1777 message(txt,1);
1778 obj->status |= S_INVISIBLE;
1779 add_to_timeq(obj->id,T_INVISIBILITY,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,INVISIBILITY_RESPAWN_TIME);
1780 sendall_update_status(obj,0);
1782 return 2;
1784 case T_JETPACK:
1786 char txt[256];
1787 if (p->type!=T_PLAYER)break;
1788 p->status |= S_JETPACK;
1789 sendall_update_status(p, 0);
1790 send_message((struct player*)(p->data),0,"You got a jetpack", M_ITEM);
1791 snprintf(txt,256,"%s got a jetpack.\n",((struct player*)(p->data))->name);
1792 message(txt,1);
1793 obj->status |= S_INVISIBLE;
1794 add_to_timeq(obj->id,T_JETPACK,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,ARMOR_RESPAWN_TIME);
1795 sendall_update_status(obj,0);
1797 return 2;
1799 case T_TELEPORT:
1801 char txt[256];
1802 if (p->type!=T_PLAYER)break;
1804 find_birthplace(&px,&py);
1805 o=new_obj(id,T_NOISE,NOISE_TTL,noise_sprite,0,0,int2double(px),int2double(py),0,0,(void *)(long)(p->id));
1806 if (!o)
1807 return 2;
1808 id++;
1809 sendall_new_object(o,0);
1810 p->x=int2double(px);
1811 p->y=int2double(py);
1812 sendall_update_object(((struct player*)p->data)->obj,0,3);
1814 sendall_update_status(p,0);
1815 send_message((struct player*)(p->data),0,"You teleported", M_INFO);
1816 snprintf(txt,256,"%s teleported.\n",((struct player*)(p->data))->name);
1817 message(txt,1);
1818 add_to_timeq(obj->id,T_TELEPORT,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,0);
1819 sendall_update_status(obj,0);
1821 return 2;
1823 case T_ARMOR:
1825 char txt[256];
1826 if (p->type!=T_PLAYER)break;
1827 if (((struct player*)(p->data))->armor>=100)break; /* he has 100% armor */
1828 ((struct player*)(p->data))->armor+=ARMOR_ADD;
1829 if (((struct player*)(p->data))->armor>100)((struct player*)(p->data))->armor=100;
1830 send_update_player((struct player*)(p->data));
1831 send_message((struct player*)(p->data),0,"You got armor", M_ITEM);
1832 snprintf(txt,256,"%s got armor.\n",((struct player*)(p->data))->name);
1833 message(txt,1);
1834 obj->status |= S_INVISIBLE;
1835 add_to_timeq(obj->id,T_ARMOR,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,ARMOR_RESPAWN_TIME);
1836 sendall_update_status(obj,0);
1838 return 2;
1840 case T_MEDIKIT:
1842 char txt[256];
1843 if (p->type!=T_PLAYER)break;
1844 if (((struct player*)(p->data))->health>=100)break; /* he's healthy */
1845 ((struct player*)(p->data))->health+=MEDIKIT_HEALTH_ADD;
1846 if (((struct player*)(p->data))->health>100)((struct player*)(p->data))->health=100;
1847 send_update_player((struct player*)(p->data));
1848 send_message((struct player*)(p->data),0,"You picked up a medikit", M_ITEM);
1849 snprintf(txt,256,"%s picked up a medikit.\n",((struct player*)(p->data))->name);
1850 message(txt,1);
1851 obj->status |= S_INVISIBLE;
1852 add_to_timeq(obj->id,T_MEDIKIT,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,MEDIKIT_RESPAWN_TIME);
1853 sendall_update_status(obj,0);
1855 return 2;
1857 case T_BIOMED:
1859 char txt[256];
1860 if (p->type!=T_PLAYER)break;
1861 if (((struct player*)(p->data))->obj->status & S_ILL)
1862 ((struct player*)(p->data))->obj->status &= ~S_ILL;
1863 else
1864 ((struct player*)(p->data))->health=1; /* really hardcore chemical cocktail :-) */
1865 send_update_player((struct player*)(p->data));
1866 send_message((struct player*)(p->data),0,"You picked up a bio-medikit", M_ITEM);
1867 snprintf(txt,256,"%s picked up a bio-medikit.\n",((struct player*)(p->data))->name);
1868 message(txt,1);
1869 obj->status |= S_INVISIBLE;
1870 add_to_timeq(obj->id,T_BIOMED,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,MEDIKIT_RESPAWN_TIME);
1871 sendall_update_status(obj,0);
1873 return 2;
1875 case T_BIOSKULL:
1876 if (p->type!=T_PLAYER || ((struct player*)(p->data))->obj->status & S_ILL)
1877 break;
1878 ((struct player*)(p->data))->obj->status |= S_ILL;
1879 send_message((struct player*)(p->data),0,"You got infected from skull", M_INFO);
1880 snprintf(txt,256,"%s got infected",((struct player*)(p->data))->name);
1881 sendall_message(0,txt,(struct player*)(p->data),0, M_INFO);
1882 snprintf(txt,256,"%s got infected.\n",((struct player*)(p->data))->name);
1883 message(txt,2);
1885 sendall_update_object(p,0,0); /* update everything */
1886 send_update_player((struct player*)(p->data));
1887 send_info(0,0);
1888 return 0;
1890 case T_JETFIRE:
1891 if (p->type!=T_PLAYER)
1892 break;
1893 if (((struct player*)(p->data))->obj->id == (long)obj->data || ((struct player*)(p->data))->obj->status & S_ONFIRE)
1894 break;
1895 ((struct player*)(p->data))->obj->status |= S_ONFIRE;
1896 o=&(((ol = find_in_table((long)(obj->data))))->member); /* owner of the flame */
1897 snprintf(txt,256,"You caught fire from %s's jetpack", ((struct player*)(o->data))->name);
1898 send_message((struct player*)(p->data),0,txt, M_INFO);
1900 sendall_update_object(p,0,0); /* update everything */
1901 send_update_player((struct player*)(p->data));
1902 send_info(0,0);
1903 return 0;
1905 case T_PLAYER: /* illness is spreading :-) */
1906 if (p->type!=T_PLAYER || p->data == obj->data ||
1907 ((struct player*)(p->data))->obj->status & S_ILL)
1908 break;
1909 if (((struct player*)(obj->data))->obj->status & S_ILL) {
1910 ((struct player*)(p->data))->obj->status |= S_ILL;
1912 snprintf(txt,256,"%s infected %s.",((struct player*)(obj->data))->name,((struct player*)(p->data))->name);
1913 sendall_message(0,txt,(struct player*)(obj->data),(struct player*)(p->data), M_INFO);
1914 snprintf(txt,256,"%s infected you",((struct player*)(obj->data))->name);
1915 send_message((struct player*)(p->data),0,txt, M_INFO); /* the dead */
1916 snprintf(txt,256,"You infected %s",((struct player*)(p->data))->name);
1917 send_message((struct player*)(obj->data),0,txt, M_INFO); /* the dead */
1918 snprintf(txt,256,"%s infected %s.\n",((struct player*)(obj->data))->name,((struct player*)(p->data))->name);
1919 message(txt,2);
1921 sendall_update_object(p,0,0); /* update everything */
1922 send_update_player((struct player*)(p->data));
1923 send_info(0,0);
1925 return 0;
1927 case T_CORPSE: /* illness is spreading from corpses too */
1928 if (p->type!=T_PLAYER || p->data == obj->data ||
1929 ((struct player*)(p->data))->obj->status & S_ILL)
1930 break;
1931 if (obj->status & S_ILL) {
1932 ((struct player*)(p->data))->obj->status |= S_ILL;
1934 snprintf(txt,256,"%s got infected from a corpse.",((struct player*)(p->data))->name);
1935 sendall_message(0,txt,(struct player*)(obj->data),(struct player*)(p->data), M_INFO);
1936 snprintf(txt,256,"You got infected from a corpse");
1937 send_message((struct player*)(p->data),0,txt, M_INFO); /* the dead */
1938 snprintf(txt,256,"%s got infected from a corpse.\n",((struct player*)(p->data))->name);
1939 message(txt,2);
1941 sendall_update_object(p,0,0); /* update everything */
1942 send_update_player((struct player*)(p->data));
1943 send_info(0,0);
1945 return 0;
1947 case T_KILL:
1948 if (p->type!=T_PLAYER)break;
1949 a=(int)((1-(double)A/100)*KILL_LETHALNESS);
1950 c=KILL_ARMOR_DAMAGE;
1951 if (a>=H) /* player died */
1953 ((struct player*)(p->data))->deaths++;
1954 send_message((struct player*)(p->data),0,"You killed yourself", M_DEATH);
1955 snprintf(txt,256,"%s suicides",((struct player*)(p->data))->name);
1956 sendall_message(0,txt,(struct player*)(p->data),0, M_DEATH);
1957 snprintf(txt,256,"%s suicides.\n",((struct player*)(p->data))->name);
1958 message(txt,2);
1960 s=p->status;
1961 px=PX;
1962 py=PY;
1963 h=H;
1964 H=0;
1965 p->xspeed=0;
1966 p->yspeed=0;
1967 p->status |= S_DEAD; /* dead flag */
1968 sendall_update_object(p,0,0); /* update everything */
1969 send_update_player((struct player*)(p->data)); /* dead player */
1970 send_info(0,0);
1971 if (a-h>=OVERKILL)
1972 create_mess(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-MESS_HEIGHT,py);
1973 else
1974 create_corpse(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->data))->color,0);
1976 else
1978 H-=a; /* health */
1979 A=(c>=A)?0:(A-c); /* armor */
1980 send_update_player((struct player*)(p->data));
1982 return 0;
1984 case T_SHRAPNEL:
1985 if (p->type==T_CORPSE)
1987 char packet[5];
1988 int offset = 0;
1989 px=PX;
1990 py=PY;
1991 packet[offset++]=P_DELETE_OBJECT;
1992 put_int(packet,p->id,&offset);
1993 sendall_chunked(packet,offset,0);
1994 delete_obj(p->id);
1995 create_mess(px,py,py);
1996 return 1;
1998 case T_BULLET:
1999 case T_BFGCELL:
2000 case T_CHAIN:
2001 if (p->type!=T_PLAYER)break;
2002 b=((obj->type==T_BULLET||obj->type==T_BFGCELL||obj->type==T_CHAIN)?FIRE_IMPACT:SHRAPNEL_IMPACT);
2003 p->status |= S_HIT;
2004 if (obj->type != T_CHAIN)
2005 p->xspeed+=obj->xspeed>0?b:-b;
2006 sendall_update_object(p,0,4); /* update speed + status */
2007 p->status &= ~S_HIT;
2008 a=(int)((1-(double)A/100)*weapon[obj->status].lethalness*(2-double2int(obj->y-p->y)/(double)PLAYER_HEIGHT)*obj->ttl/weapon[obj->status].ttl);
2009 c=(int)(weapon[obj->status].armor_damage*(2-double2int(obj->y-p->y)/(double)PLAYER_HEIGHT)*obj->ttl/weapon[obj->status].ttl);
2010 if (a>=H) /* player was slain */
2012 o=&(((ol = find_in_table((long)(obj->data))))->member); /* owner of the bullet */
2013 ((struct player*)(p->data))->deaths++;
2014 if (!ol) { /* for now only bloodrain */
2015 snprintf(txt,256,"Bloody shrapnel killed %s.",((struct player*)(p->data))->name);
2016 sendall_message(0,txt,NULL,(struct player*)(p->data), M_DEATH);
2017 snprintf(txt,256,"Bloody shrapnel killed you");
2018 send_message((struct player*)(p->data),0,txt, M_DEATH); /* the dead */
2019 snprintf(txt,256,"Bloody shrapnel killed %s.\n",((struct player*)(p->data))->name);
2020 message(txt,2);
2022 else if (o->data==p->data) /* suicide */
2024 ((struct player*)(o->data))->frags-=!!(((struct player*)(o->data))->frags);
2025 send_message((struct player*)(o->data),0,"You killed yourself", M_DEATH);
2026 snprintf(txt,256,"%s suicides",((struct player*)(o->data))->name);
2027 sendall_message(0,txt,(struct player*)(o->data),0, M_DEATH);
2028 snprintf(txt,256,"%s suicides.\n",((struct player*)(o->data))->name);
2029 message(txt,2);
2031 else
2033 ((struct player*)(o->data))->frags++;
2034 snprintf(txt,256,"%s killed %s.",((struct player*)(o->data))->name,((struct player*)(p->data))->name);
2035 sendall_message(0,txt,(struct player*)(o->data),(struct player*)(p->data), M_DEATH);
2036 snprintf(txt,256,"%s killed you",((struct player*)(o->data))->name);
2037 send_message((struct player*)(p->data),0,txt, M_DEATH); /* the dead */
2038 snprintf(txt,256,"You killed %s",((struct player*)(p->data))->name);
2039 send_message((struct player*)(o->data),0,txt, M_DEATH); /* the dead */
2040 snprintf(txt,256,"%s killed %s.\n",((struct player*)(o->data))->name,((struct player*)(p->data))->name);
2041 message(txt,2);
2043 s=p->status;
2044 px=PX;
2045 py=PY;
2046 h=H;
2047 H=0;
2048 p->xspeed=0;
2049 p->yspeed=0;
2050 p->status |= S_DEAD; /* dead flag */
2051 sendall_update_object(p,0,0); /* update everything */
2052 send_update_player((struct player*)(p->data)); /* dead player */
2053 if (ol)
2054 send_update_player((struct player*)(o->data)); /* owner of bullet/shrapnel */
2055 send_info(0,0);
2056 if (a-h>=OVERKILL)
2057 create_mess(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-MESS_HEIGHT,py);
2058 else
2059 create_corpse(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->data))->color,0);
2061 else
2063 H-=a; /* health */
2064 A=(c>=A)?0:(A-c); /* armor */
2065 sendall_hit(p->id,obj->xspeed<0,OX-PX,OY-PY,0);
2066 send_update_player((struct player*)(p->data));
2067 /* well ... */
2068 if (obj->type == T_CHAIN) {
2069 struct it *meat=new_obj(id,T_MESS,MESS_TTL,
2070 (meatcounter==0x1)?mess3_sprite:
2071 ((meatcounter)==0x2)?mess2_sprite:mess4_sprite,
2072 0,0,obj->x,obj->y,-float2double(obj->xspeed/500),
2073 -float2double((meatcounter+2)*36),0);
2074 if (!meat) return 1;
2075 id++;
2076 sendall_new_object(meat,0);
2077 meatcounter = (meatcounter+1)%3;
2080 return 1;
2083 return 0;
2085 #undef MAX_AMMO
2086 #undef P
2087 #undef H
2088 #undef A
2089 #undef OX
2090 #undef OY
2091 #undef PX
2092 #undef PY
2096 /* recompute objects positions */
2097 static void update_game(void)
2099 static char packet[64];
2100 char txt[256];
2101 struct object_list *p, *p2;
2102 struct player_list *q;
2103 int w,h,b,a;
2104 unsigned char stop_x,stop_y;
2105 int x,y,xs,ys;
2106 int x1,y1;
2107 unsigned char sy;
2108 struct it *s; /* for grenades throwing */
2109 unsigned int status;
2110 int DELTA_TIME;
2111 unsigned long_long t;
2112 unsigned int old_status;
2113 int old_ttl;
2114 int old_x,old_y,old_x_speed,old_y_speed;
2115 int offset = 0;
2117 for(p=&objects;p->next;p=p->next)
2119 if (p->next->member.type==T_NOTHING)
2120 continue;
2121 if (p->next->member.type==T_PLAYER&&(p->next->member.status & S_DEAD))
2122 continue; /* dead player */
2123 if (p->next->member.type==T_PLAYER&&(((struct player*)(p->next->member.data))->current_level)<0) /* player hasn't entered the level yet */
2125 send_change_level((struct player*)p->next->member.data);
2126 continue;
2129 old_status=p->next->member.status;
2130 old_ttl=p->next->member.ttl;
2131 old_x=p->next->member.x;
2132 old_y=p->next->member.y;
2133 old_x_speed=p->next->member.xspeed;
2134 old_y_speed=p->next->member.yspeed;
2136 x=p->next->member.x;
2137 y=p->next->member.y;
2138 xs=p->next->member.xspeed;
2139 ys=p->next->member.yspeed;
2140 status=p->next->member.status;
2142 /* decrease invisibility counter of invisible player */
2143 if ((p->next->member.type==T_PLAYER)&&(((struct player*)(p->next->member.data))->invisibility_counter))
2145 ((struct player*)(p->next->member.data))->invisibility_counter--;
2146 if (!(((struct player*)(p->next->member.data))->invisibility_counter))
2148 p->next->member.status &= ~S_INVISIBLE;
2149 sendall_update_status(&(p->next->member),0);
2153 /* decrease life of ill player */
2154 if ((p->next->member.type==T_PLAYER)&&(((struct player*)(p->next->member.data))->obj->status & (S_ILL | S_ONFIRE)))
2156 /* hack - health with extended precision */
2157 if (!((struct player*)(p->next->member.data))->health_ep--) {
2158 ((struct player*)(p->next->member.data))->health_ep=
2159 ((((struct player*)(p->next->member.data))->obj->status & S_ILL) ? ILLNESS_SPEED : 0) +
2160 ((((struct player*)(p->next->member.data))->obj->status & S_ONFIRE) ? BURNING_SPEED : 0);
2161 ((struct player*)(p->next->member.data))->health--;
2163 send_update_player((struct player*)(p->next->member.data));
2164 if (!(((struct player*)(p->next->member.data))->health))
2166 p->next->member.status |= S_DEAD;
2167 ((struct player*)(p->next->member.data))->frags-=!!(((struct player*)(p->next->member.data))->frags);
2169 if (((struct player*)(p->next->member.data))->obj->status & S_ILL) {
2170 send_message((struct player*)(p->next->member.data),0,"You died on illness", M_DEATH);
2171 snprintf(txt,256,"%s died on illness",((struct player*)(p->next->member.data))->name);
2172 sendall_message(0,txt,(struct player*)(p->next->member.data),0, M_DEATH);
2173 snprintf(txt,256,"%s died on illness.\n",((struct player*)(p->next->member.data))->name);
2174 } else {
2175 send_message((struct player*)(p->next->member.data),0,"You burnt down to ashes", M_DEATH);
2176 snprintf(txt,256,"%s burnt down to ashes",((struct player*)(p->next->member.data))->name);
2177 sendall_message(0,txt,(struct player*)(p->next->member.data),0, M_DEATH);
2178 snprintf(txt,256,"%s burnt down to ashes.\n",((struct player*)(p->next->member.data))->name);
2180 message(txt,2);
2182 send_update_player((struct player*)(p->next->member.data)); /* dead player */
2183 sendall_update_status(&(p->next->member),0);
2184 send_info(0,0);
2186 create_corpse(double2int(p->next->member.x),double2int(p->next->member.y)+((p->next->member.status & S_CREEP)?
2187 CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->next->member.data))->color,S_ILL);
2191 /* decrement time to live */
2192 if (p->next->member.type == T_PLAYER && (p->next->member.status & S_BLOODRAIN))
2193 goto br;
2194 if (p->next->member.ttl>0)
2196 p->next->member.ttl--;
2197 /* create player */
2198 if (p->next->member.type==T_NOISE&&p->next->member.ttl==(NOISE_TTL>>1))
2200 /* find player */
2201 q=find_player(0,(long)(p->next->member.data));
2202 if (q) /* player is still in the game */
2204 init_player(&(q->member),q->member.obj->x,q->member.obj->y);
2205 q->member.obj->status &= ~(S_DEAD | S_NOISE);
2206 sendall_update_object(q->member.obj,0,0); /* update everything */
2207 send_update_player(&(q->member));
2210 goto cont_cycle; /* that's all for T_NOISE at this moment */
2212 /* grenades must be created after locking off */
2213 /* not when shoot request comes */
2214 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)
2216 s=new_obj(
2218 T_GRENADE,
2219 weapon[WEAPON_GRENADE].ttl,
2220 grenade_sprite,
2222 WEAPON_GRENADE,
2223 add_int(p->next->member.x,p->next->member.status & S_LOOKLEFT ? 2 : PLAYER_WIDTH-2),
2224 p->next->member.y+GRENADE_FIRE_YOFFSET,
2225 p->next->member.xspeed+(p->next->member.status & S_LOOKLEFT ? -weapon[WEAPON_GRENADE].shell_xspeed:weapon[WEAPON_GRENADE].shell_xspeed),
2226 p->next->member.yspeed+weapon[WEAPON_GRENADE].shell_yspeed,
2227 (void *)(long)(p->next->member.id));
2228 id++;
2229 sendall_new_object(s,0);
2231 /* if ttl is 0, delete this object */
2232 if (p->next->member.ttl<=0)
2234 /* player's ttl means how long he holds the gun */
2235 switch(p->next->member.type)
2237 case T_PLAYER:
2238 p->next->member.status &= ~S_SHOOTING;
2239 break;
2241 case T_GRENADE:
2242 case T_BFGCELL:
2243 br: offset = 0;
2244 packet[offset++]=(p->next->member.type==T_GRENADE)?P_EXPLODE_GRENADE:
2245 (p->next->member.type==T_BFGCELL)?P_EXPLODE_BFG:P_EXPLODE_BLOODRAIN;
2246 put_int(packet,id,&offset);
2247 put_int(packet,p->next->member.id,&offset);
2248 sendall_chunked(packet,offset,0);
2250 for (b=0;b<N_SHRAPNELS_EXPLODE;b++)
2252 double angle=(double)b*2*M_PI/N_SHRAPNELS_EXPLODE;
2253 int spd=add_int(mul_int(my_and(mul_int(weapon[WEAPON_GRENADE].speed,b+1),15),16),100);
2255 new_obj(
2257 T_SHRAPNEL,
2258 SHRAPNEL_TTL,
2259 (p->next->member.type==T_GRENADE)?
2260 shrapnel_sprite[random()%N_SHRAPNELS]:
2261 (p->next->member.type==T_BFGCELL)?
2262 bfgbit_sprite[random()%N_SHRAPNELS]:
2263 bloodrain_sprite[random()%N_SHRAPNELS],
2265 WEAPON_GRENADE,
2266 p->next->member.x,
2267 p->next->member.y,
2268 p->next->member.xspeed+mul(spd,float2double(cos(angle))),
2269 p->next->member.yspeed+mul(spd,float2double(sin(angle))),
2270 p->next->member.data);
2271 id++;
2273 if (p->next->member.status & S_BLOODRAIN) {
2274 p->next->member.status |= S_DEAD;
2275 ((struct player *)p->next->member.data)->frags-=!!(((struct player *)p->next->member.data)->frags);
2276 ((struct player *)p->next->member.data)->deaths++;
2277 sendall_update_object(&(p->next->member),0,0); /* update everything */
2278 send_update_player((struct player*)(p->next->member.data)); /* dead player */
2279 send_info(0,0);
2280 create_mess(double2int(p->next->member.x),double2int(p->next->member.y)+((p->next->member.status & S_CREEP)?
2281 CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,
2282 double2int(p->next->member.y)+((p->next->member.status & S_CREEP)?
2283 CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT);
2284 } else
2285 delete_obj(p->next->member.id);
2286 if (!(p->next))return;
2287 goto cont_cycle;
2289 default:
2290 offset = 0;
2291 packet[offset++]=P_DELETE_OBJECT;
2292 put_int(packet,p->next->member.id,&offset);
2293 sendall_chunked(packet,offset,0);
2294 delete_obj(p->next->member.id);
2295 if (!(p->next))return;
2296 goto cont_cycle;
2300 /* maintain only objects that you are allowed to maintain */
2301 if (!obj_attr[p->next->member.type].maintainer)goto dc;
2302 if (!(obj_attr[p->next->member.type].maintainer&2))continue;
2305 /* when not falling, slow down x motion */
2306 if (!(p->next->member.status & S_FALLING))
2307 p->next->member.xspeed=mul(p->next->member.xspeed,obj_attr[p->next->member.type].slow_down_x);
2309 /* fall */
2310 if (obj_attr[p->next->member.type].fall)
2312 if (p->next->member.type!=T_SHRAPNEL)p->next->member.status |= S_FALLING;
2313 p->next->member.yspeed+=FALL_ACCEL;
2314 /* but not too fast */
2315 if (p->next->member.yspeed>MAX_Y_SPEED)p->next->member.yspeed=MAX_Y_SPEED;
2318 t=get_time();
2319 get_dimensions(p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions,&w,&h);
2320 DELTA_TIME=float2double(((double)((long_long)(t-p->next->member.last_updated)))/MICROSECONDS);
2321 update_position(
2322 &(p->next->member),
2323 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
2324 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
2325 w,h,&stop_x,&stop_y);
2326 p->next->member.last_updated=t;
2328 /* walk up the stairs */
2329 if (stop_x&&p->next->member.type==T_PLAYER&&!(p->next->member.status & S_CREEP))
2331 x1=p->next->member.x;
2332 y1=p->next->member.y;
2333 p->next->member.x=x;
2334 p->next->member.y=y-int2double(1);
2335 update_position(
2336 &(p->next->member),
2337 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
2338 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
2339 w,h,0,&sy);
2340 if ((p->next->member.xspeed>0&&p->next->member.x<=x1)||(p->next->member.xspeed<0&&p->next->member.x>=x1)) /* restore original values */
2342 p->next->member.x=x1;
2343 p->next->member.y=y1;
2345 else
2347 stop_y=sy;
2348 stop_x=0;
2352 if (stop_x)p->next->member.xspeed=-mul(p->next->member.xspeed,obj_attr[p->next->member.type].bounce_x);
2353 if (my_abs(p->next->member.xspeed)<MIN_X_SPEED)
2355 p->next->member.xspeed=0;
2356 p->next->member.status &= ~S_WALKING;
2360 if (stop_y)
2362 p->next->member.yspeed=mul(p->next->member.yspeed,obj_attr[p->next->member.type].bounce_y);
2363 p->next->member.yspeed=-p->next->member.yspeed;
2364 if (my_abs(p->next->member.yspeed)<MIN_Y_SPEED)
2366 p->next->member.yspeed=0;
2367 if (stop_y==1)p->next->member.status &= ~S_FALLING;
2371 if ((p->next->member.type==T_SHRAPNEL||p->next->member.type==T_BULLET||
2372 p->next->member.type==T_BFGCELL||p->next->member.type==T_CHAIN)&&(stop_x||stop_y)) /* bullet and shrapnel die crashing into wall */
2374 offset = 0;
2375 packet[offset++]=P_DELETE_OBJECT;
2376 put_int(packet,p->next->member.id,&offset);
2377 sendall_chunked(packet,offset,0);
2378 delete_obj(p->next->member.id);
2379 if (!(p->next))break;
2380 continue;
2383 /* Anything crashing into PS makes him into bloody goo */
2384 for (p2=&objects;p2->next;p2=p2->next)
2385 if ((p2->next->member.type == T_PS) && (!(p2->next->member.status & S_INVISIBLE)) &&
2386 ((p->next->member.type == T_BULLET) || (p->next->member.type == T_SHRAPNEL) ||
2387 (p->next->member.type == T_CHAIN) || (p->next->member.type == T_BFGCELL)) &&
2388 collision(
2389 double2int(p2->next->member.x),double2int(p2->next->member.y),p2->next->member.type,p2->next->member.status,sprites[p2->next->member.sprite].positions,
2390 double2int(p->next->member.x),double2int(p->next->member.y),p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions)) {
2391 p2->next->member.status |= S_INVISIBLE;
2392 create_mess(double2int(p2->next->member.x),double2int(p2->next->member.y)+PLAYER_HEIGHT-MESS_HEIGHT,double2int(p2->next->member.y));
2393 add_to_timeq(p2->next->member.id,T_PS,0,p2->next->member.sprite,0,0,p2->next->member.x,p2->next->member.y,0,0,0,PS_RESPAWN_TIME);
2394 sendall_update_status(&(p2->next->member),0);
2397 /* compute collision with other objects */
2398 a=dynamic_collision(&(p->next->member));
2399 switch (a)
2401 case 1: /* object dies */
2402 offset = 0;
2403 packet[offset++]=P_DELETE_OBJECT;
2404 put_int(packet,p->next->member.id,&offset);
2405 sendall_chunked(packet,offset,0);
2407 case 2:
2408 delete_obj(p->next->member.id);
2409 if (!(p->next))return;
2410 goto cont_cycle;
2412 case 0: /* object still lives */
2413 if ( /* send update but only when something's changed and client doesn't maintain the object */
2414 (obj_attr[p->next->member.type].maintainer&4)&& /* server sends update */
2415 (x!=p->next->member.x|| /* something's changed */
2416 y!=p->next->member.y||
2417 xs!=p->next->member.xspeed||
2418 ys!=p->next->member.yspeed||
2419 status!=p->next->member.status))
2421 a=which_update(&(p->next->member),old_x,old_y,old_x_speed,old_y_speed,old_status,old_ttl);
2422 sendall_update_object(&(p->next->member),0,a);
2424 break;
2426 cont_cycle:;
2430 static void free_all_memory(void)
2432 struct queue_list *t;
2433 struct player_list *p;
2435 /* delete players */
2436 for (p=&players;p->next;)
2437 delete_player(p->next);
2438 /* delete objects */
2439 while (last_obj!=(&objects))delete_obj(last_obj->member.id);
2441 for (t=&time_queue;t->next;)
2443 struct queue_list *q;
2445 q=t->next->next;
2446 mem_free(t->next);
2447 t->next=q;
2450 /* delete birthplaces */
2451 if (n_birthplaces)mem_free(birthplace);
2453 /* delete sprites */
2454 free_sprites(0);
2456 free_area();
2457 if (level_checksum)mem_free(level_checksum);
2458 free_packet_buffer();
2461 /* fatal signal handler (sigsegv, sigabrt, ... ) */
2462 static void signal_handler(int sig_num)
2464 char packet[16];
2465 char txt[256];
2467 packet[0]=P_END;
2468 memcpy(packet+1,"server",7);
2470 sendall(packet,8,0);
2471 sendall(packet,8,0);
2472 sendall(packet,8,0);
2473 sendall(packet,8,0);
2474 sendall(packet,8,0);
2475 sendall(packet,8,0);
2476 sendall(packet,8,0);
2477 sendall(packet,8,0);
2478 /* 800 % redundancy should be enough ;-) */
2480 snprintf(txt,256,"Signal %d caught.\n",sig_num);
2481 message(txt,2);
2482 free_all_memory();
2483 check_memory_leaks();
2484 if (fd) close(fd);
2485 #ifdef WIN32
2486 hServerExitEvent=1;
2487 #else
2488 signal(sig_num,SIG_DFL);
2489 raise(sig_num);
2490 #endif
2494 /* walk with given player */
2495 static void walk_player(struct player *q,int direction, int speed, int creep)
2497 int a;
2499 unsigned int old_status=q->obj->status;
2500 int old_ttl=q->obj->ttl;
2501 int old_x=q->obj->x,
2502 old_y=q->obj->y,
2503 old_x_speed=q->obj->xspeed,
2504 old_y_speed=q->obj->yspeed;
2506 if ((q->obj->status & (S_GRENADE | S_SHOOTING)) == (S_GRENADE | S_SHOOTING))
2507 return; /* when throwing grenade can't walk */
2508 if (creep) /* creep */
2510 a=MAX_SPEED_CREEP;
2511 if (!(q->obj->status & S_CREEP))
2512 q->obj->y+=CREEP_YOFFSET;
2513 q->obj->status |= S_CREEP;
2516 else
2518 a=speed?MAX_SPEED_WALK_FAST:MAX_X_SPEED;
2519 if (q->obj->status & S_CREEP)
2520 q->obj->y-=CREEP_YOFFSET;
2521 q->obj->status &= ~S_CREEP;
2523 switch (direction)
2525 case 0: /* stop */
2526 q->obj->status &= ~S_WALKING;
2527 q->obj->xspeed=0;
2528 break;
2530 case 1: /* left */
2531 q->obj->status |= S_WALKING;
2532 q->obj->xspeed-=WALK_ACCEL;
2533 if (q->obj->xspeed<-a)q->obj->xspeed=-a;
2534 break;
2536 case 2: /* right */
2537 q->obj->status |= S_WALKING;
2538 q->obj->xspeed+=WALK_ACCEL;
2539 if (q->obj->xspeed>a)q->obj->xspeed=a;
2540 break;
2543 a=which_update(q->obj,old_x,old_y,old_x_speed,old_y_speed,old_status,old_ttl);
2545 sendall_update_object(q->obj,0,a);
2549 /* jump with given player */
2550 static void jump_player(struct player *p, char jet, int direction)
2552 int i;
2553 struct it *o;
2554 if (p->obj->status & ((jet ? 0 : S_FALLING) | S_CREEP))
2555 return;
2556 p->obj->status |= S_FALLING;
2557 p->obj->yspeed=-SPEED_JUMP;
2558 if (jet) {
2559 p->obj->status |= S_JETPACK_ON;
2560 for (i=0;i<8;i++) {
2561 o=new_obj(
2563 T_JETFIRE,
2564 JETFIRE_TTL,
2565 jetfire_sprite,
2568 add_int(p->obj->x, (direction & S_LOOKLEFT) ?
2569 PLAYER_WIDTH - 2 - (i%2) : ((direction & S_LOOKRIGHT) ?
2570 1 - (i%2) : PLAYER_WIDTH / 2)),
2571 p->obj->y+FIRE_YOFFSET+int2double(i%4),
2572 mul((double)(8*(i-4)), float2double(36*36)),
2573 (4-i),
2574 (void *)(long)(p->obj->id));
2575 if (!o)return;
2576 id++;
2577 sendall_new_object(o, 0);
2580 sendall_update_object(p->obj,0,4); /* update speed + status */
2581 p->obj->status &= ~S_JETPACK_ON;
2584 /* change weapon of given player (w=new weapon) */
2585 static void change_weapon_player(struct player *q,int w)
2587 char txt[256];
2589 if (!w)return;
2590 w--;
2591 if (q->current_weapon==w)return;
2592 if (!(q->weapons&(1<<w)))
2593 {send_message(q,0,"No weapon.", M_INFO);return;}
2594 if (!(q->ammo[w]))
2595 {send_message(q,0,"Not enough ammo.", M_INFO);return;}
2596 q->current_weapon=w;
2597 snprintf(txt,256,"%s takes %s.\n",q->name,weapon[w].name);
2598 message(txt,1);
2599 send_update_player(q);
2603 /* shoot with given player */
2604 /* direction: 0=right, 1=left */
2605 static void fire_player(struct player *q,int direction)
2607 int a;
2608 struct it *s;
2609 q->obj->status &= ~S_CHAINSAW; /* chainsaw */
2611 if (q->current_weapon==WEAPON_BLOODRAIN) {
2612 q->obj->status |= S_BLOODRAIN;
2613 return;
2615 if (!(q->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))||(q->obj->status & S_CREEP)||
2616 ((q->obj->status & S_SHOOTING)&&(q->obj->ttl>HOLD_GUN_AFTER_SHOOT)))
2617 return;
2618 if (!q->ammo[q->current_weapon])
2620 a=select_best_weapon(q);
2621 if (a==q->current_weapon) return;
2622 q->current_weapon=a;
2624 if (q->current_weapon!=WEAPON_CHAINSAW)
2625 q->ammo[q->current_weapon]--;
2626 send_update_player(q);
2627 q->obj->status &= ~S_GRENADE;
2628 if (q->current_weapon==WEAPON_SHOTGUN) /* shotgun */
2630 s=new_obj( /* SHELL */
2632 T_SHELL,
2633 SHELL_TTL,
2634 shotgun_shell_sprite,
2637 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2638 q->obj->y+FIRE_YOFFSET,
2639 q->obj->xspeed+(direction==1?-weapon[1].shell_xspeed:weapon[1].shell_xspeed),
2640 weapon[1].shell_yspeed,
2641 (void *)(long)(q->obj->id));
2642 id++;
2643 sendall_new_object(s,0);
2644 s=new_obj( /* straight */
2646 T_BULLET,
2647 weapon[q->current_weapon].ttl,
2648 slug_sprite,
2650 q->current_weapon,
2651 add_int(q->obj->x,direction==1?-2:PLAYER_WIDTH+2),
2652 q->obj->y+FIRE_YOFFSET,
2653 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2655 (void *)(long)(q->obj->id));
2656 id++;
2657 sendall_new_object(s,0);
2658 s=new_obj( /* straight */
2660 T_BULLET,
2661 weapon[q->current_weapon].ttl,
2662 slug_sprite,
2664 q->current_weapon,
2665 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2666 q->obj->y+FIRE_YOFFSET+int2double(1),
2667 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2669 (void *)(long)(q->obj->id));
2670 id++;
2671 sendall_new_object(s,0);
2672 s=new_obj( /* one up */
2674 T_BULLET,
2675 weapon[q->current_weapon].ttl,
2676 slug_sprite,
2678 q->current_weapon,
2679 add_int(q->obj->x,direction==1?-1:PLAYER_WIDTH+1),
2680 q->obj->y+FIRE_YOFFSET,
2681 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2682 float2double((double).1*36),
2683 (void *)(long)(q->obj->id));
2684 id++;
2685 sendall_new_object(s,0);
2686 s=new_obj( /* two up */
2688 T_BULLET,
2689 weapon[q->current_weapon].ttl,
2690 slug_sprite,
2692 q->current_weapon,
2693 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2694 q->obj->y+FIRE_YOFFSET-int2double(1),
2695 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2696 float2double((double).15*36),
2697 (void *)(long)(q->obj->id));
2698 id++;
2699 sendall_new_object(s,0);
2700 s=new_obj( /* one down */
2702 T_BULLET,
2703 weapon[q->current_weapon].ttl,
2704 slug_sprite,
2706 q->current_weapon,
2707 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2708 q->obj->y+FIRE_YOFFSET+int2double(1),
2709 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2710 -float2double((double).1*36),
2711 (void *)(long)(q->obj->id));
2712 id++;
2713 sendall_new_object(s,0);
2714 s=new_obj( /* two down */
2716 T_BULLET,
2717 weapon[q->current_weapon].ttl,
2718 slug_sprite,
2720 q->current_weapon,
2721 add_int(q->obj->x,direction==1?-1:PLAYER_WIDTH+1),
2722 q->obj->y+FIRE_YOFFSET,
2723 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2724 -float2double((double).15*36),
2725 (void *)(long)(q->obj->id));
2726 id++;
2727 sendall_new_object(s,0);
2729 else if (q->current_weapon==WEAPON_BFG) {
2730 s=new_obj( /* straight */
2732 T_BFGCELL,
2733 weapon[q->current_weapon].ttl,
2734 bfgcell_sprite,
2736 q->current_weapon,
2737 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2738 q->obj->y+FIRE_YOFFSET,
2739 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2741 (void *)(long)(q->obj->id));
2742 id++;
2743 sendall_new_object(s,0);
2745 else if (q->current_weapon==WEAPON_CHAINSAW) {
2746 s=new_obj(
2748 T_CHAIN,
2749 weapon[q->current_weapon].ttl,
2750 bullet_sprite,
2752 q->current_weapon,
2753 add_int(q->obj->x,direction==1?-2:PLAYER_WIDTH),
2754 q->obj->y+FIRE_YOFFSET,
2755 (int)(1.2*q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed)),
2757 (void *)(long)(q->obj->id));
2758 id++;
2759 sendall_new_object(s,0);
2760 s=new_obj(
2762 T_CHAIN,
2763 weapon[q->current_weapon].ttl,
2764 bullet_sprite,
2766 q->current_weapon,
2767 add_int(q->obj->x,direction==1?-2:PLAYER_WIDTH),
2768 q->obj->y+FIRE_YOFFSET+int2double(1),
2769 (int)(1.2*q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed)),
2771 (void *)(long)(q->obj->id));
2772 id++;
2773 sendall_new_object(s,0);
2774 q->obj->status |= S_CHAINSAW;
2775 } else if (q->current_weapon==WEAPON_GRENADE) /* grenades */
2777 q->obj->status |= S_GRENADE;
2778 q->obj->status &= ~S_WALKING;
2780 else if (!(q->obj->status & S_BLOODRAIN))
2782 s=new_obj( /* SHELL */
2784 T_SHELL,
2785 SHELL_TTL,
2786 shell_sprite,
2789 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2790 q->obj->y+FIRE_YOFFSET,
2791 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].shell_xspeed:weapon[q->current_weapon].shell_xspeed),
2792 weapon[q->current_weapon].shell_yspeed,
2793 (void *)(long)(q->obj->id));
2794 id++;
2795 sendall_new_object(s,0);
2796 s=new_obj(
2798 T_BULLET,
2799 weapon[q->current_weapon].ttl,
2800 bullet_sprite,
2802 q->current_weapon,
2803 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2804 q->obj->y+FIRE_YOFFSET,
2805 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2807 (void *)(long)(q->obj->id));
2808 id++;
2809 sendall_new_object(s,0);
2811 q->obj->xspeed+=(direction==1)?weapon[q->current_weapon].impact:-weapon[q->current_weapon].impact;
2812 q->obj->status |= S_SHOOTING;
2813 q->obj->status |= S_HOLDING;
2814 q->obj->ttl=weapon[q->current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
2815 sendall_update_object(q->obj,0,6); /* update speed and status and ttl */
2816 q->obj->status &= ~S_HOLDING;
2820 /* update given player (jump, shoot, creep, change weapon) */
2821 static void move_player(struct player *p)
2823 int a;
2825 if (p->obj->status & S_DEAD)
2826 return; /* dead player */
2828 if (p->keyboard_status.status & KBD_DOWN_LADDER) /* climb down a ladder */
2829 p->obj->status |= S_CLIMB_DOWN;
2830 else
2831 p->obj->status &=~ S_CLIMB_DOWN;
2833 if (p->keyboard_status.status & KBD_JUMP)
2834 jump_player(p, 0, (p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT)));
2835 if ((p->keyboard_status.status & KBD_JETPACK) && (p->obj->status & S_JETPACK))
2836 jump_player(p, 1, (p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT)));
2837 if (p->keyboard_status.status & KBD_RIGHT)
2839 if ((p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))==S_LOOKRIGHT) /* walk right */
2840 walk_player(p,2,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP);
2841 else
2843 if (p->obj->status & S_WALKING)
2844 walk_player(p,0,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP); /* stop */
2845 else
2847 a=p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT);
2848 p->obj->status &= ~(S_LOOKLEFT | S_LOOKRIGHT);
2849 p->obj->status |= (a == S_LOOKLEFT) ? 0 : S_LOOKRIGHT;
2850 sendall_update_status(p->obj,0);
2855 if (p->keyboard_status.status & KBD_LEFT)
2857 if ((p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))==S_LOOKLEFT) /* walk left */
2858 walk_player(p,1,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP);
2859 else
2861 if (p->obj->status & S_WALKING)
2862 walk_player(p,0,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP); /* stop */
2863 else
2865 a=p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT);
2866 p->obj->status &= ~(S_LOOKLEFT | S_LOOKRIGHT);
2867 p->obj->status |= (a == S_LOOKRIGHT) ? 0 : S_LOOKLEFT;
2868 sendall_update_status(p->obj,0);
2872 change_weapon_player(p,p->keyboard_status.weapon);
2873 if (p->keyboard_status.status & KBD_FIRE)
2874 fire_player(p,(p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))>>1);
2878 /* update players, kick out not responding players */
2879 static void update_players(void)
2881 struct player_list *p;
2882 char txt[256];
2883 char packet;
2884 unsigned long_long t=get_time();
2886 for (p=&players;p->next;p=p->next)
2888 /* this player is dead - delete him */
2889 if (t-(p->next->member).last_update>=MAX_DUMB_TIME)
2891 snprintf(txt,256,"%s not responding. Kicked out of the game.\n",p->next->member.name);
2892 message(txt,2);
2893 packet=P_PLAYER_DELETED;
2894 send_packet((char *)&packet,1,(struct sockaddr*)(&(p->next->member.address)),0,last_player->member.id);
2895 snprintf(txt,256,"%s was kicked out of the game.",p->next->member.name);
2896 sendall_message(0,txt,0,0, M_INFO);
2897 delete_player(p->next);
2898 if (!(p->next))break;
2900 else
2901 move_player(&(p->next->member));
2906 /* write help message to stdout */
2907 static void print_help(void)
2909 char *p = "";
2910 #ifdef __EMX__
2911 p = "Portions (c) 2000 by Mikulas Patocka\n";
2912 #endif
2913 #ifdef WIN32
2914 printf( "0verkill server.\n"
2915 "(c)2000 Brainsoft\n"
2916 "Portions (c) 2000 by Filip Konvicka\n"
2917 "Usage: server [-nh] [-l <level_number>] [-p <port number>] [-i username[/password]] [-I] [-r]\n"
2918 "-i Installs as a service\n"
2919 "-I Installs with the LOCAL_SYSTEM account.\n"
2920 "-r Stops and removes the service\n"
2921 "-n Server can't be ended by client\n"
2922 "You must be an administrator in order to install/remove a service.\n");
2923 #else
2924 printf( "0verkill server.\n"
2925 "(c)2000 Brainsoft\n"
2926 "%s\n"
2927 "Usage: server [-nh] [-l <level number>] [-p <port number>]\n"
2928 "-n Server can't be ended by client\n", p
2930 #endif
2934 static void parse_command_line(int argc,char **argv)
2936 int a;
2937 char *c;
2939 while(1)
2941 #ifdef WIN32
2942 a=getopt(argc,argv,"hl:np:ri:Ic");
2943 #else
2944 a=getopt(argc,argv,"hl:np:");
2945 #endif
2946 switch(a)
2948 case EOF:
2949 return;
2951 case '?':
2952 case ':':
2953 EXIT(1);
2955 #ifdef WIN32
2956 case 'c':
2957 break; /* run as console app */
2958 case 'r': /* remove service */
2959 CmdRemoveService();
2960 EXIT(1);
2961 case 'i': { /* install service */
2962 char username[80],
2963 password[80],
2964 *user=NULL,
2965 *pass=NULL;
2966 if ( optarg ) {
2967 username[sizeof(username)-1]=0;
2968 user=username;
2969 if ( (pass=strchr(optarg, '/'))==NULL ) {
2970 #ifndef WIN32
2971 strcpy(username, optarg);
2972 #else
2973 strcpy_s(username, sizeof(optarg), optarg);
2974 #endif
2975 memcpy(username, optarg, sizeof(username)-1);
2976 password[0]=0;
2978 else {
2979 int size=pass-optarg;
2980 if ( size>sizeof(username)-1 )
2981 size=sizeof(username)-1;
2982 memcpy(username, optarg, size);
2983 username[size]=0;
2984 pass++;
2985 size=strlen(pass);
2986 if ( size>sizeof(password)-1 )
2987 size=sizeof(password)-1;
2988 memcpy(password, pass, size);
2991 CmdInstallService(user, pass, NULL);
2992 EXIT(1);
2994 case 'I': { /* install service */
2995 CmdInstallService(NULL, NULL, NULL);
2996 EXIT(1);
2998 #endif
3000 case 'h':
3001 print_help();
3002 EXIT(0);
3004 case 'p':
3005 port=(unsigned short)strtoul(optarg,&c,10);
3006 if (*c){ERROR("Error: Not a number.\n");EXIT(1);}
3007 if (errno==ERANGE)
3009 if (!port){ERROR("Error: Number underflow.\n");EXIT(1);}
3010 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3012 break;
3014 case 'l':
3015 level_number=strtoul(optarg,&c,10);
3016 if (*c){ERROR("Error: Not a number.\n");EXIT(1);}
3017 if (errno==ERANGE)
3019 if (!level_number){ERROR("Error: Number underflow.\n");EXIT(1);}
3020 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3022 break;
3024 case 'n':
3025 nonquitable=1;
3026 break;
3032 /*-----------------------------------------------------------------------------------*/
3033 static int server(void)
3035 int a;
3036 char txt[256];
3037 unsigned long_long last_time;
3038 char *LEVEL;
3040 last_player=&players;
3041 last_obj=&objects;
3043 snprintf(txt,256,"Running 0verkill server version %d.%d\n",VERSION_MAJOR,VERSION_MINOR);
3044 message(txt,2);
3045 #ifdef WIN32
3046 snprintf(txt,256,"This is 0verkill server for Win32, build #%u\n",VERSION_PORT);
3047 message(txt,2);
3048 #endif
3049 message("Initialization.\n",2);
3050 #ifdef WIN32
3051 message("Starting Windows Sockets\n",2);
3053 WSADATA wd;
3054 WSAStartup(0x101, &wd);
3055 snprintf(txt,256,"Started WinSock version %X.%02X\n", wd.wVersion/0x100, wd.wVersion&0xFF);
3056 message(txt, 2);
3058 #endif
3059 init_area(); /* initialize playing area */
3060 hash_table_init();
3062 #ifdef WIN32
3063 if ( !consoleApp )
3064 ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 2000);
3065 #endif
3067 message("Loading sprites.\n",2);
3068 load_sprites(DATA_PATH GAME_SPRITES_FILE); /* players, corpses, bullets, ... */
3069 if (find_sprite("bullet",&bullet_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"bullet\".\n");ERROR(msg);EXIT(1);}
3070 if (find_sprite("slug",&slug_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"slug\".\n");ERROR(msg);EXIT(1);}
3071 if (find_sprite("shell",&shell_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"shell\".\n");ERROR(msg);EXIT(1);}
3072 if (find_sprite("sshell",&shotgun_shell_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"sshell\".\n");ERROR(msg);EXIT(1);}
3073 if (find_sprite("grenade",&grenade_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"grenade\".\n");ERROR(msg);EXIT(1);}
3074 if (find_sprite("mess1",&mess1_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess1\".\n");ERROR(msg);EXIT(1);}
3075 if (find_sprite("mess2",&mess2_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess2\".\n");ERROR(msg);EXIT(1);}
3076 if (find_sprite("mess3",&mess3_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess3\".\n");ERROR(msg);EXIT(1);}
3077 if (find_sprite("mess4",&mess4_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess4\".\n");ERROR(msg);EXIT(1);}
3078 if (find_sprite("noise",&noise_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"noise\".\n");ERROR(msg);EXIT(1);}
3079 if (find_sprite("bfgcell",&bfgcell_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"bfgcell\".\n");ERROR(msg);EXIT(1);}
3080 for (a=0;a<N_SHRAPNELS;a++)
3082 snprintf(txt, sizeof(txt), "shrapnel%d",a+1);
3083 if (find_sprite(txt,&shrapnel_sprite[a])){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3084 snprintf(txt, sizeof(txt), "bfgbit%d",a+1);
3085 if (find_sprite(txt,&bfgbit_sprite[a])){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3086 snprintf(txt, sizeof(txt), "bloodrain%d",a+1);
3087 if (find_sprite(txt,&bloodrain_sprite[a])){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3089 snprintf(txt, sizeof(txt), "jetfire");
3090 if (find_sprite(txt,&jetfire_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3092 LEVEL=load_level(level_number);
3093 level_checksum=md5_level(level_number);
3094 if (!LEVEL){char txt[256];snprintf(txt,256,"Can't load level number %d\n",level_number);ERROR(txt);EXIT(1);}
3095 snprintf(txt,256,"Loading level \"%s\"....\n",LEVEL);
3096 message(txt,2);
3097 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,LEVEL_SPRITES_SUFFIX);
3098 message("Loading level graphics.\n",2);
3099 load_sprites(txt);
3100 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
3101 message("Loading level map.\n",2);
3102 load_data(txt);
3103 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,DYNAMIC_DATA_SUFFIX);
3104 message("Loading level objects.\n",2);
3105 mem_free(LEVEL);
3106 load_dynamic(txt);
3108 message("Initializing socket.\n",2);
3109 init_socket(); /* initialize socket */
3111 message("Installing signal handlers.\n",2);
3112 signal(SIGINT,signal_handler);
3113 signal(SIGTERM,signal_handler);
3114 signal(SIGFPE,signal_handler);
3115 signal(SIGILL,signal_handler);
3116 signal(SIGABRT,signal_handler);
3117 #ifndef WIN32
3118 signal(SIGBUS,signal_handler);
3119 signal(SIGQUIT,signal_handler);
3120 #endif
3121 message("Game started.\n",2);
3123 #ifdef __EMX__
3124 DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 1, 0);
3125 #endif
3127 game_start=get_time();
3128 srandom(game_start);
3130 #ifdef WIN32
3131 if ( !consoleApp )
3132 ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
3133 #endif
3135 last_time=get_time();
3136 again:
3137 last_time+=PERIOD_USEC;
3138 if (get_time()-last_time>PERIOD_USEC*100)last_time=get_time();
3139 read_data();
3140 update_timeq();
3141 update_game();
3142 update_players(); /* MUST come after update_game otherwise when player shoots he hit himself */
3143 send_chunks();
3144 last_tick=get_time();
3145 if (!active_players&&(last_tick-last_player_left)>DELAY_BEFORE_SLEEP_USEC&&(last_tick-last_packet_came)>DELAY_BEFORE_SLEEP_USEC)
3147 #ifndef WIN32
3148 message("Sleep\n",2);
3150 fd_set fds;
3151 FD_ZERO(&fds);
3152 FD_SET(fd,&fds);
3153 select(fd+1,&fds,0,0,0);
3155 message("Wakeup\n",2);
3156 #else
3157 WaitForSingleObject(&fd, 500); /* wait max. 0.5 seconds, then we must test hServerExitEvent */
3158 #endif
3160 #ifdef WIN32
3161 /* we must return so that the service can be properly stopped */
3162 if ( hServerExitEvent )
3163 return 0;
3164 #endif
3165 sleep_until(last_time+PERIOD_USEC);
3166 goto again;
3168 return 0;
3172 int main(int argc, char **argv)
3174 int a;
3176 #ifdef WIN32
3177 SERVICE_TABLE_ENTRY dispatchTable[]={{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain}, {NULL, NULL}};
3178 if ( argc==1 ) {
3179 if ( !StartServiceCtrlDispatcher(dispatchTable) ) {
3180 globErr=GetLastError();
3181 /*LPTSTR pszError=CErrorContext::LoadWin32ErrorString(globErr);
3182 ::CharToOem(pszError, pszError);
3183 _tprintf(_T("StartServiceCtrlDispatcher failed: %u"), globErr);
3184 if ( pszError!=NULL ) {
3185 _tprintf(_T(": %s\r\n"), pszError);
3186 ::LocalFree(pszError);
3188 else
3189 _tprintf(_T("\r\n"));*/
3190 AddToMessageLog("StartServiceCtrlDispatcher failed", 0);
3193 consoleApp=1;
3194 #endif
3195 chdir_to_data_files();
3196 parse_command_line(argc,argv);
3198 a=server();
3199 free_all_memory();
3200 check_memory_leaks();
3201 if (fd) close(fd);
3202 return a;