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,last_player
->member
.id
);
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,last_player
->member
.id
);
1259 if (is_playername_in_use(packet
+5))
1261 snprintf(txt
,256,"Name \"%s\" already in use. Player refused.\n",packet
+5);
1263 packet
[0]=P_PLAYER_REFUSED
;
1264 packet
[1]=E_NAME_IN_USE
;
1265 send_packet(packet
,2,(struct sockaddr
*)(&client
),0,last_player
->member
.id
);
1269 find_birthplace(&x
,&y
);
1270 if (add_player(packet
[4],packet
+5,&client
,x
,y
)) /* failed to add player */
1272 message("Player refused.\n",2);
1273 packet
[0]=P_PLAYER_REFUSED
;
1274 packet
[1]=E_PLAYER_REFUSED
;
1275 send_packet(packet
,2,(struct sockaddr
*)(&client
),0,last_player
->member
.id
);
1278 snprintf(txt
,256,"Player #%d accepted, name \"%s\", address %s.\n",n_players
,packet
+5,txt1
);
1280 snprintf(txt
,256,"%s entered the game.",packet
+5);
1283 packet
[offset
++]=P_PLAYER_ACCEPTED
;
1284 last_player
->member
.obj
->status
|= S_DEAD
;
1285 put_int(packet
,last_player
->member
.obj
->id
,&offset
);
1286 put_int16(packet
,last_player
->member
.obj
->sprite
,&offset
);
1287 put_int(packet
,last_player
->member
.obj
->x
,&offset
);
1288 put_int(packet
,last_player
->member
.obj
->y
,&offset
);
1289 put_int(packet
,last_player
->member
.obj
->xspeed
,&offset
);
1290 put_int(packet
,last_player
->member
.obj
->yspeed
,&offset
);
1291 put_int(packet
,last_player
->member
.obj
->status
,&offset
);
1293 put_long_long(packet
,t
-game_start
,&offset
);
1294 put_int(packet
,last_player
->member
.id
,&offset
);
1295 packet
[offset
++]=VERSION_MAJOR
;
1296 packet
[offset
++]=VERSION_MINOR
;
1297 send_packet(packet
,offset
,(struct sockaddr
*)(&client
),0,0);
1298 send_change_level(&(last_player
->member
));
1300 sendall_message(0,txt
,0,0, M_ENTER
);
1301 snprintf(txt
,256,"There'%s %d %s in the game.",active_players
==1?"s":"re",active_players
,active_players
==1?"player":"players");
1302 sendall_message(0,txt
,0,0, M_INFO
);
1307 case P_LEVEL_ACCEPTED
:
1308 q
=find_player(&client
,s
);
1310 if (q
->member
.current_level
>=0)break;
1312 q
->member
.current_level
=level_number
;
1313 sendall_new_object(q
->member
.obj
,&(q
->member
));
1314 create_noise(double2int(q
->member
.obj
->x
),double2int(q
->member
.obj
->y
),&(q
->member
));
1315 /* send all objects in the game */
1316 send_objects(&(q
->member
),q
->member
.obj
);
1317 /* send all objects waiting for respawn */
1318 send_timeq_objects(&(q
->member
));
1322 q
=find_player(&client
,s
);
1323 if (!q
) send_info((struct sockaddr
*)(&client
),0);
1324 else send_info((struct sockaddr
*)(&client
),q
->member
.id
);
1327 case P_REENTER_GAME
:
1328 q
=find_player(&client
,s
);
1330 if (!(q
->member
.obj
->status
& S_DEAD
) || (q
->member
.obj
->status
& S_NOISE
))
1332 find_birthplace(&x
,&y
);
1333 create_noise(x
,y
,&(q
->member
));
1334 q
->member
.obj
->x
=int2double(x
);
1335 q
->member
.obj
->y
=int2double(y
);
1336 sendall_update_object(q
->member
.obj
,0,3); /* update coordinates */
1340 if (nonquitable
)break;
1341 q
=find_player(&client
,s
);
1345 memcpy(packet
+1,p
->name
,strlen(p
->name
)+1);
1346 sendall(packet
,2+strlen(p
->name
),0);
1347 snprintf(txt
,256,"Game terminated by player \"%s\".\n",p
->name
);
1351 case P_QUIT_REQUEST
:
1352 q
=find_player(&client
,s
);
1353 if (!q
) /* this player has been deleted, but due to network inconsistency he doesn't know it */
1355 packet
[0]=P_PLAYER_DELETED
;
1356 send_packet(packet
,1,(struct sockaddr
*)(&client
),0,last_player
->member
.id
);
1359 snprintf(txt
,256,"%s left the game.\n",q
->member
.name
);
1361 packet
[0]=P_PLAYER_DELETED
;
1362 send_packet((char *)packet
,1,(struct sockaddr
*)(&client
),0,last_player
->member
.id
);
1363 snprintf(txt
,256,"%s left the game.",q
->member
.name
);
1364 sendall_message(0,txt
,0,0, M_LEAVE
);
1370 if (l
<3)break; /* invalid packet */
1371 q
=find_player(&client
,s
);
1373 q
->member
.last_update
=get_time();
1374 q
->member
.keyboard_status
.status
=packet
[1];
1375 q
->member
.keyboard_status
.weapon
=packet
[2];
1380 break; /* invalid packet */
1381 q
= find_player(&client
, s
);
1384 sendall_message(q
->member
.name
, packet
+ 2, 0, 0, M_CHAT
);
1385 snprintf(txt
, 256, "%s> %s\n", q
->member
.name
, packet
+ 2);
1390 snprintf(txt
,256,"Unknown packet: head=%d\n",*packet
);
1398 /* compute collision of two objects */
1399 /* return value: 0=nothing */
1401 static int collision(int x1
,int y1
,int t1
,int s1
,struct pos
* p1
,int x2
,int y2
,int t2
,int s2
,struct pos
*p2
)
1404 unsigned char h
=0,v
=0;
1406 get_dimensions(t1
,s1
,p1
,&w1
,&h1
);
1407 get_dimensions(t2
,s2
,p2
,&w2
,&h2
);
1409 if ((x2
>=x1
&&x2
<=x1
+w1
-1)||(x2
+w2
-1>=x1
&&x2
+w2
-1<=x1
+w1
-1))h
=1;
1410 if ((x1
>=x2
&&x1
<=x2
+w2
-1)||(x1
+w1
-1>=x2
&&x1
+w1
-1<=x2
+w2
-1))h
=1;
1413 if ((y2
>=y1
&&y2
<=y1
+h1
-1)||(y2
+h2
-1>=y1
&&y2
+h2
-1<=y1
+h1
-1))v
=1;
1414 if ((y1
>=y2
&&y1
<=y2
+h2
-1)||(y1
+h1
-1>=y2
&&y1
+h1
-1<=y2
+h2
-1))v
=1;
1420 /* create corpse on given position and with color num */
1421 /* num is number of dead player */
1422 static void create_corpse(int x
,int y
,int num
, int status
)
1425 static char txt
[32];
1427 int xoffs
=num
>15?-15:-5;
1428 int yoffs
=num
>15?-1:0;
1430 snprintf(txt
, sizeof(txt
), "corpse%d",num
);
1431 if (find_sprite(txt
,&a
))return;
1433 o
=new_obj(id
,T_CORPSE
,CORPSE_TTL
,a
,0,status
,int2double(x
+xoffs
),int2double(y
+yoffs
),0,0,0);
1436 sendall_new_object(o
,0);
1440 /* create mess on given position */
1441 /* y1=y coordinate of the mess */
1442 /* y2=y coordinate of the player (place where blood gushes and guts fly from */
1443 static void create_mess(int x
,int y1
,int y2
)
1447 o
=new_obj(id
,T_CORPSE
,CORPSE_TTL
,mess1_sprite
,0,0,int2double(x
),int2double(y1
),0,0,0);
1450 sendall_new_object(o
,0);
1452 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess2_sprite
,0,0,int2double(x
),int2double(y2
),-float2double(2*36),-float2double((double)1.4*36),0);
1455 sendall_new_object(o
,0);
1457 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess2_sprite
,0,0,int2double(x
),int2double(y2
),float2double((double)2.8*36),-float2double(1*36),0);
1460 sendall_new_object(o
,0);
1462 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess2_sprite
,0,0,int2double(x
),int2double(y2
),float2double(3*36),float2double((double).5*36),0);
1465 sendall_new_object(o
,0);
1467 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess3_sprite
,0,0,int2double(x
),int2double(y2
),-float2double((double)2.5*36),float2double((double).3*36),0);
1470 sendall_new_object(o
,0);
1472 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess4_sprite
,0,0,int2double(x
),int2double(y2
),-float2double((double)3.3*36),-float2double((double)2.1*36),0);
1475 sendall_new_object(o
,0);
1477 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess4_sprite
,0,0,int2double(x
),int2double(y2
),float2double((double)2.9*36),-float2double((double)1.7*36),0);
1480 sendall_new_object(o
,0);
1482 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess4_sprite
,0,0,int2double(x
),int2double(y2
),-float2double((double)1.3*36),float2double((double).8*36),0);
1485 sendall_new_object(o
,0);
1487 o
=new_obj(id
,T_MESS
,MESS_TTL
,mess3_sprite
,0,0,int2double(x
),int2double(y2
),float2double((double).7*36),-float2double((double)1.2*36),0);
1490 sendall_new_object(o
,0);
1494 /* compute collision of given object with the others */
1495 /* return value: 1=delete this object */
1496 /* 0=don't delete */
1497 /* 2= delete this object but don't send delete packet */
1498 static int dynamic_collision(struct it
*obj
)
1501 struct player_list
*pl
;
1502 struct object_list
*ol
;
1509 #define OX (double2int(obj->x))
1510 #define OY (double2int(obj->y))
1511 #define PX (double2int(p->x))
1512 #define PY (double2int(p->y))
1513 #define A ((struct player*)(p->data))->armor
1514 #define H ((struct player*)(p->data))->health
1515 #define P ((struct player*)(p->data))
1516 #define MAX_AMMO(x) (weapon[x].max_ammo)
1519 for (pl
=&players
;pl
->next
;pl
=pl
->next
)
1521 p
=pl
->next
->member
.obj
;
1522 if (p
->type
==T_PLAYER
&&(p
->status
& S_DEAD
))
1523 continue; /* dead player */
1524 if (collision(OX
,OY
,obj
->type
,obj
->status
,sprites
[obj
->sprite
].positions
,PX
,PY
,p
->type
,p
->status
,sprites
[p
->sprite
].positions
))
1527 case T_AMMO_GRENADE
:
1530 if (p
->type
!=T_PLAYER
)break;
1531 if (((struct player
*)(p
->data
))->ammo
[WEAPON_GRENADE
]==MAX_AMMO(WEAPON_GRENADE
))break;
1532 ((struct player
*)(p
->data
))->ammo
[WEAPON_GRENADE
]+=weapon
[WEAPON_GRENADE
].add_ammo
;
1533 if (((struct player
*)(p
->data
))->ammo
[WEAPON_GRENADE
]>MAX_AMMO(WEAPON_GRENADE
))
1534 ((struct player
*)(p
->data
))->ammo
[WEAPON_GRENADE
]=MAX_AMMO(WEAPON_GRENADE
);
1535 /* P->current_weapon=select_best_weapon(P); */
1536 send_update_player((struct player
*)(p
->data
));
1537 send_message((struct player
*)(p
->data
),0,"You got grenades", M_AMMO
);
1538 snprintf(txt
,256,"%s got grenades.\n",((struct player
*)(p
->data
))->name
);
1540 obj
->status
|= S_INVISIBLE
;
1541 add_to_timeq(obj
->id
,T_AMMO_GRENADE
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,AMMO_RESPAWN_TIME
);
1542 sendall_update_status(obj
,0);
1549 if (p
->type
!=T_PLAYER
)break;
1550 if (((struct player
*)(p
->data
))->ammo
[WEAPON_GUN
]==MAX_AMMO(WEAPON_GUN
))break;
1552 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_GUN
)
1553 && is_weapon_empty((struct player
*)(p
->data
), WEAPON_GUN
))
1554 P
->current_weapon
= WEAPON_GUN
;
1556 ((struct player
*)(p
->data
))->ammo
[WEAPON_GUN
]+=weapon
[WEAPON_GUN
].add_ammo
;
1557 if (((struct player
*)(p
->data
))->ammo
[WEAPON_GUN
]>MAX_AMMO(WEAPON_GUN
))
1558 ((struct player
*)(p
->data
))->ammo
[WEAPON_GUN
]=MAX_AMMO(WEAPON_GUN
);
1559 /* P->current_weapon=select_best_weapon(P); */
1560 send_update_player((struct player
*)(p
->data
));
1561 send_message((struct player
*)(p
->data
),0,"You got a magazine", M_AMMO
);
1562 snprintf(txt
,256,"%s got a magazine.\n",((struct player
*)(p
->data
))->name
);
1564 obj
->status
|= S_INVISIBLE
;
1565 add_to_timeq(obj
->id
,T_AMMO_GUN
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,AMMO_RESPAWN_TIME
);
1566 sendall_update_status(obj
,0);
1570 case T_AMMO_SHOTGUN
:
1573 if (p
->type
!=T_PLAYER
)break;
1574 if (((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]==MAX_AMMO(WEAPON_SHOTGUN
))break;
1576 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_SHOTGUN
)
1577 && is_weapon_empty((struct player
*)(p
->data
), WEAPON_SHOTGUN
))
1578 P
->current_weapon
= WEAPON_SHOTGUN
;
1580 ((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]+=weapon
[WEAPON_SHOTGUN
].add_ammo
;
1581 if (((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]>MAX_AMMO(WEAPON_SHOTGUN
))
1582 ((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]=MAX_AMMO(WEAPON_SHOTGUN
);
1583 /* P->current_weapon=select_best_weapon(P); */
1584 send_update_player((struct player
*)(p
->data
));
1585 send_message((struct player
*)(p
->data
),0,"You got shotgun shells", M_AMMO
);
1586 snprintf(txt
,256,"%s got shotgun shells.\n",((struct player
*)(p
->data
))->name
);
1588 obj
->status
|= S_INVISIBLE
;
1589 add_to_timeq(obj
->id
,T_AMMO_SHOTGUN
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,AMMO_RESPAWN_TIME
);
1590 sendall_update_status(obj
,0);
1597 if (p
->type
!=T_PLAYER
)break;
1598 if (((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]==MAX_AMMO(WEAPON_RIFLE
))break;
1600 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_RIFLE
)
1601 && is_weapon_empty((struct player
*)(p
->data
), WEAPON_RIFLE
))
1602 P
->current_weapon
= WEAPON_RIFLE
;
1604 ((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]+=weapon
[WEAPON_RIFLE
].add_ammo
;
1605 if (((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]>MAX_AMMO(WEAPON_RIFLE
))
1606 ((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]=MAX_AMMO(WEAPON_RIFLE
);
1607 /* P->current_weapon=select_best_weapon(P); */
1608 send_update_player((struct player
*)(p
->data
));
1609 send_message((struct player
*)(p
->data
),0,"You got cartridges", M_AMMO
);
1610 snprintf(txt
,256,"%s got cartridges.\n",((struct player
*)(p
->data
))->name
);
1612 obj
->status
|= S_INVISIBLE
;
1613 add_to_timeq(obj
->id
,T_AMMO_RIFLE
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,AMMO_RESPAWN_TIME
);
1614 sendall_update_status(obj
,0);
1621 if (p
->type
!=T_PLAYER
)break;
1622 if (((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]==MAX_AMMO(WEAPON_UZI
))break;
1624 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_UZI
)
1625 && is_weapon_empty((struct player
*)(p
->data
), WEAPON_UZI
))
1626 P
->current_weapon
= WEAPON_UZI
;
1628 ((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]+=weapon
[WEAPON_UZI
].add_ammo
;
1629 if (((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]>MAX_AMMO(WEAPON_UZI
))
1630 ((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]=MAX_AMMO(WEAPON_UZI
);
1631 /* P->current_weapon=select_best_weapon(P); */
1632 send_update_player((struct player
*)(p
->data
));
1633 send_message((struct player
*)(p
->data
),0,"You got ammo for Uzi", M_AMMO
);
1634 snprintf(txt
,256,"%s got Uzi ammo.\n",((struct player
*)(p
->data
))->name
);
1636 obj
->status
|= S_INVISIBLE
;
1637 add_to_timeq(obj
->id
,T_AMMO_UZI
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,AMMO_RESPAWN_TIME
);
1638 sendall_update_status(obj
,0);
1645 if (p
->type
!=T_PLAYER
)break;
1646 if ((((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]==MAX_AMMO(WEAPON_UZI
))&&((((struct player
*)(p
->data
))->weapons
)&WEAPON_MASK_UZI
))break;
1648 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_UZI
)
1649 && !is_weapon_usable((struct player
*)(p
->data
), WEAPON_UZI
))
1650 P
->current_weapon
= WEAPON_UZI
;
1652 ((struct player
*)(p
->data
))->weapons
|=WEAPON_MASK_UZI
;
1653 ((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]+=weapon
[WEAPON_UZI
].basic_ammo
;
1654 if (((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]>MAX_AMMO(WEAPON_UZI
))
1655 ((struct player
*)(p
->data
))->ammo
[WEAPON_UZI
]=MAX_AMMO(WEAPON_UZI
);
1656 // P->current_weapon=select_best_weapon(P);
1657 send_update_player((struct player
*)(p
->data
));
1658 send_message((struct player
*)(p
->data
),0,"You got Uzi", M_WEAPON
);
1659 snprintf(txt
,256,"%s got Uzi.\n",((struct player
*)(p
->data
))->name
);
1661 obj
->status
|= S_INVISIBLE
;
1662 add_to_timeq(obj
->id
,T_UZI
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,WEAPON_RESPAWN_TIME
);
1663 sendall_update_status(obj
,0);
1670 if (p
->type
!=T_PLAYER
)break;
1671 if ((((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]==MAX_AMMO(WEAPON_RIFLE
))&&((((struct player
*)(p
->data
))->weapons
)&WEAPON_MASK_RIFLE
))break;
1673 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_RIFLE
)
1674 && !is_weapon_usable((struct player
*)(p
->data
), WEAPON_RIFLE
))
1675 P
->current_weapon
= WEAPON_RIFLE
;
1677 ((struct player
*)(p
->data
))->weapons
|=WEAPON_MASK_RIFLE
;
1678 ((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]+=weapon
[WEAPON_RIFLE
].basic_ammo
;
1679 if (((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]>MAX_AMMO(WEAPON_RIFLE
))
1680 ((struct player
*)(p
->data
))->ammo
[WEAPON_RIFLE
]=MAX_AMMO(WEAPON_RIFLE
);
1681 // P->current_weapon=select_best_weapon(P);
1682 send_update_player((struct player
*)(p
->data
));
1683 send_message((struct player
*)(p
->data
),0,"You got sniper rifle", M_WEAPON
);
1684 snprintf(txt
,256,"%s got sniper rifle.\n",((struct player
*)(p
->data
))->name
);
1686 obj
->status
|= S_INVISIBLE
;
1687 add_to_timeq(obj
->id
,T_RIFLE
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,WEAPON_RESPAWN_TIME
);
1688 sendall_update_status(obj
,0);
1695 if (p
->type
!=T_PLAYER
)break;
1696 if ((((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]==MAX_AMMO(WEAPON_SHOTGUN
))&&((((struct player
*)(p
->data
))->weapons
)&WEAPON_MASK_SHOTGUN
))break;
1698 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_SHOTGUN
)
1699 && !is_weapon_usable((struct player
*)(p
->data
), WEAPON_SHOTGUN
))
1700 P
->current_weapon
= WEAPON_SHOTGUN
;
1702 ((struct player
*)(p
->data
))->weapons
|=WEAPON_MASK_SHOTGUN
;
1703 ((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]+=weapon
[WEAPON_SHOTGUN
].basic_ammo
;
1704 if (((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]>MAX_AMMO(WEAPON_SHOTGUN
))
1705 ((struct player
*)(p
->data
))->ammo
[WEAPON_SHOTGUN
]=MAX_AMMO(WEAPON_SHOTGUN
);
1706 // P->current_weapon=select_best_weapon(P);
1707 send_update_player((struct player
*)(p
->data
));
1708 send_message((struct player
*)(p
->data
),0,"You got a shotgun", M_WEAPON
);
1709 snprintf(txt
,256,"%s got a shotgun.\n",((struct player
*)(p
->data
))->name
);
1711 obj
->status
|= S_INVISIBLE
;
1712 add_to_timeq(obj
->id
,T_SHOTGUN
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,WEAPON_RESPAWN_TIME
);
1713 sendall_update_status(obj
,0);
1720 if (p
->type
!=T_PLAYER
)break;
1721 if ((((struct player
*)(p
->data
))->ammo
[WEAPON_BFG
]==MAX_AMMO(WEAPON_BFG
))&&((((struct player
*)(p
->data
))->weapons
)&WEAPON_MASK_BFG
))break;
1723 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_BFG
)
1724 && !is_weapon_usable((struct player
*)(p
->data
), WEAPON_BFG
))
1725 P
->current_weapon
= WEAPON_BFG
;
1727 ((struct player
*)(p
->data
))->weapons
|=WEAPON_MASK_BFG
;
1728 ((struct player
*)(p
->data
))->ammo
[WEAPON_BFG
]+=weapon
[WEAPON_BFG
].basic_ammo
;
1729 if (((struct player
*)(p
->data
))->ammo
[WEAPON_BFG
]>MAX_AMMO(WEAPON_BFG
))
1730 ((struct player
*)(p
->data
))->ammo
[WEAPON_BFG
]=MAX_AMMO(WEAPON_BFG
);
1731 // P->current_weapon=select_best_weapon(P);
1732 send_update_player((struct player
*)(p
->data
));
1733 send_message((struct player
*)(p
->data
),0,"You got a BFG", M_WEAPON
);
1734 snprintf(txt
,256,"%s got a BFG.\n",((struct player
*)(p
->data
))->name
);
1736 obj
->status
|= S_INVISIBLE
;
1737 add_to_timeq(obj
->id
,T_BFG
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,WEAPON_RESPAWN_TIME
);
1738 sendall_update_status(obj
,0);
1745 if (p
->type
!=T_PLAYER
)break;
1746 if ((((struct player
*)(p
->data
))->ammo
[WEAPON_BLOODRAIN
]==MAX_AMMO(WEAPON_BLOODRAIN
))&&((((struct player
*)(p
->data
))->weapons
)&WEAPON_MASK_BLOODRAIN
))break;
1748 if(is_weapon_better((struct player
*)(p
->data
), WEAPON_BLOODRAIN
)
1749 && !is_weapon_usable((struct player
*)(p
->data
), WEAPON_BLOODRAIN
))
1750 P
->current_weapon
= WEAPON_BLOODRAIN
;
1752 ((struct player
*)(p
->data
))->weapons
|=WEAPON_MASK_BLOODRAIN
;
1753 ((struct player
*)(p
->data
))->ammo
[WEAPON_BLOODRAIN
]+=weapon
[WEAPON_BLOODRAIN
].basic_ammo
;
1754 if (((struct player
*)(p
->data
))->ammo
[WEAPON_BLOODRAIN
]>MAX_AMMO(WEAPON_BLOODRAIN
))
1755 ((struct player
*)(p
->data
))->ammo
[WEAPON_BLOODRAIN
]=MAX_AMMO(WEAPON_BLOODRAIN
);
1756 // P->current_weapon=select_best_weapon(P);
1757 send_update_player((struct player
*)(p
->data
));
1758 send_message((struct player
*)(p
->data
),0,"You charged your Bloodrain", M_WEAPON
);
1759 snprintf(txt
,256,"%s charged his Bloodrain.\n",((struct player
*)(p
->data
))->name
);
1761 obj
->status
|= S_INVISIBLE
;
1762 add_to_timeq(obj
->id
,T_BLOODRAIN
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,WEAPON_RESPAWN_TIME
);
1763 sendall_update_status(obj
,0);
1767 case T_INVISIBILITY
:
1770 if (p
->type
!=T_PLAYER
)break;
1772 ((struct player
*)(p
->data
))->invisibility_counter
=INVISIBILITY_DURATION
;
1773 p
->status
|= S_INVISIBLE
; /* hide player */
1774 sendall_update_status(p
,0);
1775 send_message((struct player
*)(p
->data
),0,"You got invisibility dope", M_ITEM
);
1776 snprintf(txt
,256,"%s got invisibility.\n",((struct player
*)(p
->data
))->name
);
1778 obj
->status
|= S_INVISIBLE
;
1779 add_to_timeq(obj
->id
,T_INVISIBILITY
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,INVISIBILITY_RESPAWN_TIME
);
1780 sendall_update_status(obj
,0);
1787 if (p
->type
!=T_PLAYER
)break;
1788 p
->status
|= S_JETPACK
;
1789 sendall_update_status(p
, 0);
1790 send_message((struct player
*)(p
->data
),0,"You got a jetpack", M_ITEM
);
1791 snprintf(txt
,256,"%s got a jetpack.\n",((struct player
*)(p
->data
))->name
);
1793 obj
->status
|= S_INVISIBLE
;
1794 add_to_timeq(obj
->id
,T_JETPACK
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,ARMOR_RESPAWN_TIME
);
1795 sendall_update_status(obj
,0);
1802 if (p
->type
!=T_PLAYER
)break;
1804 find_birthplace(&px
,&py
);
1805 o
=new_obj(id
,T_NOISE
,NOISE_TTL
,noise_sprite
,0,0,int2double(px
),int2double(py
),0,0,(void *)(long)(p
->id
));
1809 sendall_new_object(o
,0);
1810 p
->x
=int2double(px
);
1811 p
->y
=int2double(py
);
1812 sendall_update_object(((struct player
*)p
->data
)->obj
,0,3);
1814 sendall_update_status(p
,0);
1815 send_message((struct player
*)(p
->data
),0,"You teleported", M_INFO
);
1816 snprintf(txt
,256,"%s teleported.\n",((struct player
*)(p
->data
))->name
);
1818 add_to_timeq(obj
->id
,T_TELEPORT
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,0);
1819 sendall_update_status(obj
,0);
1826 if (p
->type
!=T_PLAYER
)break;
1827 if (((struct player
*)(p
->data
))->armor
>=100)break; /* he has 100% armor */
1828 ((struct player
*)(p
->data
))->armor
+=ARMOR_ADD
;
1829 if (((struct player
*)(p
->data
))->armor
>100)((struct player
*)(p
->data
))->armor
=100;
1830 send_update_player((struct player
*)(p
->data
));
1831 send_message((struct player
*)(p
->data
),0,"You got armor", M_ITEM
);
1832 snprintf(txt
,256,"%s got armor.\n",((struct player
*)(p
->data
))->name
);
1834 obj
->status
|= S_INVISIBLE
;
1835 add_to_timeq(obj
->id
,T_ARMOR
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,ARMOR_RESPAWN_TIME
);
1836 sendall_update_status(obj
,0);
1843 if (p
->type
!=T_PLAYER
)break;
1844 if (((struct player
*)(p
->data
))->health
>=100)break; /* he's healthy */
1845 ((struct player
*)(p
->data
))->health
+=MEDIKIT_HEALTH_ADD
;
1846 if (((struct player
*)(p
->data
))->health
>100)((struct player
*)(p
->data
))->health
=100;
1847 send_update_player((struct player
*)(p
->data
));
1848 send_message((struct player
*)(p
->data
),0,"You picked up a medikit", M_ITEM
);
1849 snprintf(txt
,256,"%s picked up a medikit.\n",((struct player
*)(p
->data
))->name
);
1851 obj
->status
|= S_INVISIBLE
;
1852 add_to_timeq(obj
->id
,T_MEDIKIT
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,MEDIKIT_RESPAWN_TIME
);
1853 sendall_update_status(obj
,0);
1860 if (p
->type
!=T_PLAYER
)break;
1861 if (((struct player
*)(p
->data
))->obj
->status
& S_ILL
)
1862 ((struct player
*)(p
->data
))->obj
->status
&= ~S_ILL
;
1864 ((struct player
*)(p
->data
))->health
=1; /* really hardcore chemical cocktail :-) */
1865 send_update_player((struct player
*)(p
->data
));
1866 send_message((struct player
*)(p
->data
),0,"You picked up a bio-medikit", M_ITEM
);
1867 snprintf(txt
,256,"%s picked up a bio-medikit.\n",((struct player
*)(p
->data
))->name
);
1869 obj
->status
|= S_INVISIBLE
;
1870 add_to_timeq(obj
->id
,T_BIOMED
,0,obj
->sprite
,0,0,obj
->x
,obj
->y
,0,0,0,MEDIKIT_RESPAWN_TIME
);
1871 sendall_update_status(obj
,0);
1876 if (p
->type
!=T_PLAYER
|| ((struct player
*)(p
->data
))->obj
->status
& S_ILL
)
1878 ((struct player
*)(p
->data
))->obj
->status
|= S_ILL
;
1879 send_message((struct player
*)(p
->data
),0,"You got infected from skull", M_INFO
);
1880 snprintf(txt
,256,"%s got infected",((struct player
*)(p
->data
))->name
);
1881 sendall_message(0,txt
,(struct player
*)(p
->data
),0, M_INFO
);
1882 snprintf(txt
,256,"%s got infected.\n",((struct player
*)(p
->data
))->name
);
1885 sendall_update_object(p
,0,0); /* update everything */
1886 send_update_player((struct player
*)(p
->data
));
1891 if (p
->type
!=T_PLAYER
)
1893 if (((struct player
*)(p
->data
))->obj
->id
== (long)obj
->data
|| ((struct player
*)(p
->data
))->obj
->status
& S_ONFIRE
)
1895 ((struct player
*)(p
->data
))->obj
->status
|= S_ONFIRE
;
1896 o
=&(((ol
= find_in_table((long)(obj
->data
))))->member
); /* owner of the flame */
1897 snprintf(txt
,256,"You caught fire from %s's jetpack", ((struct player
*)(o
->data
))->name
);
1898 send_message((struct player
*)(p
->data
),0,txt
, M_INFO
);
1900 sendall_update_object(p
,0,0); /* update everything */
1901 send_update_player((struct player
*)(p
->data
));
1905 case T_PLAYER
: /* illness is spreading :-) */
1906 if (p
->type
!=T_PLAYER
|| p
->data
== obj
->data
||
1907 ((struct player
*)(p
->data
))->obj
->status
& S_ILL
)
1909 if (((struct player
*)(obj
->data
))->obj
->status
& S_ILL
) {
1910 ((struct player
*)(p
->data
))->obj
->status
|= S_ILL
;
1912 snprintf(txt
,256,"%s infected %s.",((struct player
*)(obj
->data
))->name
,((struct player
*)(p
->data
))->name
);
1913 sendall_message(0,txt
,(struct player
*)(obj
->data
),(struct player
*)(p
->data
), M_INFO
);
1914 snprintf(txt
,256,"%s infected you",((struct player
*)(obj
->data
))->name
);
1915 send_message((struct player
*)(p
->data
),0,txt
, M_INFO
); /* the dead */
1916 snprintf(txt
,256,"You infected %s",((struct player
*)(p
->data
))->name
);
1917 send_message((struct player
*)(obj
->data
),0,txt
, M_INFO
); /* the dead */
1918 snprintf(txt
,256,"%s infected %s.\n",((struct player
*)(obj
->data
))->name
,((struct player
*)(p
->data
))->name
);
1921 sendall_update_object(p
,0,0); /* update everything */
1922 send_update_player((struct player
*)(p
->data
));
1927 case T_CORPSE
: /* illness is spreading from corpses too */
1928 if (p
->type
!=T_PLAYER
|| p
->data
== obj
->data
||
1929 ((struct player
*)(p
->data
))->obj
->status
& S_ILL
)
1931 if (obj
->status
& S_ILL
) {
1932 ((struct player
*)(p
->data
))->obj
->status
|= S_ILL
;
1934 snprintf(txt
,256,"%s got infected from a corpse.",((struct player
*)(p
->data
))->name
);
1935 sendall_message(0,txt
,(struct player
*)(obj
->data
),(struct player
*)(p
->data
), M_INFO
);
1936 snprintf(txt
,256,"You got infected from a corpse");
1937 send_message((struct player
*)(p
->data
),0,txt
, M_INFO
); /* the dead */
1938 snprintf(txt
,256,"%s got infected from a corpse.\n",((struct player
*)(p
->data
))->name
);
1941 sendall_update_object(p
,0,0); /* update everything */
1942 send_update_player((struct player
*)(p
->data
));
1948 if (p
->type
!=T_PLAYER
)break;
1949 a
=(int)((1-(double)A
/100)*KILL_LETHALNESS
);
1950 c
=KILL_ARMOR_DAMAGE
;
1951 if (a
>=H
) /* player died */
1953 ((struct player
*)(p
->data
))->deaths
++;
1954 send_message((struct player
*)(p
->data
),0,"You killed yourself", M_DEATH
);
1955 snprintf(txt
,256,"%s suicides",((struct player
*)(p
->data
))->name
);
1956 sendall_message(0,txt
,(struct player
*)(p
->data
),0, M_DEATH
);
1957 snprintf(txt
,256,"%s suicides.\n",((struct player
*)(p
->data
))->name
);
1967 p
->status
|= S_DEAD
; /* dead flag */
1968 sendall_update_object(p
,0,0); /* update everything */
1969 send_update_player((struct player
*)(p
->data
)); /* dead player */
1972 create_mess(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-MESS_HEIGHT
,py
);
1974 create_corpse(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-CORPSE_HEIGHT
,((struct player
*)(p
->data
))->color
,0);
1979 A
=(c
>=A
)?0:(A
-c
); /* armor */
1980 send_update_player((struct player
*)(p
->data
));
1985 if (p
->type
==T_CORPSE
)
1991 packet
[offset
++]=P_DELETE_OBJECT
;
1992 put_int(packet
,p
->id
,&offset
);
1993 sendall_chunked(packet
,offset
,0);
1995 create_mess(px
,py
,py
);
2001 if (p
->type
!=T_PLAYER
)break;
2002 b
=((obj
->type
==T_BULLET
||obj
->type
==T_BFGCELL
||obj
->type
==T_CHAIN
)?FIRE_IMPACT
:SHRAPNEL_IMPACT
);
2004 if (obj
->type
!= T_CHAIN
)
2005 p
->xspeed
+=obj
->xspeed
>0?b
:-b
;
2006 sendall_update_object(p
,0,4); /* update speed + status */
2007 p
->status
&= ~S_HIT
;
2008 a
=(int)((1-(double)A
/100)*weapon
[obj
->status
].lethalness
*(2-double2int(obj
->y
-p
->y
)/(double)PLAYER_HEIGHT
)*obj
->ttl
/weapon
[obj
->status
].ttl
);
2009 c
=(int)(weapon
[obj
->status
].armor_damage
*(2-double2int(obj
->y
-p
->y
)/(double)PLAYER_HEIGHT
)*obj
->ttl
/weapon
[obj
->status
].ttl
);
2010 if (a
>=H
) /* player was slain */
2012 o
=&(((ol
= find_in_table((long)(obj
->data
))))->member
); /* owner of the bullet */
2013 ((struct player
*)(p
->data
))->deaths
++;
2014 if (!ol
) { /* for now only bloodrain */
2015 snprintf(txt
,256,"Bloody shrapnel killed %s.",((struct player
*)(p
->data
))->name
);
2016 sendall_message(0,txt
,NULL
,(struct player
*)(p
->data
), M_DEATH
);
2017 snprintf(txt
,256,"Bloody shrapnel killed you");
2018 send_message((struct player
*)(p
->data
),0,txt
, M_DEATH
); /* the dead */
2019 snprintf(txt
,256,"Bloody shrapnel killed %s.\n",((struct player
*)(p
->data
))->name
);
2022 else if (o
->data
==p
->data
) /* suicide */
2024 ((struct player
*)(o
->data
))->frags
-=!!(((struct player
*)(o
->data
))->frags
);
2025 send_message((struct player
*)(o
->data
),0,"You killed yourself", M_DEATH
);
2026 snprintf(txt
,256,"%s suicides",((struct player
*)(o
->data
))->name
);
2027 sendall_message(0,txt
,(struct player
*)(o
->data
),0, M_DEATH
);
2028 snprintf(txt
,256,"%s suicides.\n",((struct player
*)(o
->data
))->name
);
2033 ((struct player
*)(o
->data
))->frags
++;
2034 snprintf(txt
,256,"%s killed %s.",((struct player
*)(o
->data
))->name
,((struct player
*)(p
->data
))->name
);
2035 sendall_message(0,txt
,(struct player
*)(o
->data
),(struct player
*)(p
->data
), M_DEATH
);
2036 snprintf(txt
,256,"%s killed you",((struct player
*)(o
->data
))->name
);
2037 send_message((struct player
*)(p
->data
),0,txt
, M_DEATH
); /* the dead */
2038 snprintf(txt
,256,"You killed %s",((struct player
*)(p
->data
))->name
);
2039 send_message((struct player
*)(o
->data
),0,txt
, M_DEATH
); /* the dead */
2040 snprintf(txt
,256,"%s killed %s.\n",((struct player
*)(o
->data
))->name
,((struct player
*)(p
->data
))->name
);
2050 p
->status
|= S_DEAD
; /* dead flag */
2051 sendall_update_object(p
,0,0); /* update everything */
2052 send_update_player((struct player
*)(p
->data
)); /* dead player */
2054 send_update_player((struct player
*)(o
->data
)); /* owner of bullet/shrapnel */
2057 create_mess(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-MESS_HEIGHT
,py
);
2059 create_corpse(px
,py
+((s
& S_CREEP
)?CREEP_HEIGHT
:PLAYER_HEIGHT
)-CORPSE_HEIGHT
,((struct player
*)(p
->data
))->color
,0);
2064 A
=(c
>=A
)?0:(A
-c
); /* armor */
2065 sendall_hit(p
->id
,obj
->xspeed
<0,OX
-PX
,OY
-PY
,0);
2066 send_update_player((struct player
*)(p
->data
));
2068 if (obj
->type
== T_CHAIN
) {
2069 struct it
*meat
=new_obj(id
,T_MESS
,MESS_TTL
,
2070 (meatcounter
==0x1)?mess3_sprite
:
2071 ((meatcounter
)==0x2)?mess2_sprite
:mess4_sprite
,
2072 0,0,obj
->x
,obj
->y
,-float2double(obj
->xspeed
/500),
2073 -float2double((meatcounter
+2)*36),0);
2074 if (!meat
) return 1;
2076 sendall_new_object(meat
,0);
2077 meatcounter
= (meatcounter
+1)%3;
2096 /* recompute objects positions */
2097 static void update_game(void)
2099 static char packet
[64];
2101 struct object_list
*p
, *p2
;
2102 struct player_list
*q
;
2104 unsigned char stop_x
,stop_y
;
2108 struct it
*s
; /* for grenades throwing */
2109 unsigned int status
;
2111 unsigned long_long t
;
2112 unsigned int old_status
;
2114 int old_x
,old_y
,old_x_speed
,old_y_speed
;
2117 for(p
=&objects
;p
->next
;p
=p
->next
)
2119 if (p
->next
->member
.type
==T_NOTHING
)
2121 if (p
->next
->member
.type
==T_PLAYER
&&(p
->next
->member
.status
& S_DEAD
))
2122 continue; /* dead player */
2123 if (p
->next
->member
.type
==T_PLAYER
&&(((struct player
*)(p
->next
->member
.data
))->current_level
)<0) /* player hasn't entered the level yet */
2125 send_change_level((struct player
*)p
->next
->member
.data
);
2129 old_status
=p
->next
->member
.status
;
2130 old_ttl
=p
->next
->member
.ttl
;
2131 old_x
=p
->next
->member
.x
;
2132 old_y
=p
->next
->member
.y
;
2133 old_x_speed
=p
->next
->member
.xspeed
;
2134 old_y_speed
=p
->next
->member
.yspeed
;
2136 x
=p
->next
->member
.x
;
2137 y
=p
->next
->member
.y
;
2138 xs
=p
->next
->member
.xspeed
;
2139 ys
=p
->next
->member
.yspeed
;
2140 status
=p
->next
->member
.status
;
2142 /* decrease invisibility counter of invisible player */
2143 if ((p
->next
->member
.type
==T_PLAYER
)&&(((struct player
*)(p
->next
->member
.data
))->invisibility_counter
))
2145 ((struct player
*)(p
->next
->member
.data
))->invisibility_counter
--;
2146 if (!(((struct player
*)(p
->next
->member
.data
))->invisibility_counter
))
2148 p
->next
->member
.status
&= ~S_INVISIBLE
;
2149 sendall_update_status(&(p
->next
->member
),0);
2153 /* decrease life of ill player */
2154 if ((p
->next
->member
.type
==T_PLAYER
)&&(((struct player
*)(p
->next
->member
.data
))->obj
->status
& (S_ILL
| S_ONFIRE
)))
2156 /* hack - health with extended precision */
2157 if (!((struct player
*)(p
->next
->member
.data
))->health_ep
--) {
2158 ((struct player
*)(p
->next
->member
.data
))->health_ep
=
2159 ((((struct player
*)(p
->next
->member
.data
))->obj
->status
& S_ILL
) ? ILLNESS_SPEED
: 0) +
2160 ((((struct player
*)(p
->next
->member
.data
))->obj
->status
& S_ONFIRE
) ? BURNING_SPEED
: 0);
2161 ((struct player
*)(p
->next
->member
.data
))->health
--;
2163 send_update_player((struct player
*)(p
->next
->member
.data
));
2164 if (!(((struct player
*)(p
->next
->member
.data
))->health
))
2166 p
->next
->member
.status
|= S_DEAD
;
2167 ((struct player
*)(p
->next
->member
.data
))->frags
-=!!(((struct player
*)(p
->next
->member
.data
))->frags
);
2169 if (((struct player
*)(p
->next
->member
.data
))->obj
->status
& S_ILL
) {
2170 send_message((struct player
*)(p
->next
->member
.data
),0,"You died on illness", M_DEATH
);
2171 snprintf(txt
,256,"%s died on illness",((struct player
*)(p
->next
->member
.data
))->name
);
2172 sendall_message(0,txt
,(struct player
*)(p
->next
->member
.data
),0, M_DEATH
);
2173 snprintf(txt
,256,"%s died on illness.\n",((struct player
*)(p
->next
->member
.data
))->name
);
2175 send_message((struct player
*)(p
->next
->member
.data
),0,"You burnt down to ashes", M_DEATH
);
2176 snprintf(txt
,256,"%s burnt down to ashes",((struct player
*)(p
->next
->member
.data
))->name
);
2177 sendall_message(0,txt
,(struct player
*)(p
->next
->member
.data
),0, M_DEATH
);
2178 snprintf(txt
,256,"%s burnt down to ashes.\n",((struct player
*)(p
->next
->member
.data
))->name
);
2182 send_update_player((struct player
*)(p
->next
->member
.data
)); /* dead player */
2183 sendall_update_status(&(p
->next
->member
),0);
2186 create_corpse(double2int(p
->next
->member
.x
),double2int(p
->next
->member
.y
)+((p
->next
->member
.status
& S_CREEP
)?
2187 CREEP_HEIGHT
:PLAYER_HEIGHT
)-CORPSE_HEIGHT
,((struct player
*)(p
->next
->member
.data
))->color
,S_ILL
);
2191 /* decrement time to live */
2192 if (p
->next
->member
.type
== T_PLAYER
&& (p
->next
->member
.status
& S_BLOODRAIN
))
2194 if (p
->next
->member
.ttl
>0)
2196 p
->next
->member
.ttl
--;
2198 if (p
->next
->member
.type
==T_NOISE
&&p
->next
->member
.ttl
==(NOISE_TTL
>>1))
2201 q
=find_player(0,(long)(p
->next
->member
.data
));
2202 if (q
) /* player is still in the game */
2204 init_player(&(q
->member
),q
->member
.obj
->x
,q
->member
.obj
->y
);
2205 q
->member
.obj
->status
&= ~(S_DEAD
| S_NOISE
);
2206 sendall_update_object(q
->member
.obj
,0,0); /* update everything */
2207 send_update_player(&(q
->member
));
2210 goto cont_cycle
; /* that's all for T_NOISE at this moment */
2212 /* grenades must be created after locking off */
2213 /* not when shoot request comes */
2214 if (p
->next
->member
.type
==T_PLAYER
&&p
->next
->member
.ttl
==GRENADE_DELAY
+HOLD_GUN_AFTER_SHOOT
&&((struct player
*)(p
->next
->member
.data
))->current_weapon
==WEAPON_GRENADE
)
2219 weapon
[WEAPON_GRENADE
].ttl
,
2223 add_int(p
->next
->member
.x
,p
->next
->member
.status
& S_LOOKLEFT
? 2 : PLAYER_WIDTH
-2),
2224 p
->next
->member
.y
+GRENADE_FIRE_YOFFSET
,
2225 p
->next
->member
.xspeed
+(p
->next
->member
.status
& S_LOOKLEFT
? -weapon
[WEAPON_GRENADE
].shell_xspeed
:weapon
[WEAPON_GRENADE
].shell_xspeed
),
2226 p
->next
->member
.yspeed
+weapon
[WEAPON_GRENADE
].shell_yspeed
,
2227 (void *)(long)(p
->next
->member
.id
));
2229 sendall_new_object(s
,0);
2231 /* if ttl is 0, delete this object */
2232 if (p
->next
->member
.ttl
<=0)
2234 /* player's ttl means how long he holds the gun */
2235 switch(p
->next
->member
.type
)
2238 p
->next
->member
.status
&= ~S_SHOOTING
;
2244 packet
[offset
++]=(p
->next
->member
.type
==T_GRENADE
)?P_EXPLODE_GRENADE
:
2245 (p
->next
->member
.type
==T_BFGCELL
)?P_EXPLODE_BFG
:P_EXPLODE_BLOODRAIN
;
2246 put_int(packet
,id
,&offset
);
2247 put_int(packet
,p
->next
->member
.id
,&offset
);
2248 sendall_chunked(packet
,offset
,0);
2250 for (b
=0;b
<N_SHRAPNELS_EXPLODE
;b
++)
2252 double angle
=(double)b
*2*M_PI
/N_SHRAPNELS_EXPLODE
;
2253 int spd
=add_int(mul_int(my_and(mul_int(weapon
[WEAPON_GRENADE
].speed
,b
+1),15),16),100);
2259 (p
->next
->member
.type
==T_GRENADE
)?
2260 shrapnel_sprite
[random()%N_SHRAPNELS
]:
2261 (p
->next
->member
.type
==T_BFGCELL
)?
2262 bfgbit_sprite
[random()%N_SHRAPNELS
]:
2263 bloodrain_sprite
[random()%N_SHRAPNELS
],
2268 p
->next
->member
.xspeed
+mul(spd
,float2double(cos(angle
))),
2269 p
->next
->member
.yspeed
+mul(spd
,float2double(sin(angle
))),
2270 p
->next
->member
.data
);
2273 if (p
->next
->member
.status
& S_BLOODRAIN
) {
2274 p
->next
->member
.status
|= S_DEAD
;
2275 ((struct player
*)p
->next
->member
.data
)->frags
-=!!(((struct player
*)p
->next
->member
.data
)->frags
);
2276 ((struct player
*)p
->next
->member
.data
)->deaths
++;
2277 sendall_update_object(&(p
->next
->member
),0,0); /* update everything */
2278 send_update_player((struct player
*)(p
->next
->member
.data
)); /* dead player */
2280 create_mess(double2int(p
->next
->member
.x
),double2int(p
->next
->member
.y
)+((p
->next
->member
.status
& S_CREEP
)?
2281 CREEP_HEIGHT
:PLAYER_HEIGHT
)-CORPSE_HEIGHT
,
2282 double2int(p
->next
->member
.y
)+((p
->next
->member
.status
& S_CREEP
)?
2283 CREEP_HEIGHT
:PLAYER_HEIGHT
)-CORPSE_HEIGHT
);
2285 delete_obj(p
->next
->member
.id
);
2286 if (!(p
->next
))return;
2291 packet
[offset
++]=P_DELETE_OBJECT
;
2292 put_int(packet
,p
->next
->member
.id
,&offset
);
2293 sendall_chunked(packet
,offset
,0);
2294 delete_obj(p
->next
->member
.id
);
2295 if (!(p
->next
))return;
2300 /* maintain only objects that you are allowed to maintain */
2301 if (!obj_attr
[p
->next
->member
.type
].maintainer
)goto dc
;
2302 if (!(obj_attr
[p
->next
->member
.type
].maintainer
&2))continue;
2305 /* when not falling, slow down x motion */
2306 if (!(p
->next
->member
.status
& S_FALLING
))
2307 p
->next
->member
.xspeed
=mul(p
->next
->member
.xspeed
,obj_attr
[p
->next
->member
.type
].slow_down_x
);
2310 if (obj_attr
[p
->next
->member
.type
].fall
)
2312 if (p
->next
->member
.type
!=T_SHRAPNEL
)p
->next
->member
.status
|= S_FALLING
;
2313 p
->next
->member
.yspeed
+=FALL_ACCEL
;
2314 /* but not too fast */
2315 if (p
->next
->member
.yspeed
>MAX_Y_SPEED
)p
->next
->member
.yspeed
=MAX_Y_SPEED
;
2319 get_dimensions(p
->next
->member
.type
,p
->next
->member
.status
,sprites
[p
->next
->member
.sprite
].positions
,&w
,&h
);
2320 DELTA_TIME
=float2double(((double)((long_long
)(t
-p
->next
->member
.last_updated
)))/MICROSECONDS
);
2323 p
->next
->member
.x
+mul(p
->next
->member
.xspeed
,DELTA_TIME
),
2324 p
->next
->member
.y
+mul(p
->next
->member
.yspeed
,DELTA_TIME
),
2325 w
,h
,&stop_x
,&stop_y
);
2326 p
->next
->member
.last_updated
=t
;
2328 /* walk up the stairs */
2329 if (stop_x
&&p
->next
->member
.type
==T_PLAYER
&&!(p
->next
->member
.status
& S_CREEP
))
2331 x1
=p
->next
->member
.x
;
2332 y1
=p
->next
->member
.y
;
2333 p
->next
->member
.x
=x
;
2334 p
->next
->member
.y
=y
-int2double(1);
2337 p
->next
->member
.x
+mul(p
->next
->member
.xspeed
,DELTA_TIME
),
2338 p
->next
->member
.y
+mul(p
->next
->member
.yspeed
,DELTA_TIME
),
2340 if ((p
->next
->member
.xspeed
>0&&p
->next
->member
.x
<=x1
)||(p
->next
->member
.xspeed
<0&&p
->next
->member
.x
>=x1
)) /* restore original values */
2342 p
->next
->member
.x
=x1
;
2343 p
->next
->member
.y
=y1
;
2352 if (stop_x
)p
->next
->member
.xspeed
=-mul(p
->next
->member
.xspeed
,obj_attr
[p
->next
->member
.type
].bounce_x
);
2353 if (my_abs(p
->next
->member
.xspeed
)<MIN_X_SPEED
)
2355 p
->next
->member
.xspeed
=0;
2356 p
->next
->member
.status
&= ~S_WALKING
;
2362 p
->next
->member
.yspeed
=mul(p
->next
->member
.yspeed
,obj_attr
[p
->next
->member
.type
].bounce_y
);
2363 p
->next
->member
.yspeed
=-p
->next
->member
.yspeed
;
2364 if (my_abs(p
->next
->member
.yspeed
)<MIN_Y_SPEED
)
2366 p
->next
->member
.yspeed
=0;
2367 if (stop_y
==1)p
->next
->member
.status
&= ~S_FALLING
;
2371 if ((p
->next
->member
.type
==T_SHRAPNEL
||p
->next
->member
.type
==T_BULLET
||
2372 p
->next
->member
.type
==T_BFGCELL
||p
->next
->member
.type
==T_CHAIN
)&&(stop_x
||stop_y
)) /* bullet and shrapnel die crashing into wall */
2375 packet
[offset
++]=P_DELETE_OBJECT
;
2376 put_int(packet
,p
->next
->member
.id
,&offset
);
2377 sendall_chunked(packet
,offset
,0);
2378 delete_obj(p
->next
->member
.id
);
2379 if (!(p
->next
))break;
2383 /* Anything crashing into PS makes him into bloody goo */
2384 for (p2
=&objects
;p2
->next
;p2
=p2
->next
)
2385 if ((p2
->next
->member
.type
== T_PS
) && (!(p2
->next
->member
.status
& S_INVISIBLE
)) &&
2386 ((p
->next
->member
.type
== T_BULLET
) || (p
->next
->member
.type
== T_SHRAPNEL
) ||
2387 (p
->next
->member
.type
== T_CHAIN
) || (p
->next
->member
.type
== T_BFGCELL
)) &&
2389 double2int(p2
->next
->member
.x
),double2int(p2
->next
->member
.y
),p2
->next
->member
.type
,p2
->next
->member
.status
,sprites
[p2
->next
->member
.sprite
].positions
,
2390 double2int(p
->next
->member
.x
),double2int(p
->next
->member
.y
),p
->next
->member
.type
,p
->next
->member
.status
,sprites
[p
->next
->member
.sprite
].positions
)) {
2391 p2
->next
->member
.status
|= S_INVISIBLE
;
2392 create_mess(double2int(p2
->next
->member
.x
),double2int(p2
->next
->member
.y
)+PLAYER_HEIGHT
-MESS_HEIGHT
,double2int(p2
->next
->member
.y
));
2393 add_to_timeq(p2
->next
->member
.id
,T_PS
,0,p2
->next
->member
.sprite
,0,0,p2
->next
->member
.x
,p2
->next
->member
.y
,0,0,0,PS_RESPAWN_TIME
);
2394 sendall_update_status(&(p2
->next
->member
),0);
2397 /* compute collision with other objects */
2398 a
=dynamic_collision(&(p
->next
->member
));
2401 case 1: /* object dies */
2403 packet
[offset
++]=P_DELETE_OBJECT
;
2404 put_int(packet
,p
->next
->member
.id
,&offset
);
2405 sendall_chunked(packet
,offset
,0);
2408 delete_obj(p
->next
->member
.id
);
2409 if (!(p
->next
))return;
2412 case 0: /* object still lives */
2413 if ( /* send update but only when something's changed and client doesn't maintain the object */
2414 (obj_attr
[p
->next
->member
.type
].maintainer
&4)&& /* server sends update */
2415 (x
!=p
->next
->member
.x
|| /* something's changed */
2416 y
!=p
->next
->member
.y
||
2417 xs
!=p
->next
->member
.xspeed
||
2418 ys
!=p
->next
->member
.yspeed
||
2419 status
!=p
->next
->member
.status
))
2421 a
=which_update(&(p
->next
->member
),old_x
,old_y
,old_x_speed
,old_y_speed
,old_status
,old_ttl
);
2422 sendall_update_object(&(p
->next
->member
),0,a
);
2430 static void free_all_memory(void)
2432 struct queue_list
*t
;
2433 struct player_list
*p
;
2435 /* delete players */
2436 for (p
=&players
;p
->next
;)
2437 delete_player(p
->next
);
2438 /* delete objects */
2439 while (last_obj
!=(&objects
))delete_obj(last_obj
->member
.id
);
2441 for (t
=&time_queue
;t
->next
;)
2443 struct queue_list
*q
;
2450 /* delete birthplaces */
2451 if (n_birthplaces
)mem_free(birthplace
);
2453 /* delete sprites */
2457 if (level_checksum
)mem_free(level_checksum
);
2458 free_packet_buffer();
2461 /* fatal signal handler (sigsegv, sigabrt, ... ) */
2462 static void signal_handler(int sig_num
)
2468 memcpy(packet
+1,"server",7);
2470 sendall(packet
,8,0);
2471 sendall(packet
,8,0);
2472 sendall(packet
,8,0);
2473 sendall(packet
,8,0);
2474 sendall(packet
,8,0);
2475 sendall(packet
,8,0);
2476 sendall(packet
,8,0);
2477 sendall(packet
,8,0);
2478 /* 800 % redundancy should be enough ;-) */
2480 snprintf(txt
,256,"Signal %d caught.\n",sig_num
);
2483 check_memory_leaks();
2488 signal(sig_num
,SIG_DFL
);
2494 /* walk with given player */
2495 static void walk_player(struct player
*q
,int direction
, int speed
, int creep
)
2499 unsigned int old_status
=q
->obj
->status
;
2500 int old_ttl
=q
->obj
->ttl
;
2501 int old_x
=q
->obj
->x
,
2503 old_x_speed
=q
->obj
->xspeed
,
2504 old_y_speed
=q
->obj
->yspeed
;
2506 if ((q
->obj
->status
& (S_GRENADE
| S_SHOOTING
)) == (S_GRENADE
| S_SHOOTING
))
2507 return; /* when throwing grenade can't walk */
2508 if (creep
) /* creep */
2511 if (!(q
->obj
->status
& S_CREEP
))
2512 q
->obj
->y
+=CREEP_YOFFSET
;
2513 q
->obj
->status
|= S_CREEP
;
2518 a
=speed
?MAX_SPEED_WALK_FAST
:MAX_X_SPEED
;
2519 if (q
->obj
->status
& S_CREEP
)
2520 q
->obj
->y
-=CREEP_YOFFSET
;
2521 q
->obj
->status
&= ~S_CREEP
;
2526 q
->obj
->status
&= ~S_WALKING
;
2531 q
->obj
->status
|= S_WALKING
;
2532 q
->obj
->xspeed
-=WALK_ACCEL
;
2533 if (q
->obj
->xspeed
<-a
)q
->obj
->xspeed
=-a
;
2537 q
->obj
->status
|= S_WALKING
;
2538 q
->obj
->xspeed
+=WALK_ACCEL
;
2539 if (q
->obj
->xspeed
>a
)q
->obj
->xspeed
=a
;
2543 a
=which_update(q
->obj
,old_x
,old_y
,old_x_speed
,old_y_speed
,old_status
,old_ttl
);
2545 sendall_update_object(q
->obj
,0,a
);
2549 /* jump with given player */
2550 static void jump_player(struct player
*p
, char jet
, int direction
)
2554 if (p
->obj
->status
& ((jet
? 0 : S_FALLING
) | S_CREEP
))
2556 p
->obj
->status
|= S_FALLING
;
2557 p
->obj
->yspeed
=-SPEED_JUMP
;
2559 p
->obj
->status
|= S_JETPACK_ON
;
2568 add_int(p
->obj
->x
, (direction
& S_LOOKLEFT
) ?
2569 PLAYER_WIDTH
- 2 - (i
%2) : ((direction
& S_LOOKRIGHT
) ?
2570 1 - (i
%2) : PLAYER_WIDTH
/ 2)),
2571 p
->obj
->y
+FIRE_YOFFSET
+int2double(i
%4),
2572 mul((double)(8*(i
-4)), float2double(36*36)),
2574 (void *)(long)(p
->obj
->id
));
2577 sendall_new_object(o
, 0);
2580 sendall_update_object(p
->obj
,0,4); /* update speed + status */
2581 p
->obj
->status
&= ~S_JETPACK_ON
;
2584 /* change weapon of given player (w=new weapon) */
2585 static void change_weapon_player(struct player
*q
,int w
)
2591 if (q
->current_weapon
==w
)return;
2592 if (!(q
->weapons
&(1<<w
)))
2593 {send_message(q
,0,"No weapon.", M_INFO
);return;}
2595 {send_message(q
,0,"Not enough ammo.", M_INFO
);return;}
2596 q
->current_weapon
=w
;
2597 snprintf(txt
,256,"%s takes %s.\n",q
->name
,weapon
[w
].name
);
2599 send_update_player(q
);
2603 /* shoot with given player */
2604 /* direction: 0=right, 1=left */
2605 static void fire_player(struct player
*q
,int direction
)
2609 q
->obj
->status
&= ~S_CHAINSAW
; /* chainsaw */
2611 if (q
->current_weapon
==WEAPON_BLOODRAIN
) {
2612 q
->obj
->status
|= S_BLOODRAIN
;
2615 if (!(q
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
))||(q
->obj
->status
& S_CREEP
)||
2616 ((q
->obj
->status
& S_SHOOTING
)&&(q
->obj
->ttl
>HOLD_GUN_AFTER_SHOOT
)))
2618 if (!q
->ammo
[q
->current_weapon
])
2620 a
=select_best_weapon(q
);
2621 if (a
==q
->current_weapon
) return;
2622 q
->current_weapon
=a
;
2624 if (q
->current_weapon
!=WEAPON_CHAINSAW
)
2625 q
->ammo
[q
->current_weapon
]--;
2626 send_update_player(q
);
2627 q
->obj
->status
&= ~S_GRENADE
;
2628 if (q
->current_weapon
==WEAPON_SHOTGUN
) /* shotgun */
2630 s
=new_obj( /* SHELL */
2634 shotgun_shell_sprite
,
2637 add_int(q
->obj
->x
,direction
==1?0:PLAYER_WIDTH
),
2638 q
->obj
->y
+FIRE_YOFFSET
,
2639 q
->obj
->xspeed
+(direction
==1?-weapon
[1].shell_xspeed
:weapon
[1].shell_xspeed
),
2640 weapon
[1].shell_yspeed
,
2641 (void *)(long)(q
->obj
->id
));
2643 sendall_new_object(s
,0);
2644 s
=new_obj( /* straight */
2647 weapon
[q
->current_weapon
].ttl
,
2651 add_int(q
->obj
->x
,direction
==1?-2:PLAYER_WIDTH
+2),
2652 q
->obj
->y
+FIRE_YOFFSET
,
2653 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2655 (void *)(long)(q
->obj
->id
));
2657 sendall_new_object(s
,0);
2658 s
=new_obj( /* straight */
2661 weapon
[q
->current_weapon
].ttl
,
2665 add_int(q
->obj
->x
,direction
==1?0:PLAYER_WIDTH
),
2666 q
->obj
->y
+FIRE_YOFFSET
+int2double(1),
2667 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2669 (void *)(long)(q
->obj
->id
));
2671 sendall_new_object(s
,0);
2672 s
=new_obj( /* one up */
2675 weapon
[q
->current_weapon
].ttl
,
2679 add_int(q
->obj
->x
,direction
==1?-1:PLAYER_WIDTH
+1),
2680 q
->obj
->y
+FIRE_YOFFSET
,
2681 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2682 float2double((double).1*36),
2683 (void *)(long)(q
->obj
->id
));
2685 sendall_new_object(s
,0);
2686 s
=new_obj( /* two up */
2689 weapon
[q
->current_weapon
].ttl
,
2693 add_int(q
->obj
->x
,direction
==1?0:PLAYER_WIDTH
),
2694 q
->obj
->y
+FIRE_YOFFSET
-int2double(1),
2695 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2696 float2double((double).15*36),
2697 (void *)(long)(q
->obj
->id
));
2699 sendall_new_object(s
,0);
2700 s
=new_obj( /* one down */
2703 weapon
[q
->current_weapon
].ttl
,
2707 add_int(q
->obj
->x
,direction
==1?0:PLAYER_WIDTH
),
2708 q
->obj
->y
+FIRE_YOFFSET
+int2double(1),
2709 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2710 -float2double((double).1*36),
2711 (void *)(long)(q
->obj
->id
));
2713 sendall_new_object(s
,0);
2714 s
=new_obj( /* two down */
2717 weapon
[q
->current_weapon
].ttl
,
2721 add_int(q
->obj
->x
,direction
==1?-1:PLAYER_WIDTH
+1),
2722 q
->obj
->y
+FIRE_YOFFSET
,
2723 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2724 -float2double((double).15*36),
2725 (void *)(long)(q
->obj
->id
));
2727 sendall_new_object(s
,0);
2729 else if (q
->current_weapon
==WEAPON_BFG
) {
2730 s
=new_obj( /* straight */
2733 weapon
[q
->current_weapon
].ttl
,
2737 add_int(q
->obj
->x
,direction
==1?0:PLAYER_WIDTH
),
2738 q
->obj
->y
+FIRE_YOFFSET
,
2739 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2741 (void *)(long)(q
->obj
->id
));
2743 sendall_new_object(s
,0);
2745 else if (q
->current_weapon
==WEAPON_CHAINSAW
) {
2749 weapon
[q
->current_weapon
].ttl
,
2753 add_int(q
->obj
->x
,direction
==1?-2:PLAYER_WIDTH
),
2754 q
->obj
->y
+FIRE_YOFFSET
,
2755 (int)(1.2*q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
)),
2757 (void *)(long)(q
->obj
->id
));
2759 sendall_new_object(s
,0);
2763 weapon
[q
->current_weapon
].ttl
,
2767 add_int(q
->obj
->x
,direction
==1?-2:PLAYER_WIDTH
),
2768 q
->obj
->y
+FIRE_YOFFSET
+int2double(1),
2769 (int)(1.2*q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
)),
2771 (void *)(long)(q
->obj
->id
));
2773 sendall_new_object(s
,0);
2774 q
->obj
->status
|= S_CHAINSAW
;
2775 } else if (q
->current_weapon
==WEAPON_GRENADE
) /* grenades */
2777 q
->obj
->status
|= S_GRENADE
;
2778 q
->obj
->status
&= ~S_WALKING
;
2780 else if (!(q
->obj
->status
& S_BLOODRAIN
))
2782 s
=new_obj( /* SHELL */
2789 add_int(q
->obj
->x
,direction
==1?0:PLAYER_WIDTH
),
2790 q
->obj
->y
+FIRE_YOFFSET
,
2791 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].shell_xspeed
:weapon
[q
->current_weapon
].shell_xspeed
),
2792 weapon
[q
->current_weapon
].shell_yspeed
,
2793 (void *)(long)(q
->obj
->id
));
2795 sendall_new_object(s
,0);
2799 weapon
[q
->current_weapon
].ttl
,
2803 add_int(q
->obj
->x
,direction
==1?0:PLAYER_WIDTH
),
2804 q
->obj
->y
+FIRE_YOFFSET
,
2805 q
->obj
->xspeed
+(direction
==1?-weapon
[q
->current_weapon
].speed
:weapon
[q
->current_weapon
].speed
),
2807 (void *)(long)(q
->obj
->id
));
2809 sendall_new_object(s
,0);
2811 q
->obj
->xspeed
+=(direction
==1)?weapon
[q
->current_weapon
].impact
:-weapon
[q
->current_weapon
].impact
;
2812 q
->obj
->status
|= S_SHOOTING
;
2813 q
->obj
->status
|= S_HOLDING
;
2814 q
->obj
->ttl
=weapon
[q
->current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
2815 sendall_update_object(q
->obj
,0,6); /* update speed and status and ttl */
2816 q
->obj
->status
&= ~S_HOLDING
;
2820 /* update given player (jump, shoot, creep, change weapon) */
2821 static void move_player(struct player
*p
)
2825 if (p
->obj
->status
& S_DEAD
)
2826 return; /* dead player */
2828 if (p
->keyboard_status
.status
& KBD_DOWN_LADDER
) /* climb down a ladder */
2829 p
->obj
->status
|= S_CLIMB_DOWN
;
2831 p
->obj
->status
&=~ S_CLIMB_DOWN
;
2833 if (p
->keyboard_status
.status
& KBD_JUMP
)
2834 jump_player(p
, 0, (p
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
)));
2835 if ((p
->keyboard_status
.status
& KBD_JETPACK
) && (p
->obj
->status
& S_JETPACK
))
2836 jump_player(p
, 1, (p
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
)));
2837 if (p
->keyboard_status
.status
& KBD_RIGHT
)
2839 if ((p
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
))==S_LOOKRIGHT
) /* walk right */
2840 walk_player(p
,2,p
->keyboard_status
.status
& KBD_SPEED
,p
->keyboard_status
.status
& KBD_CREEP
);
2843 if (p
->obj
->status
& S_WALKING
)
2844 walk_player(p
,0,p
->keyboard_status
.status
& KBD_SPEED
,p
->keyboard_status
.status
& KBD_CREEP
); /* stop */
2847 a
=p
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
);
2848 p
->obj
->status
&= ~(S_LOOKLEFT
| S_LOOKRIGHT
);
2849 p
->obj
->status
|= (a
== S_LOOKLEFT
) ? 0 : S_LOOKRIGHT
;
2850 sendall_update_status(p
->obj
,0);
2855 if (p
->keyboard_status
.status
& KBD_LEFT
)
2857 if ((p
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
))==S_LOOKLEFT
) /* walk left */
2858 walk_player(p
,1,p
->keyboard_status
.status
& KBD_SPEED
,p
->keyboard_status
.status
& KBD_CREEP
);
2861 if (p
->obj
->status
& S_WALKING
)
2862 walk_player(p
,0,p
->keyboard_status
.status
& KBD_SPEED
,p
->keyboard_status
.status
& KBD_CREEP
); /* stop */
2865 a
=p
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
);
2866 p
->obj
->status
&= ~(S_LOOKLEFT
| S_LOOKRIGHT
);
2867 p
->obj
->status
|= (a
== S_LOOKRIGHT
) ? 0 : S_LOOKLEFT
;
2868 sendall_update_status(p
->obj
,0);
2872 change_weapon_player(p
,p
->keyboard_status
.weapon
);
2873 if (p
->keyboard_status
.status
& KBD_FIRE
)
2874 fire_player(p
,(p
->obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
))>>1);
2878 /* update players, kick out not responding players */
2879 static void update_players(void)
2881 struct player_list
*p
;
2884 unsigned long_long t
=get_time();
2886 for (p
=&players
;p
->next
;p
=p
->next
)
2888 /* this player is dead - delete him */
2889 if (t
-(p
->next
->member
).last_update
>=MAX_DUMB_TIME
)
2891 snprintf(txt
,256,"%s not responding. Kicked out of the game.\n",p
->next
->member
.name
);
2893 packet
=P_PLAYER_DELETED
;
2894 send_packet((char *)&packet
,1,(struct sockaddr
*)(&(p
->next
->member
.address
)),0,last_player
->member
.id
);
2895 snprintf(txt
,256,"%s was kicked out of the game.",p
->next
->member
.name
);
2896 sendall_message(0,txt
,0,0, M_INFO
);
2897 delete_player(p
->next
);
2898 if (!(p
->next
))break;
2901 move_player(&(p
->next
->member
));
2906 /* write help message to stdout */
2907 static void print_help(void)
2911 p
= "Portions (c) 2000 by Mikulas Patocka\n";
2914 printf( "0verkill server.\n"
2915 "(c)2000 Brainsoft\n"
2916 "Portions (c) 2000 by Filip Konvicka\n"
2917 "Usage: server [-nh] [-l <level_number>] [-p <port number>] [-i username[/password]] [-I] [-r]\n"
2918 "-i Installs as a service\n"
2919 "-I Installs with the LOCAL_SYSTEM account.\n"
2920 "-r Stops and removes the service\n"
2921 "-n Server can't be ended by client\n"
2922 "You must be an administrator in order to install/remove a service.\n");
2924 printf( "0verkill server.\n"
2925 "(c)2000 Brainsoft\n"
2927 "Usage: server [-nh] [-l <level number>] [-p <port number>]\n"
2928 "-n Server can't be ended by client\n", p
2934 static void parse_command_line(int argc
,char **argv
)
2942 a
=getopt(argc
,argv
,"hl:np:ri:Ic");
2944 a
=getopt(argc
,argv
,"hl:np:");
2957 break; /* run as console app */
2958 case 'r': /* remove service */
2961 case 'i': { /* install service */
2967 username
[sizeof(username
)-1]=0;
2969 if ( (pass
=strchr(optarg
, '/'))==NULL
) {
2971 strcpy(username
, optarg
);
2973 strcpy_s(username
, sizeof(optarg
), optarg
);
2975 memcpy(username
, optarg
, sizeof(username
)-1);
2979 int size
=pass
-optarg
;
2980 if ( size
>sizeof(username
)-1 )
2981 size
=sizeof(username
)-1;
2982 memcpy(username
, optarg
, size
);
2986 if ( size
>sizeof(password
)-1 )
2987 size
=sizeof(password
)-1;
2988 memcpy(password
, pass
, size
);
2991 CmdInstallService(user
, pass
, NULL
);
2994 case 'I': { /* install service */
2995 CmdInstallService(NULL
, NULL
, NULL
);
3005 port
=(unsigned short)strtoul(optarg
,&c
,10);
3006 if (*c
){ERROR("Error: Not a number.\n");EXIT(1);}
3009 if (!port
){ERROR("Error: Number underflow.\n");EXIT(1);}
3010 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3015 level_number
=strtoul(optarg
,&c
,10);
3016 if (*c
){ERROR("Error: Not a number.\n");EXIT(1);}
3019 if (!level_number
){ERROR("Error: Number underflow.\n");EXIT(1);}
3020 else {ERROR("Error: Number overflow.\n");EXIT(1);}
3032 /*-----------------------------------------------------------------------------------*/
3033 static int server(void)
3037 unsigned long_long last_time
;
3040 last_player
=&players
;
3043 snprintf(txt
,256,"Running 0verkill server version %d.%d\n",VERSION_MAJOR
,VERSION_MINOR
);
3046 snprintf(txt
,256,"This is 0verkill server for Win32, build #%u\n",VERSION_PORT
);
3049 message("Initialization.\n",2);
3051 message("Starting Windows Sockets\n",2);
3054 WSAStartup(0x101, &wd
);
3055 snprintf(txt
,256,"Started WinSock version %X.%02X\n", wd
.wVersion
/0x100, wd
.wVersion
&0xFF);
3059 init_area(); /* initialize playing area */
3064 ReportStatusToSCMgr(SERVICE_START_PENDING
, NO_ERROR
, 2000);
3067 message("Loading sprites.\n",2);
3068 load_sprites(DATA_PATH GAME_SPRITES_FILE
); /* players, corpses, bullets, ... */
3069 if (find_sprite("bullet",&bullet_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"bullet\".\n");ERROR(msg
);EXIT(1);}
3070 if (find_sprite("slug",&slug_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"slug\".\n");ERROR(msg
);EXIT(1);}
3071 if (find_sprite("shell",&shell_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"shell\".\n");ERROR(msg
);EXIT(1);}
3072 if (find_sprite("sshell",&shotgun_shell_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"sshell\".\n");ERROR(msg
);EXIT(1);}
3073 if (find_sprite("grenade",&grenade_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"grenade\".\n");ERROR(msg
);EXIT(1);}
3074 if (find_sprite("mess1",&mess1_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"mess1\".\n");ERROR(msg
);EXIT(1);}
3075 if (find_sprite("mess2",&mess2_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"mess2\".\n");ERROR(msg
);EXIT(1);}
3076 if (find_sprite("mess3",&mess3_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"mess3\".\n");ERROR(msg
);EXIT(1);}
3077 if (find_sprite("mess4",&mess4_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"mess4\".\n");ERROR(msg
);EXIT(1);}
3078 if (find_sprite("noise",&noise_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"noise\".\n");ERROR(msg
);EXIT(1);}
3079 if (find_sprite("bfgcell",&bfgcell_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"bfgcell\".\n");ERROR(msg
);EXIT(1);}
3080 for (a
=0;a
<N_SHRAPNELS
;a
++)
3082 snprintf(txt
, sizeof(txt
), "shrapnel%d",a
+1);
3083 if (find_sprite(txt
,&shrapnel_sprite
[a
])){char msg
[256];snprintf(msg
,256,"Can't find sprite \"%s\".\n",txt
);ERROR(msg
);EXIT(1);}
3084 snprintf(txt
, sizeof(txt
), "bfgbit%d",a
+1);
3085 if (find_sprite(txt
,&bfgbit_sprite
[a
])){char msg
[256];snprintf(msg
,256,"Can't find sprite \"%s\".\n",txt
);ERROR(msg
);EXIT(1);}
3086 snprintf(txt
, sizeof(txt
), "bloodrain%d",a
+1);
3087 if (find_sprite(txt
,&bloodrain_sprite
[a
])){char msg
[256];snprintf(msg
,256,"Can't find sprite \"%s\".\n",txt
);ERROR(msg
);EXIT(1);}
3089 snprintf(txt
, sizeof(txt
), "jetfire");
3090 if (find_sprite(txt
,&jetfire_sprite
)){char msg
[256];snprintf(msg
,256,"Can't find sprite \"%s\".\n",txt
);ERROR(msg
);EXIT(1);}
3092 LEVEL
=load_level(level_number
);
3093 level_checksum
=md5_level(level_number
);
3094 if (!LEVEL
){char txt
[256];snprintf(txt
,256,"Can't load level number %d\n",level_number
);ERROR(txt
);EXIT(1);}
3095 snprintf(txt
,256,"Loading level \"%s\"....\n",LEVEL
);
3097 snprintf(txt
,256,"%s%s%s",DATA_PATH
,LEVEL
,LEVEL_SPRITES_SUFFIX
);
3098 message("Loading level graphics.\n",2);
3100 snprintf(txt
,256,"%s%s%s",DATA_PATH
,LEVEL
,STATIC_DATA_SUFFIX
);
3101 message("Loading level map.\n",2);
3103 snprintf(txt
,256,"%s%s%s",DATA_PATH
,LEVEL
,DYNAMIC_DATA_SUFFIX
);
3104 message("Loading level objects.\n",2);
3108 message("Initializing socket.\n",2);
3109 init_socket(); /* initialize socket */
3111 message("Installing signal handlers.\n",2);
3112 signal(SIGINT
,signal_handler
);
3113 signal(SIGTERM
,signal_handler
);
3114 signal(SIGFPE
,signal_handler
);
3115 signal(SIGILL
,signal_handler
);
3116 signal(SIGABRT
,signal_handler
);
3118 signal(SIGBUS
,signal_handler
);
3119 signal(SIGQUIT
,signal_handler
);
3121 message("Game started.\n",2);
3124 DosSetPriority(PRTYS_PROCESS
, PRTYC_FOREGROUNDSERVER
, 1, 0);
3127 game_start
=get_time();
3128 srandom(game_start
);
3132 ReportStatusToSCMgr(SERVICE_RUNNING
, NO_ERROR
, 0);
3135 last_time
=get_time();
3137 last_time
+=PERIOD_USEC
;
3138 if (get_time()-last_time
>PERIOD_USEC
*100)last_time
=get_time();
3142 update_players(); /* MUST come after update_game otherwise when player shoots he hit himself */
3144 last_tick
=get_time();
3145 if (!active_players
&&(last_tick
-last_player_left
)>DELAY_BEFORE_SLEEP_USEC
&&(last_tick
-last_packet_came
)>DELAY_BEFORE_SLEEP_USEC
)
3148 message("Sleep\n",2);
3153 select(fd
+1,&fds
,0,0,0);
3155 message("Wakeup\n",2);
3157 WaitForSingleObject(&fd
, 500); /* wait max. 0.5 seconds, then we must test hServerExitEvent */
3161 /* we must return so that the service can be properly stopped */
3162 if ( hServerExitEvent
)
3165 sleep_until(last_time
+PERIOD_USEC
);
3172 int main(int argc
, char **argv
)
3177 SERVICE_TABLE_ENTRY dispatchTable
[]={{SERVICE_NAME
, (LPSERVICE_MAIN_FUNCTION
)ServiceMain
}, {NULL
, NULL
}};
3179 if ( !StartServiceCtrlDispatcher(dispatchTable
) ) {
3180 globErr
=GetLastError();
3181 /*LPTSTR pszError=CErrorContext::LoadWin32ErrorString(globErr);
3182 ::CharToOem(pszError, pszError);
3183 _tprintf(_T("StartServiceCtrlDispatcher failed: %u"), globErr);
3184 if ( pszError!=NULL ) {
3185 _tprintf(_T(": %s\r\n"), pszError);
3186 ::LocalFree(pszError);
3189 _tprintf(_T("\r\n"));*/
3190 AddToMessageLog("StartServiceCtrlDispatcher failed", 0);
3195 chdir_to_data_files();
3196 parse_command_line(argc
,argv
);
3200 check_memory_leaks();