]> icculus.org git repositories - taylor/freespace2.git/blob - src/object/object.cpp
make first pass at async popups
[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] = { 0 };
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 = free_object_slots(MAX_OBJECTS-10);
730
731                 if (num_freed) {
732                         nprintf(("warning", " *** Freed %i objects\n", num_freed));
733                 }
734         }
735
736         if (num_objects >= MAX_OBJECTS) {
737                 #ifndef NDEBUG
738                 mprintf(("Object creation failed - too many objects!\n" ));
739                 #endif
740                 return -1;
741         }
742
743         // Find next available object
744         objp = GET_FIRST(&obj_free_list);
745         SDL_assert ( objp != &obj_free_list );          // shouldn't have the dummy element
746
747         // remove objp from the free list
748         list_remove( &obj_free_list, objp );
749         
750         // insert objp onto the end of create list
751         list_append( &obj_create_list, objp );
752
753         // increment counter
754         num_objects++;
755
756         if (num_objects > num_objects_hwm) {
757                 //nprintf(("AI", "*** MAX Num Objects = %i\n", num_objects));
758                 num_objects_hwm = num_objects;
759         }
760
761         // get objnum
762         objnum = OBJ_INDEX(objp);
763
764         if (objnum > Highest_object_index) {
765                 Highest_object_index = objnum;
766                 if (Highest_object_index > Highest_ever_object_index)
767                         Highest_ever_object_index = Highest_object_index;
768         }
769
770         return objnum;
771 }
772
773 //frees up an object.  Generally, obj_delete() should be called to get
774 //rid of an object.  This function deallocates the object entry after
775 //the object has been unlinked
776 void obj_free(int objnum)
777 {
778         object *objp;
779
780         if (!Object_inited) obj_init();
781
782         SDL_assert( objnum >= 0 );      // Trying to free bogus object!!!
783
784         // get object pointer
785         objp = &Objects[objnum];
786
787         // remove objp from the used list
788         list_remove( &obj_used_list, objp);
789
790         // add objp to the end of the free
791         list_append( &obj_free_list, objp );
792
793         // decrement counter
794         num_objects--;
795
796         Objects[objnum].type = OBJ_NONE;
797
798         SDL_assert(num_objects >= 0);
799
800         if (objnum == Highest_object_index)
801                 while (Objects[--Highest_object_index].type == OBJ_NONE);
802
803 }
804
805 //initialize a new object.  adds to the list for the given segment.
806 //returns the object number.  The object will be a non-rendering, non-physics
807 //object.   Pass -1 if no parent.
808 int obj_create(ubyte type,int parent_obj,int instance, matrix * orient, 
809                vector * pos, float radius, uint flags )
810 {
811         int objnum,idx;
812         object *obj;
813
814         // Find next free object
815         objnum = obj_allocate();
816
817         if (objnum == -1)               //no free objects
818                 return -1;
819
820         obj = &Objects[objnum];
821         SDL_assert(obj->type == OBJ_NONE);              //make sure unused 
822
823         // Zero out object structure to keep weird bugs from happening
824         // in uninitialized fields.
825 //      memset( obj, 0, sizeof(object) );
826
827         if(obj->type == OBJ_SHIP){
828                 obj->signature                          = Object_next_ship_signature++;
829
830                 if (!Object_next_ship_signature){
831                         Object_next_ship_signature = OBJECT_SIG_SHIP_START;             // 0 is bogus!
832                 }
833         } else {
834                 obj->signature                          = Object_next_signature++;
835
836                 if (!Object_next_signature){
837                         Object_next_signature = 1;              // 0 is bogus!
838                 }
839         }       
840         
841         obj->type                                       = type;
842         obj->instance                           = instance;
843         obj->parent                                     = parent_obj;
844         if (obj->parent != -1)  {
845                 obj->parent_sig         = Objects[parent_obj].signature;
846                 obj->parent_type                = Objects[parent_obj].type;
847         } else {
848                 obj->parent_sig = obj->signature;
849                 obj->parent_type = obj->type;
850         }
851
852         obj->flags                                      = flags | OF_NOT_IN_COLL;
853         if (pos)        {
854                 obj->pos                                = *pos;
855                 obj->last_pos                   = *pos;
856         }
857
858         obj->orient                             = orient?*orient:vmd_identity_matrix;
859         obj->last_orient                        = obj->orient;
860         obj->radius                             = radius;
861
862         obj->flags &= ~OF_INVULNERABLE;         //      Make vulnerable.
863         physics_init( &obj->phys_info );
864
865         for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
866                 obj->objsnd_num[idx] = -1;
867         }
868         obj->num_pairs = 0;
869         obj->net_signature = 0;                 // be sure to reset this value so new objects don't take on old signatures.     
870
871         return objnum;
872 }
873
874 //remove object from the world
875 //      If Player_obj, don't remove it!
876 void obj_delete(int objnum)
877 {
878         object *objp;
879
880         SDL_assert(objnum >= 0 && objnum < MAX_OBJECTS);
881         objp = &Objects[objnum];
882         SDL_assert(objp->type != OBJ_NONE);     
883
884         // Remove all object pairs
885         obj_remove_pairs( objp );
886         
887         switch( objp->type )    {
888         case OBJ_WEAPON:
889                 weapon_delete( objp );
890                 break;
891         case OBJ_SHIP:
892                 if ((objp == Player_obj) && !Fred_running) {
893                         objp->type = OBJ_GHOST;
894                         objp->flags &= ~(OF_SHOULD_BE_DEAD);
895                         
896                         // we have to traverse the ship_obj list and remove this guy from it as well
897                         ship_obj *moveup = GET_FIRST(&Ship_obj_list);
898                         while(moveup != END_OF_LIST(&Ship_obj_list)){
899                                 if(OBJ_INDEX(objp) == moveup->objnum){
900                                         list_remove(&Ship_obj_list,moveup);
901                                         break;
902                                 }
903                                 moveup = GET_NEXT(moveup);
904                         }
905
906                         physics_init(&objp->phys_info);
907                         
908                         obj_snd_delete(OBJ_INDEX(objp));
909                         return;
910                 } else
911                         ship_delete( objp );
912                 break;
913         case OBJ_FIREBALL:
914                 fireball_delete( objp );
915                 break;
916         case OBJ_SHOCKWAVE:
917                 shockwave_delete( objp );
918                 break;
919         case OBJ_START:
920         case OBJ_WAYPOINT:
921         case OBJ_POINT:
922         case OBJ_JUMP_NODE:
923                 SDL_assert(Fred_running);
924                 break;  // requires no action, handled by the Fred code.
925         case OBJ_DEBRIS:
926                 debris_delete( objp );
927                 break;
928         case OBJ_ASTEROID:
929                 asteroid_delete(objp);
930                 break;
931         case OBJ_CMEASURE:
932                 cmeasure_delete( objp );
933                 break;
934         case OBJ_GHOST:
935                 if(!(Game_mode & GM_MULTIPLAYER)){
936                         mprintf(("Warning: Tried to delete a ghost!"));
937                         objp->flags &= ~OF_SHOULD_BE_DEAD;
938                         return;
939                 } else {
940                         // we need to be able to delete GHOST objects in multiplayer to allow for player respawns.
941                         nprintf(("Network","Deleting GHOST object\n"));
942                 }               
943                 break;
944         case OBJ_OBSERVER:
945                 observer_delete(objp);
946                 break;  
947         case OBJ_BEAM:
948                 break;
949         case OBJ_NONE:
950                 Int3();
951                 break;
952         default:
953                 Error( LOCATION, "Unhandled object type %d in obj_delete_all_that_should_be_dead", objp->type );
954         }
955
956         // if a persistant sound has been created, delete it
957         obj_snd_delete(OBJ_INDEX(objp));                
958
959         objp->type = OBJ_NONE;          //unused!
960         objp->signature = 0;            
961
962         obj_free(objnum);
963 }
964
965
966 //      ------------------------------------------------------------------------------------------------------------------
967 void obj_delete_all_that_should_be_dead()
968 {
969         object *objp, *temp;
970
971         if (!Object_inited) obj_init();
972
973         // Move all objects
974         objp = GET_FIRST(&obj_used_list);
975         while( objp !=END_OF_LIST(&obj_used_list) )     {
976                 temp = GET_NEXT(objp);
977                 if ( objp->flags&OF_SHOULD_BE_DEAD )
978                         obj_delete( OBJ_INDEX(objp) );                  // MWA says that john says that let obj_delete handle everything because of the editor
979                 objp = temp;
980         }
981
982 }
983
984 // Add all newly created objects to the end of the used list and create their
985 // object pairs for collision detection
986 void obj_merge_created_list(void)
987 {
988         // The old way just merged the two.   This code takes one out of the create list,
989         // creates object pairs for it, and then adds it to the used list.
990         //      OLD WAY: list_merge( &obj_used_list, &obj_create_list );
991         object *objp = GET_FIRST(&obj_create_list);
992         while( objp !=END_OF_LIST(&obj_create_list) )   {
993                 list_remove( obj_create_list, objp );
994
995                 // Add it to the object pairs array
996                 obj_add_pairs(OBJ_INDEX(objp));
997
998                 // Then add it to the object used list
999                 list_append( &obj_used_list, objp );
1000
1001                 objp = GET_FIRST(&obj_create_list);
1002         }
1003
1004         // Make sure the create list is empty.
1005         list_init(&obj_create_list);
1006 }
1007
1008 int physics_paused = 0, ai_paused = 0;
1009
1010 extern void call_doa(object *obj1, object *obj2, ship_info *sip1);
1011
1012 //      If this is a cargo container or a repair ship, move it along with the ship it's docked to.
1013 void move_docked_objects(object *objp)
1014 {
1015         ai_info         *aip;
1016         ai_info *other_aip;
1017
1018         if (objp->type != OBJ_SHIP)
1019                 return;
1020
1021         SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
1022
1023         aip = &Ai_info[Ships[objp->instance].ai_index];
1024
1025         if (aip->ai_flags & AIF_DOCKED) {
1026                 ship_info       *sip;
1027                 sip = &Ship_info[Ships[objp->instance].ship_info_index];
1028                 if ((sip->flags & SIF_SUPPORT) || (sip->flags & SIF_CARGO)) {
1029                         SDL_assert(!((sip->flags & SIF_SUPPORT) && (sip->flags & SIF_CARGO)));  //      Ship can't be both repair and cargo
1030                         if (aip->dock_objnum != -1) {
1031                                 if (aip->mode == AIM_DOCK) {
1032                                         if (aip->submode < AIS_UNDOCK_1)
1033                                                 call_doa(objp, &Objects[aip->dock_objnum], sip);
1034                                 } else {
1035                                         // if I am not in dock mode then I need to check the guy that I'm docked with
1036                                         // and only move with him if he isn't undocking.
1037                                         other_aip = &Ai_info[Ships[Objects[aip->dock_objnum].instance].ai_index];
1038                                         if ( other_aip->mode == AIM_DOCK ) {
1039                                                 if (other_aip->submode < AIS_UNDOCK_1 )
1040                                                         call_doa(objp, &Objects[aip->dock_objnum], sip);
1041                                         } else {
1042                                                 call_doa(objp, &Objects[aip->dock_objnum], sip);
1043                                         }
1044                                 }
1045                         }
1046                 } else {
1047                         if (aip->dock_objnum != -1) {
1048                                 SDL_assert( aip->dock_objnum != -1 );
1049                                 other_aip = &Ai_info[Ships[Objects[aip->dock_objnum].instance].ai_index];
1050
1051                                 // if the other object that I am docked with is undocking, then don't do anything.
1052                                 if ( !((other_aip->mode == AIM_DOCK) && (other_aip->submode >= AIS_UNDOCK_1)) ) {
1053                                         if ( (aip->mode != AIM_DOCK) && (aip->mode != AIM_WARP_OUT) ) {
1054                                                 object  *objp1, *objp2;
1055
1056                                                 objp1 = &Objects[aip->dock_objnum];
1057                                                 objp2 = objp;
1058
1059                                                 if (objp1->phys_info.speed > objp2->phys_info.speed) {
1060                                                         object *t = objp1;
1061                                                         objp1 = objp2;
1062                                                         objp2 = t;
1063                                                 }
1064
1065                                                 //nprintf(("AI", "Calling doa, frame %i: %s, %s\n", Framecount, Ships[objp1->instance].ship_name, Ships[objp2->instance].ship_name));
1066                                                 call_doa(objp1, objp2, sip);
1067                                         }
1068                                 }
1069                         }
1070                 }
1071         }
1072 }
1073
1074 /*
1075 float   Last_fire_time = 0.0f;
1076 int Avg_delay_count = 0;
1077 float Avg_delay_total;
1078 */
1079
1080 // function to deal with firing player things like lasers, missiles, etc.
1081 // separated out because of multiplayer issues.
1082 void obj_player_fire_stuff( object *objp, control_info ci )
1083 {
1084         ship *shipp;
1085
1086         SDL_assert( objp->flags & OF_PLAYER_SHIP);
1087
1088         // try and get the ship pointer
1089         shipp = NULL;
1090         if((objp->type == OBJ_SHIP) && (objp->instance >= 0) && (objp->instance < MAX_SHIPS)){
1091                 shipp = &Ships[objp->instance];
1092         }
1093
1094         // single player pilots, and all players in multiplayer take care of firing their own primaries
1095         if(!(Game_mode & GM_MULTIPLAYER) || (objp == Player_obj)){
1096                 if ( ci.fire_primary_count ) {
1097                         // flag the ship as having the trigger down
1098                         if(shipp != NULL){
1099                                 shipp->flags |= SF_TRIGGER_DOWN;
1100                         }
1101
1102                         // fire non-streaming primaries here
1103                         ship_fire_primary( objp, 0 );                   
1104                 } else {
1105                         // unflag the ship as having the trigger down
1106                         if(shipp != NULL){
1107                                 shipp->flags &= ~(SF_TRIGGER_DOWN);
1108                         }
1109                 }
1110
1111                 if ( ci.fire_countermeasure_count ){
1112                         ship_launch_countermeasure( objp );
1113                 }
1114         }
1115
1116         // single player and multiplayer masters do all of the following
1117         if ( !MULTIPLAYER_CLIENT ) {            
1118                 if ( ci.fire_secondary_count ){
1119                         ship_fire_secondary( objp );
1120
1121                         // kill the secondary count
1122                         ci.fire_secondary_count = 0;
1123                 }
1124         }
1125
1126         // everyone does the following for their own ships.
1127         if ( ci.afterburner_start ){
1128                 if (ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE)){
1129                         afterburners_start( objp );
1130                 }
1131         }
1132         
1133         if ( ci.afterburner_stop ){
1134                 afterburners_stop( objp, 1 );
1135         }
1136 }
1137
1138 void obj_move_call_physics(object *objp, float frametime)
1139 {
1140         //      Do physics for objects with OF_PHYSICS flag set and with some engine strength remaining.
1141         if ( objp->flags & OF_PHYSICS ) {
1142                 // only set phys info if ship is not dead
1143                 if ((objp->type == OBJ_SHIP) && !(Ships[objp->instance].flags & SF_DYING)) {
1144                         float   engine_strength;
1145                         engine_strength = ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE);
1146                         if ( ship_subsys_disrupted(&Ships[objp->instance], SUBSYSTEM_ENGINE) ) {
1147                                 engine_strength=0.0f;
1148                         }
1149
1150                         if (engine_strength == 0.0f) {  //      All this is necessary to make ship gradually come to a stop after engines are blown.
1151                                 vm_vec_zero(&objp->phys_info.desired_vel);
1152                                 vm_vec_zero(&objp->phys_info.desired_rotvel);
1153                                 objp->phys_info.flags |= (PF_REDUCED_DAMP | PF_DEAD_DAMP);
1154                                 objp->phys_info.side_slip_time_const = Ship_info[Ships[objp->instance].ship_info_index].damp * 4.0f;
1155                         } // else {
1156                                 // DA: comment out lines that resets PF_DEAD_DAMP after every frame.
1157                                 // This is now reset during engine repair.
1158                                 //      objp->phys_info.flags &= ~(PF_REDUCED_DAMP | PF_DEAD_DAMP);
1159                                 // objp->phys_info.side_slip_time_const = Ship_info[Ships[objp->instance].ship_info_index].damp;
1160                         // }
1161                 }
1162
1163                 // if a weapon is flagged as dead, kill its engines just like a ship
1164                 if((objp->type == OBJ_WEAPON) && (Weapons[objp->instance].weapon_flags & WF_DEAD_IN_WATER)){
1165                         vm_vec_zero(&objp->phys_info.desired_vel);
1166                         vm_vec_zero(&objp->phys_info.desired_rotvel);
1167                         objp->phys_info.flags |= (PF_REDUCED_DAMP | PF_DEAD_DAMP);
1168                         objp->phys_info.side_slip_time_const = Ship_info[Ships[objp->instance].ship_info_index].damp * 4.0f;
1169                 }
1170
1171                 if (physics_paused)     {
1172                         if (objp==Player_obj){
1173                                 physics_sim(&objp->pos, &objp->orient, &objp->phys_info, frametime );           // simulate the physics
1174                         }
1175                 } else {
1176                         //      Hack for dock mode.
1177                         //      If docking with a ship, we don't obey the normal ship physics, we can slew about.
1178                         if (objp->type == OBJ_SHIP) {
1179                                 ai_info *aip = &Ai_info[Ships[objp->instance].ai_index];
1180
1181                                 //      Note: This conditional for using PF_USE_VEL (instantaneous acceleration) is probably too loose.
1182                                 //      A ships awaiting support will fly towards the support ship with instantaneous acceleration.
1183                                 //      But we want to have ships in the process of docking have quick acceleration, or they overshoot their goals.
1184                                 //      Probably can not key off dock_objnum, but then need to add some other condition.  Live with it for now. -- MK, 2/19/98
1185                                 if ((aip->dock_objnum != -1) || 
1186                                         ((aip->mode == AIM_DOCK) && ((aip->submode == AIS_DOCK_2) || (aip->submode == AIS_DOCK_3) || (aip->submode == AIS_UNDOCK_0))) ||
1187                                         ((aip->mode == AIM_WARP_OUT) && (aip->submode >= AIS_WARP_3))) {
1188                                         if (ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) > 0.0f){
1189                                                 objp->phys_info.flags |= PF_USE_VEL;
1190                                         } else {
1191                                                 objp->phys_info.flags &= ~PF_USE_VEL;   //      If engine blown, don't PF_USE_VEL, or ships stop immediately
1192                                         }
1193                                 } else {
1194                                         objp->phys_info.flags &= ~PF_USE_VEL;
1195                                 }
1196                         }                       
1197
1198                         // in multiplayer, if this object was just updatd (i.e. clients send their own positions),
1199                         // then reset the flag and don't move the object.
1200                         if ( MULTIPLAYER_MASTER && (objp->flags & OF_JUST_UPDATED) ) {
1201                                 objp->flags &= ~OF_JUST_UPDATED;
1202                                 goto obj_maybe_fire;
1203                         }
1204
1205                         physics_sim(&objp->pos, &objp->orient, &objp->phys_info, frametime );           // simulate the physics
1206
1207                         // This code seems to have no effect - DB 1/12/99
1208                         //if ( MULTIPLAYER_CLIENT && (objp != Player_obj) ){
1209                         //      return;
1210                         //}
1211
1212                         // if the object is the player object, do things that need to be done after the ship
1213                         // is moved (like firing weapons, etc).  This routine will get called either single
1214                         // or multiplayer.  We must find the player object to get to the control info field
1215 obj_maybe_fire:
1216                         if ( (objp->flags & OF_PLAYER_SHIP) && (objp->type != OBJ_OBSERVER) && (objp == Player_obj)) {
1217                                 player *pp;
1218                                 if(Player != NULL){
1219                                         pp = Player;
1220                                         obj_player_fire_stuff( objp, pp->ci );                          
1221                                 }
1222                         }
1223
1224                         // fire streaming weapons for ships in here - ALL PLAYERS, regardless of client, single player, server, whatever.
1225                         // do stream weapon firing for all ships themselves. 
1226                         if(objp->type == OBJ_SHIP){
1227                                 ship_fire_primary(objp, 1, 0);
1228                         }
1229                 }
1230         }
1231 }
1232
1233
1234 #define IMPORTANT_FLAGS (OF_COLLIDES)
1235
1236 #ifdef OBJECT_CHECK 
1237
1238
1239 void obj_check_object( object *obj )
1240 {
1241         int objnum = OBJ_INDEX(obj);
1242
1243         // PROGRAMMERS: If one of these Int3() gets hit, then someone
1244         // is changing a value in the object structure that might cause
1245         // collision detection to not work.  See John for more info if
1246         // you are hitting one of these.
1247
1248         if ( CheckObjects[objnum].type != obj->type )   {
1249                 if ( (obj->type==OBJ_WAYPOINT) && (CheckObjects[objnum].type==OBJ_SHIP) )       {
1250                         // We know about ships changing into waypoints and that is
1251                         // ok.
1252                         CheckObjects[objnum].type = OBJ_WAYPOINT;
1253                  } else if ( (obj->type==OBJ_SHIP) && (CheckObjects[objnum].type==OBJ_GHOST) )  {
1254                         // We know about player changing into a ghost after dying and that is
1255                         // ok.
1256                         CheckObjects[objnum].type = OBJ_GHOST;
1257                 } else if ( (obj->type==OBJ_GHOST) && (CheckObjects[objnum].type==OBJ_SHIP) )   {
1258                         // We know about player changing into a ghost after dying and that is
1259                         // ok.
1260                         CheckObjects[objnum].type = OBJ_SHIP;
1261                 } else {
1262                         mprintf(( "Object type changed!\n" ));
1263                         Int3();
1264                 }
1265         }
1266         if ( CheckObjects[objnum].signature != obj->signature ) {
1267                 mprintf(( "Object signature changed!\n" ));
1268                 Int3();
1269         }
1270         if ( (CheckObjects[objnum].flags&IMPORTANT_FLAGS) != (obj->flags&IMPORTANT_FLAGS) ) {
1271                 mprintf(( "Object flags changed!\n" ));
1272                 Int3();
1273         }
1274         if ( CheckObjects[objnum].parent_sig != obj->parent_sig ) {
1275                 mprintf(( "Object parent sig changed!\n" ));
1276                 Int3();
1277         }
1278         if ( CheckObjects[objnum].parent_type != obj->parent_type ) {
1279                 mprintf(( "Object's parent type changed!\n" ));
1280                 Int3();
1281         }
1282 }
1283 #endif
1284
1285 // Call this if you want to change an object flag so that the
1286 // object code knows what's going on.  For instance if you turn
1287 // off OF_COLLIDES, the object code needs to know this in order to
1288 // actually turn the object collision detection off.  By calling
1289 // this you shouldn't get Int3's in the checkobject code.  If you
1290 // do, then put code in here to correctly handle the case.
1291 void obj_set_flags( object *obj, uint new_flags )
1292 {
1293         int objnum = OBJ_INDEX(obj);    
1294
1295         // turning collision detection off
1296         if ( (obj->flags & OF_COLLIDES) && (!(new_flags&OF_COLLIDES)))  {               
1297                 // Remove all object pairs
1298                 obj_remove_pairs( obj );
1299
1300                 // update object flags properly         
1301                 obj->flags = new_flags;
1302                 obj->flags |= OF_NOT_IN_COLL;           
1303 #ifdef OBJECT_CHECK
1304                 CheckObjects[objnum].flags = new_flags;
1305                 CheckObjects[objnum].flags |= OF_NOT_IN_COLL;           
1306 #endif          
1307                 return;
1308         }
1309         
1310         
1311         // turning collision detection on
1312         if ( (!(obj->flags & OF_COLLIDES)) && (new_flags&OF_COLLIDES) ) {
1313                 
1314                 // observers can't collide or be hit, and they therefore have no hit or collide functions
1315                 // So, don't allow this bit to be set
1316                 if(obj->type == OBJ_OBSERVER){
1317                         mprintf(("Illegal to set collision bit for OBJ_OBSERVER!!\n"));
1318                         Int3();
1319                 }
1320
1321                 obj->flags |= OF_COLLIDES;
1322
1323                 // Turn on collision detection
1324                 obj_add_pairs(objnum);
1325                                 
1326                 obj->flags = new_flags;
1327                 obj->flags &= ~(OF_NOT_IN_COLL);                
1328 #ifdef OBJECT_CHECK
1329                 CheckObjects[objnum].flags = new_flags;
1330                 CheckObjects[objnum].flags &= ~(OF_NOT_IN_COLL);                
1331 #endif
1332                 return;
1333         }
1334
1335         // for a multiplayer host -- use this debug code to help trap when non-player ships are getting
1336         // marked as OF_COULD_BE_PLAYER
1337         // this code is pretty much debug code and shouldn't be relied on to always do the right thing
1338         // for flags other than 
1339         if ( MULTIPLAYER_MASTER && !(obj->flags & OF_COULD_BE_PLAYER) && (new_flags & OF_COULD_BE_PLAYER) ) {
1340                 ship *shipp;
1341                 int team, slot;
1342
1343                 // this flag sometimes gets set for observers.
1344                 if ( obj->type == OBJ_OBSERVER ) {
1345                         return;
1346                 }
1347
1348                 // sanity checks
1349                 if ( (obj->type != OBJ_SHIP) || (obj->instance < 0) ) {
1350                         // Int3();
1351                         return;                         // return because we really don't want to set the flag
1352                 }
1353
1354                 // see if this ship is really a player ship (or should be)
1355                 shipp = &Ships[obj->instance];
1356                 extern void multi_ts_get_team_and_slot(char *, int *, int *);
1357                 multi_ts_get_team_and_slot(shipp->ship_name,&team,&slot);
1358                 if ( (shipp->wingnum == -1) || (team == -1) || (slot==-1) ) {
1359                         Int3();
1360                         return;
1361                 }
1362
1363                 // set the flag
1364                 obj->flags = new_flags;
1365 #ifdef OBJECT_CHECK
1366                 CheckObjects[objnum].flags = new_flags;
1367 #endif
1368
1369                 return;
1370         }
1371
1372         // Check for unhandled flag changing
1373         if ( (new_flags&IMPORTANT_FLAGS) != (obj->flags&IMPORTANT_FLAGS) ) {
1374                 mprintf(( "Unhandled flag changing in obj_set_flags!!\n" ));
1375                 mprintf(( "Add code to support it, see John for questions!!\n" ));
1376                 Int3();
1377         } else {
1378                 // Since it wasn't an important flag, just bash it.
1379                 obj->flags = new_flags;
1380                 #ifdef OBJECT_CHECK 
1381                 CheckObjects[objnum].flags = new_flags;
1382                 #endif
1383         }       
1384 }
1385
1386
1387 void obj_move_all_pre(object *objp, float frametime)
1388 {
1389         switch( objp->type )    {
1390         case OBJ_WEAPON:
1391                 if (!physics_paused){
1392                         weapon_process_pre( objp, frametime );
1393                 }
1394                 break;  
1395         case OBJ_SHIP:
1396                 if (!physics_paused || (objp==Player_obj )){
1397                         ship_process_pre( objp, frametime );
1398                 }
1399                 break;
1400         case OBJ_FIREBALL:
1401                 if (!physics_paused){
1402                         fireball_process_pre(objp,frametime);
1403                 }
1404                 break;
1405         case OBJ_SHOCKWAVE:
1406                 // all shockwaves are moved via shockwave_move_all()
1407                 break;
1408         case OBJ_DEBRIS:
1409                 if (!physics_paused){
1410                         debris_process_pre(objp,frametime);
1411                 }
1412                 break;
1413         case OBJ_ASTEROID:
1414                 if (!physics_paused){
1415                         asteroid_process_pre(objp,frametime);
1416                 }
1417                 break;
1418         case OBJ_CMEASURE:
1419                 if (!physics_paused){
1420                         cmeasure_process_pre(objp, frametime);
1421                 }
1422                 break;
1423         case OBJ_WAYPOINT:
1424                 break;  // waypoints don't move..
1425         case OBJ_GHOST:
1426                 break;
1427         case OBJ_OBSERVER:
1428         case OBJ_JUMP_NODE:     
1429                 break;  
1430         case OBJ_BEAM:          
1431                 break;
1432         case OBJ_NONE:
1433                 Int3();
1434                 break;
1435         default:
1436                 Error( LOCATION, "Unhandled object type %d in obj_move_one\n", objp->type );
1437         }       
1438 }
1439
1440 // Used to tell if a particular group of lasers has cast light yet.
1441 ubyte Obj_weapon_group_id_used[WEAPON_MAX_GROUP_IDS];
1442
1443 // Called once a frame to mark all weapon groups as not having cast light yet.
1444 void obj_clear_weapon_group_id_list()
1445 {
1446         memset( Obj_weapon_group_id_used, 0, sizeof(Obj_weapon_group_id_used) );
1447 }
1448
1449 int Arc_light = 1;              // If set, electrical arcs on debris cast light
1450 DCF_BOOL(arc_light, Arc_light)  
1451
1452 void obj_move_all_post(object *objp, float frametime)
1453 {
1454         switch( objp->type )    {
1455         case OBJ_WEAPON:
1456                 if (!physics_paused)    {
1457                         weapon_process_post( objp, frametime );
1458                 }
1459                 // Cast light
1460                 if ( Detail.lighting > 2 ) {
1461                         // Weapons cast light
1462
1463                         int group_id = Weapons[objp->instance].group_id;
1464                         int cast_light = 1;
1465
1466                         if ( (group_id>-1) && (Obj_weapon_group_id_used[group_id]==0) ) {
1467                                 // Mark this group as done
1468                                 Obj_weapon_group_id_used[group_id]++;
1469                         } else {
1470                                 // This group has already done its light casting
1471                                 cast_light = 0;
1472                         }
1473
1474                         if ( cast_light )       {
1475                                 weapon_info * wi = &Weapon_info[Weapons[objp->instance].weapon_info_index];
1476
1477                                 if ( wi->render_type == WRT_LASER )     {
1478                                         color c;
1479                                         float r,g,b;
1480
1481                                         // get the laser color
1482                                         weapon_get_laser_color(&c, objp);
1483
1484                                         r = i2fl(c.red)/255.0f;
1485                                         g = i2fl(c.green)/255.0f;
1486                                         b = i2fl(c.blue)/255.0f;
1487                                         light_add_point( &objp->pos, 10.0f, 20.0f, 1.0f, r, g, b, objp->parent );
1488                                         //light_add_point( &objp->pos, 10.0f, 20.0f, 1.0f, 0.0f, 0.0f, 1.0f, objp->parent );
1489                                 } else {
1490                                         light_add_point( &objp->pos, 10.0f, 20.0f, 1.0f, 1.0f, 1.0f, 1.0f, objp->parent );
1491                                 }
1492                         }
1493                 }
1494                 break;  
1495         case OBJ_SHIP:
1496                 if (!physics_paused || (objp==Player_obj ))
1497                         ship_process_post( objp, frametime );
1498
1499                 // Make any electrical arcs on ships cast light
1500                 if (Arc_light)  {
1501                         if ( Detail.lighting > 2 ) {
1502                                 int i;
1503                                 ship            *shipp;
1504                                 shipp = &Ships[objp->instance];
1505
1506                                 for (i=0; i<MAX_SHIP_ARCS; i++ )        {
1507                                         if ( timestamp_valid( shipp->arc_timestamp[i] ) )       {
1508                                                 // Move arc endpoints into world coordinates    
1509                                                 vector tmp1, tmp2;
1510                                                 vm_vec_unrotate(&tmp1,&shipp->arc_pts[i][0],&objp->orient);
1511                                                 vm_vec_add2(&tmp1,&objp->pos);
1512
1513                                                 vm_vec_unrotate(&tmp2,&shipp->arc_pts[i][1],&objp->orient);
1514                                                 vm_vec_add2(&tmp2,&objp->pos);
1515
1516                                                 light_add_point( &tmp1, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1517                                                 light_add_point( &tmp2, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1518                                         }
1519                                 }
1520                         }
1521                 }               
1522
1523                 break;
1524         case OBJ_FIREBALL:
1525                 if (!physics_paused)    {
1526                         fireball_process_post(objp,frametime);
1527                 }
1528                 if ( Detail.lighting > 3 ) {
1529                         // Make explosions cast light
1530                         float p = fireball_lifeleft_percent(objp);
1531                         if ( p > 0.5f ) {
1532                                 p = 1.0f - p;
1533                         }
1534                         p *= 2.0f;
1535                         // P goes from 0 to 1 to 0 over the life of the explosion
1536                         float rad = p*(1.0f+frand()*0.05f)*objp->radius;
1537
1538                         light_add_point( &objp->pos, rad*2.0f, rad*5.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1 );
1539                 }
1540                 break;
1541         case OBJ_SHOCKWAVE:
1542                 // all shockwaves are moved via shockwave_move_all()
1543                 break;
1544         case OBJ_DEBRIS:
1545                 if (!physics_paused)
1546                         debris_process_post(objp,frametime);
1547
1548                 // Make any electrical arcs on debris cast light
1549                 if (Arc_light)  {
1550                         if ( Detail.lighting > 2 ) {
1551                                 int i;
1552                                 debris          *db;
1553                                 db = &Debris[objp->instance];
1554
1555                                 for (i=0; i<MAX_DEBRIS_ARCS; i++ )      {
1556                                         if ( timestamp_valid( db->arc_timestamp[i] ) )  {
1557                                                 // Move arc endpoints into world coordinates    
1558                                                 vector tmp1, tmp2;
1559                                                 vm_vec_unrotate(&tmp1,&db->arc_pts[i][0],&objp->orient);
1560                                                 vm_vec_add2(&tmp1,&objp->pos);
1561
1562                                                 vm_vec_unrotate(&tmp2,&db->arc_pts[i][1],&objp->orient);
1563                                                 vm_vec_add2(&tmp2,&objp->pos);
1564
1565                                                 light_add_point( &tmp1, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1566                                                 light_add_point( &tmp2, 10.0f, 20.0f, frand(), 1.0f, 1.0f, 1.0f, -1 );
1567                                         }
1568                                 }
1569                         }
1570                 }               
1571                 break;
1572         case OBJ_ASTEROID:
1573                 if (!physics_paused)
1574                         asteroid_process_post(objp, frametime);
1575                 break;
1576         case OBJ_CMEASURE:
1577                 if (!physics_paused)
1578                         cmeasure_process_post(objp, frametime);
1579                 break;
1580         case OBJ_WAYPOINT:
1581                 break;  // waypoints don't move..
1582         case OBJ_GHOST:
1583                 break;
1584         case OBJ_OBSERVER:
1585                 void observer_process_post(object *objp);
1586                 observer_process_post(objp);
1587                 break;
1588         case OBJ_JUMP_NODE:
1589                 radar_plot_object(objp);
1590                 break;  
1591         case OBJ_BEAM:          
1592                 break;
1593         case OBJ_NONE:
1594                 Int3();
1595                 break;
1596         default:
1597                 Error( LOCATION, "Unhandled object type %d in obj_move_one\n", objp->type );
1598         }       
1599 }
1600
1601
1602 int Collisions_enabled = 1;
1603
1604 DCF_BOOL( collisions, Collisions_enabled )
1605
1606 MONITOR( NumObjects );  
1607
1608 //--------------------------------------------------------------------
1609 //move all objects for the current frame
1610 void obj_move_all(float frametime)
1611 {
1612         object *objp;   
1613
1614         obj_delete_all_that_should_be_dead();
1615
1616         obj_merge_created_list();
1617
1618         // Clear the table that tells which groups of weapons have cast light so far.
1619         if(!(Game_mode & GM_MULTIPLAYER) || (MULTIPLAYER_MASTER)){
1620                 obj_clear_weapon_group_id_list();
1621         }
1622
1623         MONITOR_INC( NumObjects, num_objects ); 
1624
1625         objp = GET_FIRST(&obj_used_list);
1626         while( objp !=END_OF_LIST(&obj_used_list) )     {
1627                 // skip objects which should be dead
1628                 if ( !(objp->flags&OF_SHOULD_BE_DEAD) ) {               
1629                         vector  cur_pos = objp->pos;                    // Save the current position
1630
1631                         // if this is an observer object, skip it
1632                         if(objp->type == OBJ_OBSERVER){
1633                                 objp = GET_NEXT(objp);
1634                                 continue;
1635                         }
1636
1637                         // if we're playing a demo back, only sim stuff that we're supposed to
1638                         if((Game_mode & GM_DEMO_PLAYBACK) && !demo_should_sim(objp)){
1639                                 objp = GET_NEXT(objp);
1640                                 continue;
1641                         }
1642
1643 #ifdef OBJECT_CHECK 
1644                         // if(! ((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) ){
1645                                 obj_check_object( objp );
1646                         // }
1647 #endif
1648
1649                         // pre-move
1650                         obj_move_all_pre(objp, frametime);
1651
1652                         // store last pos and orient
1653                         objp->last_pos = cur_pos;
1654                         objp->last_orient = objp->orient;
1655
1656                         // if this is an object which should be interpolated in multiplayer, do so
1657                         if(multi_oo_is_interp_object(objp)){
1658                                 multi_oo_interp(objp);
1659                         } else {
1660                                 // physics
1661                                 obj_move_call_physics(objp, frametime);
1662                         }
1663
1664                         // move post
1665                         obj_move_all_post(objp, frametime);
1666                 }
1667                 objp = GET_NEXT(objp);
1668         }
1669
1670         //      After all objects have been moved, move all docked objects.
1671         if(!(Game_mode & GM_DEMO_PLAYBACK)){
1672                 objp = GET_FIRST(&obj_used_list);
1673                 while( objp !=END_OF_LIST(&obj_used_list) )     {
1674                         if (objp->type == OBJ_SHIP){
1675                                 move_docked_objects(objp);
1676                         }
1677
1678                         // unflag all objects as being updates
1679                         objp->flags &= ~OF_JUST_UPDATED;
1680
1681                         objp = GET_NEXT(objp);
1682                 }
1683         }
1684
1685         // Now that all objects have moved, we should calculate the
1686         // velocities from how far they moved.
1687         // DA: Commented out 2/23, unnecessary since colliding objects calculate their post collision velocities through physics.
1688         /*
1689         objp = GET_FIRST(&obj_used_list);
1690         while( objp !=END_OF_LIST(&obj_used_list) )     {
1691                 if ( !(objp->flags&OF_SHOULD_BE_DEAD) && (objp->type != OBJ_OBSERVER) && (objp->type != OBJ_ASTEROID) && (objp->type != OBJ_DEBRIS))    {
1692                         objp->phys_info.vel.x = (objp->pos.x - objp->last_pos.x) / frametime;
1693                         objp->phys_info.vel.y = (objp->pos.y - objp->last_pos.y) / frametime;
1694                         objp->phys_info.vel.z = (objp->pos.z - objp->last_pos.z) / frametime;
1695                 }
1696                 objp = GET_NEXT(objp);
1697         } */
1698
1699         if(!(Game_mode & GM_DEMO_PLAYBACK)){
1700                 find_homing_object_cmeasures(); //      If any cmeasures fired, maybe steer away homing missiles        
1701         }
1702
1703         // do pre-collision stuff for beam weapons
1704         beam_move_all_pre();
1705
1706         if ( Collisions_enabled )       {
1707                 obj_check_all_collisions();             
1708         }
1709
1710         if(!(Game_mode & GM_DEMO_PLAYBACK)){
1711                 turret_swarm_check_validity();
1712         }
1713
1714         // do post-collision stuff for beam weapons
1715         beam_move_all_post();
1716
1717         // update artillery locking info now
1718         ship_update_artillery_lock();
1719 }
1720
1721
1722 MONITOR( NumObjectsRend );      
1723
1724 // -----------------------------------------------------------------------------
1725 //      Render an object.  Calls one of several routines based on type
1726 void obj_render(object *obj)
1727 {
1728         if ( obj->flags & OF_SHOULD_BE_DEAD ) return;
1729 //      if ( obj == Viewer_obj ) return;
1730
1731         MONITOR_INC( NumObjectsRend, 1 );       
1732
1733         switch( obj->type )     {
1734         case OBJ_NONE:
1735                 #ifndef NDEBUG
1736                 mprintf(( "ERROR!!!! Bogus obj %d is rendering!\n", obj-Objects ));
1737                 Int3();
1738                 #endif
1739                 break;
1740         case OBJ_WEAPON:
1741                 weapon_render(obj);
1742                 break;
1743         case OBJ_SHIP:
1744                 ship_render(obj);
1745                 break;
1746         case OBJ_FIREBALL:
1747                 fireball_render(obj);
1748                 break;
1749         case OBJ_SHOCKWAVE:
1750                 shockwave_render(obj);
1751                 break;
1752         case OBJ_DEBRIS:
1753                 debris_render(obj);
1754                 break;
1755         case OBJ_ASTEROID:
1756                 asteroid_render(obj);
1757                 break;
1758         case OBJ_CMEASURE:
1759                 cmeasure_render(obj);
1760                 break;
1761         case OBJ_JUMP_NODE:
1762                 jumpnode_render(obj, &obj->pos, &Eye_position);
1763                 break;
1764         case OBJ_WAYPOINT:
1765                 if (Show_waypoints)     {
1766                         //ship_render(obj);
1767                         gr_set_color( 128, 128, 128 );
1768                         g3_draw_sphere_ez( &obj->pos, 5.0f );
1769                 }
1770                 break;
1771         case OBJ_GHOST:
1772                 break;
1773         case OBJ_BEAM:
1774                 break;
1775         default:
1776                 Error( LOCATION, "Unhandled obj type %d in obj_render", obj->type );
1777         }
1778 }
1779
1780 void obj_init_all_ships_physics()
1781 {
1782         object  *objp;
1783
1784         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
1785                 if (objp->type == OBJ_SHIP)
1786                         physics_ship_init(objp);
1787         }
1788
1789 }
1790
1791 // do client-side pre-interpolation object movement
1792 void obj_client_pre_interpolate()
1793 {
1794         object *objp;
1795         
1796         // duh
1797         obj_delete_all_that_should_be_dead();
1798
1799         // client side processing of warping in effect stages
1800         multi_do_client_warp(flFrametime);     
1801         
1802         // client side movement of an observer
1803         if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
1804                 obj_observer_move(flFrametime);   
1805         }
1806         
1807         // run everything except ships through physics (and ourselves of course)        
1808         obj_merge_created_list();                                               // must merge any objects created by the host!
1809
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 frametime)
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 = frametime;
1935         obj_move_call_physics( objp, ft );
1936         obj_move_all_post(objp, frametime);
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