2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Network/multi_respawn.cpp $
16 * Revision 1.6 2005/10/02 09:30:10 taylor
17 * sync up rest of big-endian network changes. it should at least be as good as what's in FS2_Open now, only better :)
19 * Revision 1.5 2004/06/11 01:43:48 tigital
20 * byte-swapping changes for bigendian systems
22 * Revision 1.4 2002/06/17 06:33:10 relnev
23 * ryan's struct patch for gcc 2.95
25 * Revision 1.3 2002/06/09 04:41:23 relnev
26 * added copyright header
28 * Revision 1.2 2002/05/07 03:16:47 theoddone33
29 * The Great Newline Fix
31 * Revision 1.1.1.1 2002/05/03 03:28:10 root
35 * 24 9/13/99 4:52p Dave
38 * 23 8/24/99 8:55p Dave
39 * Make sure nondimming pixels work properly in tech menu.
41 * 22 8/22/99 5:53p Dave
42 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
43 * instead of ship designations for multiplayer players.
45 * 21 8/06/99 9:46p Dave
46 * Hopefully final changes for the demo.
48 * 20 8/06/99 2:44a Dave
49 * Make sure dead players who leave respawn AI.
51 * 19 8/03/99 11:02p Dave
52 * Maybe fixed sync problems in multiplayer.
54 * 18 6/16/99 6:33p Dave
55 * Fixed HUD text problem in multiplayer respawns.
57 * 17 4/02/99 4:11p Anoop
58 * Temporary fix for RFC code.
60 * 16 3/19/99 9:51a Dave
61 * Checkin to repair massive source safe crash. Also added support for
62 * pof-style nebulae, and some new weapons code.
64 * 16 3/12/99 3:13p Anoop
65 * Temporary fix to get by dumb TvT respawning problem.
67 * 15 3/10/99 6:50p Dave
68 * Changed the way we buffer packets for all clients. Optimized turret
69 * fired packets. Did some weapon firing optimizations.
71 * 14 3/09/99 6:24p Dave
72 * More work on object update revamping. Identified several sources of
73 * unnecessary bandwidth.
75 * 13 3/02/99 9:25p Dave
76 * Added a bunch of model rendering debug code. Started work on fixing
77 * beam weapon wacky firing.
79 * 12 3/01/99 7:39p Dave
80 * Added prioritizing ship respawns. Also fixed respawns in TvT so teams
81 * don't mix respawn points.
83 * 11 2/24/99 4:12p Anoop
84 * Switched TEAM_TRAITOR on respawn from TvT to dogfight mode.
86 * 10 2/24/99 3:57p Dave
87 * Fixed yet another TEAM_TRAITOR problem in non-dogfight multiplayer.
89 * 9 2/24/99 2:25p Dave
90 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
91 * bug for dogfight more.
93 * 8 2/23/99 8:11p Dave
94 * Tidied up dogfight mode. Fixed TvT ship type problems for alpha wing.
95 * Small pass over todolist items.
97 * 7 2/23/99 2:29p Dave
98 * First run of oldschool dogfight mode.
100 * 6 2/11/99 3:08p Dave
101 * PXO refresh button. Very preliminary squad war support.
103 * 5 11/19/98 8:03a Dave
104 * Full support for D3-style reliable sockets. Revamped packet lag/loss
105 * system, made it receiver side and at the lowest possible level.
107 * 4 11/17/98 11:12a Dave
108 * Removed player identification by address. Now assign explicit id #'s.
110 * 3 11/05/98 5:55p Dave
111 * Big pass at reducing #includes
113 * 2 10/07/98 10:53a Dave
116 * 1 10/07/98 10:50a Dave
121 #include "systemvars.h"
124 #include "linklist.h"
125 #include "multimsgs.h"
126 #include "multiutil.h"
127 #include "missionweaponchoice.h"
128 #include "observer.h"
129 #include "gamesequence.h"
130 #include "hudconfig.h"
131 #include "hudobserver.h"
132 #include "hudmessage.h"
133 #include "multi_respawn.h"
134 #include "multi_observer.h"
135 #include "multi_team.h"
136 #include "hudwingmanstatus.h"
137 #include "missionparse.h"
138 #include "multiteamselect.h"
141 extern void get_vector_data(ubyte *data, int *size, vector vec);
142 extern void add_vector_data(ubyte *data, int *size, vector vec);
144 // ---------------------------------------------------------------------------------------
145 // MULTI RESPAWN DEFINES/VARS
148 // respawn notice codes
149 #define RESPAWN_BROADCAST 0x1 // server to clients - create this ship, and if you're the respawner, set it to be your object
150 #define RESPAWN_REQUEST 0x2 // client to server requesting a respawn (observer or normal)
151 #define AI_RESPAWN_NOTICE 0x3 // respawn an AI ship
153 // struct used to store AI objects which should get respawned
154 #define MAX_AI_RESPAWNS MAX_PLAYERS
155 #define AI_RESPAWN_TIME (7000) // should respawn 2.0 seconds after they die
157 typedef struct ai_respawn
159 p_object *pobjp; // parse object
160 int timestamp; // timestamp when this object should get respawned
163 ai_respawn Ai_respawns[MAX_AI_RESPAWNS]; // this is way too many, but I don't care
166 typedef struct respawn_point {
167 char ship_name[NAME_LENGTH+1]; // for priority respawns
168 vector pos; // respawn location (non-priority respawns)
169 int team; // team it belongs to
173 #define MAX_MULTI_RESPAWN_POINTS MAX_PLAYERS
174 respawn_point Multi_respawn_points[MAX_MULTI_RESPAWN_POINTS];
175 int Multi_respawn_point_count = 0;
176 int Multi_next_respawn_point = 0;
178 // priority ships for respawning
179 #define MAX_PRIORITY_POINTS 10
180 respawn_point Multi_respawn_priority_ships[MAX_PRIORITY_POINTS];
181 int Multi_respawn_priority_count = 0;
183 // ---------------------------------------------------------------------------------------
184 // MULTI RESPAWN FORWARD DECLARATIONS
187 // respawn the passed player with the passed ship object and weapon link settings
188 void multi_respawn_player(net_player *pl, char cur_primary_bank, char cur_secondary_bank, ubyte cur_link_status, ushort ship_ets, ushort net_sign, char *parse_name, vector *pos = NULL);
190 // respawn an AI ship
191 void multi_respawn_ai(p_object *pobjp);
193 // respawn myself as an observer
194 void multi_respawn_as_observer();
196 // send a request to the server saying I want to respawn (as an observer or not)
197 void multi_respawn_send_request(int as_observer);
199 // send a request to respawn an AI ship
200 void multi_respawn_send_ai_respawn(ushort net_signature);
202 // send a broadcast pack indicating a player has respawned
203 void multi_respawn_broadcast(net_player *player);
205 // <server> make the given player an observer
206 void multi_respawn_make_observer(net_player *pl);
208 // place a newly respawned object intelligently
209 void multi_respawn_place(object *new_obj, int team);
211 // respawn the server immediately
212 void multi_respawn_server();
215 // ---------------------------------------------------------------------------------------
216 // MULTI RESPAWN FUNCTIONS
219 // check to see if a net player needs to be respawned
220 void multi_respawn_check(object *objp)
223 net_player *pl = NULL;
226 // get the parse object since we are storing all data for the respawns in the parse object
227 pobjp = mission_parse_get_arrival_ship( objp->net_signature );
229 // the server should check against all players
230 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
231 player_index = multi_find_player_by_object(objp);
232 if(player_index != -1){
233 pl = &Net_players[player_index];
236 // clients should just check against themselves
237 else if(objp == Player_obj){
241 // if this ship isn't a player ship, then maybe it is an AI ship which should get respawed. Only respawn
242 // on the server, then send message to respawn on client.
245 // try and find the parse object with this net signature. If we found it, and it's a player start
246 // position, respawn it.
247 if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
252 // if we need to respawn this ai ship, add him to a list of ships to get respawned
253 if ( (pobjp->flags & P_OF_PLAYER_START) && (pobjp->respawn_count < Netgame.respawn) && !(Netgame.type_flags & NG_TYPE_DOGFIGHT) ){
256 for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
257 if ( Ai_respawns[i].pobjp == NULL ) {
258 Ai_respawns[i].pobjp = pobjp;
259 Ai_respawns[i].timestamp = timestamp(AI_RESPAWN_TIME);
263 SDL_assert( i < MAX_AI_RESPAWNS );
269 // reset his datarate timestamp
271 pl->s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) );
274 SDL_assert( pl != NULL );
275 SDL_assert( pobjp ); // we have a player, and we should have a record of it.
277 // mark the player as in the state of respawning
278 if( (pobjp->respawn_count < Netgame.respawn) || (Netgame.type_flags & NG_TYPE_DOGFIGHT) ){
279 pl->flags |= NETINFO_FLAG_RESPAWNING;
281 // otherwise mark the player as being in limbo
283 pl->flags |= NETINFO_FLAG_LIMBO;
287 // notify of a player leaving
288 void multi_respawn_player_leave(net_player *pl)
294 if( MULTI_OBSERVER((*pl)) ){
297 if((Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
300 if(pl->p_info.p_objp == NULL){
305 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){
309 // if we need to respawn this ai ship, add him to a list of ships to get respawned
310 p_object *pobjp = pl->p_info.p_objp;
311 if ( (pobjp->flags & P_OF_PLAYER_START) && (pobjp->respawn_count < Netgame.respawn) ){
314 for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
315 if ( Ai_respawns[i].pobjp == NULL ) {
316 Ai_respawns[i].pobjp = pobjp;
317 Ai_respawns[i].timestamp = timestamp(AI_RESPAWN_TIME);
325 void multi_respawn_normal()
327 // make sure we should be respawning and _not_ as an observer
328 SDL_assert((Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO));
330 // server respawns immediately
331 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
332 multi_respawn_server();
334 // client sends a respawn request (multiple ones are ok if he clicks over and over)
335 multi_respawn_send_request(0);
339 // respawn as an observer
340 void multi_respawn_observer()
342 // make sure we should be respawning as an observer
343 SDL_assert(!(Net_player->flags & NETINFO_FLAG_RESPAWNING) && (Net_player->flags & NETINFO_FLAG_LIMBO));
345 // respawn as an observer
346 multi_respawn_as_observer();
348 // clients should notify the server that they are doing so
349 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
350 multi_respawn_send_request(1);
353 // jump back into the game right away
354 gameseq_post_event(GS_EVENT_ENTER_GAME);
357 // server should check to see if any respawned players have run out of their invulnerability
358 void multi_respawn_handle_invul_players()
362 for(idx=0;idx<MAX_PLAYERS;idx++){
363 if(MULTI_CONNECTED(Net_players[idx]) && (Objects[Net_players[idx].player->objnum].flags & OF_INVULNERABLE)){
364 // make him normal (_non_ invulnerable) on either of 2 conditions :
365 // 1.) More than 5 seconds have passed
366 // 2.) He's fired either a primary or a secondary weapon
367 if( ((Net_players[idx].s_info.invul_timestamp != -1) && (timestamp_elapsed(Net_players[idx].s_info.invul_timestamp))) ||
368 ((Net_players[idx].player->ci.fire_primary_count > 0) || (Net_players[idx].player->ci.fire_secondary_count > 0)) ) {
369 objp = &Objects[Net_players[idx].player->objnum];
370 obj_set_flags(objp,objp->flags & ~(OF_INVULNERABLE));
376 // build a list of respawn points for the mission
377 void multi_respawn_build_points()
383 Multi_respawn_point_count = 0;
384 Multi_next_respawn_point = 0;
385 moveup = GET_FIRST(&Ship_obj_list);
386 while(moveup != END_OF_LIST(&Ship_obj_list)){
388 if(Objects[moveup->objnum].flags & (OF_PLAYER_SHIP | OF_COULD_BE_PLAYER)){
389 r = &Multi_respawn_points[Multi_respawn_point_count++];
391 r->pos = Objects[moveup->objnum].pos;
392 r->team = Ships[Objects[moveup->objnum].instance].team;
394 moveup = GET_NEXT(moveup);
397 // priority respawn points
398 Multi_respawn_priority_count = 0;
399 moveup = GET_FIRST(&Ship_obj_list);
400 while(moveup != END_OF_LIST(&Ship_obj_list)){
402 if((Ships[Objects[moveup->objnum].instance].respawn_priority > 0) && (Multi_respawn_priority_count < MAX_PRIORITY_POINTS)){
403 r = &Multi_respawn_priority_ships[Multi_respawn_priority_count++];
405 strcpy(r->ship_name, Ships[Objects[moveup->objnum].instance].ship_name);
406 r->team = Ships[Objects[moveup->objnum].instance].team;
408 moveup = GET_NEXT(moveup);
413 // ---------------------------------------------------------------------------------------
414 // MULTI RESPAWN FORWARD DECLARATIONS
417 void multi_respawn_wing_stuff(ship *shipp)
421 // deal with re-adding this ship to it's wing
422 SDL_assert( shipp->wingnum != -1 );
423 wingp = &Wings[shipp->wingnum];
424 wingp->ship_index[wingp->current_count] = SHIP_INDEX(shipp);
425 wingp->current_count++;
427 hud_set_wingman_status_alive(shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
430 int multi_respawn_common_stuff(p_object *pobjp)
432 int objnum, team, slot_index;
438 objnum = parse_create_object(pobjp);
439 SDL_assert(objnum != -1);
440 objp = &Objects[objnum];
442 // get the team and slot
443 shipp = &Ships[objp->instance];
444 multi_ts_get_team_and_slot(shipp->ship_name, &team, &slot_index);
445 SDL_assert( team != -1 );
446 SDL_assert( slot_index != -1 );
448 // reset object update stuff
449 for(idx=0; idx<MAX_PLAYERS; idx++){
450 shipp->np_updates[idx].orient_chksum = 0;
451 shipp->np_updates[idx].pos_chksum = 0;
452 shipp->np_updates[idx].seq = 0;
453 shipp->np_updates[idx].status_update_stamp = -1;
454 shipp->np_updates[idx].subsys_update_stamp = -1;
455 shipp->np_updates[idx].update_stamp = -1;
458 // change the ship type and the weapons
459 change_ship_type(objp->instance, Wss_slots_teams[team][slot_index].ship_class);
460 wl_bash_ship_weapons(&shipp->weapons,&Wss_slots_teams[team][slot_index]);
461 multi_respawn_wing_stuff( shipp );
463 if(Netgame.type_flags & NG_TYPE_TEAM){
464 multi_team_mark_ship(&Ships[Objects[objnum].instance]);
467 pobjp->respawn_count++;
472 // respawn the passed player with the passed ship object and weapon link settings
473 void multi_respawn_player(net_player *pl, char cur_primary_bank, char cur_secondary_bank, ubyte cur_link_status, ushort ship_ets, ushort net_sig, char *parse_name, vector *pos)
480 // try and find the parse object
481 pobjp = mission_parse_get_arrival_ship(parse_name);
482 SDL_assert(pobjp != NULL);
486 objnum = multi_respawn_common_stuff(pobjp);
488 SDL_assert( objnum != -1 );
489 objp = &Objects[objnum];
490 shipp = &Ships[objp->instance];
492 // this is a player, so mark him as a player,
493 objp->flags |= OF_PLAYER_SHIP;
494 objp->flags &= ~OF_COULD_BE_PLAYER;
496 // server should mark this player as invulerable for a short time
497 if ( MULTIPLAYER_MASTER ) {
498 objp->flags |= OF_INVULNERABLE;
499 pl->s_info.invul_timestamp = timestamp(RESPAWN_INVUL_TIMESTAMP);
500 multi_respawn_place( objp, shipp->team );
503 // reset his datarate timestamp
505 pl->s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) );
507 // set some player information
508 pl->player->objnum = objnum;
509 if ( pl == Net_player ) {
510 // this is a hack to ensure that old (dead) player ships are destroyed, since at this point he's actually an OBJ_GHOST
511 Player_obj->flags |= OF_SHOULD_BE_DEAD;
512 obj_delete(OBJ_INDEX(Player_obj));
516 Player_ai = &Ai_info[Player_ship->ai_index];
518 // get rid of the annoying HUD dead message text.
519 HUD_init_fixed_text();
522 // clients bash net signature
523 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
524 objp->net_signature = net_sig;
527 // restore the correct weapon bank selections
528 shipp->weapons.current_primary_bank = (int)cur_primary_bank;
529 shipp->weapons.current_secondary_bank = (int)cur_secondary_bank;
530 if(cur_link_status & (1<<0)){
531 shipp->flags |= SF_PRIMARY_LINKED;
533 shipp->flags &= ~(SF_PRIMARY_LINKED);
535 if(cur_link_status & (1<<1)){
536 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
538 shipp->flags &= ~(SF_SECONDARY_DUAL_FIRE);
541 SDL_assert( ship_ets != 0 ); // find dave or allender
543 // restore the correct ets settings
544 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
546 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
548 shipp->engine_recharge_index = (ship_ets & 0x000f);
550 // if this is a dogfight mission, make him TEAM_TRAITOR
551 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
552 shipp->team = TEAM_TRAITOR;
555 // maybe bash ship position
560 // unset his respawning flag
561 pl->flags &= ~(NETINFO_FLAG_RESPAWNING | NETINFO_FLAG_LIMBO);
563 // blast his control and button info clear
564 memset(&pl->player->bi, 0, sizeof(pl->player->bi));
565 memset(&pl->player->ci, 0, sizeof(pl->player->ci));
567 // if this is me, clear accum button info
568 if(pl == Net_player){
569 // clear multiplayer button info
570 extern button_info Multi_ship_status_bi;
571 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
574 // notify other players of the respawn
575 if ( MULTIPLAYER_MASTER ){
576 multi_respawn_broadcast(pl);
580 // respawns an AI ship.
581 void multi_respawn_ai( p_object *pobjp )
586 // create the object and change the ship type
587 objnum = multi_respawn_common_stuff( pobjp );
588 objp = &Objects[objnum];
590 // be sure the the OF_PLAYER_SHIP flag is unset, and the could be player flag is set
591 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
592 objp->flags &= ~OF_PLAYER_SHIP;
595 // <server> make the given player an observer
596 void multi_respawn_make_observer(net_player *pl)
598 pl->flags |= (NETINFO_FLAG_OBSERVER | NETINFO_FLAG_OBS_PLAYER);
599 pl->flags &= ~(NETINFO_FLAG_RESPAWNING | NETINFO_FLAG_LIMBO);
601 // MWA 6/3/98 -- don't set to high -- let it default to whatever player chose
602 //pl->p_info.options.obj_update_level = OBJ_UPDATE_HIGH;
603 pl->last_heard_time = timer_get_fixed_seconds();
605 // reset the ping time for this player
606 multi_ping_reset(&pl->s_info.ping);
608 // timestamp his last_full_update_time
609 pl->s_info.last_full_update_time = timestamp(0);
611 // create an observer object for him
612 multi_obs_create_observer(pl);
615 // respawn myself as an observer
616 void multi_respawn_as_observer()
618 // configure the hud to be in "observer" mode
619 hud_config_as_observer(Player_ship,Player_ai);
621 // blow away my old player object
622 Player_obj->flags |= OF_SHOULD_BE_DEAD;
623 obj_delete(OBJ_INDEX(Player_obj));
625 // create a new shiny observer object for me
626 multi_obs_create_observer(Net_player);
628 // set my object to be the observer object
629 Player_obj = &Objects[Net_player->player->objnum];
630 Player_ship = &Hud_obs_ship;
631 Player_ai = &Hud_obs_ai;
633 // set some flags for myself
634 Net_player->flags |= NETINFO_FLAG_OBSERVER;
635 Net_player->flags |= NETINFO_FLAG_OBS_PLAYER;
636 Net_player->flags &= ~(NETINFO_FLAG_LIMBO);
638 // clear my auto-match speed flag
639 Net_player->player->flags &= ~(PLAYER_FLAGS_AUTO_MATCH_SPEED | PLAYER_FLAGS_MATCH_TARGET);
641 // reset the control info structure
642 memset(&Player->ci,0,sizeof(control_info));
645 // send a request to respawn an AI object
646 void multi_respawn_send_ai_respawn( ushort net_signature )
651 // build the header and add the opcode
652 BUILD_HEADER(RESPAWN_NOTICE);
653 val = AI_RESPAWN_NOTICE;
655 ADD_USHORT( net_signature );
657 // broadcast the packet to all players
658 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
659 multi_io_send_to_all_reliable(data, packet_size);
662 // send a request to the server saying I want to respawn (as an observer or not)
663 void multi_respawn_send_request(int as_observer)
668 // build the header and add the opcode
669 BUILD_HEADER(RESPAWN_NOTICE);
670 val = RESPAWN_REQUEST;
673 // add a byte indicating whether or not we want to respawn as an observer
674 val = (ubyte)as_observer;
677 // send the request to the server
678 multi_io_send_reliable(Net_player, data, packet_size);
681 // send a broadcast pack indicating a player has respawned
682 void multi_respawn_broadcast(net_player *np)
689 // broadcast the packet to all players
690 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
692 signature = Objects[np->player->objnum].net_signature;
693 pos = Objects[np->player->objnum].pos;
695 // build the header and add the opcode
696 BUILD_HEADER(RESPAWN_NOTICE);
697 val = RESPAWN_BROADCAST;
700 // add the data for the respawn
701 ADD_USHORT(signature);
702 add_vector_data( data, &packet_size, pos );
703 ADD_SHORT(np->player_id);
704 ADD_DATA(np->s_info.cur_primary_bank);
705 ADD_DATA(np->s_info.cur_secondary_bank);
706 ADD_DATA(np->s_info.cur_link_status);
707 ADD_USHORT(np->s_info.ship_ets);
708 ADD_STRING(np->p_info.p_objp->name);
710 SDL_assert( np->s_info.ship_ets != 0 ); // find dave or allender
712 multi_io_send_to_all_reliable(data, packet_size);
715 // process an incoming respawn info packet
716 void multi_respawn_process_packet(ubyte *data, header *hinfo)
718 ubyte code,cur_link_status;
719 char cur_primary_bank,cur_secondary_bank;
720 ushort net_sig,ship_ets;
724 char parse_name[1024] = "";
725 int offset = HEADER_LENGTH;
727 // determine who send the packet
728 player_index = find_player_id(hinfo->id);
729 if(player_index == -1){
730 nprintf(("Network","Couldn't find player for processing respawn packet!\n"));
736 // do something based upon the opcode
739 case AI_RESPAWN_NOTICE:
742 GET_USHORT( net_sig );
743 pobjp = mission_parse_get_arrival_ship( net_sig );
744 SDL_assert( pobjp != NULL );
745 multi_respawn_ai( pobjp );
748 case RESPAWN_BROADCAST:
749 // get the respawn data
751 get_vector_data( data, &offset, v );
752 GET_SHORT(player_id);
753 GET_DATA(cur_primary_bank);
754 GET_DATA(cur_secondary_bank);
755 GET_DATA(cur_link_status);
756 GET_USHORT(ship_ets);
757 GET_STRING(parse_name);
758 player_index = find_player_id(player_id);
759 if(player_index == -1){
760 nprintf(("Network","Couldn't find player to respawn!\n"));
764 // create the ship and assign its position, net_signature, and class
765 // respawn the player
766 multi_respawn_player(&Net_players[player_index], cur_primary_bank, cur_secondary_bank, cur_link_status, ship_ets, net_sig, parse_name, &v);
768 // if this is for me, I should jump back into gameplay
769 if(&Net_players[player_index] == Net_player){
770 extern int Player_multi_died_check;
771 Player_multi_died_check = -1;
773 gameseq_post_event(GS_EVENT_ENTER_GAME);
777 case RESPAWN_REQUEST:
778 // determine whether he wants to respawn as an observer or not
781 nprintf(("Network","Received respawn request\n"));
782 if(player_index == -1){
783 nprintf(("Network","Received respawn request from unknown player!\n"));
787 // make sure he's not making an invalid request
788 if((code == 0) && !(Net_players[player_index].flags & NETINFO_FLAG_RESPAWNING)){
789 nprintf(("Network","Received respawn request from player who shouldn't be respawning!\n"));
792 } else if((code == 1) && !(Net_players[player_index].flags & NETINFO_FLAG_LIMBO)){
793 nprintf(("Network","Received respawn observer request from a player who shouldn't be respawning as an observer!\n"));
798 // otherwise perform the operation
799 // respawn the guy as an observer
801 multi_respawn_make_observer(&Net_players[player_index]);
803 // respawn him as normal
805 // create his new ship, and change him from respawning to respawned
806 SDL_assert(Net_players[player_index].p_info.p_objp != NULL);
807 if(Net_players[player_index].p_info.p_objp != NULL){
808 multi_respawn_player(&Net_players[player_index], Net_players[player_index].s_info.cur_primary_bank, Net_players[player_index].s_info.cur_secondary_bank,Net_players[player_index].s_info.cur_link_status, Net_players[player_index].s_info.ship_ets, 0, Net_players[player_index].p_info.p_objp->name);
817 // respawn the server immediately
818 void multi_respawn_server()
820 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
823 multi_respawn_player(Net_player, Net_player->s_info.cur_primary_bank, Net_player->s_info.cur_secondary_bank, Net_player->s_info.cur_link_status, Net_player->s_info.ship_ets, 0, Net_player->p_info.p_objp->name);
825 // jump back into the game
826 gameseq_post_event(GS_EVENT_ENTER_GAME);
829 // level init for respawn stuff
830 void multi_respawn_init()
834 for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
835 Ai_respawns[i].pobjp = NULL;
836 Ai_respawns[i].timestamp = timestamp(-1);
840 // function to detect whether or not we have AI ships to respawn this frame
841 void multi_respawn_check_ai()
845 for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
846 if ( Ai_respawns[i].pobjp != NULL ) {
847 if ( timestamp_elapsed(Ai_respawns[i].timestamp) ) {
849 // be sure that ship is actually gone before respawning it.
850 if ( ship_name_lookup(Ai_respawns[i].pobjp->name) != -1 ) {
851 Ai_respawns[i].timestamp = timestamp(1000);
853 multi_respawn_ai( Ai_respawns[i].pobjp );
854 multi_respawn_send_ai_respawn( Ai_respawns[i].pobjp->net_signature );
855 Ai_respawns[i].pobjp = NULL;
856 Ai_respawns[i].timestamp = timestamp(-1);
865 // this is a completely off the cuff way of doing things. Feel free to find a better way.
867 // 1. Take the average vector position of all the ships in the game
868 // 2. Check to make sure we aren't within the radius of any of the ships in the game
869 // a.) If we are, move away along the vector between the two ships (by the radius of the ship it collided with)
872 #define MOVE_AWAY() { vector away; vm_vec_sub(&away,&new_obj->pos,&hit_check->pos); \
873 vm_vec_normalize_quick(&away); vm_vec_scale(&away,hit_check->radius+hit_check->radius); \
874 vm_vec_add2(&new_obj->pos,&away); }
876 #define WITHIN_RADIUS() { float dist; dist=vm_vec_dist(&new_obj->pos,&hit_check->pos); \
877 if(dist <= hit_check->radius) collided = 1; }
880 #define WITHIN_BBOX() do { \
881 float scale = 2.0f; \
882 polymodel *pm = model_get(s_check->modelnum); \
885 vector temp = new_obj->pos; \
887 vm_vec_sub2(&temp, &hit_check->pos); \
888 vm_vec_rotate(&gpos, &temp, &hit_check->orient); \
889 if((gpos.xyz.x >= pm->mins.xyz.x * scale) && (gpos.xyz.y >= pm->mins.xyz.y * scale) && (gpos.xyz.z >= pm->mins.xyz.z * scale) && (gpos.xyz.x <= pm->maxs.xyz.x * scale) && (gpos.xyz.y <= pm->maxs.xyz.y * scale) && (gpos.xyz.z <= pm->maxs.xyz.z * scale)) { \
895 #define MOVE_AWAY_BBOX() do { \
896 polymodel *pm = model_get(s_check->modelnum); \
898 switch((int)frand_range(0.0f, 3.9f)){ \
900 new_obj->pos.xyz.x += 200.0f; \
903 new_obj->pos.xyz.x -= 200.0f; \
906 new_obj->pos.xyz.y += 200.0f; \
909 new_obj->pos.xyz.y -= 200.0f; \
912 new_obj->pos.xyz.z -= 200.0f; \
918 void multi_respawn_place(object *new_obj, int team)
923 object *pri_obj = NULL;
925 int collided, idx, lookup;
927 // first determine if there are any appropriate priority ships to use
930 for(idx=0; idx<Multi_respawn_priority_count; idx++){
931 // all relevant ships
932 if((Multi_respawn_priority_ships[idx].team == team) || !(Netgame.type_flags & NG_TYPE_TEAM)){
934 lookup = ship_name_lookup(Multi_respawn_priority_ships[idx].ship_name);
935 if( (lookup >= 0) && ((pri == NULL) || (Ships[lookup].respawn_priority > pri->respawn_priority)) && (Ships[lookup].objnum >= 0) && (Ships[lookup].objnum < MAX_OBJECTS)){
936 pri = &Ships[lookup];
937 pri_obj = &Objects[Ships[lookup].objnum];
942 // if we have a relevant respawn ship
943 if((pri != NULL) && (pri_obj != NULL)){
944 // pick a point just outside his bounding box
945 polymodel *pm = model_get(pri->modelnum);
947 // hmm, ugly. Pick a point 2000 meters to the y direction
949 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, 2000.0f);
951 // pick a random direction
952 int d = (int)frand_range(0.0f, 5.9f);
955 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, (pm->maxs.xyz.x - pm->mins.xyz.x));
959 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, -(pm->maxs.xyz.x - pm->mins.xyz.x));
963 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, (pm->maxs.xyz.y - pm->mins.xyz.y));
967 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y));
971 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.fvec, (pm->maxs.xyz.z - pm->mins.xyz.z));
975 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.fvec, -(pm->maxs.xyz.z - pm->mins.xyz.z));
979 vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y));
984 // otherwise, resort to plain respawn points
986 SDL_assert(Multi_respawn_point_count > 0);
988 // get the next appropriate respawn point by team
991 while(!lookup && (count < 13)){
992 if((team == TEAM_TRAITOR) || (team == Multi_respawn_points[Multi_next_respawn_point].team)){
998 if(Multi_next_respawn_point >= (Multi_respawn_point_count-1)){
999 Multi_next_respawn_point = 0;
1001 Multi_next_respawn_point++;
1009 new_obj->pos = Multi_respawn_points[Multi_next_respawn_point].pos;
1012 // now make sure we're not colliding with anyone
1015 moveup = GET_FIRST(&Ship_obj_list);
1016 while(moveup!=END_OF_LIST(&Ship_obj_list)){
1017 // don't check the new_obj itself!!
1018 if(Objects[moveup->objnum].net_signature != new_obj->net_signature){
1019 hit_check = &Objects[moveup->objnum];
1020 SDL_assert(hit_check->type == OBJ_SHIP);
1021 SDL_assert(hit_check->instance >= 0);
1022 if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){
1025 s_check = &Ships[hit_check->instance];
1027 // just to make sure we don't get any strange magnitude errors
1028 if(vm_vec_same(&hit_check->pos, &new_obj->pos)){
1029 new_obj->pos.xyz.x += 1.0f;
1039 moveup = GET_NEXT(moveup);