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