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