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