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