9 #ifdef TIME_WITH_SYS_TIME
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
39 #ifdef HAVE_SYS_SELECT_H
40 #include <sys/select.h>
59 unsigned short port
=DEFAULT_PORT
; /* game port (not a gameport ;-) )*/
60 int level_number
=0; /* line number in the LEVEL_FILE */
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
,
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 */
77 unsigned short weapons_order
[ARMS
]={4,0,3,1,2,5};
79 struct birthplace_type
89 struct player_list
*next
,*prev
;
94 /* time queue of respawning objects */
97 struct queue_list
* next
;
98 unsigned long_long time
;
103 /* list of objects */
104 struct object_list objects
;
106 struct player_list
*last_player
;
107 struct object_list
*last_obj
;
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 */
122 SERVICE_STATUS ssStatus
;
123 SERVICE_STATUS_HANDLE sshStatusHandle
;
124 DWORD globErr
=ERROR_SUCCESS
;
126 int hServerExitEvent
=0; /* close server flag */
128 LPTSTR
GetLastErrorText(LPTSTR lpszBuf
, DWORD dwSize
) {
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
);
138 lpszTemp
[lstrlen(lpszTemp
)-2] = TEXT('\0');
139 CharToOem(lpszTemp
, lpszTemp
);
140 snprintf(lpszBuf
, sizeof(lpszBuf
), ": %u: %s", globErr
, lpszTemp
);
143 LocalFree((HLOCAL
)lpszTemp
);
147 void CmdInstallService(LPCTSTR pszUserName
, LPCTSTR pszUserPassword
, LPCTSTR pszDependencies
) {
148 SC_HANDLE schService
;
149 SC_HANDLE schSCManager
;
151 printf("Installing %s as ", SERVICE_NAME
);
152 if ( pszUserName
==NULL
)
153 printf("LOCAL_SYSTEM");
155 printf("\"%s\"", pszUserName
);
156 if ( pszUserPassword
)
157 printf("/\"%s\"", pszUserPassword
);
160 if ( GetModuleFileName(NULL
, szPath
, 2046)==0 ) {
161 printf("Unable to install %s%s\r\n", SERVICE_NAME
, GetLastErrorText(szErr
, 2046));
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 */
181 printf("%s was installed successfully.\r\n", SERVICE_NAME
);
182 globErr
=ERROR_SUCCESS
;
183 CloseServiceHandle(schService
);
186 printf("CreateService failed%s\r\n", GetLastErrorText(szErr
, 2046));
187 CloseServiceHandle(schSCManager
);
190 printf("OpenSCManager failed%s\r\n", GetLastErrorText(szErr
, 2046));
193 void CmdRemoveService() {
194 SC_HANDLE schService
,
196 schSCManager
=OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
197 if ( schSCManager
) {
198 schService
=OpenService(schSCManager
, SERVICE_NAME
, SERVICE_ALL_ACCESS
);
200 if ( ControlService(schService
, SERVICE_CONTROL_STOP
, &ssStatus
) ) {
201 printf("Stopping %s...\r\n", SERVICE_NAME
);
203 while( QueryServiceStatus(schService
, &ssStatus
) ) {
204 if ( ssStatus
.dwCurrentState
==SERVICE_STOP_PENDING
) {
211 if ( ssStatus
.dwCurrentState
== SERVICE_STOPPED
)
212 printf("\r\n%s stopped successfully.\r\n", SERVICE_NAME
);
214 printf("\r\n%s failed to stop.\r\n", SERVICE_NAME
);
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
);
223 printf("DeleteService failed%s\r\n", GetLastErrorText(szErr
, 2046));
224 CloseServiceHandle(schService
);
227 printf("OpenService failed%s\r\n", GetLastErrorText(szErr
, 2046));
228 CloseServiceHandle(schSCManager
);
231 printf("OpenSCManager failed%s\r\n", GetLastErrorText(szErr
, 2046));
234 void AddToMessageLog(LPTSTR lpszMsg
, int infoOnly
) {
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;
255 if ( dwCurrentState
==SERVICE_START_PENDING
)
256 ssStatus
.dwControlsAccepted
=0;
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;
268 ssStatus
.dwCheckPoint
=dwCheckPoint
++;
269 if ( !(fResult
=SetServiceStatus(sshStatusHandle
, &ssStatus
)) ) {
270 globErr
=GetLastError();
271 AddToMessageLog("SetServiceStatus failed", 0);
281 void WINAPI
ServiceCtrl(DWORD dwCtrlCode
) {
282 switch( dwCtrlCode
) {
283 case SERVICE_CONTROL_STOP
:
284 ReportStatusToSCMgr(SERVICE_STOP_PENDING
, NO_ERROR
, 500);
288 if ( hServerExitEvent
)
289 ReportStatusToSCMgr(SERVICE_STOP_PENDING
, NO_ERROR
, 0);
291 ReportStatusToSCMgr(SERVICE_RUNNING
, NO_ERROR
, 0);
295 void ServiceStart(DWORD dwArgc
, LPTSTR
*lpszArgv
) {
297 SetCurrentDirectory(lpszArgv
[1]);
301 GetModuleFileName(NULL
, path
, sizeof(path
));
302 p2
=path
+strlen(path
);
303 while(( p2
>=path
)&&( *p2
!='\\' )&&( *p2
!='/' ))
306 SetCurrentDirectory(path
);
311 void WINAPI
ServiceMain(DWORD dwArgc
, LPTSTR
*lpszArgv
) {
312 if ( !(sshStatusHandle
=RegisterServiceCtrlHandler(SERVICE_NAME
, ServiceCtrl
)) )
315 ssStatus
.dwServiceType
=SERVICE_WIN32_OWN_PROCESS
;
316 ssStatus
.dwServiceSpecificExitCode
=0;
317 if ( !ReportStatusToSCMgr(SERVICE_START_PENDING
, NO_ERROR
, 3000))
321 ServiceStart(dwArgc
, lpszArgv
);
324 ReportStatusToSCMgr(SERVICE_STOPPED
, globErr
, 0);
327 /* WINDOWS NT SERVICE INSTALLATION/REMOVAL */
328 /*******************************************/
332 /* load dynamic data */
333 static void load_dynamic(char * filename
)
336 static char line
[1024];
341 if (!(stream
=fopen(filename
,"rb")))
343 if (!fopen_s(&stream
, filename
, "rb"))
347 snprintf(msg
,256,"Can't open file \"%s\"!\n",filename
);
351 while(fgets(line
,1024,stream
))
355 for (name
=p
;(*p
)!=' '&&(*p
)!=9&&(*p
)!=10&&(*p
);p
++);
359 if ((t
=_convert_type(*p
))<0){char msg
[256];snprintf(msg
,256,"Unknown object type '%c'.\n",*p
);ERROR(msg
);EXIT(1);}
365 if (t
==TYPE_BIRTHPLACE
) /* birthplace */
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
;
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);
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
)
387 static char timestamp
[64];
398 localtime_s(&tm
, &t
);
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
);
406 printf("%s%s",timestamp
,msg
);
411 fprintf(stderr
,"%s%s",timestamp
,msg
);
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};
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
)
438 for(i
=ARMS
-1;i
>=0;i
--)
440 if(weapons_order
[i
]==p
->current_weapon
)
442 if(weapons_order
[i
]==weapon
)
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
);
470 ERROR("Error: Can't create socket!\n");
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
)))
481 snprintf(msg
,256,"Error: Can't bind socket to port %d!\n",port
);
488 /* selects random birthplace and returns */
489 static void find_birthplace(int *x
,int *y
)
491 int a
=random()%n_birthplaces
;
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
)
505 snprintf(txt
, sizeof(txt
), "hero%d",num
);
506 if (find_sprite(txt
,&a
))return -1;
511 /* initialize player */
512 static void init_player(struct player
* p
,int x
,int y
)
517 p
->health_ep
=ILLNESS_SPEED
;
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;
527 p
->ammo
[WEAPON_GUN
]=weapon
[WEAPON_GUN
].basic_ammo
;
528 p
->ammo
[WEAPON_CHAINSAW
]=weapon
[WEAPON_CHAINSAW
].basic_ammo
;
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
)
544 struct player_list
*cp
;
546 /* alloc memory for new player */
547 cp
=mem_alloc(sizeof(struct player_list
));
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
;
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
);
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
)));
572 {mem_free(cp
->member
.name
);mem_free(cp
);message("Can't create object.\n",1);return 1;}
574 init_player(&(cp
->member
),int2double(x
),int2double(y
));
577 cp
->prev
=last_player
;
579 last_player
->next
=cp
;
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;
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
);
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
));
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
)
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 */
672 /* send a packet to all players except one */
673 /* if not_this_player is null, sends to all players */
676 1=update speed+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];
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
768 default: /* don't update */
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
));
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];
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
));
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];
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
));
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
)
832 fa
=(*((struct player
**)a
))->frags
;
833 fb
=(*((struct player
**)b
))->frags
;
834 da
=(*((struct player
**)a
))->deaths
;
835 db
=(*((struct player
**)b
))->deaths
;
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
)
854 int p
=active_players
>TOP_PLAYERS_N
?TOP_PLAYERS_N
:active_players
;
856 struct player
**t
; /* table for qsort */
857 struct player_list
*q
;
860 t
=mem_alloc(active_players
*sizeof(struct player
*));
862 packet
=mem_alloc(1+4+1+p
*(MAX_NAME_LEN
+4+4));
865 /* fill table for quicksort */
866 for (a
=0,q
=(&players
);q
->next
;a
++,q
=q
->next
)
867 t
[a
]=&(q
->next
->member
);
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
);
877 /* put players into packet */
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);
887 sendall(packet
,offset
,0);
888 else send_packet(packet
,offset
,addr
,0,id
);
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
)
899 /* assert(maxlen > 2); */
900 packet
[0] = P_MESSAGE
;
905 n
= snprintf(packet
+ len
, maxlen
- len
, "%s", msg
);
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
);
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];
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];
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)
943 struct player_list
* p
;
946 for (p
=&players
;p
->next
;p
=p
->next
)
947 send_chunk_packet_to_player(&packet
,1,&(p
->next
->member
));
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];
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
);
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];
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];
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
);
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
));
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
)
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
)
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
;
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(
1105 void * data
,unsigned long_long t
)
1107 struct queue_list
*p
;
1108 struct queue_list
*q
;
1111 for (p
=&time_queue
;p
->next
&&p
->next
->member
.last_updated
<t
;p
=p
->next
);
1115 p
->next
=mem_alloc(sizeof(struct queue_list
));
1116 if (!p
->next
){p
->next
=q
;return 0;}
1121 p
->member
.xspeed
=xspeed
;
1122 p
->member
.yspeed
=yspeed
;
1123 p
->member
.type
=type
;
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
;
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);
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
;
1165 for(p
=&players
;p
->next
;p
=p
->next
)
1166 if (p
->next
->member
.id
==id
)
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
))
1179 /* create noise on given position */
1180 static void create_noise(int x
,int y
,struct player
*p
)
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
));
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
))
1204 /* read packet from socket */
1205 static void read_data(void)
1211 struct sockaddr_in client
;
1212 int a
=sizeof(client
);
1213 static char packet
[280];
1215 struct player_list
*q
;
1216 unsigned char min
,maj
;
1217 int s
,x
,y
,l
,offset
= 0;
1225 while (select(fd
+1,&rfds
,0,0,&tv
))
1227 if ((l
=recv_packet(packet
,256,(struct sockaddr
*)(&client
),&a
,0,0,&s
))==-1)
1230 last_packet_came
=get_time();
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);
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
);
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);
1259 if (strlen(packet
+5) > MAX_NAME_LEN
)
1261 snprintf(txt
,256,"Name too long, shortening it to %i characters\n",MAX_NAME_LEN
);
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);
1269 packet
[0]=P_PLAYER_REFUSED
;
1270 packet
[1]=E_NAME_IN_USE
;
1271 send_packet(packet
,2,(struct sockaddr
*)(&client
),0,0);
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);
1284 snprintf(txt
,256,"Player #%d accepted, name \"%s\", address %s.\n",n_players
,packet
+5,txt1
);
1286 snprintf(txt
,256,"%s entered the game.",packet
+5);
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
);
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
));
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
);
1313 case P_LEVEL_ACCEPTED
:
1314 q
=find_player(&client
,s
);
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
));
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
);
1333 case P_REENTER_GAME
:
1334 q
=find_player(&client
,s
);
1336 if (!(q
->member
.obj
->status
& S_DEAD
) || (q
->member
.obj
->status
& S_NOISE
))
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 */
1346 if (nonquitable
)break;
1347 q
=find_player(&client
,s
);
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
);
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
);
1365 snprintf(txt
,256,"%s left the game.\n",q
->member
.name
);
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
);
1376 if (l
<3)break; /* invalid packet */
1377 q
=find_player(&client
,s
);
1379 q
->member
.last_update
=get_time();
1380 q
->member
.keyboard_status
.status
=packet
[1];
1381 q
->member
.keyboard_status
.weapon
=packet
[2];
1386 break; /* invalid packet */
1387 q
= find_player(&client
, s
);
1390 sendall_message(q
->member
.name
, packet
+ 2, 0, 0, M_CHAT
);
1391 snprintf(txt
, 256, "%s> %s\n", q
->member
.name
, packet
+ 2);
1396 snprintf(txt
,256,"Unknown packet: head=%d\n",*packet
);
1404 /* compute collision of two objects */
1405 /* return value: 0=nothing */
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
)
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;
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;
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
)
1431 static char txt
[32];
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);
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
)
1453 o
=new_obj(id
,T_CORPSE
,CORPSE_TTL
,mess1_sprite
,0,0,int2double(x
),int2double(y1
),0,0,0);
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);
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);
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);
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);
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);
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);
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);
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);
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
)
1507 struct player_list
*pl
;
1508 struct object_list
*ol
;
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
))
1533 case T_AMMO_GRENADE
:
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
);
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);
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
);
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);
1576 case T_AMMO_SHOTGUN
:
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
);
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);
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
);
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);
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
);
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);
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
);
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);
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
);
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);
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
);
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);
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
);
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);
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
);
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);
1773 case T_INVISIBILITY
:
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
);
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);
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
);
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);
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
));
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
);
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);
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
);
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);
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
);
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);
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
;
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
);
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);
1882 if (p
->type
!=T_PLAYER
|| ((struct player
*)(p
->data
))->obj
->status
& S_ILL
)
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
);
1891 sendall_update_object(p
,0,0); /* update everything */
1892 send_update_player((struct player
*)(p
->data
));
1897 if (p
->type
!=T_PLAYER
)
1899 if (((struct player
*)(p
->data
))->obj
->id
== (long)obj
->data
|| ((struct player
*)(p
->data
))->obj
->status
& S_ONFIRE
)
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
));
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
)
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
);
1927 sendall_update_object(p
,0,0); /* update everything */
1928 send_update_player((struct player
*)(p
->data
));
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
)
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
);
1947 sendall_update_object(p
,0,0); /* update everything */
1948 send_update_player((struct player
*)(p
->data
));
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
);
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 */
1978 create_mess(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-MESS_HEIGHT
,py
);
1980 create_corpse(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-CORPSE_HEIGHT
,((struct player
*)(p
->data
))->color
,0);
1985 A
=(c
>=A
)?0:(A
-c
); /* armor */
1986 send_update_player((struct player
*)(p
->data
));
1991 if (p
->type
==T_CORPSE
)
1997 packet
[offset
++]=P_DELETE_OBJECT
;
1998 put_int(packet
,p
->id
,&offset
);
1999 sendall_chunked(packet
,offset
,0);
2001 create_mess(px
,py
,py
);
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
);
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
);
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
);
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
);
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 */
2060 send_update_player((struct player
*)(o
->data
)); /* owner of bullet/shrapnel */
2063 create_mess(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-MESS_HEIGHT
,py
);
2065 create_corpse(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-CORPSE_HEIGHT
,((struct player
*)(p
->data
))->color
,0);
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
));
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;
2082 sendall_new_object(meat
,0);
2083 meatcounter
= (meatcounter
+1)%3;
2102 /* recompute objects positions */
2103 static void update_game(void)
2105 static char packet
[64];
2107 struct object_list
*p
, *p2
;
2108 struct player_list
*q
;
2110 unsigned char stop_x
,stop_y
;
2114 struct it
*s
; /* for grenades throwing */
2115 unsigned int status
;
2117 unsigned long_long t
;
2118 unsigned int old_status
;
2120 int old_x
,old_y
,old_x_speed
,old_y_speed
;
2123 for(p
=&objects
;p
->next
;p
=p
->next
)
2125 if (p
->next
->member
.type
==T_NOTHING
)
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
);
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
);
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
);
2188 send_update_player((struct player
*)(p
->next
->member
.data
)); /* dead player */
2189 sendall_update_status(&(p
->next
->member
),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
))
2200 if (p
->next
->member
.ttl
>0)
2202 p
->next
->member
.ttl
--;
2204 if (p
->next
->member
.type
==T_NOISE
&&p
->next
->member
.ttl
==(NOISE_TTL
>>1))
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
)
2225 weapon
[WEAPON_GRENADE
].ttl
,
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
));
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
)
2244 p
->next
->member
.status
&= ~S_SHOOTING
;
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);
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
],
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
);
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 */
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
);
2291 delete_obj(p
->next
->member
.id
);
2292 if (!(p
->next
))return;
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;
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
);
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
;
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
);
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);
2343 p
->next
->member
.x
+mul(p
->next
->member
.xspeed
,DELTA_TIME
),
2344 p
->next
->member
.y
+mul(p
->next
->member
.yspeed
,DELTA_TIME
),
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
;
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
;
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 */
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;
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
)) &&
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
));
2407 case 1: /* object dies */
2409 packet
[offset
++]=P_DELETE_OBJECT
;
2410 put_int(packet
,p
->next
->member
.id
,&offset
);
2411 sendall_chunked(packet
,offset
,0);
2414 delete_obj(p
->next
->member
.id
);
2415 if (!(p
->next
))return;
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
);
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
;
2456 /* delete birthplaces */
2457 if (n_birthplaces
)mem_free(birthplace
);
2459 /* delete sprites */
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
)
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
);
2489 check_memory_leaks();
2494 signal(sig_num
,SIG_DFL
);
2500 /* walk with given player */
2501 static void walk_player(struct player
*q
,int direction
, int speed
, int creep
)
2505 unsigned int old_status
=q
->obj
->status
;
2506 int old_ttl
=q
->obj
->ttl
;
2507 int old_x
=q
->obj
->x
,
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 */
2517 if (!(q
->obj
->status
& S_CREEP
))
2518 q
->obj
->y
+=CREEP_YOFFSET
;
2519 q
->obj
->status
|= S_CREEP
;
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
;
2532 q
->obj
->status
&= ~S_WALKING
;
2537 q
->obj
->status
|= S_WALKING
;
2538 q
->obj
->xspeed
-=WALK_ACCEL
;
2539 if (q
->obj
->xspeed
<-a
)q
->obj
->xspeed
=-a
;
2543 q
->obj
->status
|= S_WALKING
;
2544 q
->obj
->xspeed
+=WALK_ACCEL
;
2545 if (q
->obj
->xspeed
>a
)q
->obj
->xspeed
=a
;
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
)
2560 if (p
->obj
->status
& ((jet
? 0 : S_FALLING
) | S_CREEP
))
2562 p
->obj
->status
|= S_FALLING
;
2563 p
->obj
->yspeed
=-SPEED_JUMP
;
2565 p
->obj
->status
|= S_JETPACK_ON
;
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)),
2580 (void *)(long)(p
->obj
->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
)
2597 if (q
->current_weapon
==w
)return;
2598 if (!(q
->weapons
&(1<<w
)))
2599 {send_message(q
,0,"No weapon.", M_INFO
);return;}
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
);
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
)
2615 q
->obj
->status
&= ~S_CHAINSAW
; /* chainsaw */
2617 if (q
->current_weapon
==WEAPON_BLOODRAIN
) {
2618 q
->obj
->status
|= S_BLOODRAIN
;
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
)))
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 */
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
));
2649 sendall_new_object(s
,0);
2650 s
=new_obj( /* straight */
2653 weapon
[q
->current_weapon
].ttl
,
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
));
2663 sendall_new_object(s
,0);
2664 s
=new_obj( /* straight */
2667 weapon
[q
->current_weapon
].ttl
,
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
));
2677 sendall_new_object(s
,0);
2678 s
=new_obj( /* one up */
2681 weapon
[q
->current_weapon
].ttl
,
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
));
2691 sendall_new_object(s
,0);
2692 s
=new_obj( /* two up */
2695 weapon
[q
->current_weapon
].ttl
,
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
));
2705 sendall_new_object(s
,0);
2706 s
=new_obj( /* one down */
2709 weapon
[q
->current_weapon
].ttl
,
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
));
2719 sendall_new_object(s
,0);
2720 s
=new_obj( /* two down */
2723 weapon
[q
->current_weapon
].ttl
,
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
));
2733 sendall_new_object(s
,0);
2735 else if (q
->current_weapon
==WEAPON_BFG
) {
2736 s
=new_obj( /* straight */
2739 weapon
[q
->current_weapon
].ttl
,
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
));
2749 sendall_new_object(s
,0);
2751 else if (q
->current_weapon
==WEAPON_CHAINSAW
) {
2755 weapon
[q
->current_weapon
].ttl
,
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
));
2765 sendall_new_object(s
,0);
2769 weapon
[q
->current_weapon
].ttl
,
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
));
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 */
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
));
2801 sendall_new_object(s
,0);
2805 weapon
[q
->current_weapon
].ttl
,
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
));
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
)
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
;
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
);
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 */
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
);
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 */
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
;
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
);
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;
2907 move_player(&(p
->next
->member
));
2912 /* write help message to stdout */
2913 static void print_help(void)
2917 p
= "Portions (c) 2000 by Mikulas Patocka\n";
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");
2930 printf( "0verkill server.\n"
2931 "(c)2000 Brainsoft\n"
2933 "Usage: server [-nh] [-l <level number>] [-p <port number>]\n"
2934 "-n Server can't be ended by client\n", p
2940 static void parse_command_line(int argc
,char **argv
)
2948 a
=getopt(argc
,argv
,"hl:np:ri:Ic");
2950 a
=getopt(argc
,argv
,"hl:np:");
2963 break; /* run as console app */
2964 case 'r': /* remove service */
2967 case 'i': { /* install service */
2973 username
[sizeof(username
)-1]=0;
2975 if ( (pass
=strchr(optarg
, '/'))==NULL
) {
2977 strcpy(username
, optarg
);
2979 strcpy_s(username
, sizeof(optarg
), optarg
);
2981 memcpy(username
, optarg
, sizeof(username
)-1);
2985 int size
=pass
-optarg
;
2986 if ( size
>sizeof(username
)-1 )
2987 size
=sizeof(username
)-1;
2988 memcpy(username
, optarg
, size
);
2992 if ( size
>sizeof(password
)-1 )
2993 size
=sizeof(password
)-1;
2994 memcpy(password
, pass
, size
);
2997 CmdInstallService(user
, pass
, NULL
);
3000 case 'I': { /* install service */
3001 CmdInstallService(NULL
, NULL
, NULL
);
3011 port
=(unsigned short)strtoul(optarg
,&c
,10);
3012 if (*c
){ERROR("Error: Not a number.\n");EXIT(1);}
3015 if (!port
){ERROR("Error: Number underflow.\n");EXIT(1);}
3016 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3021 level_number
=strtoul(optarg
,&c
,10);
3022 if (*c
){ERROR("Error: Not a number.\n");EXIT(1);}
3025 if (!level_number
){ERROR("Error: Number underflow.\n");EXIT(1);}
3026 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3038 /*-----------------------------------------------------------------------------------*/
3039 static int server(void)
3043 unsigned long_long last_time
;
3046 last_player
=&players
;
3049 snprintf(txt
,256,"Running 0verkill server version %d.%d\n",VERSION_MAJOR
,VERSION_MINOR
);
3052 snprintf(txt
,256,"This is 0verkill server for Win32, build #%u\n",VERSION_PORT
);
3055 message("Initialization.\n",2);
3057 message("Starting Windows Sockets\n",2);
3060 WSAStartup(0x101, &wd
);
3061 snprintf(txt
,256,"Started WinSock version %X.%02X\n", wd
.wVersion
/0x100, wd
.wVersion
&0xFF);
3065 init_area(); /* initialize playing area */
3070 ReportStatusToSCMgr(SERVICE_START_PENDING
, NO_ERROR
, 2000);
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
);
3103 snprintf(txt
,256,"%s%s%s",DATA_PATH
,LEVEL
,LEVEL_SPRITES_SUFFIX
);
3104 message("Loading level graphics.\n",2);
3106 snprintf(txt
,256,"%s%s%s",DATA_PATH
,LEVEL
,STATIC_DATA_SUFFIX
);
3107 message("Loading level map.\n",2);
3109 snprintf(txt
,256,"%s%s%s",DATA_PATH
,LEVEL
,DYNAMIC_DATA_SUFFIX
);
3110 message("Loading level objects.\n",2);
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
);
3124 signal(SIGBUS
,signal_handler
);
3125 signal(SIGQUIT
,signal_handler
);
3127 message("Game started.\n",2);
3130 DosSetPriority(PRTYS_PROCESS
, PRTYC_FOREGROUNDSERVER
, 1, 0);
3133 game_start
=get_time();
3134 srandom(game_start
);
3138 ReportStatusToSCMgr(SERVICE_RUNNING
, NO_ERROR
, 0);
3141 last_time
=get_time();
3143 last_time
+=PERIOD_USEC
;
3144 if (get_time()-last_time
>PERIOD_USEC
*100)last_time
=get_time();
3148 update_players(); /* MUST come after update_game otherwise when player shoots he hit himself */
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
)
3154 message("Sleep\n",2);
3159 select(fd
+1,&fds
,0,0,0);
3161 message("Wakeup\n",2);
3163 WaitForSingleObject(&fd
, 500); /* wait max. 0.5 seconds, then we must test hServerExitEvent */
3167 /* we must return so that the service can be properly stopped */
3168 if ( hServerExitEvent
)
3171 sleep_until(last_time
+PERIOD_USEC
);
3178 int main(int argc
, char **argv
)
3183 SERVICE_TABLE_ENTRY dispatchTable
[]={{SERVICE_NAME
, (LPSERVICE_MAIN_FUNCTION
)ServiceMain
}, {NULL
, NULL
}};
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);
3195 _tprintf(_T("\r\n"));*/
3196 AddToMessageLog("StartServiceCtrlDispatcher failed", 0);
3201 chdir_to_data_files();
3202 parse_command_line(argc
,argv
);
3206 check_memory_leaks();