FS2_Open
Open source remastering of the Freespace 2 engine
multi_respawn.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "network/multi_respawn.h"
14 #include "network/multi.h"
15 #include "object/object.h"
16 #include "globalincs/linklist.h"
17 #include "network/multimsgs.h"
18 #include "network/multiutil.h"
21 #include "hud/hudconfig.h"
22 #include "hud/hudobserver.h"
23 #include "hud/hudmessage.h"
24 #include "network/multi_observer.h"
25 #include "network/multi_team.h"
26 #include "hud/hudwingmanstatus.h"
27 #include "mission/missionparse.h"
28 #include "ship/ship.h"
29 #include "playerman/player.h"
32 #include "io/timer.h"
33 #include "iff_defs/iff_defs.h"
34 
35 
36 // ---------------------------------------------------------------------------------------
37 // MULTI RESPAWN DEFINES/VARS
38 //
39 
40 // respawn notice codes
41 #define RESPAWN_BROADCAST 0x1 // server to clients - create this ship, and if you're the respawner, set it to be your object
42 #define RESPAWN_REQUEST 0x2 // client to server requesting a respawn (observer or normal)
43 #define AI_RESPAWN_NOTICE 0x3 // respawn an AI ship
44 
45 // struct used to store AI objects which should get respawned
46 #define MAX_AI_RESPAWNS MAX_PLAYERS
47 #define AI_RESPAWN_TIME (7000) // should respawn 2.0 seconds after they die
48 
49 typedef struct ai_respawn
50 {
51  p_object *pobjp; // parse object
52  int timestamp; // timestamp when this object should get respawned
53 } ai_respawn;
54 
55 ai_respawn Ai_respawns[MAX_AI_RESPAWNS]; // this is way too many, but I don't care
56 
57 // respawn point
58 typedef struct respawn_point {
59  char ship_name[NAME_LENGTH+1]; // for priority respawns
60  vec3d pos; // respawn location (non-priority respawns)
61  int team; // team it belongs to
63 
64 // respawn points
65 #define MAX_MULTI_RESPAWN_POINTS MAX_PLAYERS
69 
70 // priority ships for respawning
71 #define MAX_PRIORITY_POINTS 10
74 
75 // ---------------------------------------------------------------------------------------
76 // MULTI RESPAWN FORWARD DECLARATIONS
77 //
78 
79 // respawn the passed player with the passed ship object and weapon link settings
80 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, vec3d *pos = NULL);
81 
82 // respawn an AI ship
83 void multi_respawn_ai(p_object *pobjp);
84 
85 // respawn myself as an observer
87 
88 // send a request to the server saying I want to respawn (as an observer or not)
89 void multi_respawn_send_request(int as_observer);
90 
91 // send a request to respawn an AI ship
92 void multi_respawn_send_ai_respawn(ushort net_signature);
93 
94 // send a broadcast pack indicating a player has respawned
96 
97 // <server> make the given player an observer
99 
100 // place a newly respawned object intelligently
101 void multi_respawn_place(object *new_obj, int team);
102 
103 // respawn the server immediately
104 void multi_respawn_server();
105 
106 void prevent_spawning_collision(object *new_obj);
107 
108 // ---------------------------------------------------------------------------------------
109 // MULTI RESPAWN FUNCTIONS
110 //
111 
112 // check to see if a net player needs to be respawned
114 {
115  int player_index;
116  net_player *pl = NULL;
117  p_object *pobjp;
118 
119  // get the parse object since we are storing all data for the respawns in the parse object
121 
122  // the server should check against all players
124  player_index = multi_find_player_by_object(objp);
125  if(player_index != -1){
126  pl = &Net_players[player_index];
127  }
128  }
129  // clients should just check against themselves
130  else if(objp == Player_obj){
131  pl = Net_player;
132  }
133 
134  // if this ship isn't a player ship, then maybe it is an AI ship which should get respawed. Only respawn
135  // on the server, then send message to respawn on client.
136  if( pl == NULL ) {
137 
138  // try and find the parse object with this net signature. If we found it, and it's a player start
139  // position, respawn it.
141  if ( !pobjp ){
142  return;
143  }
144 
145  // if we need to respawn this ai ship, add him to a list of ships to get respawned
146  if ( (pobjp->flags & P_OF_PLAYER_START) && (pobjp->respawn_count < Netgame.respawn) && !(Netgame.type_flags & NG_TYPE_DOGFIGHT) ){
147  int i;
148 
149  for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
150  if ( Ai_respawns[i].pobjp == NULL ) {
151  Ai_respawns[i].pobjp = pobjp;
152  Ai_respawns[i].timestamp = timestamp(AI_RESPAWN_TIME);
153  break;
154  }
155  }
156  Assert( i < MAX_AI_RESPAWNS );
157  }
158  }
159 
160  return;
161  } else {
162  // reset his datarate timestamp
163  extern int OO_gran;
164  pl->s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) );
165  }
166 
167  Assert( pl != NULL );
168  Assert( pobjp ); // we have a player, and we should have a record of it.
169 
170  // mark the player as in the state of respawning
173  }
174  // otherwise mark the player as being in limbo
175  else {
176  pl->flags |= NETINFO_FLAG_LIMBO;
177  }
178 }
179 
180 // notify of a player leaving
182 {
183  // bogus
184  if(pl == NULL){
185  return;
186  }
187  if( MULTI_OBSERVER((*pl)) ){
188  return;
189  }
190  if((Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
191  return;
192  }
193  if(pl->p_info.p_objp == NULL){
194  return;
195  }
196 
197  // dogfight mode
198  if(MULTI_DOGFIGHT){
199  return;
200  }
201 
202  // if we need to respawn this ai ship, add him to a list of ships to get respawned
203  p_object *pobjp = pl->p_info.p_objp;
204  if ( (pobjp->flags & P_OF_PLAYER_START) && (pobjp->respawn_count < Netgame.respawn) ){
205  int i;
206 
207  for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
208  if ( Ai_respawns[i].pobjp == NULL ) {
209  Ai_respawns[i].pobjp = pobjp;
210  Ai_respawns[i].timestamp = timestamp(AI_RESPAWN_TIME);
211  break;
212  }
213  }
214  }
215 }
216 
217 // respawn normally
219 {
220  // make sure we should be respawning and _not_ as an observer
223 
224  // server respawns immediately
227  } else {
228  // client sends a respawn request (multiple ones are ok if he clicks over and over)
230  }
231 }
232 
233 // respawn as an observer
235 {
236  // make sure we should be respawning as an observer
238 
239  // respawn as an observer
241 
242  // clients should notify the server that they are doing so
245  }
246 
247  // jump back into the game right away
249 }
250 
251 // server should check to see if any respawned players have run out of their invulnerability
253 {
254  int idx;
255  object *objp;
256  for(idx=0;idx<MAX_PLAYERS;idx++){
257  if(MULTI_CONNECTED(Net_players[idx]) && (Objects[Net_players[idx].m_player->objnum].flags & OF_INVULNERABLE)){
258  // make him normal (_non_ invulnerable) on either of 2 conditions :
259  // 1.) More than 5 seconds have passed
260  // 2.) He's fired either a primary or a secondary weapon
261  if( ((Net_players[idx].s_info.invul_timestamp != -1) && (timestamp_elapsed(Net_players[idx].s_info.invul_timestamp))) ||
264  obj_set_flags(objp,objp->flags & ~(OF_INVULNERABLE));
265  }
266  }
267  }
268 }
269 
270 // build a list of respawn points for the mission
272 {
273  ship_obj *moveup;
274  respawn_point *r;
275 
276  // respawn points
279  moveup = GET_FIRST(&Ship_obj_list);
280  while(moveup != END_OF_LIST(&Ship_obj_list)){
281  // player ships
283  r = &Multi_respawn_points[Multi_respawn_point_count++];
284 
285  r->pos = Objects[moveup->objnum].pos;
286  r->team = Ships[Objects[moveup->objnum].instance].team;
287  }
288  moveup = GET_NEXT(moveup);
289  }
290 
291  // priority respawn points
293  moveup = GET_FIRST(&Ship_obj_list);
294  while(moveup != END_OF_LIST(&Ship_obj_list)){
295  // stuff info
297  r = &Multi_respawn_priority_ships[Multi_respawn_priority_count++];
298 
300  r->team = Ships[Objects[moveup->objnum].instance].team;
301  }
302  moveup = GET_NEXT(moveup);
303  }
304 }
305 
306 
307 // ---------------------------------------------------------------------------------------
308 // MULTI RESPAWN FORWARD DECLARATIONS
309 //
310 
312 {
313  wing *wingp;
314 
315  // deal with re-adding this ship to it's wing
316  Assert( shipp->wingnum != -1 );
317  wingp = &Wings[shipp->wingnum];
318  wingp->ship_index[wingp->current_count] = SHIP_INDEX(shipp);
319  wingp->current_count++;
320 
322 }
323 
325 {
326  int objnum, team, slot_index;
327  object *objp;
328  ship *shipp;
329  int idx;
330 
331  // create the object
332  objnum = parse_create_object(pobjp);
333  Assert(objnum != -1);
334  objp = &Objects[objnum];
335 
336  // get the team and slot
337  shipp = &Ships[objp->instance];
338  multi_ts_get_team_and_slot(shipp->ship_name, &team, &slot_index);
339  Assert( team != -1 );
340  Assert( slot_index != -1 );
341 
342  // reset object update stuff
343  for(idx=0; idx<MAX_PLAYERS; idx++){
344  shipp->np_updates[idx].orient_chksum = 0;
345  shipp->np_updates[idx].pos_chksum = 0;
346  shipp->np_updates[idx].seq = 0;
347  shipp->np_updates[idx].status_update_stamp = -1;
348  shipp->np_updates[idx].subsys_update_stamp = -1;
349  shipp->np_updates[idx].update_stamp = -1;
350  }
351 
352  // change the ship type and the weapons
353  if (team != -1 && slot_index != -1) {
354  change_ship_type(objp->instance, Wss_slots_teams[team][slot_index].ship_class);
355  wl_bash_ship_weapons(&shipp->weapons,&Wss_slots_teams[team][slot_index]);
356  }
357  multi_respawn_wing_stuff( shipp );
358 
360  multi_team_mark_ship(&Ships[Objects[objnum].instance]);
361  }
362 
363  pobjp->respawn_count++;
364 
365  return objnum;
366 }
367 
368 // respawn the passed player with the passed ship object and weapon link settings
369 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, vec3d *pos)
370 {
371  int objnum;
372  object *objp;
373  ship *shipp;
374  p_object *pobjp;
375 
376  // try and find the parse object
377  pobjp = mission_parse_get_arrival_ship(parse_name);
378  Assert(pobjp != NULL);
379  if(pobjp == NULL){
380  return;
381  }
382  objnum = multi_respawn_common_stuff(pobjp);
383 
384  Assert( objnum != -1 );
385  objp = &Objects[objnum];
386  shipp = &Ships[objp->instance];
387 
388  // this is a player, so mark him as a player,
389  objp->flags |= OF_PLAYER_SHIP;
390  objp->flags &= ~OF_COULD_BE_PLAYER;
391 
392  // server should mark this player as invulerable for a short time
393  if ( MULTIPLAYER_MASTER ) {
394  objp->flags |= OF_INVULNERABLE;
396  multi_respawn_place( objp, shipp->team );
397  }
398 
399  // reset his datarate timestamp
400  extern int OO_gran;
401  pl->s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) );
402 
403  // set some player information
404  pl->m_player->objnum = objnum;
405  if ( pl == Net_player ) {
406  object *oldplr = Player_obj;
407 
408  Player_obj = objp;
409  Player_ship = shipp;
411 
412  // this is a hack to ensure that old (dead) player ships are destroyed, since at this point he's actually an OBJ_GHOST
413  oldplr->flags |= OF_SHOULD_BE_DEAD;
414  obj_delete(OBJ_INDEX(oldplr));
415 
416  // get rid of the annoying HUD dead message text.
418  }
419 
420  // clients bash net signature
422  objp->net_signature = net_sig;
423  }
424 
425  // restore the correct weapon bank selections
426  shipp->weapons.current_primary_bank = (int)cur_primary_bank;
427  shipp->weapons.current_secondary_bank = (int)cur_secondary_bank;
428  if(cur_link_status & (1<<0)){
429  shipp->flags |= SF_PRIMARY_LINKED;
430  } else {
431  shipp->flags &= ~(SF_PRIMARY_LINKED);
432  }
433  if(cur_link_status & (1<<1)){
434  shipp->flags |= SF_SECONDARY_DUAL_FIRE;
435  } else {
436  shipp->flags &= ~(SF_SECONDARY_DUAL_FIRE);
437  }
438 
439  Assert( ship_ets != 0 ); // find dave or allender
440 
441  // restore the correct ets settings
442  shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
443  // weapon ets
444  shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
445  // engine ets
446  shipp->engine_recharge_index = (ship_ets & 0x000f);
447 
448  // give the current bank a half-second timestamp so that we don't fire immediately unpon respawn
450 
451  // if this is a dogfight mission, make him TEAM_TRAITOR
453  shipp->team = Iff_traitor;
454  }
455 
456  // maybe bash ship position
457  if(pos != NULL){
458  objp->pos = *pos;
459  }
460 
461  // unset his respawning flag
463 
464  // blast his control and button info clear
465  memset(&pl->m_player->bi, 0, sizeof(pl->m_player->bi));
466  memset(&pl->m_player->ci, 0, sizeof(pl->m_player->ci));
467 
468  // set throttle based on initial velocity specified in mission (the vel gets calculated
469  // like a percentage of our max speed, so we can just use it as-is for the throttle)
471  CLAMP(pl->m_player->ci.forward_cruise_percent, 0.0f, 100.0f);
472 
473  // if this is me, clear accum button info
474  if(pl == Net_player){
475  // clear multiplayer button info
477  memset(&Multi_ship_status_bi, 0, sizeof(button_info));
478  }
479 
480  // notify other players of the respawn
481  if ( MULTIPLAYER_MASTER ){
483  }
484 }
485 
486 // respawns an AI ship.
488 {
489  int objnum;
490  object *objp;
491 
492  // create the object and change the ship type
493  objnum = multi_respawn_common_stuff( pobjp );
494  objp = &Objects[objnum];
495 
496  // be sure the the OF_PLAYER_SHIP flag is unset, and the could be player flag is set
497  obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
498  objp->flags &= ~OF_PLAYER_SHIP;
499 }
500 
501 // <server> make the given player an observer
503 {
506 
507  // MWA 6/3/98 -- don't set to high -- let it default to whatever player chose
508  //pl->p_info.options.obj_update_level = OBJ_UPDATE_HIGH;
510 
511  // reset the ping time for this player
513 
514  // timestamp his last_full_update_time
516 
517  // create an observer object for him
519 }
520 
521 // respawn myself as an observer
523 {
524  // configure the hud to be in "observer" mode
526 
527  // blow away my old player object
530 
531  // create a new shiny observer object for me
533 
534  // set my object to be the observer object
537  Player_ai = &Hud_obs_ai;
538 
539  // set some flags for myself
543 
544  // clear my auto-match speed flag
546 
547  // reset the control info structure
548  memset(&Player->ci,0,sizeof(control_info));
549 }
550 
551 // send a request to respawn an AI object
553 {
554  ubyte data[50],val;
555  int packet_size = 0;
556 
557  // build the header and add the opcode
559  val = AI_RESPAWN_NOTICE;
560  ADD_DATA(val);
561  ADD_USHORT( net_signature );
562 
563  // broadcast the packet to all players
565  multi_io_send_to_all_reliable(data, packet_size);
566 }
567 
568 // send a request to the server saying I want to respawn (as an observer or not)
569 void multi_respawn_send_request(int as_observer)
570 {
571  ubyte data[10],val;
572  int packet_size = 0;
573 
574  // build the header and add the opcode
576  val = RESPAWN_REQUEST;
577  ADD_DATA(val);
578 
579  // add a byte indicating whether or not we want to respawn as an observer
580  val = (ubyte)as_observer;
581  ADD_DATA(val);
582 
583  // send the request to the server
584  multi_io_send_reliable(Net_player, data, packet_size);
585 }
586 
587 // send a broadcast pack indicating a player has respawned
589 {
590  ubyte data[50],val;
591  int packet_size = 0;
592  ushort signature;
593  vec3d pos;
594 
595  // broadcast the packet to all players
597 
598  signature = Objects[np->m_player->objnum].net_signature;
599  pos = Objects[np->m_player->objnum].pos;
600 
601  // build the header and add the opcode
603  val = RESPAWN_BROADCAST;
604  ADD_DATA(val);
605 
606  // add the data for the respawn
607  ADD_USHORT(signature);
608  ADD_VECTOR(pos);
609  ADD_SHORT(np->player_id);
615 
616  Assert( np->s_info.ship_ets != 0 ); // find dave or allender
617 
618  multi_io_send_to_all_reliable(data, packet_size);
619 }
620 
621 // process an incoming respawn info packet
623 {
624  ubyte code,cur_link_status;
625  char cur_primary_bank,cur_secondary_bank;
626  ushort net_sig,ship_ets;
627  short player_id;
628  int player_index;
629  vec3d v;
630  char parse_name[1024] = "";
631  int offset = HEADER_LENGTH;
632 
633  // determine who send the packet
634  player_index = find_player_id(hinfo->id);
635  if(player_index == -1){
636  nprintf(("Network","Couldn't find player for processing respawn packet!\n"));
637  }
638 
639  // get the opcode
640  GET_DATA(code);
641 
642  // do something based upon the opcode
643  switch((int)code){
644 
645  case AI_RESPAWN_NOTICE:
646  p_object *pobjp;
647 
648  GET_USHORT( net_sig );
649  pobjp = mission_parse_get_arrival_ship( net_sig );
650  Assert( pobjp != NULL );
651  multi_respawn_ai( pobjp );
652  break;
653 
654  case RESPAWN_BROADCAST:
655  // get the respawn data
656  GET_USHORT(net_sig);
657  GET_VECTOR(v);
658  GET_SHORT(player_id);
659  GET_DATA(cur_primary_bank);
660  GET_DATA(cur_secondary_bank);
661  GET_DATA(cur_link_status);
662  GET_USHORT(ship_ets);
663  GET_STRING(parse_name);
664  player_index = find_player_id(player_id);
665  if(player_index == -1){
666  nprintf(("Network","Couldn't find player to respawn!\n"));
667  break;
668  }
669 
670  // create the ship and assign its position, net_signature, and class
671  // respawn the player
672  multi_respawn_player(&Net_players[player_index], cur_primary_bank, cur_secondary_bank, cur_link_status, ship_ets, net_sig, parse_name, &v);
673 
674  // if this is for me, I should jump back into gameplay
675  if(&Net_players[player_index] == Net_player){
677  }
678  break;
679 
680  case RESPAWN_REQUEST:
681  // determine whether he wants to respawn as an observer or not
682  GET_DATA(code);
683 
684  if(player_index == -1){
685  nprintf(("Network","Received respawn request from unknown player!\n"));
686  break;
687  }
688  nprintf(("Network","Received respawn request for player %s\n", Net_players[player_index].m_player->callsign));
689 
690  // make sure he's not making an invalid request
691  if((code == 0) && !(Net_players[player_index].flags & NETINFO_FLAG_RESPAWNING)){
692  nprintf(("Network","This player shouldn't be respawning!\n"));
693  Int3();
694  break;
695  } else if((code == 1) && !(Net_players[player_index].flags & NETINFO_FLAG_LIMBO)){
696  nprintf(("Network","This is a respawn observer request from a player who shouldn't be respawning as an observer!\n"));
697  Int3();
698  break;
699  }
700 
701  // otherwise perform the operation
702  // respawn the guy as an observer
703  if(code){
704  multi_respawn_make_observer(&Net_players[player_index]);
705  }
706  // respawn him as normal
707  else {
708  // create his new ship, and change him from respawning to respawned
709  Assert(Net_players[player_index].p_info.p_objp != NULL);
710  if(Net_players[player_index].p_info.p_objp != NULL){
711  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);
712  }
713  }
714  break;
715  }
716 
717  PACKET_SET_SIZE();
718 }
719 
720 // respawn the server immediately
722 {
724 
725  // respawn me
727 
728  // jump back into the game
730 }
731 
732 // level init for respawn stuff
734 {
735  int i;
736 
737  for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
738  Ai_respawns[i].pobjp = NULL;
739  Ai_respawns[i].timestamp = timestamp(-1);
740  }
741 }
742 
743 // function to detect whether or not we have AI ships to respawn this frame
745 {
746  int i;
747 
748  for (i = 0; i < MAX_AI_RESPAWNS; i++ ) {
749  if ( Ai_respawns[i].pobjp != NULL ) {
750  if ( timestamp_elapsed(Ai_respawns[i].timestamp) ) {
751 
752  // be sure that ship is actually gone before respawning it.
753  if ( ship_name_lookup(Ai_respawns[i].pobjp->name) != -1 ) {
754  Ai_respawns[i].timestamp = timestamp(1000);
755  } else {
756  multi_respawn_ai( Ai_respawns[i].pobjp );
757  multi_respawn_send_ai_respawn( Ai_respawns[i].pobjp->net_signature );
758  Ai_respawns[i].pobjp = NULL;
759  Ai_respawns[i].timestamp = timestamp(-1);
760  }
761  }
762  }
763  }
764 }
765 
766 
767 
768 // this is a completely off the cuff way of doing things. Feel free to find a better way.
769 // Currently :
770 // 1. Take the average vector position of all the ships in the game
771 // 2. Check to make sure we aren't within the radius of any of the ships in the game
772 // a.) If we are, move away along the vector between the two ships (by the radius of the ship it collided with)
773 // b.) repeat step 2
774 
775 void multi_respawn_place(object *new_obj, int team)
776 {
777  ship *pri = NULL;
778  object *pri_obj = NULL;
779  int idx, lookup;
780 
781  // first determine if there are any appropriate priority ships to use
782  pri = NULL;
783  pri_obj = NULL;
784  for(idx=0; idx<Multi_respawn_priority_count; idx++){
785  // all relevant ships
786  if((Multi_respawn_priority_ships[idx].team == team) || !(Netgame.type_flags & NG_TYPE_TEAM)){
787 
788  lookup = ship_name_lookup(Multi_respawn_priority_ships[idx].ship_name);
789  if( (lookup >= 0) && ((pri == NULL) || (Ships[lookup].respawn_priority > pri->respawn_priority)) && (Ships[lookup].objnum >= 0) && (Ships[lookup].objnum < MAX_OBJECTS)){
790  pri = &Ships[lookup];
791  pri_obj = &Objects[Ships[lookup].objnum];
792  }
793  }
794  }
795 
796  // if we have a relevant respawn ship
797  if((pri != NULL) && (pri_obj != NULL)){
798  // pick a point just outside his bounding box
799  polymodel *pm = model_get(Ship_info[pri->ship_info_index].model_num);
800 
801  // hmm, ugly. Pick a point 2000 meters to the y direction
802  if(pm == NULL){
803  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, 2000.0f);
804  } else {
805  // pick a random direction
806  int d = (int)frand_range(0.0f, 5.9f);
807  switch(d){
808  case 0:
809  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, (pm->maxs.xyz.x - pm->mins.xyz.x));
810  break;
811 
812  case 1:
813  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, -(pm->maxs.xyz.x - pm->mins.xyz.x));
814  break;
815 
816  case 2:
817  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, (pm->maxs.xyz.y - pm->mins.xyz.y));
818  break;
819 
820  case 3:
821  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y));
822  break;
823 
824  case 4:
825  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.fvec, (pm->maxs.xyz.z - pm->mins.xyz.z));
826  break;
827 
828  case 5:
829  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.fvec, -(pm->maxs.xyz.z - pm->mins.xyz.z));
830  break;
831 
832  default:
833  vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y));
834  break;
835  }
836  }
837  }
838  // otherwise, resort to plain respawn points
839  else {
841 
842  // get the next appropriate respawn point by team
843  lookup = 0;
844  int count = 0;
845  while(!lookup && (count < 13)){
846  if((team == Iff_traitor) || (team == Multi_respawn_points[Multi_next_respawn_point].team)){
847  lookup = 1;
848  }
849 
850  // next item
851  if(!lookup){
854  } else {
856  }
857  }
858 
859  count++;
860  }
861 
862  // set respawn info
863  new_obj->pos = Multi_respawn_points[Multi_next_respawn_point].pos;
864  }
865 
866  // now make sure we're not colliding with anyone
868 }
869 
870 
871 /*
872 #define MOVE_AWAY() { vec3d 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); }
875 
876 #define WITHIN_RADIUS() { float dist; dist=vm_vec_dist(&new_obj->pos,&hit_check->pos); \
877  if(dist <= hit_check->radius) collided = 1; }
878 */
879 
880 #define WITHIN_BBOX() do { \
881  if (pm != NULL) { \
882  float scale = 2.0f; \
883  collided = 0; \
884  vec3d temp = new_obj->pos; \
885  vec3d gpos; \
886  vm_vec_sub2(&temp, &hit_check->pos); \
887  vm_vec_rotate(&gpos, &temp, &hit_check->orient); \
888  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)) { \
889  collided = 1; \
890  } \
891  } \
892 } while(0)
893 
894 #define MOVE_AWAY_BBOX() do { \
895  if (pm != NULL) { \
896  switch((int)frand_range(0.0f, 3.9f)){ \
897  case 0: \
898  new_obj->pos.xyz.x += 200.0f; \
899  break; \
900  case 1: \
901  new_obj->pos.xyz.x -= 200.0f; \
902  break; \
903  case 2: \
904  new_obj->pos.xyz.y += 200.0f; \
905  break; \
906  case 3: \
907  new_obj->pos.xyz.y -= 200.0f; \
908  break; \
909  default : \
910  new_obj->pos.xyz.z -= 200.0f; \
911  break; \
912  } \
913  } \
914 } while(0)
915 
916 
917 void prevent_spawning_collision(object *new_obj)
918 {
919  int collided;
920  ship_obj *moveup;
921  object *hit_check;
922  ship *s_check;
923 
924  do {
925  collided = 0;
926 
927  for (moveup = GET_FIRST(&Ship_obj_list); moveup != END_OF_LIST(&Ship_obj_list); moveup = GET_NEXT(moveup))
928  {
929  // don't check the new object itself!!
930  if (moveup->objnum == OBJ_INDEX(new_obj))
931  continue;
932 
933  hit_check = &Objects[moveup->objnum];
934 
935  Assert(hit_check->type == OBJ_SHIP);
936  Assert(hit_check->instance >= 0);
937  if ((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0))
938  continue;
939 
940  s_check = &Ships[hit_check->instance];
941 
942  // just to make sure we don't get any strange magnitude errors
943  if (vm_vec_same(&hit_check->pos, &new_obj->pos))
944  new_obj->pos.xyz.x += 1.0f;
945 
946  polymodel *pm = model_get(Ship_info[s_check->ship_info_index].model_num);
947  WITHIN_BBOX();
948  if (collided)
949  {
950  MOVE_AWAY_BBOX();
951  break;
952  }
953  }
954  } while (collided);
955 }
uint respawn
Definition: multi.h:507
#define OF_INVULNERABLE
Definition: object.h:107
int timestamp(int delta_ms)
Definition: timer.cpp:226
#define PLAYER_FLAGS_MATCH_TARGET
Definition: player.h:36
wing Wings[MAX_WINGS]
Definition: ship.cpp:128
void obj_set_flags(object *obj, uint new_flags)
Definition: object.cpp:1000
int i
Definition: multi_pxo.cpp:466
char wing_status_wing_pos
Definition: ship.h:553
char ship_name[NAME_LENGTH+1]
#define GET_DATA(d)
Definition: multimsgs.h:47
struct respawn_point respawn_point
char name[NAME_LENGTH]
Definition: missionparse.h:346
ai_info * Player_ai
Definition: ai.cpp:24
int team
Definition: ship.h:606
control_info ci
Definition: player.h:126
int flags
Definition: player.h:104
void multi_respawn_build_points()
np_update np_updates[MAX_PLAYERS]
Definition: ship.h:731
int objnum
Definition: ship.h:537
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
vec3d mins
Definition: model.h:746
#define AI_RESPAWN_TIME
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
ship_weapon weapons
Definition: ship.h:658
net_player * Net_player
Definition: multi.cpp:94
#define WITHIN_BBOX()
p_object * pobjp
#define PACKET_SET_SIZE()
Definition: multimsgs.h:57
char wing_status_wing_index
Definition: ship.h:552
player * m_player
Definition: multi.h:459
void multi_respawn_make_observer(net_player *pl)
void multi_respawn_player_leave(net_player *pl)
int fire_secondary_count
Definition: physics.h:111
void multi_respawn_server()
void prevent_spawning_collision(object *new_obj)
void multi_respawn_send_request(int as_observer)
#define ADD_DATA(d)
Definition: multimsgs.h:37
int next_secondary_fire_stamp[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:115
Assert(pm!=NULL)
void multi_ts_get_team_and_slot(char *ship_name, int *team_index, int *slot_index, bool mantis2757switch)
int fire_primary_count
Definition: physics.h:110
Definition: pstypes.h:88
#define ADD_STRING(s)
Definition: multimsgs.h:43
int ai_index
Definition: ship.h:538
#define NETINFO_FLAG_OBSERVER
Definition: multi.h:605
void multi_io_send_to_all_reliable(ubyte *data, int length, net_player *ignore)
Definition: multimsgs.cpp:496
ushort net_signature
Definition: object.h:163
int weapon_recharge_index
Definition: ship.h:638
#define RESPAWN_REQUEST
void multi_respawn_normal()
struct vec3d::@225::@227 xyz
CButton * team
void wl_bash_ship_weapons(ship_weapon *swp, wss_unit *slot)
void multi_io_send_reliable(net_player *pl, ubyte *data, int len)
Definition: multimsgs.cpp:459
int find_player_id(short player_id)
Definition: multiutil.cpp:465
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
#define SHIP_INDEX(shipp)
Definition: ship.h:1602
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
respawn_point Multi_respawn_priority_ships[MAX_PRIORITY_POINTS]
vec3d maxs
Definition: model.h:746
int status_update_stamp
Definition: multi_obj.h:41
Definition: ship.h:1516
int current_primary_bank
Definition: ship.h:106
int update_stamp
Definition: multi_obj.h:40
#define NETINFO_FLAG_OBS_PLAYER
Definition: multi.h:606
uint flags
Definition: ship.h:644
void multi_respawn_handle_invul_players()
int flags
Definition: multi.h:463
#define OF_PLAYER_SHIP
Definition: object.h:109
object * objp
Definition: lua.cpp:3105
int current_secondary_bank
Definition: ship.h:107
#define MAX_AI_RESPAWNS
#define Int3()
Definition: pstypes.h:292
void multi_respawn_send_ai_respawn(ushort net_signature)
#define AI_RESPAWN_NOTICE
#define RESPAWN_BROADCAST
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
int packet_size
Definition: multi_sexp.cpp:41
respawn_point Multi_respawn_points[MAX_MULTI_RESPAWN_POINTS]
ai_info Hud_obs_ai
Definition: hudobserver.cpp:21
#define GET_VECTOR(d)
Definition: multimsgs.h:55
int Multi_next_respawn_point
#define PLAYER_FLAGS_AUTO_MATCH_SPEED
Definition: player.h:39
#define CLAMP(x, min, max)
Definition: pstypes.h:488
void HUD_init_fixed_text()
Definition: hudmessage.cpp:207
void multi_ping_reset(ping_struct *ps)
Definition: multi_ping.cpp:41
HWND DWORD code
Definition: vddraw.h:425
int objnum
Definition: ship.h:1483
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
void multi_respawn_place(object *new_obj, int team)
GLintptr offset
Definition: Glext.h:5497
Definition: player.h:85
p_object * mission_parse_get_arrival_ship(const char *name)
Returns the parse object on the ship arrival list associated with the given name. ...
net_player_info p_info
Definition: multi.h:473
int type_flags
Definition: multi.h:493
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
struct matrix::@228::@230 vec
#define NETINFO_FLAG_AM_MASTER
Definition: multi.h:599
int Multi_respawn_priority_count
#define nprintf(args)
Definition: pstypes.h:239
#define BUILD_HEADER(t)
Definition: multimsgs.h:36
fix last_heard_time
Definition: multi.h:470
int wingnum
Definition: ship.h:623
netgame_info Netgame
Definition: multi.cpp:97
void multi_respawn_ai(p_object *pobjp)
void multi_respawn_init()
void multi_team_mark_ship(ship *sp)
Definition: multi_team.cpp:514
void multi_respawn_check_ai()
#define NG_TYPE_TEAM
Definition: multi.h:650
#define MULTI_OBSERVER(np)
Definition: multi.h:140
int engine_recharge_index
Definition: ship.h:639
#define SF_PRIMARY_LINKED
Definition: ship.h:458
net_player_server_info s_info
Definition: multi.h:472
#define RESPAWN_INVUL_TIMESTAMP
Definition: multi.h:101
#define MAX_PLAYERS
Definition: pstypes.h:32
short player_id
Definition: multi.h:460
int current_count
Definition: ship.h:1530
#define MULTI_DOGFIGHT
Definition: multi.h:656
#define OF_COULD_BE_PLAYER
Definition: object.h:112
#define ADD_SHORT(d)
Definition: multimsgs.h:38
Definition: ship.h:534
void multi_respawn_check(object *objp)
int idx
Definition: multiui.cpp:761
uint respawn_count
Definition: missionparse.h:419
int Multi_respawn_point_count
button_info Multi_ship_status_bi
Definition: multiutil.cpp:1240
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
#define RESPAWN_NOTICE
Definition: multi.h:161
unsigned char ubyte
Definition: pstypes.h:62
ubyte seq
Definition: multi_obj.h:39
void hud_config_as_observer(ship *shipp, ai_info *aif)
Definition: hudconfig.cpp:1595
int objnum
Definition: player.h:124
#define OBJ_INDEX(objp)
Definition: object.h:235
#define NETINFO_FLAG_LIMBO
Definition: multi.h:607
ship * Player_ship
Definition: ship.cpp:124
matrix orient
Definition: object.h:153
#define OBJ_SHIP
Definition: object.h:32
#define P_OF_PLAYER_START
Definition: missionparse.h:453
GLbitfield flags
Definition: Glext.h:6722
float forward_cruise_percent
Definition: physics.h:106
#define ADD_USHORT(d)
Definition: multimsgs.h:39
GLuint GLfloat * val
Definition: Glext.h:6741
#define MOVE_AWAY_BBOX()
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
ping_struct ping
Definition: multi.h:395
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
void obj_delete(int objnum)
Definition: object.cpp:522
int vm_vec_same(const vec3d *v1, const vec3d *v2)
Definition: vecmat.cpp:1526
int initial_velocity
Definition: missionparse.h:365
#define NAME_LENGTH
Definition: globals.h:15
#define SF_SECONDARY_DUAL_FIRE
Definition: ship.h:459
#define MAX_MULTI_RESPAWN_POINTS
void multi_respawn_as_observer()
#define MULTI_CONNECTED(np)
Definition: multi.h:136
#define ADD_VECTOR(d)
Definition: multimsgs.h:45
fix timer_get_fixed_seconds()
Definition: timer.cpp:116
ai_respawn Ai_respawns[MAX_AI_RESPAWNS]
player * Player
#define GET_USHORT(d)
Definition: multimsgs.h:49
ushort orient_chksum
Definition: multi_obj.h:44
Definition: multi.h:385
unsigned short ushort
Definition: pstypes.h:63
#define NETINFO_FLAG_RESPAWNING
Definition: multi.h:609
void hud_set_wingman_status_alive(int wing_index, int wing_pos)
ship_obj Ship_obj_list
Definition: ship.cpp:162
int ship_info_index
Definition: ship.h:539
int HEADER_LENGTH
Definition: multi.cpp:106
#define MULTIPLAYER_MASTER
Definition: multi.h:130
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, vec3d *pos=NULL)
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
struct ai_respawn ai_respawn
#define timestamp_elapsed(stamp)
Definition: timer.h:102
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
short id
Definition: multi.h:390
hull_check pos
Definition: lua.cpp:5050
int Iff_traitor
Definition: iff_defs.cpp:22
wss_unit Wss_slots_teams[MAX_TVT_TEAMS][MAX_WSS_SLOTS]
void change_ship_type(int n, int ship_type, int by_sexp)
Definition: ship.cpp:9983
void multi_respawn_observer()
int subsys_update_stamp
Definition: multi_obj.h:42
GLint GLsizei count
Definition: Gl.h:1491
p_object * p_objp
Definition: multi.h:448
void multi_respawn_broadcast(net_player *player)
object * Player_obj
Definition: object.cpp:56
#define GET_SHORT(d)
Definition: multimsgs.h:48
int ship_index[MAX_SHIPS_PER_WING]
Definition: ship.h:1531
polymodel * pm
Definition: lua.cpp:1598
int OO_gran
Definition: multi_obj.cpp:1571
void multi_respawn_wing_stuff(ship *shipp)
#define MAX_PRIORITY_POINTS
int respawn_priority
Definition: ship.h:544
int ship_name_lookup(const char *name, int inc_players)
Definition: ship.cpp:12900
uint flags
Definition: object.h:151
char type
Definition: object.h:146
void multi_respawn_process_packet(ubyte *data, header *hinfo)
int multi_find_player_by_object(object *objp)
Definition: multiutil.cpp:500
int parse_create_object(p_object *pobjp)
net_player Net_players[MAX_PLAYERS]
Definition: multi.cpp:93
ushort pos_chksum
Definition: multi_obj.h:43
void gameseq_post_event(int event)
ship Hud_obs_ship
Definition: hudobserver.cpp:20
#define GET_STRING(s)
Definition: multimsgs.h:53
int shield_recharge_index
Definition: ship.h:637
const GLdouble * v
Definition: Glext.h:5322
button_info bi
Definition: player.h:125
char ship_name[NAME_LENGTH]
Definition: ship.h:604
int multi_respawn_common_stuff(p_object *pobjp)
void multi_obs_create_observer(net_player *pl)
#define NG_TYPE_DOGFIGHT
Definition: multi.h:651
#define strcpy_s(...)
Definition: safe_strings.h:67