]> icculus.org git repositories - taylor/freespace2.git/blob - src/object/object.cpp
silence various compiler warnings (clang:rel)
[taylor/freespace2.git] / src / object / object.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Object/Object.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code to manage objects
16  *
17  * $Log$
18  * Revision 1.4  2004/09/20 01:31:44  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.3  2002/06/09 04:41:24  relnev
22  * added copyright header
23  *
24  * Revision 1.2  2002/05/07 03:16:48  theoddone33
25  * The Great Newline Fix
26  *
27  * Revision 1.1.1.1  2002/05/03 03:28:10  root
28  * Initial import.
29  *
30  * 
31  * 33    8/27/99 10:36a Dave
32  * Impose a 2% penalty for hitting the shield balance key.
33  * 
34  * 32    8/24/99 8:55p Dave
35  * Make sure nondimming pixels work properly in tech menu.
36  * 
37  * 31    7/26/99 10:24p Anoop
38  * Oops. Don't do anything to checkobjects in a release build.
39  * 
40  * 30    7/26/99 5:50p Dave
41  * Revised ingame join. Better? We'll see....
42  * 
43  * 29    7/22/99 3:58p Jefff
44  * Temporarily remove object checking for multiplayer clients.
45  * 
46  * 28    7/08/99 10:53a Dave
47  * New multiplayer interpolation scheme. Not 100% done yet, but still
48  * better than the old way.
49  * 
50  * 27    7/03/99 5:50p Dave
51  * Make rotated bitmaps draw properly in padlock views.
52  * 
53  * 26    7/01/99 11:44a Dave
54  * Updated object sound system to allow multiple obj sounds per ship.
55  * Added hit-by-beam sound. Added killed by beam sound.
56  * 
57  * 25    5/27/99 6:17p Dave
58  * Added in laser glows.
59  * 
60  * 24    5/18/99 12:08p Andsager
61  * Added observer_process_post to handle observer too far away
62  * 
63  * 23    5/18/99 11:50a Andsager
64  * Remove unused object type OBJ_GHOST_SAVE
65  * 
66  * 22    4/23/99 5:53p Dave
67  * Started putting in new pof nebula support into Fred.
68  * 
69  * 21    4/21/99 6:15p Dave
70  * Did some serious housecleaning in the beam code. Made it ready to go
71  * for anti-fighter "pulse" weapons. Fixed collision pair creation. Added
72  * a handy macro for recalculating collision pairs for a given object.
73  * 
74  * 20    4/20/99 6:39p Dave
75  * Almost done with artillery targeting. Added support for downloading
76  * images on the PXO screen.
77  * 
78  * 19    4/19/99 11:01p Dave
79  * More sophisticated targeting laser support. Temporary checkin.
80  * 
81  * 18    4/16/99 5:54p Dave
82  * Support for on/off style "stream" weapons. Real early support for
83  * target-painting lasers.
84  * 
85  * 17    3/29/99 6:17p Dave
86  * More work on demo system. Got just about everything in except for
87  * blowing ships up, secondary weapons and player death/warpout.
88  * 
89  * 16    3/10/99 6:50p Dave
90  * Changed the way we buffer packets for all clients. Optimized turret
91  * fired packets. Did some weapon firing optimizations.
92  * 
93  * 15    3/09/99 6:24p Dave
94  * More work on object update revamping. Identified several sources of
95  * unnecessary bandwidth.
96  * 
97  * 14    3/08/99 7:03p Dave
98  * First run of new object update system. Looks very promising.
99  * 
100  * 13    1/30/99 5:08p Dave
101  * More new hi-res stuff.Support for nice D3D textures.
102  * 
103  * 12    1/29/99 2:25p Andsager
104  * Added turret_swarm_missiles
105  * 
106  * 11    1/25/99 5:03a Dave
107  * First run of stealth, AWACS and TAG missile support. New mission type
108  * :)
109  * 
110  * 10    1/24/99 11:37p Dave
111  * First full rev of beam weapons. Very customizable. Removed some bogus
112  * Int3()'s in low level net code.
113  * 
114  * 9     1/14/99 12:48a Dave
115  * Todo list bug fixes. Made a pass at putting briefing icons back into
116  * FRED. Sort of works :(
117  * 
118  * 8     1/12/99 5:45p Dave
119  * Moved weapon pipeline in multiplayer to almost exclusively client side.
120  * Very good results. Bandwidth goes down, playability goes up for crappy
121  * connections. Fixed object update problem for ship subsystems.
122  * 
123  * 7     1/12/99 12:53a Dave
124  * More work on beam weapons - made collision detection very efficient -
125  * collide against all object types properly - made 3 movement types
126  * smooth. Put in test code to check for possible non-darkening pixels on
127  * object textures.
128  * 
129  * 6     1/08/99 2:08p Dave
130  * Fixed software rendering for pofview. Super early support for AWACS and
131  * beam weapons.
132  * 
133  * 5     11/14/98 5:32p Dave
134  * Lots of nebula work. Put in ship contrails.
135  * 
136  * 4     11/09/98 2:11p Dave
137  * Nebula optimizations.
138  * 
139  * 3     11/05/98 4:18p Dave
140  * First run nebula support. Beefed up localization a bit. Removed all
141  * conditional compiles for foreign versions. Modified mission file
142  * format.
143  * 
144  * 2     10/07/98 10:53a Dave
145  * Initial checkin.
146  * 
147  * 1     10/07/98 10:50a Dave
148  * 
149  * 242   8/28/98 3:29p Dave
150  * EMP effect done. AI effects may need some tweaking as required.
151  * 
152  * 241   8/07/98 10:13a Allender
153  * new object flag setting code for OF_COULD_BE_PLAYER since it was
154  * getting set incorrectly
155  * 
156  * 240   7/02/98 6:16p Dave
157  * Make rear facing prediction much better. Tweak update levels and
158  * viewcone values. Make sure observers send targeting info correctly.
159  * 
160  * 239   6/30/98 2:43p Dave
161  * Fixed merge problems.
162  * 
163  * 238   6/30/98 2:25p Dave
164  * Revamped object update system
165  * 
166  * 237   6/22/98 8:36a Allender
167  * revamping of homing weapon system.  don't send as object updates
168  * anymore
169  * 
170  * 236   5/25/98 10:58a Allender
171  * more object update stuff -- fix duplicate repair ship messages
172  * 
173  * 235   5/24/98 10:38a Allender
174  * make docked objects move properly on multiplayer clients
175  * 
176  * 234   5/20/98 4:32p Allender
177  * changed RELEASE to NDEBUG
178  * 
179  * 233   5/20/98 10:07a John
180  * put back in object flag checking for DEBUG.
181  * 
182  * 232   5/18/98 4:21p Frank
183  * AL: fix problem with same vectors in obj_visible_from_eye()
184  * 
185  * 231   5/18/98 10:05a Lawrance
186  * use old client prediction code for player ships
187  * 
188  * 230   5/18/98 12:52a Lawrance
189  * Client-side prediction improvements
190  * 
191  * 229   5/15/98 3:54p John
192  * Added code so that only "perishable" fireballs get removed.
193  * 
194  * 228   5/15/98 9:59a John
195  * Removed OBJECT_CHECKING.  This should be on DEBUG only, but we need to
196  * verify it.
197  * 
198  * 227   5/11/98 4:33p Allender
199  * fixed ingame join problems -- started to work on new object updating
200  * code (currently ifdef'ed out)
201  * 
202  * 226   5/01/98 12:59a Dave
203  * Put in some test code for a new object update system. Found the problem
204  * with the current system (low-level packet buffering). Gonna fix it :)
205  * 
206  * 225   4/16/98 3:06p Adam
207  * reset net_signature when creating a new object so that the multi code
208  * doesn't see two objects with the same signature
209  * 
210  * 224   4/14/98 11:11p John
211  * Made ships with < 50% hull left show electrical damage arcs.
212  * 
213  * 223   4/12/98 9:56a John
214  * Made lighting detail flags work.   Made explosions cast light on
215  * highest.
216  * 
217  * 222   4/03/98 12:24a Mike
218  * Comment out nprintfs.
219  * 
220  * 221   4/01/98 9:21p John
221  * Made NDEBUG, optimized build with no warnings or errors.
222  * 
223  * 220   4/01/98 1:48p Allender
224  * major changes to ship collision in multiplayer.  Clients now do own
225  * ship/ship collisions (with their own ship only)  Modifed the hull
226  * update packet to be sent quicker when object is target of player.
227  * 
228  * 219   4/01/98 9:20a Mike
229  * Reduce MAX_SHIPS, MAX_OBJECTS and make MAX_AI_INFO same as MAX_SHIPS
230  * 
231  * 217   3/26/98 10:36p Andsager
232  * 
233  * 216   3/26/98 5:43p Lawrance
234  * rename ship_team_from_obj(), obj_team() and move to object lib
235  * 
236  * 215   3/23/98 9:20a Andsager
237  * Remove all velocity updates in object code.
238  * 
239  * 214   3/21/98 7:36p Lawrance
240  * Move jump nodes to own lib.
241  * 
242  * 213   3/17/98 1:09p Andsager
243  * Don't update debris velocity in object code.  was leading to
244  * fluctuating and increasing debris velocity (from numerical imprecision)
245  * 
246  * 212   3/11/98 5:33p Lawrance
247  * Support rendering and targeting of jump nodes
248  * 
249  * 211   3/09/98 10:56a Hoffoss
250  * Added jump node objects to Fred.
251  * 
252  * 210   3/08/98 12:03p Allender
253  * changed how ship network signatures are handed out.  Done at mission
254  * load time.  Space reserved in wings for all waves/counts for their
255  * signatures.  Fixed some secondary firing issues
256  * 
257  * 209   3/06/98 10:35a Mike
258  * Make ships ramp up their warpout speed.
259  * 
260  * 208   3/05/98 2:38p Mike
261  * Fix bug in obj_set_flags which didn't properly add collision pairs.
262  * 
263  * 207   3/04/98 4:38p Mike
264  * Make weapon firing less framerate dependent.  Also support cycling
265  * backwards through weapons with debug key.
266  * 
267  * 206   3/03/98 1:00p John
268  * Fixed bug where asteroids weren't rotating for Glide.
269  * 
270  * 205   3/02/98 5:42p John
271  * Removed WinAVI stuff from Freespace.  Made all HUD gauges wriggle from
272  * afterburner.  Made gr_set_clip work good with negative x &y.  Made
273  * model_caching be on by default.  Made each cached model have it's own
274  * bitmap id.  Made asteroids not rotate when model_caching is on.  
275  * 
276  * 204   2/27/98 4:48p John
277  * Made objects keep track of number of pairs they have associated with
278  * them.  Then, I can early out of the obj_remove_all which was 2.5% of
279  * frametime at beginning of sm2-2 which then is 0% after this.
280  * 
281  * 203   2/23/98 8:59p Allender
282  * fixed two docking bugs:  1) don't move cargo when ship it's docked with
283  * is undocking.  2) aigoal code was clearing dock goals when it shouldn't
284  * have been
285  * 
286  * 202   2/22/98 12:19p John
287  * Externalized some strings
288  * 
289  * 201   2/19/98 11:18p Mike
290  * Make ships not come to an immediate stop when they have been disabled
291  * while awaiting repair.
292  * 
293  * 200   2/19/98 10:51p John
294  * Enabled colored lighting for hardware (Glide)
295  * 
296  * 199   2/19/98 12:46a Lawrance
297  * Further work on asteroids.
298  * 
299  * 198   2/15/98 10:12p Allender
300  * fix up problems where ship flies away from repair ship too soon after
301  * getting repaired.
302  * 
303  * 197   2/13/98 5:15p Allender
304  * 
305  * 196   2/12/98 2:41p John
306  * Fixed bug I added the other day that caused all object created on the
307  * same frame to have two pairs.
308  * 
309  * 195   2/09/98 10:44a John
310  * Made object pairs get created when they get added to the used_list, not
311  * when they get created.
312  * 
313  * 194   2/06/98 12:00p Allender
314  * fixed some pretty darn embarassing code!
315  * 
316  * 193   2/06/98 12:25a Mike
317  * More asteroid stuff.
318  * 
319  * 192   2/05/98 9:41p Mike
320  * Asteroid work, intermediate checkin to resolve compile errors.
321  * 
322  * 191   2/05/98 9:21p John
323  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
324  * game.
325  * 
326  * 190   2/05/98 12:51a Mike
327  * Early asteroid stuff.
328  * 
329  * 189   2/02/98 4:36p Mike
330  * Prevent damage from occurring between two ships during very last frame
331  * of warpout if docked and on opposite sides.
332  * 
333  * 188   1/30/98 11:48a John
334  * Made debris arcs cast light.  Added sound effects for them.
335  * 
336  * 187   1/29/98 8:18a John
337  * Put in some commented out hooks for RGB lighting
338  * 
339  * 186   1/23/98 5:08p John
340  * Took L out of vertex structure used B (blue) instead.   Took all small
341  * fireballs out of fireball types and used particles instead.  Fixed some
342  * debris explosion things.  Restructured fireball code.   Restructured
343  * some lighting code.   Made dynamic lighting on by default. Made groups
344  * of lasers only cast one light.  Made fireballs not cast light.
345  * 
346  * 185   1/20/98 3:09p Dave
347  * Fixed a bug in observer movement caused by uninitialized data fix.
348  * 
349  * 184   1/20/98 9:47a Mike
350  * Suppress optimized compiler warnings.
351  * Some secondary weapon work.
352  * 
353  * 183   1/19/98 10:01p Lawrance
354  * Implement "Electronics" missiles
355  * 
356  * 182   1/17/98 4:45p Mike
357  * Better support for AI selection of secondary weapons.
358  * 
359  * 181   1/16/98 11:43a Mike
360  * Fix countermeasures.
361  * 
362  * 180   1/14/98 5:21p Allender
363  * system to delete object when buffer is nearly full.  System in place to
364  * delete weapons when nearly out of weapons slots
365  * 
366  * 179   1/13/98 8:09p John
367  * Removed the old collision system that checked all pairs.   Added code
368  * to disable collisions and particles.
369  * 
370  * 178   1/13/98 5:50p Andsager
371  * Deathroll rotvel is now ramped up to using standard physics code.
372  * After death, controls are no longer read and deathroll_rotvel is set in
373  * ship\ship_dying_frame.cpp
374  * 
375  * 177   1/12/98 5:21p Dave
376  * Put in a bunch of multiplayer sequencing code. Made weapon/ship select
377  * work through the standalone.
378  * 
379  * 176   12/29/97 9:48p Mike
380  * When two ships of equivalent class are docked together, move according
381  * to the faster moving one.
382  * 
383  * 175   12/22/97 9:14p Allender
384  * fix up some code relating to afterburners in multiplayer.  Clients now
385  * control their own afterburners
386  * 
387  * 174   12/22/97 1:42a Lawrance
388  * Change in set_shield_strength() avoid weird rounding error
389  * 
390  * 173   12/12/97 1:43p John
391  * took out old debug light code
392  * 
393  * 172   12/11/97 5:46p Hoffoss
394  * Changed Fred to not display weapons that are not available to various
395  * ships.
396  * 
397  * 171   12/09/97 11:36p Allender
398  * made clients determine their own positions
399  * 
400  * 170   12/04/97 9:20a John
401  * 
402  * 169   12/03/97 3:17p Andsager
403  * Reset of physics flags for engine moved to rearm and repair.
404  *
405  * $NoKeywords: $
406  */
407
408 #include <string.h>     // for memset
409 #include <stdio.h>
410
411 #include "pstypes.h"
412 #include "object.h"
413 #include "weapon.h"
414 #include "ship.h"
415 #include "fireballs.h"
416 #include "debris.h"
417 #include "fvi.h"
418 #include "physics.h"
419 #include "model.h"
420 #include "linklist.h"
421 #include "freespace.h"
422 #include        "ai.h"
423 #include "objectsnd.h"
424 #include "gamesnd.h"
425 #include "player.h"
426 #include "cmeasure.h"
427 #include "timer.h"
428 #include "systemvars.h"
429 #include "3d.h"
430 #include "shockwave.h"
431 #include "afterburner.h"
432 #include "timer.h"
433 #include "multi.h"
434 #include "multiutil.h"
435 #include "objcollide.h"
436 #include "lighting.h"
437 #include "observer.h"
438 #include "asteroid.h"
439 #include "radar.h"
440 #include "jumpnode.h"
441 #include "neb.h"
442 #include "beam.h"
443 #include "swarm.h"
444 #include "demo.h"
445
446 /*
447  *  Global variables
448  */
449
450 object obj_free_list;
451 object obj_used_list;
452 object obj_create_list; 
453
454 object *Player_obj = NULL;
455 object *Viewer_obj = NULL;
456
457
458
459 //Data for objects
460 object Objects[MAX_OBJECTS];
461
462 #ifdef OBJECT_CHECK 
463 typedef struct checkobject
464 {
465         int     type;
466         int     signature;
467         uint    flags;
468         int     parent_sig;
469         int     parent_type;
470 } checkobject;
471 checkobject CheckObjects[MAX_OBJECTS];
472 #endif
473
474 int num_objects=-1;
475 int Highest_object_index=-1;
476 int Highest_ever_object_index=0;
477 int Object_next_signature = 1;  //0 is bogus, start at 1
478 int Object_next_ship_signature = OBJECT_SIG_SHIP_START;
479 int Object_inited = 0;
480 int Show_waypoints = 0;
481
482 #ifndef NDEBUG
483 const char *Object_type_names[MAX_OBJECT_TYPES] = {
484 //XSTR:OFF
485         "NONE",
486         "SHIP",
487         "WEAPON",
488         "FIREBALL",
489         "START",
490         "WAYPOINT",
491         "DEBRIS",
492         "CMEASURE",
493         "GHOST",
494         "POINT",
495         "SHOCKWAVE",
496         "WING",
497         "GHOST SAVE",
498         "OBSERVER",
499         "ASTEROID",
500         "JUMP NODE",
501 //XSTR:ON
502 };
503 #endif
504
505 //-----------------------------------------------------------------------------
506 //      Scan the object list, freeing down to num_used objects
507 //      Returns number of slots freed.
508 int free_object_slots(int num_used)
509 {
510         int     i, olind, deleted_weapons;
511         int     obj_list[MAX_OBJECTS];
512         int     num_already_free, num_to_free, original_num_to_free;
513         object *objp;
514
515         olind = 0;
516
517         // calc num_already_free by walking the obj_free_list
518         num_already_free = 0;
519         for ( objp = GET_FIRST(&obj_free_list); objp != END_OF_LIST(&obj_free_list); objp = GET_NEXT(objp) )
520                 num_already_free++;
521
522         if (MAX_OBJECTS - num_already_free < num_used)
523                 return 0;
524
525         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
526                 if (objp->flags & OF_SHOULD_BE_DEAD) {
527                         num_already_free++;
528                         if (MAX_OBJECTS - num_already_free < num_used)
529                                 return num_already_free;
530                 } else
531                         switch (objp->type) {
532                                 case OBJ_NONE:
533                                         num_already_free++;
534                                         if (MAX_OBJECTS - num_already_free < num_used)
535                                                 return 0;
536                                         break;
537                                 case OBJ_FIREBALL:
538                                 case OBJ_WEAPON:
539                                 case OBJ_DEBRIS:
540                                 case OBJ_CMEASURE:
541                                         obj_list[olind++] = OBJ_INDEX(objp);
542                                         break;
543
544                                 case OBJ_GHOST:
545                                 case OBJ_SHIP:
546                                 case OBJ_START:
547                                 case OBJ_WAYPOINT:
548                                 case OBJ_POINT:
549                                 case OBJ_SHOCKWAVE:
550                                 case OBJ_WING:
551                                 case OBJ_OBSERVER:
552                                 case OBJ_ASTEROID:
553                                 case OBJ_JUMP_NODE:                             
554                                 case OBJ_BEAM:
555                                         break;
556                                 default:
557                                         Int3(); //      Hey, what kind of object is this?  Unknown!
558                                         break;
559                         }
560
561         }
562
563         num_to_free = MAX_OBJECTS - num_used - num_already_free;
564         original_num_to_free = num_to_free;
565
566         if (num_to_free > olind) {
567                 nprintf(("allender", "Warning: Asked to free %i objects, but can only free %i.\n", num_to_free, olind));
568                 num_to_free = olind;
569         }
570
571         for (i=0; i<num_to_free; i++)
572                 if ( (Objects[obj_list[i]].type == OBJ_DEBRIS) && (Debris[Objects[obj_list[i]].instance].flags & DEBRIS_EXPIRE) ) {
573                         num_to_free--;
574                         nprintf(("allender", "Freeing   DEBRIS object %3i\n", obj_list[i]));
575                         Objects[obj_list[i]].flags |= OF_SHOULD_BE_DEAD;
576                 }
577
578         if (!num_to_free)
579                 return original_num_to_free;
580
581 //JAS - I removed this because small fireballs are now particles, which aren't objects.
582 //JAS   for (i=0; i<num_to_free; i++)
583 //JAS           if ( (Objects[obj_list[i]].type == OBJ_FIREBALL) && (Fireball_data[Objects[obj_list[i]].instance].type == FIREBALL_TYPE_SMALL) ) {
584 //JAS                   num_to_free--;
585 //JAS                   nprintf(("allender", "Freeing FIREBALL object %3i\n", obj_list[i]));
586 //JAS                   Objects[obj_list[i]].flags |= OF_SHOULD_BE_DEAD;
587 //JAS           }
588 //JAS
589 //JAS   if (!num_to_free)
590 //JAS           return original_num_to_free;
591
592         for (i=0; i<num_to_free; i++)   {
593                 object *tmp_obj = &Objects[obj_list[i]];
594                 if ( (tmp_obj->type == OBJ_FIREBALL) && (fireball_is_perishable(tmp_obj)) ) {
595                         num_to_free--;
596                         nprintf(("allender", "Freeing FIREBALL object %3i\n", obj_list[i]));
597                         tmp_obj->flags |= OF_SHOULD_BE_DEAD;
598                 }
599         }
600
601         if (!num_to_free){
602                 return original_num_to_free;
603         }
604
605         deleted_weapons = collide_remove_weapons();
606         num_to_free -= deleted_weapons;
607         if ( !num_to_free ){
608                 return original_num_to_free;
609         }
610
611         for (i=0; i<num_to_free; i++){
612                 if ( Objects[obj_list[i]].type == OBJ_WEAPON ) {
613                         num_to_free--;
614                         Objects[obj_list[i]].flags |= OF_SHOULD_BE_DEAD;
615                 }
616         }
617
618         if (!num_to_free){
619                 return original_num_to_free;
620         }
621
622         return original_num_to_free - num_to_free;
623 }
624
625
626
627 float get_shield_strength(object *objp)
628 {
629         int     i;
630         float   strength;
631
632         strength = 0.0f;
633
634         // no shield system, no strength!
635         if ( objp->flags & OF_NO_SHIELDS ){
636                 return strength;
637         }
638
639         for (i=0; i<MAX_SHIELD_SECTIONS; i++){
640                 strength += objp->shields[i];
641         }
642
643         return strength;
644 }
645
646 void set_shield_strength(object *objp, float strength)
647 {
648         int     i;
649
650         if ( (strength - Ship_info[Ships[objp->instance].ship_info_index].shields) > 0.1 ){
651                 Int3();
652         }
653
654         for (i=0; i<MAX_SHIELD_SECTIONS; i++){
655                 objp->shields[i] = strength/MAX_SHIELD_SECTIONS;
656         }
657 }
658
659 //      Recharge whole shield.
660 //      Apply delta/MAX_SHIELD_SECTIONS to each shield section.
661 void add_shield_strength(object *objp, float delta)
662 {
663         int     i;
664         float   section_max;
665
666         section_max = Ship_info[Ships[objp->instance].ship_info_index].shields/MAX_SHIELD_SECTIONS;
667
668         for (i=0; i<MAX_SHIELD_SECTIONS; i++) {
669                 objp->shields[i] += delta/MAX_SHIELD_SECTIONS;
670                 if (objp->shields[i] > section_max)
671                         objp->shields[i] = section_max;
672                 else if (objp->shields[i] < 0.0f)
673                         objp->shields[i] = 0.0f;
674         }
675
676 }
677
678 //sets up the free list & init player & whatever else
679 void obj_init()
680 {
681         int i, idx;
682         object *objp;
683         
684         Object_inited = 1;
685         memset( Objects, 0, sizeof(object)*MAX_OBJECTS );
686         Viewer_obj = NULL;
687
688         list_init( &obj_free_list );
689         list_init( &obj_used_list );
690         list_init( &obj_create_list );
691
692         // Link all object slots into the free list
693         objp = Objects;
694         for (i=0; i<MAX_OBJECTS; i++)   {
695                 objp->type = OBJ_NONE;
696                 objp->signature = i + 100;
697
698                 // zero all object sounds
699                 for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
700                         objp->objsnd_num[idx] = -1;
701                 }
702                 
703                 list_append(&obj_free_list, objp);
704                 objp++;
705         }
706
707         Object_next_signature = 1;      //0 is invalid, others start at 1
708         Object_next_ship_signature = OBJECT_SIG_SHIP_START;
709         num_objects = 0;                        
710         Highest_object_index = 0;
711
712         obj_reset_pairs();
713 }
714
715 int     num_objects_hwm = 0;
716
717 //returns the number of a free object, updating Highest_object_index.
718 //Generally, obj_create() should be called to get an object, since it
719 //fills in important fields and does the linking.
720 //returns -1 if no free objects
721 int obj_allocate(void)
722 {
723         int objnum;
724         object *objp;
725
726         if (!Object_inited) obj_init();
727
728         if ( num_objects >= MAX_OBJECTS-10 ) {
729 #ifndef NDEBUG
730                 int     num_freed;
731
732                 num_freed = free_object_slots(MAX_OBJECTS-10);
733                 nprintf(("warning", " *** Freed %i objects\n", num_freed));
734 #else
735                 free_object_slots(MAX_OBJECTS-10);
736 #endif
737         }
738
739         if (num_objects >= MAX_OBJECTS) {
740                 #ifndef NDEBUG
741                 mprintf(("Object creation failed - too many objects!\n" ));
742                 #endif
743                 return -1;
744         }
745
746         // Find next available object
747         objp = GET_FIRST(&obj_free_list);
748         SDL_assert ( objp != &obj_free_list );          // shouldn't have the dummy element
749
750         // remove objp from the free list
751         list_remove( &obj_free_list, objp );
752         
753         // insert objp onto the end of create list
754         list_append( &obj_create_list, objp );
755
756         // increment counter
757         num_objects++;
758
759         if (num_objects > num_objects_hwm) {
760                 //nprintf(("AI", "*** MAX Num Objects = %i\n", num_objects));
761                 num_objects_hwm = num_objects;
762         }
763
764         // get objnum
765         objnum = OBJ_INDEX(objp);
766
767         if (objnum > Highest_object_index) {
768                 Highest_object_index = objnum;
769                 if (Highest_object_index > Highest_ever_object_index)
770                         Highest_ever_object_index = Highest_object_index;
771         }
772
773         return objnum;
774 }
775
776 //frees up an object.  Generally, obj_delete() should be called to get
777 //rid of an object.  This function deallocates the object entry after
778 //the object has been unlinked
779 void obj_free(int objnum)
780 {
781         object *objp;
782
783         if (!Object_inited) obj_init();
784
785         SDL_assert( objnum >= 0 );      // Trying to free bogus object!!!
786
787         // get object pointer
788         objp = &Objects[objnum];
789
790         // remove objp from the used list
791         list_remove( &obj_used_list, objp);
792
793         // add objp to the end of the free
794         list_append( &obj_free_list, objp );
795
796         // decrement counter
797         num_objects--;
798
799         Objects[objnum].type = OBJ_NONE;
800
801         SDL_assert(num_objects >= 0);
802
803         if (objnum == Highest_object_index)
804                 while (Objects[--Highest_object_index].type == OBJ_NONE);
805
806 }
807
808 //initialize a new object.  adds to the list for the given segment.
809 //returns the object number.  The object will be a non-rendering, non-physics
810 //object.   Pass -1 if no parent.
811 int obj_create(ubyte type,int parent_obj,int instance, matrix * orient, 
812                vector * pos, float radius, uint flags )
813 {
814         int objnum,idx;
815         object *obj;
816
817         // Find next free object
818         objnum = obj_allocate();
819
820         if (objnum == -1)               //no free objects
821                 return -1;
822
823         obj = &Objects[objnum];
824         SDL_assert(obj->type == OBJ_NONE);              //make sure unused 
825
826         // Zero out object structure to keep weird bugs from happening
827         // in uninitialized fields.
828 //      memset( obj, 0, sizeof(object) );
829
830         if(obj->type == OBJ_SHIP){
831                 obj->signature                          = Object_next_ship_signature++;
832
833                 if (!Object_next_ship_signature){
834                         Object_next_ship_signature = OBJECT_SIG_SHIP_START;             // 0 is bogus!
835                 }
836         } else {
837                 obj->signature                          = Object_next_signature++;
838
839                 if (!Object_next_signature){
840                         Object_next_signature = 1;              // 0 is bogus!
841                 }
842         }       
843         
844         obj->type                                       = type;
845         obj->instance                           = instance;
846         obj->parent                                     = parent_obj;
847         if (obj->parent != -1)  {
848                 obj->parent_sig         = Objects[parent_obj].signature;
849                 obj->parent_type                = Objects[parent_obj].type;
850         } else {
851                 obj->parent_sig = obj->signature;
852                 obj->parent_type = obj->type;
853         }
854
855         obj->flags                                      = flags | OF_NOT_IN_COLL;
856         if (pos)        {
857                 obj->pos                                = *pos;
858                 obj->last_pos                   = *pos;
859         }
860
861         obj->orient                             = orient?*orient:vmd_identity_matrix;
862         obj->last_orient                        = obj->orient;
863         obj->radius                             = radius;
864
865         obj->flags &= ~OF_INVULNERABLE;         //      Make vulnerable.
866         physics_init( &obj->phys_info );
867
868         for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
869                 obj->objsnd_num[idx] = -1;
870         }
871         obj->num_pairs = 0;
872         obj->net_signature = 0;                 // be sure to reset this value so new objects don't take on old signatures.     
873
874         return objnum;
875 }
876
877 //remove object from the world
878 //      If Player_obj, don't remove it!
879 void obj_delete(int objnum)
880 {
881         object *objp;
882
883         SDL_assert(objnum >= 0 && objnum < MAX_OBJECTS);
884         objp = &Objects[objnum];
885         SDL_assert(objp->type != OBJ_NONE);     
886
887         // Remove all object pairs
888         obj_remove_pairs( objp );
889         
890         switch( objp->type )    {
891         case OBJ_WEAPON:
892                 weapon_delete( objp );
893                 break;
894         case OBJ_SHIP:
895                 if ((objp == Player_obj) && !Fred_running) {
896                         objp->type = OBJ_GHOST;
897                         objp->flags &= ~(OF_SHOULD_BE_DEAD);
898                         
899                         // we have to traverse the ship_obj list and remove this guy from it as well
900                         ship_obj *moveup = GET_FIRST(&Ship_obj_list);
901                         while(moveup != END_OF_LIST(&Ship_obj_list)){
902                                 if(OBJ_INDEX(objp) == moveup->objnum){
903                                         list_remove(&Ship_obj_list,moveup);
904                                         break;
905                                 }
906                                 moveup = GET_NEXT(moveup);
907                         }
908
909                         physics_init(&objp->phys_info);
910                         
911                         obj_snd_delete(OBJ_INDEX(objp));
912                         return;
913                 } else
914                         ship_delete( objp );
915                 break;
916         case OBJ_FIREBALL:
917                 fireball_delete( objp );
918                 break;
919         case OBJ_SHOCKWAVE:
920                 shockwave_delete( objp );
921                 break;
922         case OBJ_START:
923         case OBJ_WAYPOINT:
924         case OBJ_POINT:
925         case OBJ_JUMP_NODE:
926                 SDL_assert(Fred_running);
927                 break;  // requires no action, handled by the Fred code.
928         case OBJ_DEBRIS:
929                 debris_delete( objp );
930                 break;
931         case OBJ_ASTEROID:
932                 asteroid_delete(objp);
933                 break;
934         case OBJ_CMEASURE:
935                 cmeasure_delete( objp );
936                 break;
937         case OBJ_GHOST:
938                 if((!Game_mode & GM_MULTIPLAYER)){
939                         mprintf(("Warning: Tried to delete a ghost!"));
940                         objp->flags &= ~OF_SHOULD_BE_DEAD;
941                         return;
942                 } else {
943                         // we need to be able to delete GHOST objects in multiplayer to allow for player respawns.
944                         nprintf(("Network","Deleting GHOST object\n"));
945                 }               
946                 break;
947         case OBJ_OBSERVER:
948                 observer_delete(objp);
949                 break;  
950         case OBJ_BEAM:
951                 break;
952         case OBJ_NONE:
953                 Int3();
954                 break;
955         default:
956                 Error( LOCATION, "Unhandled object type %d in obj_delete_all_that_should_be_dead", objp->type );
957         }
958
959         // if a persistant sound has been created, delete it
960         obj_snd_delete(OBJ_INDEX(objp));                
961
962         objp->type = OBJ_NONE;          //unused!
963         objp->signature = 0;            
964
965         obj_free(objnum);
966 }
967
968
969 //      ------------------------------------------------------------------------------------------------------------------
970 void obj_delete_all_that_should_be_dead()
971 {
972         object *objp, *temp;
973
974         if (!Object_inited) obj_init();
975
976         // Move all objects
977         objp = GET_FIRST(&obj_used_list);
978         while( objp !=END_OF_LIST(&obj_used_list) )     {
979                 temp = GET_NEXT(objp);
980                 if ( objp->flags&OF_SHOULD_BE_DEAD )
981                         obj_delete( OBJ_INDEX(objp) );                  // MWA says that john says that let obj_delete handle everything because of the editor
982                 objp = temp;
983         }
984
985 }
986
987 // Add all newly created objects to the end of the used list and create their
988 // object pairs for collision detection
989 void obj_merge_created_list(void)
990 {
991         // The old way just merged the two.   This code takes one out of the create list,
992         // creates object pairs for it, and then adds it to the used list.
993         //      OLD WAY: list_merge( &obj_used_list, &obj_create_list );
994         object *objp = GET_FIRST(&obj_create_list);
995         while( objp !=END_OF_LIST(&obj_create_list) )   {
996                 list_remove( obj_create_list, objp );
997
998                 // Add it to the object pairs array
999                 obj_add_pairs(OBJ_INDEX(objp));
1000
1001                 // Then add it to the object used list
1002                 list_append( &obj_used_list, objp );
1003
1004                 objp = GET_FIRST(&obj_create_list);
1005         }
1006
1007         // Make sure the create list is empty.
1008         list_init(&obj_create_list);
1009 }
1010
1011 int physics_paused = 0, ai_paused = 0;
1012
1013 extern void call_doa(object *obj1, object *obj2, ship_info *sip1);
1014
1015 //      If this is a cargo container or a repair ship, move it along with the ship it's docked to.
1016 void move_docked_objects(object *objp)
1017 {
1018         ai_info         *aip;
1019         ai_info *other_aip;
1020
1021         if (objp->type != OBJ_SHIP)
1022                 return;
1023
1024         SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
1025
1026         aip = &Ai_info[Ships[objp->instance].ai_index];
1027
1028         if (aip->ai_flags & AIF_DOCKED) {
1029                 ship_info       *sip;
1030                 sip = &Ship_info[Ships[objp->instance].ship_info_index];
1031                 if ((sip->flags & SIF_SUPPORT) || (sip->flags & SIF_CARGO)) {
1032                         SDL_assert(!((sip->flags & SIF_SUPPORT) && (sip->flags & SIF_CARGO)));  //      Ship can't be both repair and cargo
1033                         if (aip->dock_objnum != -1) {
1034                                 if (aip->mode == AIM_DOCK) {
1035                                         if (aip->submode < AIS_UNDOCK_1)
1036                                                 call_doa(objp, &Objects[aip->dock_objnum], sip);
1037                                 } else {
1038                                         // if I am not in dock mode then I need to check the guy that I'm docked with
1039                                         // and only move with him if he isn't undocking.
1040                                         other_aip = &Ai_info[Ships[Objects[aip->dock_objnum].instance].ai_index];
1041                                         if ( other_aip->mode == AIM_DOCK ) {
1042                                                 if (other_aip->submode < AIS_UNDOCK_1 )
1043                                                         call_doa(objp, &Objects[aip->dock_objnum], sip);
1044                                         } else {
1045                                                 call_doa(objp, &Objects[aip->dock_objnum], sip);
1046                                         }
1047                                 }
1048                         }
1049                 } else {
1050                         if (aip->dock_objnum != -1) {
1051                                 SDL_assert( aip->dock_objnum != -1 );
1052                                 other_aip = &Ai_info[Ships[Objects[aip->dock_objnum].instance].ai_index];
1053
1054                                 // if the other object that I am docked with is undocking, then don't do anything.
1055                                 if ( !((other_aip->mode == AIM_DOCK) && (other_aip->submode >= AIS_UNDOCK_1)) ) {
1056                                         if ( (aip->mode != AIM_DOCK) && (aip->mode != AIM_WARP_OUT) ) {
1057                                                 object  *objp1, *objp2;
1058
1059                                                 objp1 = &Objects[aip->dock_objnum];
1060                                                 objp2 = objp;
1061
1062                                                 if (objp1->phys_info.speed > objp2->phys_info.speed) {
1063                                                         object *t = objp1;
1064                                                         objp1 = objp2;
1065                                                         objp2 = t;
1066                                                 }
1067
1068                                                 //nprintf(("AI", "Calling doa, frame %i: %s, %s\n", Framecount, Ships[objp1->instance].ship_name, Ships[objp2->instance].ship_name));
1069                                                 call_doa(objp1, objp2, sip);
1070                                         }
1071                                 }
1072                         }
1073                 }
1074         }
1075 }
1076
1077 /*
1078 float   Last_fire_time = 0.0f;
1079 int Avg_delay_count = 0;
1080 float Avg_delay_total;
1081 */
1082
1083 // function to deal with firing player things like lasers, missiles, etc.
1084 // separated out because of multiplayer issues.
1085 void obj_player_fire_stuff( object *objp, control_info ci )
1086 {
1087         ship *shipp;
1088
1089         SDL_assert( objp->flags & OF_PLAYER_SHIP);
1090
1091         // try and get the ship pointer
1092         shipp = NULL;
1093         if((objp->type == OBJ_SHIP) && (objp->instance >= 0) && (objp->instance < MAX_SHIPS)){
1094                 shipp = &Ships[objp->instance];
1095         }
1096
1097         // single player pilots, and all players in multiplayer take care of firing their own primaries
1098         if(!(Game_mode & GM_MULTIPLAYER) || (objp == Player_obj)){
1099                 if ( ci.fire_primary_count ) {
1100                         // flag the ship as having the trigger down
1101                         if(shipp != NULL){
1102                                 shipp->flags |= SF_TRIGGER_DOWN;
1103                         }
1104
1105                         // fire non-streaming primaries here
1106                         ship_fire_primary( objp, 0 );                   
1107                 } else {
1108                         // unflag the ship as having the trigger down
1109                         if(shipp != NULL){
1110                                 shipp->flags &= ~(SF_TRIGGER_DOWN);
1111                         }
1112                 }
1113
1114                 if ( ci.fire_countermeasure_count ){
1115                         ship_launch_countermeasure( objp );
1116                 }
1117         }
1118
1119         // single player and multiplayer masters do all of the following
1120         if ( !MULTIPLAYER_CLIENT ) {            
1121                 if ( ci.fire_secondary_count ){
1122                         ship_fire_secondary( objp );
1123
1124                         // kill the secondary count
1125                         ci.fire_secondary_count = 0;
1126                 }
1127         }
1128
1129         // everyone does the following for their own ships.
1130         if ( ci.afterburner_start ){
1131                 if (ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE)){
1132                         afterburners_start( objp );
1133                 }
1134         }
1135         
1136         if ( ci.afterburner_stop ){
1137                 afterburners_stop( objp, 1 );
1138         }
1139 }
1140
1141 void obj_move_call_physics(object *objp, float frametime)
1142 {
1143         //      Do physics for objects with OF_PHYSICS flag set and with some engine strength remaining.
1144         if ( objp->flags & OF_PHYSICS ) {
1145                 // only set phys info if ship is not dead
1146                 if ((objp->type == OBJ_SHIP) && !(Ships[objp->instance].flags & SF_DYING)) {
1147                         float   engine_strength;
1148                         engine_strength = ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE);
1149                         if ( ship_subsys_disrupted(&Ships[objp->instance], SUBSYSTEM_ENGINE) ) {
1150                                 engine_strength=0.0f;
1151                         }
1152
1153                         if (engine_strength == 0.0f) {  //      All this is necessary to make ship gradually come to a stop after engines are blown.
1154                                 vm_vec_zero(&objp->phys_info.desired_vel);
1155                                 vm_vec_zero(&objp->phys_info.desired_rotvel);
1156                                 objp->phys_info.flags |= (PF_REDUCED_DAMP | PF_DEAD_DAMP);
1157                                 objp->phys_info.side_slip_time_const = Ship_info[Ships[objp->instance].ship_info_index].damp * 4.0f;
1158                         } // else {
1159                                 // DA: comment out lines that resets PF_DEAD_DAMP after every frame.
1160                                 // This is now reset during engine repair.
1161                                 //      objp->phys_info.flags &= ~(PF_REDUCED_DAMP | PF_DEAD_DAMP);
1162                                 // objp->phys_info.side_slip_time_const = Ship_info[Ships[objp->instance].ship_info_index].damp;
1163                         // }
1164                 }
1165
1166                 // if a weapon is flagged as dead, kill its engines just like a ship
1167                 if((objp->type == OBJ_WEAPON) && (Weapons[objp->instance].weapon_flags & WF_DEAD_IN_WATER)){
1168                         vm_vec_zero(&objp->phys_info.desired_vel);
1169                         vm_vec_zero(&objp->phys_info.desired_rotvel);
1170                         objp->phys_info.flags |= (PF_REDUCED_DAMP | PF_DEAD_DAMP);
1171                         objp->phys_info.side_slip_time_const = Ship_info[Ships[objp->instance].ship_info_index].damp * 4.0f;
1172                 }
1173
1174                 if (physics_paused)     {
1175                         if (objp==Player_obj){
1176                                 physics_sim(&objp->pos, &objp->orient, &objp->phys_info, frametime );           // simulate the physics
1177                         }
1178                 } else {
1179                         //      Hack for dock mode.
1180                         //      If docking with a ship, we don't obey the normal ship physics, we can slew about.
1181                         if (objp->type == OBJ_SHIP) {
1182                                 ai_info *aip = &Ai_info[Ships[objp->instance].ai_index];
1183
1184                                 //      Note: This conditional for using PF_USE_VEL (instantaneous acceleration) is probably too loose.
1185                                 //      A ships awaiting support will fly towards the support ship with instantaneous acceleration.
1186                                 //      But we want to have ships in the process of docking have quick acceleration, or they overshoot their goals.
1187                                 //      Probably can not key off dock_objnum, but then need to add some other condition.  Live with it for now. -- MK, 2/19/98
1188                                 if ((aip->dock_objnum != -1) || 
1189                                         ((aip->mode == AIM_DOCK) && ((aip->submode == AIS_DOCK_2) || (aip->submode == AIS_DOCK_3) || (aip->submode == AIS_UNDOCK_0))) ||
1190                                         ((aip->mode == AIM_WARP_OUT) && (aip->submode >= AIS_WARP_3))) {
1191                                         if (ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) > 0.0f){
1192                                                 objp->phys_info.flags |= PF_USE_VEL;
1193                                         } else {
1194                                                 objp->phys_info.flags &= ~PF_USE_VEL;   //      If engine blown, don't PF_USE_VEL, or ships stop immediately
1195                                         }
1196                                 } else {
1197                                         objp->phys_info.flags &= ~PF_USE_VEL;
1198                                 }
1199                         }                       
1200
1201                         // in multiplayer, if this object was just updatd (i.e. clients send their own positions),
1202                         // then reset the flag and don't move the object.
1203                         if ( MULTIPLAYER_MASTER && (objp->flags & OF_JUST_UPDATED) ) {
1204                                 objp->flags &= ~OF_JUST_UPDATED;
1205                                 goto obj_maybe_fire;
1206                         }
1207
1208                         physics_sim(&objp->pos, &objp->orient, &objp->phys_info, frametime );           // simulate the physics
1209
1210                         // This code seems to have no effect - DB 1/12/99
1211                         //if ( MULTIPLAYER_CLIENT && (objp != Player_obj) ){
1212                         //      return;
1213                         //}
1214
1215                         // if the object is the player object, do things that need to be done after the ship
1216                         // is moved (like firing weapons, etc).  This routine will get called either single
1217                         // or multiplayer.  We must find the player object to get to the control info field
1218 obj_maybe_fire:
1219                         if ( (objp->flags & OF_PLAYER_SHIP) && (objp->type != OBJ_OBSERVER) && (objp == Player_obj)) {
1220                                 player *pp;
1221                                 if(Player != NULL){
1222                                         pp = Player;
1223                                         obj_player_fire_stuff( objp, pp->ci );                          
1224                                 }
1225                         }
1226
1227                         // fire streaming weapons for ships in here - ALL PLAYERS, regardless of client, single player, server, whatever.
1228                         // do stream weapon firing for all ships themselves. 
1229                         if(objp->type == OBJ_SHIP){
1230                                 ship_fire_primary(objp, 1, 0);
1231                         }
1232                 }
1233         }
1234 }
1235
1236
1237 #define IMPORTANT_FLAGS (OF_COLLIDES)
1238
1239 #ifdef OBJECT_CHECK 
1240
1241
1242 void obj_check_object( object *obj )
1243 {
1244         int objnum = OBJ_INDEX(obj);
1245
1246         // PROGRAMMERS: If one of these Int3() gets hit, then someone
1247         // is changing a value in the object structure that might cause
1248         // collision detection to not work.  See John for more info if
1249         // you are hitting one of these.
1250
1251         if ( CheckObjects[objnum].type != obj->type )   {
1252                 if ( (obj->type==OBJ_WAYPOINT) && (CheckObjects[objnum].type==OBJ_SHIP) )       {
1253                         // We know about ships changing into waypoints and that is
1254                         // ok.
1255                         CheckObjects[objnum].type = OBJ_WAYPOINT;
1256                  } else if ( (obj->type==OBJ_SHIP) && (CheckObjects[objnum].type==OBJ_GHOST) )  {
1257                         // We know about player changing into a ghost after dying and that is
1258                         // ok.
1259                         CheckObjects[objnum].type = OBJ_GHOST;
1260                 } else if ( (obj->type==OBJ_GHOST) && (CheckObjects[objnum].type==OBJ_SHIP) )   {
1261                         // We know about player changing into a ghost after dying and that is
1262                         // ok.
1263                         CheckObjects[objnum].type = OBJ_SHIP;
1264                 } else {
1265                         mprintf(( "Object type changed!\n" ));
1266                         Int3();
1267                 }
1268         }
1269         if ( CheckObjects[objnum].signature != obj->signature ) {
1270                 mprintf(( "Object signature changed!\n" ));
1271                 Int3();
1272         }
1273         if ( (CheckObjects[objnum].flags&IMPORTANT_FLAGS) != (obj->flags&IMPORTANT_FLAGS) ) {
1274                 mprintf(( "Object flags changed!\n" ));
1275                 Int3();
1276         }
1277         if ( CheckObjects[objnum].parent_sig != obj->parent_sig ) {
1278                 mprintf(( "Object parent sig changed!\n" ));
1279                 Int3();
1280         }
1281         if ( CheckObjects[objnum].parent_type != obj->parent_type ) {
1282                 mprintf(( "Object's parent type changed!\n" ));
1283                 Int3();
1284         }
1285 }
1286 #endif
1287
1288 // Call this if you want to change an object flag so that the
1289 // object code knows what's going on.  For instance if you turn
1290 // off OF_COLLIDES, the object code needs to know this in order to
1291 // actually turn the object collision detection off.  By calling
1292 // this you shouldn't get Int3's in the checkobject code.  If you
1293 // do, then put code in here to correctly handle the case.
1294 void obj_set_flags( object *obj, uint new_flags )
1295 {
1296         int objnum = OBJ_INDEX(obj);    
1297
1298         // turning collision detection off
1299         if ( (obj->flags & OF_COLLIDES) && (!(new_flags&OF_COLLIDES)))  {               
1300                 // Remove all object pairs
1301                 obj_remove_pairs( obj );
1302
1303                 // update object flags properly         
1304                 obj->flags = new_flags;
1305                 obj->flags |= OF_NOT_IN_COLL;           
1306 #ifdef OBJECT_CHECK
1307                 CheckObjects[objnum].flags = new_flags;
1308                 CheckObjects[objnum].flags |= OF_NOT_IN_COLL;           
1309 #endif          
1310                 return;
1311         }
1312         
1313         
1314         // turning collision detection on
1315         if ( (!(obj->flags & OF_COLLIDES)) && (new_flags&OF_COLLIDES) ) {
1316                 
1317                 // observers can't collide or be hit, and they therefore have no hit or collide functions
1318                 // So, don't allow this bit to be set
1319                 if(obj->type == OBJ_OBSERVER){
1320                         mprintf(("Illegal to set collision bit for OBJ_OBSERVER!!\n"));
1321                         Int3();
1322                 }
1323
1324                 obj->flags |= OF_COLLIDES;
1325
1326                 // Turn on collision detection
1327                 obj_add_pairs(objnum);
1328                                 
1329                 obj->flags = new_flags;
1330                 obj->flags &= ~(OF_NOT_IN_COLL);                
1331 #ifdef OBJECT_CHECK
1332                 CheckObjects[objnum].flags = new_flags;
1333                 CheckObjects[objnum].flags &= ~(OF_NOT_IN_COLL);                
1334 #endif
1335                 return;
1336         }
1337
1338         // for a multiplayer host -- use this debug code to help trap when non-player ships are getting
1339         // marked as OF_COULD_BE_PLAYER
1340         // this code is pretty much debug code and shouldn't be relied on to always do the right thing
1341         // for flags other than 
1342         if ( MULTIPLAYER_MASTER && !(obj->flags & OF_COULD_BE_PLAYER) && (new_flags & OF_COULD_BE_PLAYER) ) {
1343                 ship *shipp;
1344                 int team, slot;
1345
1346                 // this flag sometimes gets set for observers.
1347                 if ( obj->type == OBJ_OBSERVER ) {
1348                         return;
1349                 }
1350
1351                 // sanity checks
1352                 if ( (obj->type != OBJ_SHIP) || (obj->instance < 0) ) {
1353                         // Int3();
1354                         return;                         // return because we really don't want to set the flag
1355                 }
1356
1357                 // see if this ship is really a player ship (or should be)
1358                 shipp = &Ships[obj->instance];
1359                 extern void multi_ts_get_team_and_slot(char *, int *, int *);
1360                 multi_ts_get_team_and_slot(shipp->ship_name,&team,&slot);
1361                 if ( (shipp->wingnum == -1) || (team == -1) || (slot==-1) ) {
1362                         Int3();
1363                         return;
1364                 }
1365
1366                 // set the flag
1367                 obj->flags = new_flags;
1368 #ifdef OBJECT_CHECK
1369                 CheckObjects[objnum].flags = new_flags;
1370 #endif
1371
1372                 return;
1373         }
1374
1375         // Check for unhandled flag changing
1376         if ( (new_flags&IMPORTANT_FLAGS) != (obj->flags&IMPORTANT_FLAGS) ) {
1377                 mprintf(( "Unhandled flag changing in obj_set_flags!!\n" ));
1378                 mprintf(( "Add code to support it, see John for questions!!\n" ));
1379                 Int3();
1380         } else {
1381                 // Since it wasn't an important flag, just bash it.
1382                 obj->flags = new_flags;
1383                 #ifdef OBJECT_CHECK 
1384                 CheckObjects[objnum].flags = new_flags;
1385                 #endif
1386         }       
1387 }
1388
1389
1390 void obj_move_all_pre(object *objp, float frametime)
1391 {
1392         switch( objp->type )    {
1393         case OBJ_WEAPON:
1394                 if (!physics_paused){
1395                         weapon_process_pre( objp, frametime );
1396                 }
1397                 break;  
1398         case OBJ_SHIP:
1399                 if (!physics_paused || (objp==Player_obj )){
1400                         ship_process_pre( objp, frametime );
1401                 }
1402                 break;
1403         case OBJ_FIREBALL:
1404                 if (!physics_paused){
1405                         fireball_process_pre(objp,frametime);
1406                 }
1407                 break;
1408         case OBJ_SHOCKWAVE:
1409                 // all shockwaves are moved via shockwave_move_all()
1410                 break;
1411         case OBJ_DEBRIS:
1412                 if (!physics_paused){
1413                         debris_process_pre(objp,frametime);
1414                 }
1415                 break;
1416         case OBJ_ASTEROID:
1417                 if (!physics_paused){
1418                         asteroid_process_pre(objp,frametime);
1419                 }
1420                 break;
1421         case OBJ_CMEASURE:
1422                 if (!physics_paused){
1423                         cmeasure_process_pre(objp, frametime);
1424                 }
1425                 break;
1426         case OBJ_WAYPOINT:
1427                 break;  // waypoints don't move..
1428         case OBJ_GHOST:
1429                 break;
1430         case OBJ_OBSERVER:
1431         case OBJ_JUMP_NODE:     
1432                 break;  
1433         case OBJ_BEAM:          
1434                 break;
1435         case OBJ_NONE:
1436                 Int3();
1437                 break;
1438         default:
1439                 Error( LOCATION, "Unhandled object type %d in obj_move_one\n", objp->type );
1440         }       
1441 }
1442
1443 // Used to tell if a particular group of lasers has cast light yet.
1444 ubyte Obj_weapon_group_id_used[WEAPON_MAX_GROUP_IDS];
1445
1446 // Called once a frame to mark all weapon groups as not having cast light yet.
1447 void obj_clear_weapon_group_id_list()
1448 {
1449         memset( Obj_weapon_group_id_used, 0, sizeof(Obj_weapon_group_id_used) );
1450 }
1451
1452 int Arc_light = 1;              // If set, electrical arcs on debris cast light
1453 DCF_BOOL(arc_light, Arc_light)  
1454
1455 void obj_move_all_post(object *objp, float frametime)
1456 {
1457         switch( objp->type )    {
1458         case OBJ_WEAPON:
1459                 if (!physics_paused)    {
1460                         weapon_process_post( objp, frametime );
1461                 }
1462                 // Cast light
1463                 if ( Detail.lighting > 2 ) {
1464                         // Weapons cast light
1465
1466                         int group_id = Weapons[objp->instance].group_id;
1467                         int cast_light = 1;
1468
1469                         if ( (group_id>-1) && (Obj_weapon_group_id_used[group_id]==0) ) {
1470                                 // Mark this group as done
1471                                 Obj_weapon_group_id_used[group_id]++;
1472                         } else {
1473                                 // This group has already done its light casting
1474                                 cast_light = 0;
1475                         }
1476
1477                         if ( cast_light )       {
1478                                 weapon_info * wi = &Weapon_info[Weapons[objp->instance].weapon_info_index];
1479
1480                                 if ( wi->render_type == WRT_LASER )     {
1481                                         color c;
1482                                         float r,g,b;
1483
1484                                         // get the laser color
1485                                         weapon_get_laser_color(&c, objp);
1486
1487                                         r = i2fl(c.red)/255.0f;
1488                                         g = i2fl(c.green)/255.0f;
1489                                         b = i2fl(c.blue)/255.0f;
1490                                         light_add_point( &objp->pos, 10.0f, 20.0f, 1.0f, r, g, b, objp->parent );
1491                                         //light_add_point( &objp->pos, 10.0f, 20.0f, 1.0f, 0.0f, 0.0f, 1.0f, objp->parent );
1492                                 } else {
1493                                         light_add_point( &objp->pos, 10.0f, 20.0f, 1.0f, 1.0f, 1.0f, 1.0f, objp->parent );
1494                                 }
1495                         }
1496                 }
1497                 break;  
1498         case OBJ_SHIP:
1499                 if (!physics_paused || (objp==Player_obj ))
1500                         ship_process_post( objp, frametime );
1501
1502                 // Make any electrical arcs on ships cast light
1503                 if (Arc_light)  {
1504                         if ( Detail.lighting > 2 ) {
1505                                 int i;
1506                                 ship            *shipp;
1507                                 shipp = &Ships[objp->instance];
1508
1509                                 for (i=0; i<MAX_SHIP_ARCS; i++ )        {
1510                                         if ( timestamp_valid( shipp->arc_timestamp[i] ) )       {
1511                                                 // Move arc endpoints into world coordinates    
1512                                                 vector tmp1, tmp2;
1513                                                 vm_vec_unrotate(&tmp1,&shipp->arc_pts[i][0],&objp->orient);
1514                                                 vm_vec_add2(&tmp1,&objp->pos);
1515
1516                                                 vm_vec_unrotate(&tmp2,&shipp->arc_pts[i][1],&objp->orient);
1517                                                 vm_vec_add2(&tmp2,&objp->pos);
1518
1519                                                 light_add_point( &tmp1, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1520                                                 light_add_point( &tmp2, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1521                                         }
1522                                 }
1523                         }
1524                 }               
1525
1526                 break;
1527         case OBJ_FIREBALL:
1528                 if (!physics_paused)    {
1529                         fireball_process_post(objp,frametime);
1530                 }
1531                 if ( Detail.lighting > 3 ) {
1532                         // Make explosions cast light
1533                         float p = fireball_lifeleft_percent(objp);
1534                         if ( p > 0.5f ) {
1535                                 p = 1.0f - p;
1536                         }
1537                         p *= 2.0f;
1538                         // P goes from 0 to 1 to 0 over the life of the explosion
1539                         float rad = p*(1.0f+frand()*0.05f)*objp->radius;
1540
1541                         light_add_point( &objp->pos, rad*2.0f, rad*5.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1 );
1542                 }
1543                 break;
1544         case OBJ_SHOCKWAVE:
1545                 // all shockwaves are moved via shockwave_move_all()
1546                 break;
1547         case OBJ_DEBRIS:
1548                 if (!physics_paused)
1549                         debris_process_post(objp,frametime);
1550
1551                 // Make any electrical arcs on debris cast light
1552                 if (Arc_light)  {
1553                         if ( Detail.lighting > 2 ) {
1554                                 int i;
1555                                 debris          *db;
1556                                 db = &Debris[objp->instance];
1557
1558                                 for (i=0; i<MAX_DEBRIS_ARCS; i++ )      {
1559                                         if ( timestamp_valid( db->arc_timestamp[i] ) )  {
1560                                                 // Move arc endpoints into world coordinates    
1561                                                 vector tmp1, tmp2;
1562                                                 vm_vec_unrotate(&tmp1,&db->arc_pts[i][0],&objp->orient);
1563                                                 vm_vec_add2(&tmp1,&objp->pos);
1564
1565                                                 vm_vec_unrotate(&tmp2,&db->arc_pts[i][1],&objp->orient);
1566                                                 vm_vec_add2(&tmp2,&objp->pos);
1567
1568                                                 light_add_point( &tmp1, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1569                                                 light_add_point( &tmp2, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1570                                         }
1571                                 }
1572                         }
1573                 }               
1574                 break;
1575         case OBJ_ASTEROID:
1576                 if (!physics_paused)
1577                         asteroid_process_post(objp, frametime);
1578                 break;
1579         case OBJ_CMEASURE:
1580                 if (!physics_paused)
1581                         cmeasure_process_post(objp, frametime);
1582                 break;
1583         case OBJ_WAYPOINT:
1584                 break;  // waypoints don't move..
1585         case OBJ_GHOST:
1586                 break;
1587         case OBJ_OBSERVER:
1588                 void observer_process_post(object *objp);
1589                 observer_process_post(objp);
1590                 break;
1591         case OBJ_JUMP_NODE:
1592                 radar_plot_object(objp);
1593                 break;  
1594         case OBJ_BEAM:          
1595                 break;
1596         case OBJ_NONE:
1597                 Int3();
1598                 break;
1599         default:
1600                 Error( LOCATION, "Unhandled object type %d in obj_move_one\n", objp->type );
1601         }       
1602 }
1603
1604
1605 int Collisions_enabled = 1;
1606
1607 DCF_BOOL( collisions, Collisions_enabled )
1608
1609 MONITOR( NumObjects );  
1610
1611 //--------------------------------------------------------------------
1612 //move all objects for the current frame
1613 void obj_move_all(float frametime)
1614 {
1615         object *objp;   
1616
1617         obj_delete_all_that_should_be_dead();
1618
1619         obj_merge_created_list();
1620
1621         // Clear the table that tells which groups of weapons have cast light so far.
1622         if(!(Game_mode & GM_MULTIPLAYER) || (MULTIPLAYER_MASTER)){
1623                 obj_clear_weapon_group_id_list();
1624         }
1625
1626         MONITOR_INC( NumObjects, num_objects ); 
1627
1628         objp = GET_FIRST(&obj_used_list);
1629         while( objp !=END_OF_LIST(&obj_used_list) )     {
1630                 // skip objects which should be dead
1631                 if ( !(objp->flags&OF_SHOULD_BE_DEAD) ) {               
1632                         vector  cur_pos = objp->pos;                    // Save the current position
1633
1634                         // if this is an observer object, skip it
1635                         if(objp->type == OBJ_OBSERVER){
1636                                 objp = GET_NEXT(objp);
1637                                 continue;
1638                         }
1639
1640                         // if we're playing a demo back, only sim stuff that we're supposed to
1641                         if((Game_mode & GM_DEMO_PLAYBACK) && !demo_should_sim(objp)){
1642                                 objp = GET_NEXT(objp);
1643                                 continue;
1644                         }
1645
1646 #ifdef OBJECT_CHECK 
1647                         // if(! ((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) ){
1648                                 obj_check_object( objp );
1649                         // }
1650 #endif
1651
1652                         // pre-move
1653                         obj_move_all_pre(objp, frametime);
1654
1655                         // store last pos and orient
1656                         objp->last_pos = cur_pos;
1657                         objp->last_orient = objp->orient;
1658
1659                         // if this is an object which should be interpolated in multiplayer, do so
1660                         if(multi_oo_is_interp_object(objp)){
1661                                 multi_oo_interp(objp);
1662                         } else {
1663                                 // physics
1664                                 obj_move_call_physics(objp, frametime);
1665                         }
1666
1667                         // move post
1668                         obj_move_all_post(objp, frametime);
1669                 }
1670                 objp = GET_NEXT(objp);
1671         }
1672
1673         //      After all objects have been moved, move all docked objects.
1674         if(!(Game_mode & GM_DEMO_PLAYBACK)){
1675                 objp = GET_FIRST(&obj_used_list);
1676                 while( objp !=END_OF_LIST(&obj_used_list) )     {
1677                         if (objp->type == OBJ_SHIP){
1678                                 move_docked_objects(objp);
1679                         }
1680
1681                         // unflag all objects as being updates
1682                         objp->flags &= ~OF_JUST_UPDATED;
1683
1684                         objp = GET_NEXT(objp);
1685                 }
1686         }
1687
1688         // Now that all objects have moved, we should calculate the
1689         // velocities from how far they moved.
1690         // DA: Commented out 2/23, unnecessary since colliding objects calculate their post collision velocities through physics.
1691         /*
1692         objp = GET_FIRST(&obj_used_list);
1693         while( objp !=END_OF_LIST(&obj_used_list) )     {
1694                 if ( !(objp->flags&OF_SHOULD_BE_DEAD) && (objp->type != OBJ_OBSERVER) && (objp->type != OBJ_ASTEROID) && (objp->type != OBJ_DEBRIS))    {
1695                         objp->phys_info.vel.x = (objp->pos.x - objp->last_pos.x) / frametime;
1696                         objp->phys_info.vel.y = (objp->pos.y - objp->last_pos.y) / frametime;
1697                         objp->phys_info.vel.z = (objp->pos.z - objp->last_pos.z) / frametime;
1698                 }
1699                 objp = GET_NEXT(objp);
1700         } */
1701
1702         if(!(Game_mode & GM_DEMO_PLAYBACK)){
1703                 find_homing_object_cmeasures(); //      If any cmeasures fired, maybe steer away homing missiles        
1704         }
1705
1706         // do pre-collision stuff for beam weapons
1707         beam_move_all_pre();
1708
1709         if ( Collisions_enabled )       {
1710                 obj_check_all_collisions();             
1711         }
1712
1713         if(!(Game_mode & GM_DEMO_PLAYBACK)){
1714                 turret_swarm_check_validity();
1715         }
1716
1717         // do post-collision stuff for beam weapons
1718         beam_move_all_post();
1719
1720         // update artillery locking info now
1721         ship_update_artillery_lock();
1722 }
1723
1724
1725 MONITOR( NumObjectsRend );      
1726
1727 // -----------------------------------------------------------------------------
1728 //      Render an object.  Calls one of several routines based on type
1729 void obj_render(object *obj)
1730 {
1731         if ( obj->flags & OF_SHOULD_BE_DEAD ) return;
1732 //      if ( obj == Viewer_obj ) return;
1733
1734         MONITOR_INC( NumObjectsRend, 1 );       
1735
1736         switch( obj->type )     {
1737         case OBJ_NONE:
1738                 #ifndef NDEBUG
1739                 mprintf(( "ERROR!!!! Bogus obj %d is rendering!\n", obj-Objects ));
1740                 Int3();
1741                 #endif
1742                 break;
1743         case OBJ_WEAPON:
1744                 weapon_render(obj);
1745                 break;
1746         case OBJ_SHIP:
1747                 ship_render(obj);
1748                 break;
1749         case OBJ_FIREBALL:
1750                 fireball_render(obj);
1751                 break;
1752         case OBJ_SHOCKWAVE:
1753                 shockwave_render(obj);
1754                 break;
1755         case OBJ_DEBRIS:
1756                 debris_render(obj);
1757                 break;
1758         case OBJ_ASTEROID:
1759                 asteroid_render(obj);
1760                 break;
1761         case OBJ_CMEASURE:
1762                 cmeasure_render(obj);
1763                 break;
1764         case OBJ_JUMP_NODE:
1765                 jumpnode_render(obj, &obj->pos, &Eye_position);
1766                 break;
1767         case OBJ_WAYPOINT:
1768                 if (Show_waypoints)     {
1769                         //ship_render(obj);
1770                         gr_set_color( 128, 128, 128 );
1771                         g3_draw_sphere_ez( &obj->pos, 5.0f );
1772                 }
1773                 break;
1774         case OBJ_GHOST:
1775                 break;
1776         case OBJ_BEAM:
1777                 break;
1778         default:
1779                 Error( LOCATION, "Unhandled obj type %d in obj_render", obj->type );
1780         }
1781 }
1782
1783 void obj_init_all_ships_physics()
1784 {
1785         object  *objp;
1786
1787         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1788                 if (objp->type == OBJ_SHIP)
1789                         physics_ship_init(objp);
1790         }
1791
1792 }
1793
1794 // do client-side pre-interpolation object movement
1795 void obj_client_pre_interpolate()
1796 {
1797         object *objp;
1798         
1799         // duh
1800         obj_delete_all_that_should_be_dead();
1801
1802         // client side processing of warping in effect stages
1803         multi_do_client_warp(flFrametime);     
1804         
1805         // client side movement of an observer
1806         if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
1807                 obj_observer_move(flFrametime);   
1808         }
1809         
1810         // run everything except ships through physics (and ourselves of course)        
1811         obj_merge_created_list();                                               // must merge any objects created by the host!
1812
1813         objp = GET_FIRST(&obj_used_list);
1814         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )     {
1815                 if((objp != Player_obj) && (objp->type == OBJ_SHIP)){
1816                         continue;
1817                 }
1818
1819                 // for all non-dead object which are _not_ ships
1820                 if ( !(objp->flags&OF_SHOULD_BE_DEAD) ) {                               
1821                         // pre-move step
1822                         obj_move_all_pre(objp, flFrametime);
1823
1824                         // store position and orientation
1825                         objp->last_pos = objp->pos;
1826                         objp->last_orient = objp->orient;
1827
1828                         // call physics
1829                         obj_move_call_physics(objp, flFrametime);
1830
1831                         // post-move step
1832                         obj_move_all_post(objp, flFrametime);
1833                 }
1834         }
1835 }
1836
1837 // do client-side post-interpolation object movement
1838 void obj_client_post_interpolate()
1839 {
1840         object *objp;
1841
1842         //      After all objects have been moved, move all docked objects.
1843         objp = GET_FIRST(&obj_used_list);
1844         while( objp !=END_OF_LIST(&obj_used_list) )     {
1845                 if ( (objp->type == OBJ_SHIP) || (objp != Player_obj) ) {
1846                         move_docked_objects(objp);
1847                 }
1848                 objp = GET_NEXT(objp);
1849         }       
1850
1851         // check collisions
1852         obj_check_all_collisions();             
1853
1854         // do post-collision stuff for beam weapons
1855         beam_move_all_post();
1856 }
1857
1858 #if 0
1859 // following function is used in multiplayer only.  It deals with simulating objects on the client
1860 // side.  Lasers will always get moved by the client (i.e. no object position info is ever sent for them).
1861 // same for dumb missiles and possibly others.  We might move ships based on the last time their posision
1862 // was updated
1863 void obj_client_simulate(float frametime)
1864 {
1865         object *objp;
1866
1867         obj_delete_all_that_should_be_dead();
1868
1869         multi_do_client_warp(frametime);     // client side processing of warping in effect stages
1870         
1871         if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1872                 obj_observer_move(frametime);   // client side movement of an observer
1873         }
1874
1875         /*
1876         obj_merge_created_list();                                               // must merge any objects created by the host!
1877         objp = GET_FIRST(&obj_used_list);
1878         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )     {
1879
1880                 if ( !(objp->flags&OF_SHOULD_BE_DEAD) ) {
1881                         vector  cur_pos = objp->pos;                    // Save the current position
1882
1883                         obj_move_all_pre(objp, frametime);
1884
1885                         int predict_from_server_pos = 1;
1886
1887                         // If not visible (or not a ship), bash position
1888                         if ( (!obj_visible_from_eye(&cur_pos)) || (objp->type != OBJ_SHIP) ) {
1889                                 predict_from_server_pos = 0;
1890                         }
1891
1892                         // If this is a player ship, don't predict from server position
1893                         if ( objp->flags & OF_PLAYER_SHIP ) {
1894                                 predict_from_server_pos = 0;
1895                         }
1896
1897                         if ( predict_from_server_pos ) {
1898                                 obj_client_predict_pos(objp, frametime);
1899                         } else {
1900                                 obj_client_bash_pos(objp, frametime);
1901                         }
1902
1903                         obj_move_all_post(objp, frametime);
1904                 }
1905         }       
1906         */
1907
1908         //      After all objects have been moved, move all docked objects.
1909         objp = GET_FIRST(&obj_used_list);
1910         while( objp !=END_OF_LIST(&obj_used_list) )     {
1911                 if ( (objp->type == OBJ_SHIP) || (objp != Player_obj) ) {
1912                         move_docked_objects(objp);
1913                 }
1914                 objp = GET_NEXT(objp);
1915         }
1916
1917         obj_check_all_collisions();     
1918 }
1919 #endif
1920
1921 void obj_observer_move(float flFrametime)
1922 {
1923         object *objp;
1924         float ft;
1925
1926         // if i'm not in multiplayer, or not an observer, bail
1927         if(!(Game_mode & GM_MULTIPLAYER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type != OBJ_OBSERVER)){
1928                 return;
1929         }
1930
1931         objp = Player_obj;
1932
1933         // obj_move_all_pre(objp, flFrametime);
1934
1935         objp->last_pos = objp->pos;
1936         objp->last_orient = objp->orient;               // save the orientation -- useful in multiplayer.
1937
1938         ft = flFrametime;
1939         obj_move_call_physics( objp, ft );
1940         obj_move_all_post(objp, flFrametime);
1941    objp->flags &= ~OF_JUST_UPDATED;
1942 }
1943
1944 // function to return a vector of the average position of all ships in the mission.
1945 void obj_get_average_ship_pos( vector *pos )
1946 {
1947         int count;
1948         object *objp;
1949
1950         vm_vec_zero( pos );
1951
1952    // average up all ship positions
1953         count = 0;
1954         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1955                 if ( objp->type != OBJ_SHIP )
1956                         continue;
1957                 vm_vec_add2( pos, &objp->pos );
1958                 count++;
1959         }
1960
1961         if ( count )
1962                 vm_vec_scale( pos, 1.0f/(float)count );
1963 }
1964
1965
1966 int obj_get_SIF(object *objp)
1967 {
1968         if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START))
1969                 return Ship_info[Ships[objp->instance].ship_info_index].flags;
1970
1971         Int3();
1972         return 0;
1973 }
1974
1975 int obj_get_SIF(int obj)
1976 {
1977         if ((Objects[obj].type == OBJ_SHIP) || (Objects[obj].type == OBJ_START))
1978                 return Ship_info[Ships[Objects[obj].instance].ship_info_index].flags;
1979
1980         Int3();
1981         return 0;
1982 }
1983
1984 // Return the team for the object passed as a parameter
1985 //
1986 //      input:          objp => pointer to object that you want team for
1987 //
1988 // exit:                        success => enumerated team ( TEAM_HOSTILE, TEAM_FRIENDLY, TEAM_NEUTRAL, etc )
1989 //                                      failure => -1 (for objects that don't have teams)
1990 int obj_team(object *objp)
1991 {
1992         SDL_assert( objp != NULL );
1993         int team = -1;
1994
1995         switch ( objp->type ) {
1996                 case OBJ_SHIP:
1997                         SDL_assert( objp->instance >= 0 && objp->instance < MAX_SHIPS );
1998                         team = Ships[objp->instance].team;
1999                         break;
2000
2001                 case OBJ_DEBRIS:
2002                         team = debris_get_team(objp);
2003                         SDL_assert(team != -1);
2004                         break;
2005
2006                 case OBJ_CMEASURE:
2007                         SDL_assert( objp->instance >= 0 && objp->instance < MAX_CMEASURES);
2008                         team = Cmeasures[objp->instance].team;
2009                         break;
2010
2011                 case OBJ_WEAPON:
2012                         SDL_assert( objp->instance >= 0 && objp->instance < MAX_WEAPONS );
2013                         team = Weapons[objp->instance].team;
2014                         break;
2015
2016                 case OBJ_JUMP_NODE:
2017                         team = Player_ship->team;
2018                         break;
2019                                         
2020                 case OBJ_FIREBALL:
2021                 case OBJ_WAYPOINT:
2022                 case OBJ_START:
2023                 case OBJ_NONE:
2024                 case OBJ_GHOST:
2025                 case OBJ_SHOCKWAVE:             
2026                 case OBJ_BEAM:
2027                         nprintf(("Warning","Warning => Asking for a team for object type %d\n", Object_type_names[(unsigned char)objp->type]));
2028                         team = -1;
2029                         break;
2030
2031                 case OBJ_ASTEROID:
2032                         team = TEAM_TRAITOR;
2033                         break;
2034
2035                 default:
2036                         Int3(); // can't happen
2037                         break;
2038         } // end switch
2039
2040         SDL_assert(team != -1);
2041         return team;
2042 }
2043
2044 // -------------------------------------------------------
2045 // obj_add_pairs
2046 //
2047 // Add an element to the CheckObjects[] array, and update the 
2048 // object pairs.  This is called from obj_create(), and the restore
2049 // save-game code.
2050 // 
2051 void obj_add_pairs(int objnum)
2052 {
2053         object  *objp;
2054
2055         SDL_assert(objnum != -1);
2056         objp = &Objects[objnum];        
2057
2058         // don't do anything if its already in the object pair list
2059         if(!(objp->flags & OF_NOT_IN_COLL)){
2060                 return;
2061         }
2062
2063 #ifdef OBJECT_CHECK 
2064         CheckObjects[objnum].type = objp->type;
2065         CheckObjects[objnum].signature = objp->signature;
2066         CheckObjects[objnum].flags = objp->flags & ~(OF_NOT_IN_COLL);
2067         CheckObjects[objnum].parent_sig = objp->parent_sig;
2068         CheckObjects[objnum].parent_type = objp->parent_type;
2069 #endif  
2070
2071         // Find all the objects that can collide with this and add 
2072         // it to the collision pair list. 
2073         object * A;
2074         for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
2075                 obj_add_pair( objp, A );
2076         }
2077         
2078         objp->flags &= ~OF_NOT_IN_COLL; 
2079 }
2080
2081 // Removes any occurances of object 'a' from
2082 // the pairs list.
2083 extern int Num_pairs;
2084 extern obj_pair pair_used_list;
2085 extern obj_pair pair_free_list;
2086 void obj_remove_pairs( object * a )
2087 {
2088         obj_pair *parent, *tmp;
2089
2090         a->flags |= OF_NOT_IN_COLL;     
2091 #ifdef OBJECT_CHECK 
2092         CheckObjects[OBJ_INDEX(a)].flags |= OF_NOT_IN_COLL;
2093 #endif  
2094
2095         if ( a->num_pairs < 1 ) {
2096                 //mprintf(( "OBJPAIR: No need to remove pairs 1!\n" ));
2097                 return;
2098         }
2099
2100         Num_pairs-=a->num_pairs;
2101         
2102         parent = &pair_used_list;
2103         tmp = parent->next;
2104
2105         while( tmp != NULL )    {
2106                 if ( (tmp->a==a) || (tmp->b==a) )       {
2107                         // Hmmm... a potenial compiler optimization problem here... either tmp->a or tmp->b
2108                         // is equal to 'a' and we modify 'num_pairs' in one of these and then use the value
2109                         // stored in 'a' later one... will the optimizer find that?  Hmmm...
2110                         tmp->a->num_pairs--;
2111                         SDL_assert( tmp->a->num_pairs > -1 );
2112                         tmp->b->num_pairs--;
2113                         SDL_assert( tmp->b->num_pairs > -1 );
2114                         parent->next = tmp->next;
2115                         tmp->a = tmp->b = NULL;
2116                         tmp->next = pair_free_list.next;
2117                         pair_free_list.next = tmp;
2118                         tmp = parent->next;
2119
2120                         if ( a->num_pairs==0 )  {
2121                                 //mprintf(( "OBJPAIR: No need to remove pairs 2!\n" ));
2122                                 break;
2123                         }
2124
2125                 } else {
2126                         parent = tmp;
2127                         tmp = tmp->next;
2128                 }
2129         }
2130 }
2131
2132 // reset all collisions
2133 void obj_reset_all_collisions()
2134 {
2135         // clear checkobjects
2136 #ifndef NDEBUG
2137         memset(CheckObjects, 0, sizeof(checkobject) * MAX_OBJECTS);
2138 #endif
2139
2140         // clear object pairs
2141         obj_reset_pairs();
2142
2143         // now add every object back into the object collision pairs
2144         object *moveup;
2145         moveup = GET_FIRST(&obj_used_list);
2146         while(moveup != END_OF_LIST(&obj_used_list)){
2147                 // he's not in the collision list
2148                 moveup->flags |= OF_NOT_IN_COLL;
2149
2150                 // recalc pairs for this guy
2151                 obj_add_pairs(OBJ_INDEX(moveup));
2152
2153                 // next
2154                 moveup = GET_NEXT(moveup);
2155         }               
2156 }
2157