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