editor: #undef O after use
[0verkill.git] / server.c
blobbda9ec6aa1c090b440c73f25de3e49190d31a994
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,0);
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,0);
1257 break;
1259 if (strlen(packet+5) > MAX_NAME_LEN)
1261 snprintf(txt,256,"Name too long, shortening it to %i characters\n",MAX_NAME_LEN);
1262 message(txt,2);
1263 packet[5+MAX_NAME_LEN]='\0';
1265 if (is_playername_in_use(packet+5))
1267 snprintf(txt,256,"Name \"%s\" already in use. Player refused.\n",packet+5);
1268 message(txt,2);
1269 packet[0]=P_PLAYER_REFUSED;
1270 packet[1]=E_NAME_IN_USE;
1271 send_packet(packet,2,(struct sockaddr*)(&client),0,0);
1273 break;
1275 find_birthplace(&x,&y);
1276 if (add_player(packet[4],packet+5,&client,x,y)) /* failed to add player */
1278 message("Player refused.\n",2);
1279 packet[0]=P_PLAYER_REFUSED;
1280 packet[1]=E_PLAYER_REFUSED;
1281 send_packet(packet,2,(struct sockaddr*)(&client),0,0);
1282 break;
1284 snprintf(txt,256,"Player #%d accepted, name \"%s\", address %s.\n",n_players,packet+5,txt1);
1285 message(txt,2);
1286 snprintf(txt,256,"%s entered the game.",packet+5);
1287 active_players++;
1288 n_players++;
1289 packet[offset++]=P_PLAYER_ACCEPTED;
1290 last_player->member.obj->status |= S_DEAD;
1291 put_int(packet,last_player->member.obj->id,&offset);
1292 put_int16(packet,last_player->member.obj->sprite,&offset);
1293 put_int(packet,last_player->member.obj->x,&offset);
1294 put_int(packet,last_player->member.obj->y,&offset);
1295 put_int(packet,last_player->member.obj->xspeed,&offset);
1296 put_int(packet,last_player->member.obj->yspeed,&offset);
1297 put_int(packet,last_player->member.obj->status,&offset);
1298 t=get_time();
1299 put_long_long(packet,t-game_start,&offset);
1300 put_int(packet,last_player->member.id,&offset);
1301 packet[offset++]=VERSION_MAJOR;
1302 packet[offset++]=VERSION_MINOR;
1303 send_packet(packet,offset,(struct sockaddr*)(&client),0,0);
1304 send_change_level(&(last_player->member));
1305 sendall_bell();
1306 sendall_message(0,txt,0,0, M_ENTER);
1307 snprintf(txt,256,"There'%s %d %s in the game.",active_players==1?"s":"re",active_players,active_players==1?"player":"players");
1308 sendall_message(0,txt,0,0, M_INFO);
1309 send_info(0,0);
1311 break;
1313 case P_LEVEL_ACCEPTED:
1314 q=find_player(&client,s);
1315 if (!q)break;
1316 if (q->member.current_level>=0)break;
1318 q->member.current_level=level_number;
1319 sendall_new_object(q->member.obj,&(q->member));
1320 create_noise(double2int(q->member.obj->x),double2int(q->member.obj->y),&(q->member));
1321 /* send all objects in the game */
1322 send_objects(&(q->member),q->member.obj);
1323 /* send all objects waiting for respawn */
1324 send_timeq_objects(&(q->member));
1325 break;
1327 case P_INFO:
1328 q=find_player(&client,s);
1329 if (!q) send_info((struct sockaddr*)(&client),0);
1330 else send_info((struct sockaddr*)(&client),q->member.id);
1331 break;
1333 case P_REENTER_GAME:
1334 q=find_player(&client,s);
1335 if (!q)break;
1336 if (!(q->member.obj->status & S_DEAD) || (q->member.obj->status & S_NOISE))
1337 break;
1338 find_birthplace(&x,&y);
1339 create_noise(x,y,&(q->member));
1340 q->member.obj->x=int2double(x);
1341 q->member.obj->y=int2double(y);
1342 sendall_update_object(q->member.obj,0,3); /* update coordinates */
1343 break;
1345 case P_END:
1346 if (nonquitable)break;
1347 q=find_player(&client,s);
1348 if (!q)break;
1349 p=&(q->member);
1350 packet[0]=P_END;
1351 memcpy(packet+1,p->name,strlen(p->name)+1);
1352 sendall(packet,2+strlen(p->name),0);
1353 snprintf(txt,256,"Game terminated by player \"%s\".\n",p->name);
1354 message(txt,2);
1355 exit(0);
1357 case P_QUIT_REQUEST:
1358 q=find_player(&client,s);
1359 if (!q) /* this player has been deleted, but due to network inconsistency he doesn't know it */
1361 packet[0]=P_PLAYER_DELETED;
1362 send_packet(packet,1,(struct sockaddr*)(&client),0,last_player->member.id);
1363 break;
1365 snprintf(txt,256,"%s left the game.\n",q->member.name);
1366 message(txt,2);
1367 packet[0]=P_PLAYER_DELETED;
1368 send_packet((char *)packet,1,(struct sockaddr*)(&client),0,last_player->member.id);
1369 snprintf(txt,256,"%s left the game.",q->member.name);
1370 sendall_message(0,txt,0,0, M_LEAVE);
1371 delete_player(q);
1372 send_info(0,0);
1373 break;
1375 case P_KEYBOARD:
1376 if (l<3)break; /* invalid packet */
1377 q=find_player(&client,s);
1378 if (!q)break;
1379 q->member.last_update=get_time();
1380 q->member.keyboard_status.status=packet[1];
1381 q->member.keyboard_status.weapon=packet[2];
1382 break;
1384 case P_MESSAGE:
1385 if (l < 3)
1386 break; /* invalid packet */
1387 q = find_player(&client, s);
1388 if (!q)
1389 break;
1390 sendall_message(q->member.name, packet + 2, 0, 0, M_CHAT);
1391 snprintf(txt, 256, "%s> %s\n", q->member.name, packet + 2);
1392 message(txt, 1);
1393 break;
1395 default:
1396 snprintf(txt,256,"Unknown packet: head=%d\n",*packet);
1397 message(txt,2);
1398 break;
1404 /* compute collision of two objects */
1405 /* return value: 0=nothing */
1406 /* 1=collision */
1407 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)
1409 int w1,w2,h1,h2;
1410 unsigned char h=0,v=0;
1412 get_dimensions(t1,s1,p1,&w1,&h1);
1413 get_dimensions(t2,s2,p2,&w2,&h2);
1415 if ((x2>=x1&&x2<=x1+w1-1)||(x2+w2-1>=x1&&x2+w2-1<=x1+w1-1))h=1;
1416 if ((x1>=x2&&x1<=x2+w2-1)||(x1+w1-1>=x2&&x1+w1-1<=x2+w2-1))h=1;
1417 if (!h)return 0;
1419 if ((y2>=y1&&y2<=y1+h1-1)||(y2+h2-1>=y1&&y2+h2-1<=y1+h1-1))v=1;
1420 if ((y1>=y2&&y1<=y2+h2-1)||(y1+h1-1>=y2&&y1+h1-1<=y2+h2-1))v=1;
1421 if (!v)return 0;
1422 return 1;
1426 /* create corpse on given position and with color num */
1427 /* num is number of dead player */
1428 static void create_corpse(int x,int y,int num, int status)
1430 struct it *o;
1431 static char txt[32];
1432 int a;
1433 int xoffs=num>15?-15:-5;
1434 int yoffs=num>15?-1:0;
1436 snprintf(txt, sizeof(txt), "corpse%d",num);
1437 if (find_sprite(txt,&a))return;
1439 o=new_obj(id,T_CORPSE,CORPSE_TTL,a,0,status,int2double(x+xoffs),int2double(y+yoffs),0,0,0);
1440 if (!o)return;
1441 id++;
1442 sendall_new_object(o,0);
1446 /* create mess on given position */
1447 /* y1=y coordinate of the mess */
1448 /* y2=y coordinate of the player (place where blood gushes and guts fly from */
1449 static void create_mess(int x,int y1,int y2)
1451 struct it *o;
1453 o=new_obj(id,T_CORPSE,CORPSE_TTL,mess1_sprite,0,0,int2double(x),int2double(y1),0,0,0);
1454 if (!o)return;
1455 id++;
1456 sendall_new_object(o,0);
1458 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);
1459 if (!o)return;
1460 id++;
1461 sendall_new_object(o,0);
1463 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);
1464 if (!o)return;
1465 id++;
1466 sendall_new_object(o,0);
1468 o=new_obj(id,T_MESS,MESS_TTL,mess2_sprite,0,0,int2double(x),int2double(y2),float2double(3*36),float2double((double).5*36),0);
1469 if (!o)return;
1470 id++;
1471 sendall_new_object(o,0);
1473 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);
1474 if (!o)return;
1475 id++;
1476 sendall_new_object(o,0);
1478 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);
1479 if (!o)return;
1480 id++;
1481 sendall_new_object(o,0);
1483 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);
1484 if (!o)return;
1485 id++;
1486 sendall_new_object(o,0);
1488 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);
1489 if (!o)return;
1490 id++;
1491 sendall_new_object(o,0);
1493 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);
1494 if (!o)return;
1495 id++;
1496 sendall_new_object(o,0);
1500 /* compute collision of given object with the others */
1501 /* return value: 1=delete this object */
1502 /* 0=don't delete */
1503 /* 2= delete this object but don't send delete packet */
1504 static int dynamic_collision(struct it *obj)
1506 struct it *p;
1507 struct player_list *pl;
1508 struct object_list *ol;
1509 char txt[256];
1510 struct it *o;
1511 int b;
1512 int a,c,s;
1513 int px,py,h;
1515 #define OX (double2int(obj->x))
1516 #define OY (double2int(obj->y))
1517 #define PX (double2int(p->x))
1518 #define PY (double2int(p->y))
1519 #define A ((struct player*)(p->data))->armor
1520 #define H ((struct player*)(p->data))->health
1521 #define P ((struct player*)(p->data))
1522 #define MAX_AMMO(x) (weapon[x].max_ammo)
1525 for (pl=&players;pl->next;pl=pl->next)
1527 p=pl->next->member.obj;
1528 if (p->type==T_PLAYER&&(p->status & S_DEAD))
1529 continue; /* dead player */
1530 if (collision(OX,OY,obj->type,obj->status,sprites[obj->sprite].positions,PX,PY,p->type,p->status,sprites[p->sprite].positions))
1531 switch(obj->type)
1533 case T_AMMO_GRENADE:
1535 char txt[256];
1536 if (p->type!=T_PLAYER)break;
1537 if (((struct player*)(p->data))->ammo[WEAPON_GRENADE]==MAX_AMMO(WEAPON_GRENADE))break;
1538 ((struct player*)(p->data))->ammo[WEAPON_GRENADE]+=weapon[WEAPON_GRENADE].add_ammo;
1539 if (((struct player*)(p->data))->ammo[WEAPON_GRENADE]>MAX_AMMO(WEAPON_GRENADE))
1540 ((struct player*)(p->data))->ammo[WEAPON_GRENADE]=MAX_AMMO(WEAPON_GRENADE);
1541 /* P->current_weapon=select_best_weapon(P); */
1542 send_update_player((struct player*)(p->data));
1543 send_message((struct player*)(p->data),0,"You got grenades", M_AMMO);
1544 snprintf(txt,256,"%s got grenades.\n",((struct player*)(p->data))->name);
1545 message(txt,1);
1546 obj->status |= S_INVISIBLE;
1547 add_to_timeq(obj->id,T_AMMO_GRENADE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1548 sendall_update_status(obj,0);
1550 return 2;
1552 case T_AMMO_GUN:
1554 char txt[256];
1555 if (p->type!=T_PLAYER)break;
1556 if (((struct player*)(p->data))->ammo[WEAPON_GUN]==MAX_AMMO(WEAPON_GUN))break;
1558 if(is_weapon_better((struct player*)(p->data), WEAPON_GUN)
1559 && is_weapon_empty((struct player*)(p->data), WEAPON_GUN))
1560 P->current_weapon = WEAPON_GUN;
1562 ((struct player*)(p->data))->ammo[WEAPON_GUN]+=weapon[WEAPON_GUN].add_ammo;
1563 if (((struct player*)(p->data))->ammo[WEAPON_GUN]>MAX_AMMO(WEAPON_GUN))
1564 ((struct player*)(p->data))->ammo[WEAPON_GUN]=MAX_AMMO(WEAPON_GUN);
1565 /* P->current_weapon=select_best_weapon(P); */
1566 send_update_player((struct player*)(p->data));
1567 send_message((struct player*)(p->data),0,"You got a magazine", M_AMMO);
1568 snprintf(txt,256,"%s got a magazine.\n",((struct player*)(p->data))->name);
1569 message(txt,1);
1570 obj->status |= S_INVISIBLE;
1571 add_to_timeq(obj->id,T_AMMO_GUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1572 sendall_update_status(obj,0);
1574 return 2;
1576 case T_AMMO_SHOTGUN:
1578 char txt[256];
1579 if (p->type!=T_PLAYER)break;
1580 if (((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]==MAX_AMMO(WEAPON_SHOTGUN))break;
1582 if(is_weapon_better((struct player*)(p->data), WEAPON_SHOTGUN)
1583 && is_weapon_empty((struct player*)(p->data), WEAPON_SHOTGUN))
1584 P->current_weapon = WEAPON_SHOTGUN;
1586 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]+=weapon[WEAPON_SHOTGUN].add_ammo;
1587 if (((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]>MAX_AMMO(WEAPON_SHOTGUN))
1588 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]=MAX_AMMO(WEAPON_SHOTGUN);
1589 /* P->current_weapon=select_best_weapon(P); */
1590 send_update_player((struct player*)(p->data));
1591 send_message((struct player*)(p->data),0,"You got shotgun shells", M_AMMO);
1592 snprintf(txt,256,"%s got shotgun shells.\n",((struct player*)(p->data))->name);
1593 message(txt,1);
1594 obj->status |= S_INVISIBLE;
1595 add_to_timeq(obj->id,T_AMMO_SHOTGUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1596 sendall_update_status(obj,0);
1598 return 2;
1600 case T_AMMO_RIFLE:
1602 char txt[256];
1603 if (p->type!=T_PLAYER)break;
1604 if (((struct player*)(p->data))->ammo[WEAPON_RIFLE]==MAX_AMMO(WEAPON_RIFLE))break;
1606 if(is_weapon_better((struct player*)(p->data), WEAPON_RIFLE)
1607 && is_weapon_empty((struct player*)(p->data), WEAPON_RIFLE))
1608 P->current_weapon = WEAPON_RIFLE;
1610 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]+=weapon[WEAPON_RIFLE].add_ammo;
1611 if (((struct player*)(p->data))->ammo[WEAPON_RIFLE]>MAX_AMMO(WEAPON_RIFLE))
1612 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]=MAX_AMMO(WEAPON_RIFLE);
1613 /* P->current_weapon=select_best_weapon(P); */
1614 send_update_player((struct player*)(p->data));
1615 send_message((struct player*)(p->data),0,"You got cartridges", M_AMMO);
1616 snprintf(txt,256,"%s got cartridges.\n",((struct player*)(p->data))->name);
1617 message(txt,1);
1618 obj->status |= S_INVISIBLE;
1619 add_to_timeq(obj->id,T_AMMO_RIFLE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1620 sendall_update_status(obj,0);
1622 return 2;
1624 case T_AMMO_UZI:
1626 char txt[256];
1627 if (p->type!=T_PLAYER)break;
1628 if (((struct player*)(p->data))->ammo[WEAPON_UZI]==MAX_AMMO(WEAPON_UZI))break;
1630 if(is_weapon_better((struct player*)(p->data), WEAPON_UZI)
1631 && is_weapon_empty((struct player*)(p->data), WEAPON_UZI))
1632 P->current_weapon = WEAPON_UZI;
1634 ((struct player*)(p->data))->ammo[WEAPON_UZI]+=weapon[WEAPON_UZI].add_ammo;
1635 if (((struct player*)(p->data))->ammo[WEAPON_UZI]>MAX_AMMO(WEAPON_UZI))
1636 ((struct player*)(p->data))->ammo[WEAPON_UZI]=MAX_AMMO(WEAPON_UZI);
1637 /* P->current_weapon=select_best_weapon(P); */
1638 send_update_player((struct player*)(p->data));
1639 send_message((struct player*)(p->data),0,"You got ammo for Uzi", M_AMMO);
1640 snprintf(txt,256,"%s got Uzi ammo.\n",((struct player*)(p->data))->name);
1641 message(txt,1);
1642 obj->status |= S_INVISIBLE;
1643 add_to_timeq(obj->id,T_AMMO_UZI,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,AMMO_RESPAWN_TIME);
1644 sendall_update_status(obj,0);
1646 return 2;
1648 case T_UZI:
1650 char txt[256];
1651 if (p->type!=T_PLAYER)break;
1652 if ((((struct player*)(p->data))->ammo[WEAPON_UZI]==MAX_AMMO(WEAPON_UZI))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_UZI))break;
1654 if(is_weapon_better((struct player*)(p->data), WEAPON_UZI)
1655 && !is_weapon_usable((struct player*)(p->data), WEAPON_UZI))
1656 P->current_weapon = WEAPON_UZI;
1658 ((struct player*)(p->data))->weapons|=WEAPON_MASK_UZI;
1659 ((struct player*)(p->data))->ammo[WEAPON_UZI]+=weapon[WEAPON_UZI].basic_ammo;
1660 if (((struct player*)(p->data))->ammo[WEAPON_UZI]>MAX_AMMO(WEAPON_UZI))
1661 ((struct player*)(p->data))->ammo[WEAPON_UZI]=MAX_AMMO(WEAPON_UZI);
1662 // P->current_weapon=select_best_weapon(P);
1663 send_update_player((struct player*)(p->data));
1664 send_message((struct player*)(p->data),0,"You got Uzi", M_WEAPON);
1665 snprintf(txt,256,"%s got Uzi.\n",((struct player*)(p->data))->name);
1666 message(txt,1);
1667 obj->status |= S_INVISIBLE;
1668 add_to_timeq(obj->id,T_UZI,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1669 sendall_update_status(obj,0);
1671 return 2;
1673 case T_RIFLE:
1675 char txt[256];
1676 if (p->type!=T_PLAYER)break;
1677 if ((((struct player*)(p->data))->ammo[WEAPON_RIFLE]==MAX_AMMO(WEAPON_RIFLE))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_RIFLE))break;
1679 if(is_weapon_better((struct player*)(p->data), WEAPON_RIFLE)
1680 && !is_weapon_usable((struct player*)(p->data), WEAPON_RIFLE))
1681 P->current_weapon = WEAPON_RIFLE;
1683 ((struct player*)(p->data))->weapons|=WEAPON_MASK_RIFLE;
1684 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]+=weapon[WEAPON_RIFLE].basic_ammo;
1685 if (((struct player*)(p->data))->ammo[WEAPON_RIFLE]>MAX_AMMO(WEAPON_RIFLE))
1686 ((struct player*)(p->data))->ammo[WEAPON_RIFLE]=MAX_AMMO(WEAPON_RIFLE);
1687 // P->current_weapon=select_best_weapon(P);
1688 send_update_player((struct player*)(p->data));
1689 send_message((struct player*)(p->data),0,"You got sniper rifle", M_WEAPON);
1690 snprintf(txt,256,"%s got sniper rifle.\n",((struct player*)(p->data))->name);
1691 message(txt,1);
1692 obj->status |= S_INVISIBLE;
1693 add_to_timeq(obj->id,T_RIFLE,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1694 sendall_update_status(obj,0);
1696 return 2;
1698 case T_SHOTGUN:
1700 char txt[256];
1701 if (p->type!=T_PLAYER)break;
1702 if ((((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]==MAX_AMMO(WEAPON_SHOTGUN))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_SHOTGUN))break;
1704 if(is_weapon_better((struct player*)(p->data), WEAPON_SHOTGUN)
1705 && !is_weapon_usable((struct player*)(p->data), WEAPON_SHOTGUN))
1706 P->current_weapon = WEAPON_SHOTGUN;
1708 ((struct player*)(p->data))->weapons|=WEAPON_MASK_SHOTGUN;
1709 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]+=weapon[WEAPON_SHOTGUN].basic_ammo;
1710 if (((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]>MAX_AMMO(WEAPON_SHOTGUN))
1711 ((struct player*)(p->data))->ammo[WEAPON_SHOTGUN]=MAX_AMMO(WEAPON_SHOTGUN);
1712 // P->current_weapon=select_best_weapon(P);
1713 send_update_player((struct player*)(p->data));
1714 send_message((struct player*)(p->data),0,"You got a shotgun", M_WEAPON);
1715 snprintf(txt,256,"%s got a shotgun.\n",((struct player*)(p->data))->name);
1716 message(txt,1);
1717 obj->status |= S_INVISIBLE;
1718 add_to_timeq(obj->id,T_SHOTGUN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1719 sendall_update_status(obj,0);
1721 return 2;
1723 case T_BFG:
1725 char txt[256];
1726 if (p->type!=T_PLAYER)break;
1727 if ((((struct player*)(p->data))->ammo[WEAPON_BFG]==MAX_AMMO(WEAPON_BFG))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_BFG))break;
1729 if(is_weapon_better((struct player*)(p->data), WEAPON_BFG)
1730 && !is_weapon_usable((struct player*)(p->data), WEAPON_BFG))
1731 P->current_weapon = WEAPON_BFG;
1733 ((struct player*)(p->data))->weapons|=WEAPON_MASK_BFG;
1734 ((struct player*)(p->data))->ammo[WEAPON_BFG]+=weapon[WEAPON_BFG].basic_ammo;
1735 if (((struct player*)(p->data))->ammo[WEAPON_BFG]>MAX_AMMO(WEAPON_BFG))
1736 ((struct player*)(p->data))->ammo[WEAPON_BFG]=MAX_AMMO(WEAPON_BFG);
1737 // P->current_weapon=select_best_weapon(P);
1738 send_update_player((struct player*)(p->data));
1739 send_message((struct player*)(p->data),0,"You got a BFG", M_WEAPON);
1740 snprintf(txt,256,"%s got a BFG.\n",((struct player*)(p->data))->name);
1741 message(txt,1);
1742 obj->status |= S_INVISIBLE;
1743 add_to_timeq(obj->id,T_BFG,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1744 sendall_update_status(obj,0);
1746 return 2;
1748 case T_BLOODRAIN:
1750 char txt[256];
1751 if (p->type!=T_PLAYER)break;
1752 if ((((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]==MAX_AMMO(WEAPON_BLOODRAIN))&&((((struct player *)(p->data))->weapons)&WEAPON_MASK_BLOODRAIN))break;
1754 if(is_weapon_better((struct player*)(p->data), WEAPON_BLOODRAIN)
1755 && !is_weapon_usable((struct player*)(p->data), WEAPON_BLOODRAIN))
1756 P->current_weapon = WEAPON_BLOODRAIN;
1758 ((struct player*)(p->data))->weapons|=WEAPON_MASK_BLOODRAIN;
1759 ((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]+=weapon[WEAPON_BLOODRAIN].basic_ammo;
1760 if (((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]>MAX_AMMO(WEAPON_BLOODRAIN))
1761 ((struct player*)(p->data))->ammo[WEAPON_BLOODRAIN]=MAX_AMMO(WEAPON_BLOODRAIN);
1762 // P->current_weapon=select_best_weapon(P);
1763 send_update_player((struct player*)(p->data));
1764 send_message((struct player*)(p->data),0,"You charged your Bloodrain", M_WEAPON);
1765 snprintf(txt,256,"%s charged his Bloodrain.\n",((struct player*)(p->data))->name);
1766 message(txt,1);
1767 obj->status |= S_INVISIBLE;
1768 add_to_timeq(obj->id,T_BLOODRAIN,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,WEAPON_RESPAWN_TIME);
1769 sendall_update_status(obj,0);
1771 return 2;
1773 case T_INVISIBILITY:
1775 char txt[256];
1776 if (p->type!=T_PLAYER)break;
1778 ((struct player*)(p->data))->invisibility_counter=INVISIBILITY_DURATION;
1779 p->status |= S_INVISIBLE; /* hide player */
1780 sendall_update_status(p,0);
1781 send_message((struct player*)(p->data),0,"You got invisibility dope", M_ITEM);
1782 snprintf(txt,256,"%s got invisibility.\n",((struct player*)(p->data))->name);
1783 message(txt,1);
1784 obj->status |= S_INVISIBLE;
1785 add_to_timeq(obj->id,T_INVISIBILITY,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,INVISIBILITY_RESPAWN_TIME);
1786 sendall_update_status(obj,0);
1788 return 2;
1790 case T_JETPACK:
1792 char txt[256];
1793 if (p->type!=T_PLAYER)break;
1794 p->status |= S_JETPACK;
1795 sendall_update_status(p, 0);
1796 send_message((struct player*)(p->data),0,"You got a jetpack", M_ITEM);
1797 snprintf(txt,256,"%s got a jetpack.\n",((struct player*)(p->data))->name);
1798 message(txt,1);
1799 obj->status |= S_INVISIBLE;
1800 add_to_timeq(obj->id,T_JETPACK,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,ARMOR_RESPAWN_TIME);
1801 sendall_update_status(obj,0);
1803 return 2;
1805 case T_TELEPORT:
1807 char txt[256];
1808 if (p->type!=T_PLAYER)break;
1810 find_birthplace(&px,&py);
1811 o=new_obj(id,T_NOISE,NOISE_TTL,noise_sprite,0,0,int2double(px),int2double(py),0,0,(void *)(long)(p->id));
1812 if (!o)
1813 return 2;
1814 id++;
1815 sendall_new_object(o,0);
1816 p->x=int2double(px);
1817 p->y=int2double(py);
1818 sendall_update_object(((struct player*)p->data)->obj,0,3);
1820 sendall_update_status(p,0);
1821 send_message((struct player*)(p->data),0,"You teleported", M_INFO);
1822 snprintf(txt,256,"%s teleported.\n",((struct player*)(p->data))->name);
1823 message(txt,1);
1824 add_to_timeq(obj->id,T_TELEPORT,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,0);
1825 sendall_update_status(obj,0);
1827 return 2;
1829 case T_ARMOR:
1831 char txt[256];
1832 if (p->type!=T_PLAYER)break;
1833 if (((struct player*)(p->data))->armor>=100)break; /* he has 100% armor */
1834 ((struct player*)(p->data))->armor+=ARMOR_ADD;
1835 if (((struct player*)(p->data))->armor>100)((struct player*)(p->data))->armor=100;
1836 send_update_player((struct player*)(p->data));
1837 send_message((struct player*)(p->data),0,"You got armor", M_ITEM);
1838 snprintf(txt,256,"%s got armor.\n",((struct player*)(p->data))->name);
1839 message(txt,1);
1840 obj->status |= S_INVISIBLE;
1841 add_to_timeq(obj->id,T_ARMOR,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,ARMOR_RESPAWN_TIME);
1842 sendall_update_status(obj,0);
1844 return 2;
1846 case T_MEDIKIT:
1848 char txt[256];
1849 if (p->type!=T_PLAYER)break;
1850 if (((struct player*)(p->data))->health>=100)break; /* he's healthy */
1851 ((struct player*)(p->data))->health+=MEDIKIT_HEALTH_ADD;
1852 if (((struct player*)(p->data))->health>100)((struct player*)(p->data))->health=100;
1853 send_update_player((struct player*)(p->data));
1854 send_message((struct player*)(p->data),0,"You picked up a medikit", M_ITEM);
1855 snprintf(txt,256,"%s picked up a medikit.\n",((struct player*)(p->data))->name);
1856 message(txt,1);
1857 obj->status |= S_INVISIBLE;
1858 add_to_timeq(obj->id,T_MEDIKIT,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,MEDIKIT_RESPAWN_TIME);
1859 sendall_update_status(obj,0);
1861 return 2;
1863 case T_BIOMED:
1865 char txt[256];
1866 if (p->type!=T_PLAYER)break;
1867 if (((struct player*)(p->data))->obj->status & S_ILL)
1868 ((struct player*)(p->data))->obj->status &= ~S_ILL;
1869 else
1870 ((struct player*)(p->data))->health=1; /* really hardcore chemical cocktail :-) */
1871 send_update_player((struct player*)(p->data));
1872 send_message((struct player*)(p->data),0,"You picked up a bio-medikit", M_ITEM);
1873 snprintf(txt,256,"%s picked up a bio-medikit.\n",((struct player*)(p->data))->name);
1874 message(txt,1);
1875 obj->status |= S_INVISIBLE;
1876 add_to_timeq(obj->id,T_BIOMED,0,obj->sprite,0,0,obj->x,obj->y,0,0,0,MEDIKIT_RESPAWN_TIME);
1877 sendall_update_status(obj,0);
1879 return 2;
1881 case T_BIOSKULL:
1882 if (p->type!=T_PLAYER || ((struct player*)(p->data))->obj->status & S_ILL)
1883 break;
1884 ((struct player*)(p->data))->obj->status |= S_ILL;
1885 send_message((struct player*)(p->data),0,"You got infected from skull", M_INFO);
1886 snprintf(txt,256,"%s got infected",((struct player*)(p->data))->name);
1887 sendall_message(0,txt,(struct player*)(p->data),0, M_INFO);
1888 snprintf(txt,256,"%s got infected.\n",((struct player*)(p->data))->name);
1889 message(txt,2);
1891 sendall_update_object(p,0,0); /* update everything */
1892 send_update_player((struct player*)(p->data));
1893 send_info(0,0);
1894 return 0;
1896 case T_JETFIRE:
1897 if (p->type!=T_PLAYER)
1898 break;
1899 if (((struct player*)(p->data))->obj->id == (long)obj->data || ((struct player*)(p->data))->obj->status & S_ONFIRE)
1900 break;
1901 ((struct player*)(p->data))->obj->status |= S_ONFIRE;
1902 o=&(((ol = find_in_table((long)(obj->data))))->member); /* owner of the flame */
1903 snprintf(txt,256,"You caught fire from %s's jetpack", ((struct player*)(o->data))->name);
1904 send_message((struct player*)(p->data),0,txt, M_INFO);
1906 sendall_update_object(p,0,0); /* update everything */
1907 send_update_player((struct player*)(p->data));
1908 send_info(0,0);
1909 return 0;
1911 case T_PLAYER: /* illness is spreading :-) */
1912 if (p->type!=T_PLAYER || p->data == obj->data ||
1913 ((struct player*)(p->data))->obj->status & S_ILL)
1914 break;
1915 if (((struct player*)(obj->data))->obj->status & S_ILL) {
1916 ((struct player*)(p->data))->obj->status |= S_ILL;
1918 snprintf(txt,256,"%s infected %s.",((struct player*)(obj->data))->name,((struct player*)(p->data))->name);
1919 sendall_message(0,txt,(struct player*)(obj->data),(struct player*)(p->data), M_INFO);
1920 snprintf(txt,256,"%s infected you",((struct player*)(obj->data))->name);
1921 send_message((struct player*)(p->data),0,txt, M_INFO); /* the dead */
1922 snprintf(txt,256,"You infected %s",((struct player*)(p->data))->name);
1923 send_message((struct player*)(obj->data),0,txt, M_INFO); /* the dead */
1924 snprintf(txt,256,"%s infected %s.\n",((struct player*)(obj->data))->name,((struct player*)(p->data))->name);
1925 message(txt,2);
1927 sendall_update_object(p,0,0); /* update everything */
1928 send_update_player((struct player*)(p->data));
1929 send_info(0,0);
1931 return 0;
1933 case T_CORPSE: /* illness is spreading from corpses too */
1934 if (p->type!=T_PLAYER || p->data == obj->data ||
1935 ((struct player*)(p->data))->obj->status & S_ILL)
1936 break;
1937 if (obj->status & S_ILL) {
1938 ((struct player*)(p->data))->obj->status |= S_ILL;
1940 snprintf(txt,256,"%s got infected from a corpse.",((struct player*)(p->data))->name);
1941 sendall_message(0,txt,(struct player*)(obj->data),(struct player*)(p->data), M_INFO);
1942 snprintf(txt,256,"You got infected from a corpse");
1943 send_message((struct player*)(p->data),0,txt, M_INFO); /* the dead */
1944 snprintf(txt,256,"%s got infected from a corpse.\n",((struct player*)(p->data))->name);
1945 message(txt,2);
1947 sendall_update_object(p,0,0); /* update everything */
1948 send_update_player((struct player*)(p->data));
1949 send_info(0,0);
1951 return 0;
1953 case T_KILL:
1954 if (p->type!=T_PLAYER)break;
1955 a=(int)((1-(double)A/100)*KILL_LETHALNESS);
1956 c=KILL_ARMOR_DAMAGE;
1957 if (a>=H) /* player died */
1959 ((struct player*)(p->data))->deaths++;
1960 send_message((struct player*)(p->data),0,"You killed yourself", M_DEATH);
1961 snprintf(txt,256,"%s suicides",((struct player*)(p->data))->name);
1962 sendall_message(0,txt,(struct player*)(p->data),0, M_DEATH);
1963 snprintf(txt,256,"%s suicides.\n",((struct player*)(p->data))->name);
1964 message(txt,2);
1966 s=p->status;
1967 px=PX;
1968 py=PY;
1969 h=H;
1970 H=0;
1971 p->xspeed=0;
1972 p->yspeed=0;
1973 p->status |= S_DEAD; /* dead flag */
1974 sendall_update_object(p,0,0); /* update everything */
1975 send_update_player((struct player*)(p->data)); /* dead player */
1976 send_info(0,0);
1977 if (a-h>=OVERKILL)
1978 create_mess(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-MESS_HEIGHT,py);
1979 else
1980 create_corpse(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->data))->color,0);
1982 else
1984 H-=a; /* health */
1985 A=(c>=A)?0:(A-c); /* armor */
1986 send_update_player((struct player*)(p->data));
1988 return 0;
1990 case T_SHRAPNEL:
1991 if (p->type==T_CORPSE)
1993 char packet[5];
1994 int offset = 0;
1995 px=PX;
1996 py=PY;
1997 packet[offset++]=P_DELETE_OBJECT;
1998 put_int(packet,p->id,&offset);
1999 sendall_chunked(packet,offset,0);
2000 delete_obj(p->id);
2001 create_mess(px,py,py);
2002 return 1;
2004 case T_BULLET:
2005 case T_BFGCELL:
2006 case T_CHAIN:
2007 if (p->type!=T_PLAYER)break;
2008 b=((obj->type==T_BULLET||obj->type==T_BFGCELL||obj->type==T_CHAIN)?FIRE_IMPACT:SHRAPNEL_IMPACT);
2009 p->status |= S_HIT;
2010 if (obj->type != T_CHAIN)
2011 p->xspeed+=obj->xspeed>0?b:-b;
2012 sendall_update_object(p,0,4); /* update speed + status */
2013 p->status &= ~S_HIT;
2014 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);
2015 c=(int)(weapon[obj->status].armor_damage*(2-double2int(obj->y-p->y)/(double)PLAYER_HEIGHT)*obj->ttl/weapon[obj->status].ttl);
2016 if (a>=H) /* player was slain */
2018 o=&(((ol = find_in_table((long)(obj->data))))->member); /* owner of the bullet */
2019 ((struct player*)(p->data))->deaths++;
2020 if (!ol) { /* for now only bloodrain */
2021 snprintf(txt,256,"Bloody shrapnel killed %s.",((struct player*)(p->data))->name);
2022 sendall_message(0,txt,NULL,(struct player*)(p->data), M_DEATH);
2023 snprintf(txt,256,"Bloody shrapnel killed you");
2024 send_message((struct player*)(p->data),0,txt, M_DEATH); /* the dead */
2025 snprintf(txt,256,"Bloody shrapnel killed %s.\n",((struct player*)(p->data))->name);
2026 message(txt,2);
2028 else if (o->data==p->data) /* suicide */
2030 ((struct player*)(o->data))->frags-=!!(((struct player*)(o->data))->frags);
2031 send_message((struct player*)(o->data),0,"You killed yourself", M_DEATH);
2032 snprintf(txt,256,"%s suicides",((struct player*)(o->data))->name);
2033 sendall_message(0,txt,(struct player*)(o->data),0, M_DEATH);
2034 snprintf(txt,256,"%s suicides.\n",((struct player*)(o->data))->name);
2035 message(txt,2);
2037 else
2039 ((struct player*)(o->data))->frags++;
2040 snprintf(txt,256,"%s killed %s.",((struct player*)(o->data))->name,((struct player*)(p->data))->name);
2041 sendall_message(0,txt,(struct player*)(o->data),(struct player*)(p->data), M_DEATH);
2042 snprintf(txt,256,"%s killed you",((struct player*)(o->data))->name);
2043 send_message((struct player*)(p->data),0,txt, M_DEATH); /* the dead */
2044 snprintf(txt,256,"You killed %s",((struct player*)(p->data))->name);
2045 send_message((struct player*)(o->data),0,txt, M_DEATH); /* the dead */
2046 snprintf(txt,256,"%s killed %s.\n",((struct player*)(o->data))->name,((struct player*)(p->data))->name);
2047 message(txt,2);
2049 s=p->status;
2050 px=PX;
2051 py=PY;
2052 h=H;
2053 H=0;
2054 p->xspeed=0;
2055 p->yspeed=0;
2056 p->status |= S_DEAD; /* dead flag */
2057 sendall_update_object(p,0,0); /* update everything */
2058 send_update_player((struct player*)(p->data)); /* dead player */
2059 if (ol)
2060 send_update_player((struct player*)(o->data)); /* owner of bullet/shrapnel */
2061 send_info(0,0);
2062 if (a-h>=OVERKILL)
2063 create_mess(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-MESS_HEIGHT,py);
2064 else
2065 create_corpse(px,py+((s & S_CREEP)?CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->data))->color,0);
2067 else
2069 H-=a; /* health */
2070 A=(c>=A)?0:(A-c); /* armor */
2071 sendall_hit(p->id,obj->xspeed<0,OX-PX,OY-PY,0);
2072 send_update_player((struct player*)(p->data));
2073 /* well ... */
2074 if (obj->type == T_CHAIN) {
2075 struct it *meat=new_obj(id,T_MESS,MESS_TTL,
2076 (meatcounter==0x1)?mess3_sprite:
2077 ((meatcounter)==0x2)?mess2_sprite:mess4_sprite,
2078 0,0,obj->x,obj->y,-float2double(obj->xspeed/500),
2079 -float2double((meatcounter+2)*36),0);
2080 if (!meat) return 1;
2081 id++;
2082 sendall_new_object(meat,0);
2083 meatcounter = (meatcounter+1)%3;
2086 return 1;
2089 return 0;
2091 #undef MAX_AMMO
2092 #undef P
2093 #undef H
2094 #undef A
2095 #undef OX
2096 #undef OY
2097 #undef PX
2098 #undef PY
2102 /* recompute objects positions */
2103 static void update_game(void)
2105 static char packet[64];
2106 char txt[256];
2107 struct object_list *p, *p2;
2108 struct player_list *q;
2109 int w,h,b,a;
2110 unsigned char stop_x,stop_y;
2111 int x,y,xs,ys;
2112 int x1,y1;
2113 unsigned char sy;
2114 struct it *s; /* for grenades throwing */
2115 unsigned int status;
2116 int DELTA_TIME;
2117 unsigned long_long t;
2118 unsigned int old_status;
2119 int old_ttl;
2120 int old_x,old_y,old_x_speed,old_y_speed;
2121 int offset = 0;
2123 for(p=&objects;p->next;p=p->next)
2125 if (p->next->member.type==T_NOTHING)
2126 continue;
2127 if (p->next->member.type==T_PLAYER&&(p->next->member.status & S_DEAD))
2128 continue; /* dead player */
2129 if (p->next->member.type==T_PLAYER&&(((struct player*)(p->next->member.data))->current_level)<0) /* player hasn't entered the level yet */
2131 send_change_level((struct player*)p->next->member.data);
2132 continue;
2135 old_status=p->next->member.status;
2136 old_ttl=p->next->member.ttl;
2137 old_x=p->next->member.x;
2138 old_y=p->next->member.y;
2139 old_x_speed=p->next->member.xspeed;
2140 old_y_speed=p->next->member.yspeed;
2142 x=p->next->member.x;
2143 y=p->next->member.y;
2144 xs=p->next->member.xspeed;
2145 ys=p->next->member.yspeed;
2146 status=p->next->member.status;
2148 /* decrease invisibility counter of invisible player */
2149 if ((p->next->member.type==T_PLAYER)&&(((struct player*)(p->next->member.data))->invisibility_counter))
2151 ((struct player*)(p->next->member.data))->invisibility_counter--;
2152 if (!(((struct player*)(p->next->member.data))->invisibility_counter))
2154 p->next->member.status &= ~S_INVISIBLE;
2155 sendall_update_status(&(p->next->member),0);
2159 /* decrease life of ill player */
2160 if ((p->next->member.type==T_PLAYER)&&(((struct player*)(p->next->member.data))->obj->status & (S_ILL | S_ONFIRE)))
2162 /* hack - health with extended precision */
2163 if (!((struct player*)(p->next->member.data))->health_ep--) {
2164 ((struct player*)(p->next->member.data))->health_ep=
2165 ((((struct player*)(p->next->member.data))->obj->status & S_ILL) ? ILLNESS_SPEED : 0) +
2166 ((((struct player*)(p->next->member.data))->obj->status & S_ONFIRE) ? BURNING_SPEED : 0);
2167 ((struct player*)(p->next->member.data))->health--;
2169 send_update_player((struct player*)(p->next->member.data));
2170 if (!(((struct player*)(p->next->member.data))->health))
2172 p->next->member.status |= S_DEAD;
2173 ((struct player*)(p->next->member.data))->frags-=!!(((struct player*)(p->next->member.data))->frags);
2175 if (((struct player*)(p->next->member.data))->obj->status & S_ILL) {
2176 send_message((struct player*)(p->next->member.data),0,"You died on illness", M_DEATH);
2177 snprintf(txt,256,"%s died on illness",((struct player*)(p->next->member.data))->name);
2178 sendall_message(0,txt,(struct player*)(p->next->member.data),0, M_DEATH);
2179 snprintf(txt,256,"%s died on illness.\n",((struct player*)(p->next->member.data))->name);
2180 } else {
2181 send_message((struct player*)(p->next->member.data),0,"You burnt down to ashes", M_DEATH);
2182 snprintf(txt,256,"%s burnt down to ashes",((struct player*)(p->next->member.data))->name);
2183 sendall_message(0,txt,(struct player*)(p->next->member.data),0, M_DEATH);
2184 snprintf(txt,256,"%s burnt down to ashes.\n",((struct player*)(p->next->member.data))->name);
2186 message(txt,2);
2188 send_update_player((struct player*)(p->next->member.data)); /* dead player */
2189 sendall_update_status(&(p->next->member),0);
2190 send_info(0,0);
2192 create_corpse(double2int(p->next->member.x),double2int(p->next->member.y)+((p->next->member.status & S_CREEP)?
2193 CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,((struct player*)(p->next->member.data))->color,S_ILL);
2197 /* decrement time to live */
2198 if (p->next->member.type == T_PLAYER && (p->next->member.status & S_BLOODRAIN))
2199 goto br;
2200 if (p->next->member.ttl>0)
2202 p->next->member.ttl--;
2203 /* create player */
2204 if (p->next->member.type==T_NOISE&&p->next->member.ttl==(NOISE_TTL>>1))
2206 /* find player */
2207 q=find_player(0,(long)(p->next->member.data));
2208 if (q) /* player is still in the game */
2210 init_player(&(q->member),q->member.obj->x,q->member.obj->y);
2211 q->member.obj->status &= ~(S_DEAD | S_NOISE);
2212 sendall_update_object(q->member.obj,0,0); /* update everything */
2213 send_update_player(&(q->member));
2216 goto cont_cycle; /* that's all for T_NOISE at this moment */
2218 /* grenades must be created after locking off */
2219 /* not when shoot request comes */
2220 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)
2222 s=new_obj(
2224 T_GRENADE,
2225 weapon[WEAPON_GRENADE].ttl,
2226 grenade_sprite,
2228 WEAPON_GRENADE,
2229 add_int(p->next->member.x,p->next->member.status & S_LOOKLEFT ? 2 : PLAYER_WIDTH-2),
2230 p->next->member.y+GRENADE_FIRE_YOFFSET,
2231 p->next->member.xspeed+(p->next->member.status & S_LOOKLEFT ? -weapon[WEAPON_GRENADE].shell_xspeed:weapon[WEAPON_GRENADE].shell_xspeed),
2232 p->next->member.yspeed+weapon[WEAPON_GRENADE].shell_yspeed,
2233 (void *)(long)(p->next->member.id));
2234 id++;
2235 sendall_new_object(s,0);
2237 /* if ttl is 0, delete this object */
2238 if (p->next->member.ttl<=0)
2240 /* player's ttl means how long he holds the gun */
2241 switch(p->next->member.type)
2243 case T_PLAYER:
2244 p->next->member.status &= ~S_SHOOTING;
2245 break;
2247 case T_GRENADE:
2248 case T_BFGCELL:
2249 br: offset = 0;
2250 packet[offset++]=(p->next->member.type==T_GRENADE)?P_EXPLODE_GRENADE:
2251 (p->next->member.type==T_BFGCELL)?P_EXPLODE_BFG:P_EXPLODE_BLOODRAIN;
2252 put_int(packet,id,&offset);
2253 put_int(packet,p->next->member.id,&offset);
2254 sendall_chunked(packet,offset,0);
2256 for (b=0;b<N_SHRAPNELS_EXPLODE;b++)
2258 double angle=(double)b*2*M_PI/N_SHRAPNELS_EXPLODE;
2259 int spd=add_int(mul_int(my_and(mul_int(weapon[WEAPON_GRENADE].speed,b+1),15),16),100);
2261 new_obj(
2263 T_SHRAPNEL,
2264 SHRAPNEL_TTL,
2265 (p->next->member.type==T_GRENADE)?
2266 shrapnel_sprite[random()%N_SHRAPNELS]:
2267 (p->next->member.type==T_BFGCELL)?
2268 bfgbit_sprite[random()%N_SHRAPNELS]:
2269 bloodrain_sprite[random()%N_SHRAPNELS],
2271 WEAPON_GRENADE,
2272 p->next->member.x,
2273 p->next->member.y,
2274 p->next->member.xspeed+mul(spd,float2double(cos(angle))),
2275 p->next->member.yspeed+mul(spd,float2double(sin(angle))),
2276 p->next->member.data);
2277 id++;
2279 if (p->next->member.status & S_BLOODRAIN) {
2280 p->next->member.status |= S_DEAD;
2281 ((struct player *)p->next->member.data)->frags-=!!(((struct player *)p->next->member.data)->frags);
2282 ((struct player *)p->next->member.data)->deaths++;
2283 sendall_update_object(&(p->next->member),0,0); /* update everything */
2284 send_update_player((struct player*)(p->next->member.data)); /* dead player */
2285 send_info(0,0);
2286 create_mess(double2int(p->next->member.x),double2int(p->next->member.y)+((p->next->member.status & S_CREEP)?
2287 CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT,
2288 double2int(p->next->member.y)+((p->next->member.status & S_CREEP)?
2289 CREEP_HEIGHT:PLAYER_HEIGHT)-CORPSE_HEIGHT);
2290 } else
2291 delete_obj(p->next->member.id);
2292 if (!(p->next))return;
2293 goto cont_cycle;
2295 default:
2296 offset = 0;
2297 packet[offset++]=P_DELETE_OBJECT;
2298 put_int(packet,p->next->member.id,&offset);
2299 sendall_chunked(packet,offset,0);
2300 delete_obj(p->next->member.id);
2301 if (!(p->next))return;
2302 goto cont_cycle;
2306 /* maintain only objects that you are allowed to maintain */
2307 if (!obj_attr[p->next->member.type].maintainer)goto dc;
2308 if (!(obj_attr[p->next->member.type].maintainer&2))continue;
2311 /* when not falling, slow down x motion */
2312 if (!(p->next->member.status & S_FALLING))
2313 p->next->member.xspeed=mul(p->next->member.xspeed,obj_attr[p->next->member.type].slow_down_x);
2315 /* fall */
2316 if (obj_attr[p->next->member.type].fall)
2318 if (p->next->member.type!=T_SHRAPNEL)p->next->member.status |= S_FALLING;
2319 p->next->member.yspeed+=FALL_ACCEL;
2320 /* but not too fast */
2321 if (p->next->member.yspeed>MAX_Y_SPEED)p->next->member.yspeed=MAX_Y_SPEED;
2324 t=get_time();
2325 get_dimensions(p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions,&w,&h);
2326 DELTA_TIME=float2double(((double)((long_long)(t-p->next->member.last_updated)))/MICROSECONDS);
2327 update_position(
2328 &(p->next->member),
2329 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
2330 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
2331 w,h,&stop_x,&stop_y);
2332 p->next->member.last_updated=t;
2334 /* walk up the stairs */
2335 if (stop_x&&p->next->member.type==T_PLAYER&&!(p->next->member.status & S_CREEP))
2337 x1=p->next->member.x;
2338 y1=p->next->member.y;
2339 p->next->member.x=x;
2340 p->next->member.y=y-int2double(1);
2341 update_position(
2342 &(p->next->member),
2343 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
2344 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
2345 w,h,0,&sy);
2346 if ((p->next->member.xspeed>0&&p->next->member.x<=x1)||(p->next->member.xspeed<0&&p->next->member.x>=x1)) /* restore original values */
2348 p->next->member.x=x1;
2349 p->next->member.y=y1;
2351 else
2353 stop_y=sy;
2354 stop_x=0;
2358 if (stop_x)p->next->member.xspeed=-mul(p->next->member.xspeed,obj_attr[p->next->member.type].bounce_x);
2359 if (my_abs(p->next->member.xspeed)<MIN_X_SPEED)
2361 p->next->member.xspeed=0;
2362 p->next->member.status &= ~S_WALKING;
2366 if (stop_y)
2368 p->next->member.yspeed=mul(p->next->member.yspeed,obj_attr[p->next->member.type].bounce_y);
2369 p->next->member.yspeed=-p->next->member.yspeed;
2370 if (my_abs(p->next->member.yspeed)<MIN_Y_SPEED)
2372 p->next->member.yspeed=0;
2373 if (stop_y==1)p->next->member.status &= ~S_FALLING;
2377 if ((p->next->member.type==T_SHRAPNEL||p->next->member.type==T_BULLET||
2378 p->next->member.type==T_BFGCELL||p->next->member.type==T_CHAIN)&&(stop_x||stop_y)) /* bullet and shrapnel die crashing into wall */
2380 offset = 0;
2381 packet[offset++]=P_DELETE_OBJECT;
2382 put_int(packet,p->next->member.id,&offset);
2383 sendall_chunked(packet,offset,0);
2384 delete_obj(p->next->member.id);
2385 if (!(p->next))break;
2386 continue;
2389 /* Anything crashing into PS makes him into bloody goo */
2390 for (p2=&objects;p2->next;p2=p2->next)
2391 if ((p2->next->member.type == T_PS) && (!(p2->next->member.status & S_INVISIBLE)) &&
2392 ((p->next->member.type == T_BULLET) || (p->next->member.type == T_SHRAPNEL) ||
2393 (p->next->member.type == T_CHAIN) || (p->next->member.type == T_BFGCELL)) &&
2394 collision(
2395 double2int(p2->next->member.x),double2int(p2->next->member.y),p2->next->member.type,p2->next->member.status,sprites[p2->next->member.sprite].positions,
2396 double2int(p->next->member.x),double2int(p->next->member.y),p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions)) {
2397 p2->next->member.status |= S_INVISIBLE;
2398 create_mess(double2int(p2->next->member.x),double2int(p2->next->member.y)+PLAYER_HEIGHT-MESS_HEIGHT,double2int(p2->next->member.y));
2399 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);
2400 sendall_update_status(&(p2->next->member),0);
2403 /* compute collision with other objects */
2404 a=dynamic_collision(&(p->next->member));
2405 switch (a)
2407 case 1: /* object dies */
2408 offset = 0;
2409 packet[offset++]=P_DELETE_OBJECT;
2410 put_int(packet,p->next->member.id,&offset);
2411 sendall_chunked(packet,offset,0);
2413 case 2:
2414 delete_obj(p->next->member.id);
2415 if (!(p->next))return;
2416 goto cont_cycle;
2418 case 0: /* object still lives */
2419 if ( /* send update but only when something's changed and client doesn't maintain the object */
2420 (obj_attr[p->next->member.type].maintainer&4)&& /* server sends update */
2421 (x!=p->next->member.x|| /* something's changed */
2422 y!=p->next->member.y||
2423 xs!=p->next->member.xspeed||
2424 ys!=p->next->member.yspeed||
2425 status!=p->next->member.status))
2427 a=which_update(&(p->next->member),old_x,old_y,old_x_speed,old_y_speed,old_status,old_ttl);
2428 sendall_update_object(&(p->next->member),0,a);
2430 break;
2432 cont_cycle:;
2436 static void free_all_memory(void)
2438 struct queue_list *t;
2439 struct player_list *p;
2441 /* delete players */
2442 for (p=&players;p->next;)
2443 delete_player(p->next);
2444 /* delete objects */
2445 while (last_obj!=(&objects))delete_obj(last_obj->member.id);
2447 for (t=&time_queue;t->next;)
2449 struct queue_list *q;
2451 q=t->next->next;
2452 mem_free(t->next);
2453 t->next=q;
2456 /* delete birthplaces */
2457 if (n_birthplaces)mem_free(birthplace);
2459 /* delete sprites */
2460 free_sprites(0);
2462 free_area();
2463 if (level_checksum)mem_free(level_checksum);
2464 free_packet_buffer();
2467 /* fatal signal handler (sigsegv, sigabrt, ... ) */
2468 static void signal_handler(int sig_num)
2470 char packet[16];
2471 char txt[256];
2473 packet[0]=P_END;
2474 memcpy(packet+1,"server",7);
2476 sendall(packet,8,0);
2477 sendall(packet,8,0);
2478 sendall(packet,8,0);
2479 sendall(packet,8,0);
2480 sendall(packet,8,0);
2481 sendall(packet,8,0);
2482 sendall(packet,8,0);
2483 sendall(packet,8,0);
2484 /* 800 % redundancy should be enough ;-) */
2486 snprintf(txt,256,"Signal %d caught.\n",sig_num);
2487 message(txt,2);
2488 free_all_memory();
2489 check_memory_leaks();
2490 if (fd) close(fd);
2491 #ifdef WIN32
2492 hServerExitEvent=1;
2493 #else
2494 signal(sig_num,SIG_DFL);
2495 raise(sig_num);
2496 #endif
2500 /* walk with given player */
2501 static void walk_player(struct player *q,int direction, int speed, int creep)
2503 int a;
2505 unsigned int old_status=q->obj->status;
2506 int old_ttl=q->obj->ttl;
2507 int old_x=q->obj->x,
2508 old_y=q->obj->y,
2509 old_x_speed=q->obj->xspeed,
2510 old_y_speed=q->obj->yspeed;
2512 if ((q->obj->status & (S_GRENADE | S_SHOOTING)) == (S_GRENADE | S_SHOOTING))
2513 return; /* when throwing grenade can't walk */
2514 if (creep) /* creep */
2516 a=MAX_SPEED_CREEP;
2517 if (!(q->obj->status & S_CREEP))
2518 q->obj->y+=CREEP_YOFFSET;
2519 q->obj->status |= S_CREEP;
2522 else
2524 a=speed?MAX_SPEED_WALK_FAST:MAX_X_SPEED;
2525 if (q->obj->status & S_CREEP)
2526 q->obj->y-=CREEP_YOFFSET;
2527 q->obj->status &= ~S_CREEP;
2529 switch (direction)
2531 case 0: /* stop */
2532 q->obj->status &= ~S_WALKING;
2533 q->obj->xspeed=0;
2534 break;
2536 case 1: /* left */
2537 q->obj->status |= S_WALKING;
2538 q->obj->xspeed-=WALK_ACCEL;
2539 if (q->obj->xspeed<-a)q->obj->xspeed=-a;
2540 break;
2542 case 2: /* right */
2543 q->obj->status |= S_WALKING;
2544 q->obj->xspeed+=WALK_ACCEL;
2545 if (q->obj->xspeed>a)q->obj->xspeed=a;
2546 break;
2549 a=which_update(q->obj,old_x,old_y,old_x_speed,old_y_speed,old_status,old_ttl);
2551 sendall_update_object(q->obj,0,a);
2555 /* jump with given player */
2556 static void jump_player(struct player *p, char jet, int direction)
2558 int i;
2559 struct it *o;
2560 if (p->obj->status & ((jet ? 0 : S_FALLING) | S_CREEP))
2561 return;
2562 p->obj->status |= S_FALLING;
2563 p->obj->yspeed=-SPEED_JUMP;
2564 if (jet) {
2565 p->obj->status |= S_JETPACK_ON;
2566 for (i=0;i<8;i++) {
2567 o=new_obj(
2569 T_JETFIRE,
2570 JETFIRE_TTL,
2571 jetfire_sprite,
2574 add_int(p->obj->x, (direction & S_LOOKLEFT) ?
2575 PLAYER_WIDTH - 2 - (i%2) : ((direction & S_LOOKRIGHT) ?
2576 1 - (i%2) : PLAYER_WIDTH / 2)),
2577 p->obj->y+FIRE_YOFFSET+int2double(i%4),
2578 mul((double)(8*(i-4)), float2double(36*36)),
2579 (4-i),
2580 (void *)(long)(p->obj->id));
2581 if (!o)return;
2582 id++;
2583 sendall_new_object(o, 0);
2586 sendall_update_object(p->obj,0,4); /* update speed + status */
2587 p->obj->status &= ~S_JETPACK_ON;
2590 /* change weapon of given player (w=new weapon) */
2591 static void change_weapon_player(struct player *q,int w)
2593 char txt[256];
2595 if (!w)return;
2596 w--;
2597 if (q->current_weapon==w)return;
2598 if (!(q->weapons&(1<<w)))
2599 {send_message(q,0,"No weapon.", M_INFO);return;}
2600 if (!(q->ammo[w]))
2601 {send_message(q,0,"Not enough ammo.", M_INFO);return;}
2602 q->current_weapon=w;
2603 snprintf(txt,256,"%s takes %s.\n",q->name,weapon[w].name);
2604 message(txt,1);
2605 send_update_player(q);
2609 /* shoot with given player */
2610 /* direction: 0=right, 1=left */
2611 static void fire_player(struct player *q,int direction)
2613 int a;
2614 struct it *s;
2615 q->obj->status &= ~S_CHAINSAW; /* chainsaw */
2617 if (q->current_weapon==WEAPON_BLOODRAIN) {
2618 q->obj->status |= S_BLOODRAIN;
2619 return;
2621 if (!(q->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))||(q->obj->status & S_CREEP)||
2622 ((q->obj->status & S_SHOOTING)&&(q->obj->ttl>HOLD_GUN_AFTER_SHOOT)))
2623 return;
2624 if (!q->ammo[q->current_weapon])
2626 a=select_best_weapon(q);
2627 if (a==q->current_weapon) return;
2628 q->current_weapon=a;
2630 if (q->current_weapon!=WEAPON_CHAINSAW)
2631 q->ammo[q->current_weapon]--;
2632 send_update_player(q);
2633 q->obj->status &= ~S_GRENADE;
2634 if (q->current_weapon==WEAPON_SHOTGUN) /* shotgun */
2636 s=new_obj( /* SHELL */
2638 T_SHELL,
2639 SHELL_TTL,
2640 shotgun_shell_sprite,
2643 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2644 q->obj->y+FIRE_YOFFSET,
2645 q->obj->xspeed+(direction==1?-weapon[1].shell_xspeed:weapon[1].shell_xspeed),
2646 weapon[1].shell_yspeed,
2647 (void *)(long)(q->obj->id));
2648 id++;
2649 sendall_new_object(s,0);
2650 s=new_obj( /* straight */
2652 T_BULLET,
2653 weapon[q->current_weapon].ttl,
2654 slug_sprite,
2656 q->current_weapon,
2657 add_int(q->obj->x,direction==1?-2:PLAYER_WIDTH+2),
2658 q->obj->y+FIRE_YOFFSET,
2659 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2661 (void *)(long)(q->obj->id));
2662 id++;
2663 sendall_new_object(s,0);
2664 s=new_obj( /* straight */
2666 T_BULLET,
2667 weapon[q->current_weapon].ttl,
2668 slug_sprite,
2670 q->current_weapon,
2671 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2672 q->obj->y+FIRE_YOFFSET+int2double(1),
2673 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2675 (void *)(long)(q->obj->id));
2676 id++;
2677 sendall_new_object(s,0);
2678 s=new_obj( /* one up */
2680 T_BULLET,
2681 weapon[q->current_weapon].ttl,
2682 slug_sprite,
2684 q->current_weapon,
2685 add_int(q->obj->x,direction==1?-1:PLAYER_WIDTH+1),
2686 q->obj->y+FIRE_YOFFSET,
2687 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2688 float2double((double).1*36),
2689 (void *)(long)(q->obj->id));
2690 id++;
2691 sendall_new_object(s,0);
2692 s=new_obj( /* two up */
2694 T_BULLET,
2695 weapon[q->current_weapon].ttl,
2696 slug_sprite,
2698 q->current_weapon,
2699 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2700 q->obj->y+FIRE_YOFFSET-int2double(1),
2701 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2702 float2double((double).15*36),
2703 (void *)(long)(q->obj->id));
2704 id++;
2705 sendall_new_object(s,0);
2706 s=new_obj( /* one down */
2708 T_BULLET,
2709 weapon[q->current_weapon].ttl,
2710 slug_sprite,
2712 q->current_weapon,
2713 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2714 q->obj->y+FIRE_YOFFSET+int2double(1),
2715 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2716 -float2double((double).1*36),
2717 (void *)(long)(q->obj->id));
2718 id++;
2719 sendall_new_object(s,0);
2720 s=new_obj( /* two down */
2722 T_BULLET,
2723 weapon[q->current_weapon].ttl,
2724 slug_sprite,
2726 q->current_weapon,
2727 add_int(q->obj->x,direction==1?-1:PLAYER_WIDTH+1),
2728 q->obj->y+FIRE_YOFFSET,
2729 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2730 -float2double((double).15*36),
2731 (void *)(long)(q->obj->id));
2732 id++;
2733 sendall_new_object(s,0);
2735 else if (q->current_weapon==WEAPON_BFG) {
2736 s=new_obj( /* straight */
2738 T_BFGCELL,
2739 weapon[q->current_weapon].ttl,
2740 bfgcell_sprite,
2742 q->current_weapon,
2743 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2744 q->obj->y+FIRE_YOFFSET,
2745 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2747 (void *)(long)(q->obj->id));
2748 id++;
2749 sendall_new_object(s,0);
2751 else if (q->current_weapon==WEAPON_CHAINSAW) {
2752 s=new_obj(
2754 T_CHAIN,
2755 weapon[q->current_weapon].ttl,
2756 bullet_sprite,
2758 q->current_weapon,
2759 add_int(q->obj->x,direction==1?-2:PLAYER_WIDTH),
2760 q->obj->y+FIRE_YOFFSET,
2761 (int)(1.2*q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed)),
2763 (void *)(long)(q->obj->id));
2764 id++;
2765 sendall_new_object(s,0);
2766 s=new_obj(
2768 T_CHAIN,
2769 weapon[q->current_weapon].ttl,
2770 bullet_sprite,
2772 q->current_weapon,
2773 add_int(q->obj->x,direction==1?-2:PLAYER_WIDTH),
2774 q->obj->y+FIRE_YOFFSET+int2double(1),
2775 (int)(1.2*q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed)),
2777 (void *)(long)(q->obj->id));
2778 id++;
2779 sendall_new_object(s,0);
2780 q->obj->status |= S_CHAINSAW;
2781 } else if (q->current_weapon==WEAPON_GRENADE) /* grenades */
2783 q->obj->status |= S_GRENADE;
2784 q->obj->status &= ~S_WALKING;
2786 else if (!(q->obj->status & S_BLOODRAIN))
2788 s=new_obj( /* SHELL */
2790 T_SHELL,
2791 SHELL_TTL,
2792 shell_sprite,
2795 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2796 q->obj->y+FIRE_YOFFSET,
2797 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].shell_xspeed:weapon[q->current_weapon].shell_xspeed),
2798 weapon[q->current_weapon].shell_yspeed,
2799 (void *)(long)(q->obj->id));
2800 id++;
2801 sendall_new_object(s,0);
2802 s=new_obj(
2804 T_BULLET,
2805 weapon[q->current_weapon].ttl,
2806 bullet_sprite,
2808 q->current_weapon,
2809 add_int(q->obj->x,direction==1?0:PLAYER_WIDTH),
2810 q->obj->y+FIRE_YOFFSET,
2811 q->obj->xspeed+(direction==1?-weapon[q->current_weapon].speed:weapon[q->current_weapon].speed),
2813 (void *)(long)(q->obj->id));
2814 id++;
2815 sendall_new_object(s,0);
2817 q->obj->xspeed+=(direction==1)?weapon[q->current_weapon].impact:-weapon[q->current_weapon].impact;
2818 q->obj->status |= S_SHOOTING;
2819 q->obj->status |= S_HOLDING;
2820 q->obj->ttl=weapon[q->current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
2821 sendall_update_object(q->obj,0,6); /* update speed and status and ttl */
2822 q->obj->status &= ~S_HOLDING;
2826 /* update given player (jump, shoot, creep, change weapon) */
2827 static void move_player(struct player *p)
2829 int a;
2831 if (p->obj->status & S_DEAD)
2832 return; /* dead player */
2834 if (p->keyboard_status.status & KBD_DOWN_LADDER) /* climb down a ladder */
2835 p->obj->status |= S_CLIMB_DOWN;
2836 else
2837 p->obj->status &=~ S_CLIMB_DOWN;
2839 if (p->keyboard_status.status & KBD_JUMP)
2840 jump_player(p, 0, (p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT)));
2841 if ((p->keyboard_status.status & KBD_JETPACK) && (p->obj->status & S_JETPACK))
2842 jump_player(p, 1, (p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT)));
2843 if (p->keyboard_status.status & KBD_RIGHT)
2845 if ((p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))==S_LOOKRIGHT) /* walk right */
2846 walk_player(p,2,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP);
2847 else
2849 if (p->obj->status & S_WALKING)
2850 walk_player(p,0,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP); /* stop */
2851 else
2853 a=p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT);
2854 p->obj->status &= ~(S_LOOKLEFT | S_LOOKRIGHT);
2855 p->obj->status |= (a == S_LOOKLEFT) ? 0 : S_LOOKRIGHT;
2856 sendall_update_status(p->obj,0);
2861 if (p->keyboard_status.status & KBD_LEFT)
2863 if ((p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))==S_LOOKLEFT) /* walk left */
2864 walk_player(p,1,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP);
2865 else
2867 if (p->obj->status & S_WALKING)
2868 walk_player(p,0,p->keyboard_status.status & KBD_SPEED,p->keyboard_status.status & KBD_CREEP); /* stop */
2869 else
2871 a=p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT);
2872 p->obj->status &= ~(S_LOOKLEFT | S_LOOKRIGHT);
2873 p->obj->status |= (a == S_LOOKRIGHT) ? 0 : S_LOOKLEFT;
2874 sendall_update_status(p->obj,0);
2878 change_weapon_player(p,p->keyboard_status.weapon);
2879 if (p->keyboard_status.status & KBD_FIRE)
2880 fire_player(p,(p->obj->status & (S_LOOKLEFT | S_LOOKRIGHT))>>1);
2884 /* update players, kick out not responding players */
2885 static void update_players(void)
2887 struct player_list *p;
2888 char txt[256];
2889 char packet;
2890 unsigned long_long t=get_time();
2892 for (p=&players;p->next;p=p->next)
2894 /* this player is dead - delete him */
2895 if (t-(p->next->member).last_update>=MAX_DUMB_TIME)
2897 snprintf(txt,256,"%s not responding. Kicked out of the game.\n",p->next->member.name);
2898 message(txt,2);
2899 packet=P_PLAYER_DELETED;
2900 send_packet((char *)&packet,1,(struct sockaddr*)(&(p->next->member.address)),0,last_player->member.id);
2901 snprintf(txt,256,"%s was kicked out of the game.",p->next->member.name);
2902 sendall_message(0,txt,0,0, M_INFO);
2903 delete_player(p->next);
2904 if (!(p->next))break;
2906 else
2907 move_player(&(p->next->member));
2912 /* write help message to stdout */
2913 static void print_help(void)
2915 char *p = "";
2916 #ifdef __EMX__
2917 p = "Portions (c) 2000 by Mikulas Patocka\n";
2918 #endif
2919 #ifdef WIN32
2920 printf( "0verkill server.\n"
2921 "(c)2000 Brainsoft\n"
2922 "Portions (c) 2000 by Filip Konvicka\n"
2923 "Usage: server [-nh] [-l <level_number>] [-p <port number>] [-i username[/password]] [-I] [-r]\n"
2924 "-i Installs as a service\n"
2925 "-I Installs with the LOCAL_SYSTEM account.\n"
2926 "-r Stops and removes the service\n"
2927 "-n Server can't be ended by client\n"
2928 "You must be an administrator in order to install/remove a service.\n");
2929 #else
2930 printf( "0verkill server.\n"
2931 "(c)2000 Brainsoft\n"
2932 "%s\n"
2933 "Usage: server [-nh] [-l <level number>] [-p <port number>]\n"
2934 "-n Server can't be ended by client\n", p
2936 #endif
2940 static void parse_command_line(int argc,char **argv)
2942 int a;
2943 char *c;
2945 while(1)
2947 #ifdef WIN32
2948 a=getopt(argc,argv,"hl:np:ri:Ic");
2949 #else
2950 a=getopt(argc,argv,"hl:np:");
2951 #endif
2952 switch(a)
2954 case EOF:
2955 return;
2957 case '?':
2958 case ':':
2959 EXIT(1);
2961 #ifdef WIN32
2962 case 'c':
2963 break; /* run as console app */
2964 case 'r': /* remove service */
2965 CmdRemoveService();
2966 EXIT(1);
2967 case 'i': { /* install service */
2968 char username[80],
2969 password[80],
2970 *user=NULL,
2971 *pass=NULL;
2972 if ( optarg ) {
2973 username[sizeof(username)-1]=0;
2974 user=username;
2975 if ( (pass=strchr(optarg, '/'))==NULL ) {
2976 #ifndef WIN32
2977 strcpy(username, optarg);
2978 #else
2979 strcpy_s(username, sizeof(optarg), optarg);
2980 #endif
2981 memcpy(username, optarg, sizeof(username)-1);
2982 password[0]=0;
2984 else {
2985 int size=pass-optarg;
2986 if ( size>sizeof(username)-1 )
2987 size=sizeof(username)-1;
2988 memcpy(username, optarg, size);
2989 username[size]=0;
2990 pass++;
2991 size=strlen(pass);
2992 if ( size>sizeof(password)-1 )
2993 size=sizeof(password)-1;
2994 memcpy(password, pass, size);
2997 CmdInstallService(user, pass, NULL);
2998 EXIT(1);
3000 case 'I': { /* install service */
3001 CmdInstallService(NULL, NULL, NULL);
3002 EXIT(1);
3004 #endif
3006 case 'h':
3007 print_help();
3008 EXIT(0);
3010 case 'p':
3011 port=(unsigned short)strtoul(optarg,&c,10);
3012 if (*c){ERROR("Error: Not a number.\n");EXIT(1);}
3013 if (errno==ERANGE)
3015 if (!port){ERROR("Error: Number underflow.\n");EXIT(1);}
3016 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3018 break;
3020 case 'l':
3021 level_number=strtoul(optarg,&c,10);
3022 if (*c){ERROR("Error: Not a number.\n");EXIT(1);}
3023 if (errno==ERANGE)
3025 if (!level_number){ERROR("Error: Number underflow.\n");EXIT(1);}
3026 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3028 break;
3030 case 'n':
3031 nonquitable=1;
3032 break;
3038 /*-----------------------------------------------------------------------------------*/
3039 static int server(void)
3041 int a;
3042 char txt[256];
3043 unsigned long_long last_time;
3044 char *LEVEL;
3046 last_player=&players;
3047 last_obj=&objects;
3049 snprintf(txt,256,"Running 0verkill server version %d.%d\n",VERSION_MAJOR,VERSION_MINOR);
3050 message(txt,2);
3051 #ifdef WIN32
3052 snprintf(txt,256,"This is 0verkill server for Win32, build #%u\n",VERSION_PORT);
3053 message(txt,2);
3054 #endif
3055 message("Initialization.\n",2);
3056 #ifdef WIN32
3057 message("Starting Windows Sockets\n",2);
3059 WSADATA wd;
3060 WSAStartup(0x101, &wd);
3061 snprintf(txt,256,"Started WinSock version %X.%02X\n", wd.wVersion/0x100, wd.wVersion&0xFF);
3062 message(txt, 2);
3064 #endif
3065 init_area(); /* initialize playing area */
3066 hash_table_init();
3068 #ifdef WIN32
3069 if ( !consoleApp )
3070 ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 2000);
3071 #endif
3073 message("Loading sprites.\n",2);
3074 load_sprites(DATA_PATH GAME_SPRITES_FILE); /* players, corpses, bullets, ... */
3075 if (find_sprite("bullet",&bullet_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"bullet\".\n");ERROR(msg);EXIT(1);}
3076 if (find_sprite("slug",&slug_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"slug\".\n");ERROR(msg);EXIT(1);}
3077 if (find_sprite("shell",&shell_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"shell\".\n");ERROR(msg);EXIT(1);}
3078 if (find_sprite("sshell",&shotgun_shell_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"sshell\".\n");ERROR(msg);EXIT(1);}
3079 if (find_sprite("grenade",&grenade_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"grenade\".\n");ERROR(msg);EXIT(1);}
3080 if (find_sprite("mess1",&mess1_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess1\".\n");ERROR(msg);EXIT(1);}
3081 if (find_sprite("mess2",&mess2_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess2\".\n");ERROR(msg);EXIT(1);}
3082 if (find_sprite("mess3",&mess3_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess3\".\n");ERROR(msg);EXIT(1);}
3083 if (find_sprite("mess4",&mess4_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"mess4\".\n");ERROR(msg);EXIT(1);}
3084 if (find_sprite("noise",&noise_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"noise\".\n");ERROR(msg);EXIT(1);}
3085 if (find_sprite("bfgcell",&bfgcell_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"bfgcell\".\n");ERROR(msg);EXIT(1);}
3086 for (a=0;a<N_SHRAPNELS;a++)
3088 snprintf(txt, sizeof(txt), "shrapnel%d",a+1);
3089 if (find_sprite(txt,&shrapnel_sprite[a])){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3090 snprintf(txt, sizeof(txt), "bfgbit%d",a+1);
3091 if (find_sprite(txt,&bfgbit_sprite[a])){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3092 snprintf(txt, sizeof(txt), "bloodrain%d",a+1);
3093 if (find_sprite(txt,&bloodrain_sprite[a])){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3095 snprintf(txt, sizeof(txt), "jetfire");
3096 if (find_sprite(txt,&jetfire_sprite)){char msg[256];snprintf(msg,256,"Can't find sprite \"%s\".\n",txt);ERROR(msg);EXIT(1);}
3098 LEVEL=load_level(level_number);
3099 level_checksum=md5_level(level_number);
3100 if (!LEVEL){char txt[256];snprintf(txt,256,"Can't load level number %d\n",level_number);ERROR(txt);EXIT(1);}
3101 snprintf(txt,256,"Loading level \"%s\"....\n",LEVEL);
3102 message(txt,2);
3103 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,LEVEL_SPRITES_SUFFIX);
3104 message("Loading level graphics.\n",2);
3105 load_sprites(txt);
3106 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
3107 message("Loading level map.\n",2);
3108 load_data(txt);
3109 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,DYNAMIC_DATA_SUFFIX);
3110 message("Loading level objects.\n",2);
3111 mem_free(LEVEL);
3112 load_dynamic(txt);
3114 message("Initializing socket.\n",2);
3115 init_socket(); /* initialize socket */
3117 message("Installing signal handlers.\n",2);
3118 signal(SIGINT,signal_handler);
3119 signal(SIGTERM,signal_handler);
3120 signal(SIGFPE,signal_handler);
3121 signal(SIGILL,signal_handler);
3122 signal(SIGABRT,signal_handler);
3123 #ifndef WIN32
3124 signal(SIGBUS,signal_handler);
3125 signal(SIGQUIT,signal_handler);
3126 #endif
3127 message("Game started.\n",2);
3129 #ifdef __EMX__
3130 DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 1, 0);
3131 #endif
3133 game_start=get_time();
3134 srandom(game_start);
3136 #ifdef WIN32
3137 if ( !consoleApp )
3138 ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
3139 #endif
3141 last_time=get_time();
3142 again:
3143 last_time+=PERIOD_USEC;
3144 if (get_time()-last_time>PERIOD_USEC*100)last_time=get_time();
3145 read_data();
3146 update_timeq();
3147 update_game();
3148 update_players(); /* MUST come after update_game otherwise when player shoots he hit himself */
3149 send_chunks();
3150 last_tick=get_time();
3151 if (!active_players&&(last_tick-last_player_left)>DELAY_BEFORE_SLEEP_USEC&&(last_tick-last_packet_came)>DELAY_BEFORE_SLEEP_USEC)
3153 #ifndef WIN32
3154 message("Sleep\n",2);
3156 fd_set fds;
3157 FD_ZERO(&fds);
3158 FD_SET(fd,&fds);
3159 select(fd+1,&fds,0,0,0);
3161 message("Wakeup\n",2);
3162 #else
3163 WaitForSingleObject(&fd, 500); /* wait max. 0.5 seconds, then we must test hServerExitEvent */
3164 #endif
3166 #ifdef WIN32
3167 /* we must return so that the service can be properly stopped */
3168 if ( hServerExitEvent )
3169 return 0;
3170 #endif
3171 sleep_until(last_time+PERIOD_USEC);
3172 goto again;
3174 return 0;
3178 int main(int argc, char **argv)
3180 int a;
3182 #ifdef WIN32
3183 SERVICE_TABLE_ENTRY dispatchTable[]={{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain}, {NULL, NULL}};
3184 if ( argc==1 ) {
3185 if ( !StartServiceCtrlDispatcher(dispatchTable) ) {
3186 globErr=GetLastError();
3187 /*LPTSTR pszError=CErrorContext::LoadWin32ErrorString(globErr);
3188 ::CharToOem(pszError, pszError);
3189 _tprintf(_T("StartServiceCtrlDispatcher failed: %u"), globErr);
3190 if ( pszError!=NULL ) {
3191 _tprintf(_T(": %s\r\n"), pszError);
3192 ::LocalFree(pszError);
3194 else
3195 _tprintf(_T("\r\n"));*/
3196 AddToMessageLog("StartServiceCtrlDispatcher failed", 0);
3199 consoleApp=1;
3200 #endif
3201 chdir_to_data_files();
3202 parse_command_line(argc,argv);
3204 a=server();
3205 free_all_memory();
3206 check_memory_leaks();
3207 if (fd) close(fd);
3208 return a;