]> icculus.org git repositories - btb/d2x.git/blob - main/collide.c
use Builtin_mission_num instead of 0 (if descent.hog is present, d1 becomes
[btb/d2x.git] / main / collide.c
1 /* $Id: collide.c,v 1.11 2003-03-01 01:51:15 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines to handle collisions
18  *
19  * Old Log:
20  * Revision 1.3  1995/11/08  17:15:21  allender
21  * make collide_player_and_weapon play player_hit_sound if
22  * shareware and not my playernum
23  *
24  * Revision 1.2  1995/10/31  10:24:37  allender
25  * shareware stuff
26  *
27  * Revision 1.1  1995/05/16  15:23:34  allender
28  * Initial revision
29  *
30  * Revision 2.5  1995/07/26  12:07:46  john
31  * Made code that pages in weapon_info->robot_hit_vclip not
32  * page in unless it is a badass weapon.  Took out old functionallity
33  * of using this if no robot exp1_vclip, since all robots have these.
34  *
35  * Revision 2.4  1995/03/30  16:36:09  mike
36  * text localization.
37  *
38  * Revision 2.3  1995/03/24  15:11:13  john
39  * Added ugly robot cheat.
40  *
41  * Revision 2.2  1995/03/21  14:41:04  john
42  * Ifdef'd out the NETWORK code.
43  *
44  * Revision 2.1  1995/03/20  18:16:02  john
45  * Added code to not store the normals in the segment structure.
46  *
47  * Revision 2.0  1995/02/27  11:32:20  john
48  * New version 2.0, which has no anonymous unions, builds with
49  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
50  *
51  * Revision 1.289  1995/02/22  13:56:06  allender
52  * remove anonymous unions from object structure
53  *
54  * Revision 1.288  1995/02/11  15:52:45  rob
55  * Included text.h.
56  *
57  * Revision 1.287  1995/02/11  15:04:11  rob
58  * Localized a string.
59  *
60  * Revision 1.286  1995/02/11  14:25:41  rob
61  * Added invul. controlcen option.
62  *
63  * Revision 1.285  1995/02/06  15:53:00  mike
64  * create awareness event for player:wall collision.
65  *
66  * Revision 1.284  1995/02/05  23:18:17  matt
67  * Deal with objects (such as fusion blobs) that get created already
68  * poking through a wall
69  *
70  * Revision 1.283  1995/02/01  17:51:33  mike
71  * fusion bolt can now toast multiple proximity bombs.
72  *
73  * Revision 1.282  1995/02/01  17:29:20  john
74  * Lintized
75  *
76  * Revision 1.281  1995/02/01  15:04:00  rob
77  * Changed sound of weapons hitting invulnerable players.
78  *
79  * Revision 1.280  1995/01/31  16:16:35  mike
80  * Separate smart blobs for robot and player.
81  *
82  * Revision 1.279  1995/01/29  15:57:10  rob
83  * Fixed another bug with robot_request_change calls.
84  *
85  * Revision 1.278  1995/01/28  18:15:06  rob
86  * Fixed a bug in multi_request_robot_change.
87  *
88  * Revision 1.277  1995/01/27  15:15:44  rob
89  * Fixing problems with controlcen damage.
90  *
91  * Revision 1.276  1995/01/27  15:13:10  mike
92  * comment out mprintf.
93  *
94  * Revision 1.275  1995/01/26  22:11:51  mike
95  * Purple chromo-blaster (ie, fusion cannon) spruce up (chromification)
96  *
97  * Revision 1.274  1995/01/26  18:57:55  rob
98  * Changed two uses of digi_play_sample to digi_link_sound_to_pos which
99  * made more sense.
100  *
101  * Revision 1.273  1995/01/25  23:37:58  mike
102  * make persistent objects not hit player more than once.
103  * Also, make them hit player before degrading them, else they often did 0 damage.
104  *
105  * Revision 1.272  1995/01/25  18:23:54  rob
106  * Don't let players pick up powerups in exit tunnel.
107  *
108  * Revision 1.271  1995/01/25  13:43:18  rob
109  * Added robot transfer for player collisions.
110  * Removed mprintf from collide.c on Mike's request.
111  *
112  * Revision 1.270  1995/01/25  10:24:01  mike
113  * Make sizzle and rock happen in lava even if you're invulnerable.
114  *
115  * Revision 1.269  1995/01/22  17:05:33  mike
116  * Call multi_robot_request_change when a robot gets whacked by a player or
117  * player weapon, if player_num != Player_num
118  *
119  * Revision 1.268  1995/01/21  21:20:28  matt
120  * Fixed stupid bug
121  *
122  * Revision 1.267  1995/01/21  18:47:47  rob
123  * Fixed a really dumb bug with player keys.
124  *
125  * Revision 1.266  1995/01/21  17:39:30  matt
126  * Cleaned up laser/player hit wall confusions
127  *
128  * Revision 1.265  1995/01/19  17:44:42  mike
129  * damage_force removed, that information coming from strength field.
130  *
131  * Revision 1.264  1995/01/18  17:12:56  rob
132  * Fixed control stuff for multiplayer.
133  *
134  * Revision 1.263  1995/01/18  16:12:33  mike
135  * Make control center aware of a cloaked playerr when he fires.
136  *
137  * Revision 1.262  1995/01/17  17:48:42  rob
138  * Added key syncing for coop players.
139  *
140  * Revision 1.261  1995/01/16  19:30:28  rob
141  * Fixed an assert error in fireball.c
142  *
143  * Revision 1.260  1995/01/16  19:23:51  mike
144  * Say Boss_been_hit if he been hit so he gates appropriately.
145  *
146  * Revision 1.259  1995/01/16  11:55:16  mike
147  * make enemies become aware of player if he damages control center.
148  *
149  * Revision 1.258  1995/01/15  16:42:00  rob
150  * Fixed problem with robot bumping damage.
151  *
152  * Revision 1.257  1995/01/14  19:16:36  john
153  * First version of new bitmap paging code.
154  *
155  * Revision 1.256  1995/01/03  17:58:37  rob
156  * Fixed scoring problems.
157  *
158  * Revision 1.255  1994/12/29  12:41:11  rob
159  * Tweaking robot exploding in coop.
160  *
161  * Revision 1.254  1994/12/28  10:37:59  rob
162  * Fixed ifdef of multibot stuff.
163  *
164  * Revision 1.253  1994/12/21  19:03:14  rob
165  * Fixing score accounting for multiplayer robots
166  *
167  * Revision 1.252  1994/12/21  17:36:31  rob
168  * Fix hostage pickup problem in network.
169  * tweaking robot powerup drops.
170  *
171  * Revision 1.251  1994/12/19  20:32:34  rob
172  * Remove awareness events from player collisions and lasers that are not the console player.
173  *
174  * Revision 1.250  1994/12/19  20:01:22  rob
175  * Added multibot.h include.
176  *
177  * Revision 1.249  1994/12/19  16:36:41  rob
178  * Patches damaging of multiplayer robots.
179  *
180  * Revision 1.248  1994/12/14  21:15:18  rob
181  * play lava hiss across network.
182  *
183  * Revision 1.247  1994/12/14  17:09:09  matt
184  * Fixed problem with no sound when lasers hit closed walls, like grates.
185  *
186  * Revision 1.246  1994/12/14  09:51:49  mike
187  * make any weapon cause proximity bomb detonation.
188  *
189  * Revision 1.245  1994/12/13  12:55:25  mike
190  * change number of proximity bomb powerups which get dropped.
191  *
192  * Revision 1.244  1994/12/12  17:17:53  mike
193  * make boss cloak/teleport when get hit, make quad laser 3/4 as powerful.
194  *
195  * Revision 1.243  1994/12/12  12:07:51  rob
196  * Don't take damage if we're in endlevel sequence.
197  *
198  * Revision 1.242  1994/12/11  23:44:52  mike
199  * less phys_apply_rot() at higher skill levels.
200  *
201  * Revision 1.241  1994/12/11  12:37:02  mike
202  * remove stupid robot spinning code.  it was really stupid.  (actually, call here, code in ai.c).
203  *
204  * Revision 1.240  1994/12/10  16:44:51  matt
205  * Added debugging code to track down door that turns into rock
206  *
207  * Revision 1.239  1994/12/09  14:59:19  matt
208  * Added system to attach a fireball to another object for rendering purposes,
209  * so the fireball always renders on top of (after) the object.
210  *
211  * Revision 1.238  1994/12/09  09:57:02  mike
212  * Don't allow robots or their weapons to pass through control center.
213  *
214  * Revision 1.237  1994/12/08  15:46:03  mike
215  * better robot behavior.
216  *
217  * Revision 1.236  1994/12/08  12:32:56  mike
218  * make boss dying more interesting.
219  *
220  * Revision 1.235  1994/12/07  22:49:15  mike
221  * tweak rotation due to collision.
222  *
223  * Revision 1.234  1994/12/07  16:44:50  mike
224  * make bump sound if supposed to, even if not taking damage.
225  *
226  * Revision 1.233  1994/12/07  12:55:08  mike
227  * tweak rotvel applied from collisions.
228  *
229  * Revision 1.232  1994/12/05  19:30:48  matt
230  * Fixed horrible segment over-dereferencing
231  *
232  * Revision 1.231  1994/12/05  00:32:15  mike
233  * do rotvel on badass and bump collisions.
234  *
235  * Revision 1.230  1994/12/03  12:49:22  mike
236  * don't play bonk sound when you collide with a volatile wall (like lava).
237  *
238  * Revision 1.229  1994/12/02  16:51:09  mike
239  * make lava sound only happen at 4 Hz.
240  *
241  * Revision 1.228  1994/11/30  23:55:27  rob
242  * Fixed a bug where a laser hitting a wall was making 2 sounds.
243  *
244  * Revision 1.227  1994/11/30  20:11:00  rob
245  * Fixed # of dropped laser powerups.
246  *
247  * Revision 1.226  1994/11/30  19:19:03  rob
248  * Transmit collission sounds for net games.
249  *
250  * Revision 1.225  1994/11/30  16:33:01  mike
251  * new boss behavior.
252  *
253  * Revision 1.224  1994/11/30  15:44:17  mike
254  * /2 on boss smart children damage.
255  *
256  * Revision 1.223  1994/11/30  14:03:03  mike
257  * hook for claw sounds
258  *
259  * Revision 1.222  1994/11/29  20:41:09  matt
260  * Deleted a bunch of commented-out lines
261  *
262  * Revision 1.221  1994/11/27  23:15:08  matt
263  * Made changes for new mprintf calling convention
264  *
265  * Revision 1.220  1994/11/19  16:11:28  rob
266  * Collision damage with walls or lava is counted as suicides in net games
267  *
268  * Revision 1.219  1994/11/19  15:20:41  mike
269  * rip out unused code and data
270  *
271  * Revision 1.218  1994/11/17  18:44:27  rob
272  * Added OBJ_GHOST to list of valid player types to create eggs.
273  *
274  * Revision 1.217  1994/11/17  14:57:59  mike
275  * moved segment validation functions from editor to main.
276  *
277  * Revision 1.216  1994/11/16  23:38:36  mike
278  * new improved boss teleportation behavior.
279  *
280  * Revision 1.215  1994/11/16  12:16:29  mike
281  * Enable collisions between robots.  A hack in fvi.c only does this for robots which lunge to attack (eg, green guy)
282  *
283  * Revision 1.214  1994/11/15  16:51:50  mike
284  * bump player when he hits a volatile wall.
285  *
286  * Revision 1.213  1994/11/12  16:38:44  mike
287  * allow flares to open doors.
288  *
289  * Revision 1.212  1994/11/10  13:09:19  matt
290  * Added support for new run-length-encoded bitmaps
291  *
292  * Revision 1.211  1994/11/09  17:05:43  matt
293  * Fixed problem with volatile walls
294  *
295  * Revision 1.210  1994/11/09  12:11:46  mike
296  * only award points if ConsoleObject killed robot.
297  *
298  * Revision 1.209  1994/11/09  11:11:03  yuan
299  * Made wall volatile if either tmap_num1 or tmap_num2 is a volatile wall.
300  *
301  * Revision 1.208  1994/11/08  12:20:15  mike
302  * moved do_controlcen_destroyed_stuff from here to cntrlcen.c
303  *
304  * Revision 1.207  1994/11/02  23:22:08  mike
305  * Make ` (backquote, KEY_LAPOSTRO) tell what wall was hit by laser.
306  *
307  * Revision 1.206  1994/11/02  18:03:00  rob
308  * Fix control_center_been_hit logic so it only cares about the local player.
309  * Other players take care of their own control center 'ai'.
310  *
311  * Revision 1.205  1994/11/01  19:37:33  rob
312  * Changed the max # of consussion missiles to 4.
313  * (cause they're lame and clutter things up)
314  *
315  * Revision 1.204  1994/11/01  18:06:35  john
316  * Tweaked wall banging sound constant.
317  *
318  * Revision 1.203  1994/11/01  18:01:40  john
319  * Made wall bang less obnoxious, but volume based.
320  *
321  * Revision 1.202  1994/11/01  17:11:05  rob
322  * Changed some stuff in drop_player_eggs.
323  *
324  * Revision 1.201  1994/11/01  12:18:23  john
325  * Added sound volume support. Made wall collisions be louder/softer.
326  *
327  * Revision 1.200  1994/10/31  13:48:44  rob
328  * Fixed bug in opening doors over network/modem.  Added a new message
329  * type to multi.c that communicates door openings across the net.
330  * Changed includes in multi.c and wall.c to accomplish this.
331  *
332  * Revision 1.199  1994/10/28  14:42:52  john
333  * Added sound volumes to all sound calls.
334  *
335  * Revision 1.198  1994/10/27  16:58:37  allender
336  * added demo recording of monitors blowing up
337  *
338  * Revision 1.197  1994/10/26  23:20:52  matt
339  * Tone down flash even more
340  *
341  * Revision 1.196  1994/10/26  23:01:50  matt
342  * Toned down red flash when damaged
343  *
344  * Revision 1.195  1994/10/26  15:56:29  yuan
345  * Tweaked some palette flashes.
346  *
347  * Revision 1.194  1994/10/25  11:32:26  matt
348  * Fixed bugs with vulcan powerups in mutliplayer
349  *
350  * Revision 1.193  1994/10/25  10:51:18  matt
351  * Vulcan cannon powerups now contain ammo count
352  *
353  * Revision 1.192  1994/10/24  14:14:05  matt
354  * Fixed bug in bump_two_objects()
355  *
356  * Revision 1.191  1994/10/23  19:17:04  matt
357  * Fixed bug with "no key" messages
358  *
359  * Revision 1.190  1994/10/22  00:08:46  matt
360  * Fixed up problems with bonus & game sequencing
361  * Player doesn't get credit for hostages unless he gets them out alive
362  *
363  * Revision 1.189  1994/10/21  20:42:34  mike
364  * Clear number of hostages on board between levels.
365  *
366  * Revision 1.188  1994/10/20  15:17:43  mike
367  * control center in boss handling.
368  *
369  * Revision 1.187  1994/10/20  10:09:47  mike
370  * Only ever drop 1 shield powerup in multiplayer (as an egg).
371  *
372  * Revision 1.186  1994/10/20  09:47:11  mike
373  * Fix bug in dropping vulcan ammo in multiplayer.
374  * Also control center stuff.
375  *
376  * Revision 1.185  1994/10/19  15:14:32  john
377  * Took % hits out of player structure, made %kills work properly.
378  *
379  * Revision 1.184  1994/10/19  11:33:16  john
380  * Fixed hostage rescued percent.
381  *
382  * Revision 1.183  1994/10/19  11:16:49  mike
383  * Don't allow crazy josh to open locked doors.
384  * Don't allow weapons to harm parent.
385  *
386  * Revision 1.182  1994/10/18  18:37:01  mike
387  * No more hostage killing.  Too much stuff to do to integrate into game.
388  *
389  * Revision 1.181  1994/10/18  16:37:35  mike
390  * Debug function for Yuan: Show seg:side when hit by puny laser if Show_seg_and_side != 0.
391  *
392  * Revision 1.180  1994/10/18  10:53:17  mike
393  * Support attack type as a property of a robot, not of being == GREEN_GUY.
394  *
395  * Revision 1.179  1994/10/17  21:18:36  mike
396  * diminish damage player does to robot due to collision, only took 2-3 hits to kill a josh.
397  *
398  * Revision 1.178  1994/10/17  20:30:40  john
399  * Made player_hostages_rescued or whatever count properly.
400  *
401  * Revision 1.177  1994/10/16  12:42:56  mike
402  * Trap bogus amount of vulcan ammo dropping.
403  *
404  * Revision 1.176  1994/10/15  19:06:51  mike
405  * Drop vulcan ammo if player has it, but no vulcan cannon (when he dies).
406  *
407  * Revision 1.175  1994/10/13  15:42:06  mike
408  * Remove afterburner.
409  *
410  * Revision 1.174  1994/10/13  11:12:57  mike
411  * Apply damage to robots.  I hosed it a couple weeks ago when I made the green guy special.
412  *
413  */
414
415 #ifdef HAVE_CONFIG_H
416 #include <conf.h>
417 #endif
418
419 #include <stdlib.h>
420 #include <stdio.h>
421
422 #include "rle.h"
423 #include "inferno.h"
424 #include "game.h"
425 #include "gr.h"
426 #include "stdlib.h"
427 #include "bm.h"
428 //#include "error.h"
429 #include "mono.h"
430 #include "3d.h"
431 #include "segment.h"
432 #include "texmap.h"
433 #include "laser.h"
434 #include "key.h"
435 #include "gameseg.h"
436 #include "object.h"
437 #include "physics.h"
438 #include "slew.h"               
439 #include "render.h"
440 #include "wall.h"
441 #include "vclip.h"
442 #include "polyobj.h"
443 #include "fireball.h"
444 #include "laser.h"
445 #include "error.h"
446 #include "ai.h"
447 #include "hostage.h"
448 #include "fuelcen.h"
449 #include "sounds.h"
450 #include "robot.h"
451 #include "weapon.h"
452 #include "player.h"
453 #include "gauges.h"
454 #include "powerup.h"
455 #ifdef NETWORK
456 #include "network.h"
457 #endif
458 #include "newmenu.h"
459 #include "scores.h"
460 #include "effects.h"
461 #include "textures.h"
462 #ifdef NETWORK
463 #include "multi.h"
464 #endif
465 #include "cntrlcen.h"
466 #include "newdemo.h"
467 #include "endlevel.h"
468 #include "multibot.h"
469 #include "piggy.h"
470 #include "text.h"
471 #include "automap.h"
472 #include "switch.h"
473 #include "palette.h"
474
475 #ifdef TACTILE
476 #include "tactile.h"
477 #endif 
478
479 #ifdef EDITOR
480 #include "editor/editor.h"
481 #endif
482
483 #include "collide.h"
484
485 #define STANDARD_EXPL_DELAY (f1_0/4)
486
487 //##void collide_fireball_and_wall(object *fireball,fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)      {
488 //##    return; 
489 //##}
490
491 //      -------------------------------------------------------------------------------------------------------------
492 //      The only reason this routine is called (as of 10/12/94) is so Brain guys can open doors.
493 void collide_robot_and_wall( object * robot, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
494 {
495         ai_local                *ailp = &Ai_local_info[robot-Objects];
496
497         if ((robot->id == ROBOT_BRAIN) || (robot->ctype.ai_info.behavior == AIB_RUN_FROM) || (Robot_info[robot->id].companion == 1) || (robot->ctype.ai_info.behavior == AIB_SNIPE)) {
498                 int     wall_num = Segments[hitseg].sides[hitwall].wall_num;
499                 if (wall_num != -1) {
500                         if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].keys == KEY_NONE) && (Walls[wall_num].state == WALL_DOOR_CLOSED) && !(Walls[wall_num].flags & WALL_DOOR_LOCKED)) {
501                                 // -- mprintf((0, "Trying to open door at segment %i, side %i\n", hitseg, hitwall));
502                                 wall_open_door(&Segments[hitseg], hitwall);
503                         // -- Changed from this, 10/19/95, MK: Don't want buddy getting stranded from player
504                         //-- } else if ((Robot_info[robot->id].companion == 1) && (Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].keys != KEY_NONE) && (Walls[wall_num].state == WALL_DOOR_CLOSED) && !(Walls[wall_num].flags & WALL_DOOR_LOCKED)) {
505                         } else if ((Robot_info[robot->id].companion == 1) && (Walls[wall_num].type == WALL_DOOR)) {
506                                 if ((ailp->mode == AIM_GOTO_PLAYER) || (Escort_special_goal == ESCORT_GOAL_SCRAM)) {
507                                         if (Walls[wall_num].keys != KEY_NONE) {
508                                                 if (Walls[wall_num].keys & Players[Player_num].flags)
509                                                         wall_open_door(&Segments[hitseg], hitwall);
510                                         } else if (!(Walls[wall_num].flags & WALL_DOOR_LOCKED))
511                                                 wall_open_door(&Segments[hitseg], hitwall);
512                                 }
513                         } else if (Robot_info[robot->id].thief) {               //      Thief allowed to go through doors to which player has key.
514                                 if (Walls[wall_num].keys != KEY_NONE)
515                                         if (Walls[wall_num].keys & Players[Player_num].flags)
516                                                 wall_open_door(&Segments[hitseg], hitwall);
517                         }
518                 }
519         }
520
521         return;
522 }
523
524 //##void collide_hostage_and_wall( object * hostage, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)     {
525 //##    return;
526 //##}
527
528 //      -------------------------------------------------------------------------------------------------------------
529
530 int apply_damage_to_clutter(object *clutter, fix damage)
531 {
532         if ( clutter->flags&OF_EXPLODING) return 0;
533
534         if (clutter->shields < 0 ) return 0;    //clutter already dead...
535
536         clutter->shields -= damage;
537
538         if (clutter->shields < 0) {
539                 explode_object(clutter,0);
540                 return 1;
541         } else
542                 return 0;
543 }
544
545 char    Monster_mode = 0;               //      A cheat.  Do massive damage when collide.
546
547 //given the specified force, apply damage from that force to an object
548 void apply_force_damage(object *obj,fix force,object *other_obj)
549 {
550         int     result;
551         fix damage;
552
553         if (obj->flags & (OF_EXPLODING|OF_SHOULD_BE_DEAD))
554                 return;         //already exploding or dead
555
556         damage = fixdiv(force,obj->mtype.phys_info.mass) / 8;
557
558         if ((other_obj->type == OBJ_PLAYER) && Monster_mode)
559                 damage = 0x7fffffff;
560
561 //mprintf((0,"obj %d, damage=%x\n",obj-Objects,damage));
562
563         switch (obj->type) {
564
565                 case OBJ_ROBOT:
566
567                         if (Robot_info[obj->id].attack_type == 1) {
568                                 if (other_obj->type == OBJ_WEAPON)
569                                         result = apply_damage_to_robot(obj,damage/4, other_obj->ctype.laser_info.parent_num);
570                                 else
571                                         result = apply_damage_to_robot(obj,damage/4, other_obj-Objects);
572                         }
573                         else {
574                                 if (other_obj->type == OBJ_WEAPON)
575                                         result = apply_damage_to_robot(obj,damage/2, other_obj->ctype.laser_info.parent_num);
576                                 else
577                                         result = apply_damage_to_robot(obj,damage/2, other_obj-Objects);
578                         }               
579
580                         if (result && (other_obj->ctype.laser_info.parent_signature == ConsoleObject->signature))
581                                 add_points_to_score(Robot_info[obj->id].score_value);
582                         break;
583
584                 case OBJ_PLAYER:
585
586                         //      If colliding with a claw type robot, do damage proportional to FrameTime because you can collide with those
587                         //      bots every frame since they don't move.
588                         if ( (other_obj->type == OBJ_ROBOT) && (Robot_info[other_obj->id].attack_type) )
589                                 damage = fixmul(damage, FrameTime*2);
590
591                         //      Make trainee easier.
592                         if (Difficulty_level == 0)
593                                 damage /= 2;
594
595                         apply_damage_to_player(obj,other_obj,damage);
596                         break;
597
598                 case OBJ_CLUTTER:
599
600                         apply_damage_to_clutter(obj,damage);
601                         break;
602
603                 case OBJ_CNTRLCEN:
604
605                         apply_damage_to_controlcen(obj,damage, other_obj-Objects);
606                         break;
607
608                 case OBJ_WEAPON:
609
610                         break;          //weapons don't take damage
611
612                 default:
613
614                         Int3();
615
616         }
617 }
618
619 //      -----------------------------------------------------------------------------
620 void bump_this_object(object *objp, object *other_objp, vms_vector *force, int damage_flag)
621 {
622         fix force_mag;
623
624         if (! (objp->mtype.phys_info.flags & PF_PERSISTENT))
625         {
626                 if (objp->type == OBJ_PLAYER) {
627                         vms_vector force2;
628                         force2.x = force->x/4;
629                         force2.y = force->y/4;
630                         force2.z = force->z/4;
631                         phys_apply_force(objp,&force2);
632                         if (damage_flag && ((other_objp->type != OBJ_ROBOT) || !Robot_info[other_objp->id].companion)) {
633                                 force_mag = vm_vec_mag_quick(&force2);
634                                 apply_force_damage(objp, force_mag, other_objp);
635                         }
636                 } else if ((objp->type == OBJ_ROBOT) || (objp->type == OBJ_CLUTTER) || (objp->type == OBJ_CNTRLCEN)) {
637                         if (!Robot_info[objp->id].boss_flag) {
638                                 vms_vector force2;
639                                 force2.x = force->x/(4 + Difficulty_level);
640                                 force2.y = force->y/(4 + Difficulty_level);
641                                 force2.z = force->z/(4 + Difficulty_level);
642
643                                 phys_apply_force(objp, force);
644                                 phys_apply_rot(objp, &force2);
645                                 if (damage_flag) {
646                                         force_mag = vm_vec_mag_quick(force);
647                                         apply_force_damage(objp, force_mag, other_objp);
648                                 }
649                         }
650                 }
651         }
652 }
653
654 //      -----------------------------------------------------------------------------
655 //deal with two objects bumping into each other.  Apply force from collision
656 //to each robot.  The flags tells whether the objects should take damage from
657 //the collision.
658 void bump_two_objects(object *obj0,object *obj1,int damage_flag)
659 {
660         vms_vector      force;
661         object          *t=NULL;
662
663         if (obj0->movement_type != MT_PHYSICS)
664                 t=obj1;
665         else if (obj1->movement_type != MT_PHYSICS)
666                 t=obj0;
667
668         if (t) {
669                 Assert(t->movement_type == MT_PHYSICS);
670                 vm_vec_copy_scale(&force,&t->mtype.phys_info.velocity,-t->mtype.phys_info.mass);
671                 phys_apply_force(t,&force);
672                 return;
673         }
674
675         vm_vec_sub(&force,&obj0->mtype.phys_info.velocity,&obj1->mtype.phys_info.velocity);
676         vm_vec_scale2(&force,2*fixmul(obj0->mtype.phys_info.mass,obj1->mtype.phys_info.mass),(obj0->mtype.phys_info.mass+obj1->mtype.phys_info.mass));
677
678         bump_this_object(obj1, obj0, &force, damage_flag);
679         vm_vec_negate(&force);
680         bump_this_object(obj0, obj1, &force, damage_flag);
681
682 }
683
684 void bump_one_object(object *obj0, vms_vector *hit_dir, fix damage)
685 {
686         vms_vector      hit_vec;
687
688         hit_vec = *hit_dir;
689         vm_vec_scale(&hit_vec, damage);
690
691         phys_apply_force(obj0,&hit_vec);
692
693 }
694
695 #define DAMAGE_SCALE            128     //      Was 32 before 8:55 am on Thursday, September 15, changed by MK, walls were hurting me more than robots!
696 #define DAMAGE_THRESHOLD        (F1_0/3)
697 #define WALL_LOUDNESS_SCALE (20)
698
699 fix force_force = i2f(50);
700
701 void collide_player_and_wall( object * playerobj, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
702 {
703         fix damage;
704         char ForceFieldHit=0;
705         int tmap_num,tmap_num2;
706
707         if (playerobj->id != Player_num) // Execute only for local player
708                 return;
709
710         tmap_num = Segments[hitseg].sides[hitwall].tmap_num;
711
712         //      If this wall does damage, don't make *BONK* sound, we'll be making another sound.
713         if (TmapInfo[tmap_num].damage > 0)
714                 return;
715
716         if (TmapInfo[tmap_num].flags & TMI_FORCE_FIELD) {
717                 vms_vector force;
718
719                 PALETTE_FLASH_ADD(0, 0, 60);    //flash blue
720
721                 //knock player around
722                 force.x = 40*(d_rand() - 16384);
723                 force.y = 40*(d_rand() - 16384);
724                 force.z = 40*(d_rand() - 16384);
725                 phys_apply_rot(playerobj, &force);
726
727 #ifdef TACTILE
728                 if (TactileStick)
729                  Tactile_apply_force (&force,&playerobj->orient);
730 #endif
731
732                 //make sound
733                 digi_link_sound_to_pos( SOUND_FORCEFIELD_BOUNCE_PLAYER, hitseg, 0, hitpt, 0, f1_0 );
734 #ifdef NETWORK
735                 if (Game_mode & GM_MULTI)
736                         multi_send_play_sound(SOUND_FORCEFIELD_BOUNCE_PLAYER, f1_0);
737 #endif
738                 ForceFieldHit=1;
739         } 
740         else {
741
742         #ifdef TACTILE
743                 vms_vector force;
744                 if (TactileStick) {
745                         force.x = -playerobj->mtype.phys_info.velocity.x;
746                         force.y = -playerobj->mtype.phys_info.velocity.y;
747                         force.z = -playerobj->mtype.phys_info.velocity.z;
748                         Tactile_do_collide(&force, &playerobj->orient);
749                 }
750         #endif
751
752         wall_hit_process( &Segments[hitseg], hitwall, 20, playerobj->id, playerobj );
753         }
754
755         //      ** Damage from hitting wall **
756         //      If the player has less than 10% shields, don't take damage from bump
757         // Note: Does quad damage if hit a force field - JL
758         damage = (hitspeed / DAMAGE_SCALE) * (ForceFieldHit*8 + 1);
759
760         tmap_num2 = Segments[hitseg].sides[hitwall].tmap_num2;
761
762         //don't do wall damage and sound if hit lava or water
763         if ((TmapInfo[tmap_num].flags & (TMI_WATER|TMI_VOLATILE)) || (tmap_num2 && (TmapInfo[tmap_num2&0x3fff].flags & (TMI_WATER|TMI_VOLATILE))))
764                 damage = 0;
765
766         if (damage >= DAMAGE_THRESHOLD) {
767                 int     volume;
768                 volume = (hitspeed-(DAMAGE_SCALE*DAMAGE_THRESHOLD)) / WALL_LOUDNESS_SCALE ;
769
770                 create_awareness_event(playerobj, PA_WEAPON_WALL_COLLISION);
771
772                 if ( volume > F1_0 )
773                         volume = F1_0;
774                 if (volume > 0 && !ForceFieldHit) {  // uhhhgly hack
775                         digi_link_sound_to_pos( SOUND_PLAYER_HIT_WALL, hitseg, 0, hitpt, 0, volume );
776                         #ifdef NETWORK
777                         if (Game_mode & GM_MULTI)
778                                 multi_send_play_sound(SOUND_PLAYER_HIT_WALL, volume);   
779                         #endif
780                 }
781
782                 if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
783                         if ( Players[Player_num].shields > f1_0*10 || ForceFieldHit)
784                                 apply_damage_to_player( playerobj, playerobj, damage );
785
786                 // -- No point in doing this unless we compute a reasonable hitpt.  Currently it is just the player's position. --MK, 01/18/96
787                 // -- if (!(TmapInfo[Segments[hitseg].sides[hitwall].tmap_num].flags & TMI_FORCE_FIELD)) {
788                 // --   vms_vector      hitpt1;
789                 // --   int                     hitseg1;
790                 // --
791                 // --           vm_vec_avg(&hitpt1, hitpt, &Objects[Players[Player_num].objnum].pos);
792                 // --   hitseg1 = find_point_seg(&hitpt1, Objects[Players[Player_num].objnum].segnum);
793                 // --   if (hitseg1 != -1)
794                 // --           object_create_explosion( hitseg, hitpt, Weapon_info[0].impact_size, Weapon_info[0].wall_hit_vclip );
795                 // -- }
796
797         }
798
799         return;
800 }
801
802 fix     Last_volatile_scrape_sound_time = 0;
803
804 void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt);
805 void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt);
806
807 //see if wall is volatile or water
808 //if volatile, cause damage to player  
809 //returns 1=lava, 2=water
810 int check_volatile_wall(object *obj,int segnum,int sidenum,vms_vector *hitpt)
811 {
812         fix tmap_num,d,water;
813
814         Assert(obj->type==OBJ_PLAYER);
815
816         tmap_num = Segments[segnum].sides[sidenum].tmap_num;
817
818         d = TmapInfo[tmap_num].damage;
819         water = (TmapInfo[tmap_num].flags & TMI_WATER);
820
821         if (d > 0 || water) {
822
823                 if (obj->id == Player_num) {
824
825                         if (d > 0) {
826                                 fix damage = fixmul(d,FrameTime);
827
828                                 if (Difficulty_level == 0)
829                                         damage /= 2;
830
831                                 if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
832                                         apply_damage_to_player( obj, obj, damage );
833
834 #ifdef TACTILE
835                                 if (TactileStick)
836                                  Tactile_Xvibrate (50,25);
837 #endif
838
839                                 PALETTE_FLASH_ADD(f2i(damage*4), 0, 0); //flash red
840                         }
841
842                         obj->mtype.phys_info.rotvel.x = (d_rand() - 16384)/2;
843                         obj->mtype.phys_info.rotvel.z = (d_rand() - 16384)/2;
844                 }
845
846                 return (d>0)?1:2;
847         }
848         else
849          {
850 #ifdef TACTILE
851                 if (TactileStick && !(FrameCount & 15))
852                  Tactile_Xvibrate_clear ();
853 #endif
854
855                 return 0;
856          }
857 }
858
859 //this gets called when an object is scraping along the wall
860 void scrape_object_on_wall(object *obj, short hitseg, short hitside, vms_vector * hitpt )
861 {
862         switch (obj->type) {
863
864                 case OBJ_PLAYER:
865
866                         if (obj->id==Player_num) {
867                                 int type;
868
869                                 //mprintf((0, "Scraped segment #%3i, side #%i\n", hitseg, hitside));
870
871                                 if ((type=check_volatile_wall(obj,hitseg,hitside,hitpt))!=0) {
872                                         vms_vector      hit_dir, rand_vec;
873
874                                         if ((GameTime > Last_volatile_scrape_sound_time + F1_0/4) || (GameTime < Last_volatile_scrape_sound_time)) {
875                                                 int sound = (type==1)?SOUND_VOLATILE_WALL_HISS:SOUND_SHIP_IN_WATER;
876
877                                                 Last_volatile_scrape_sound_time = GameTime;
878
879                                                 digi_link_sound_to_pos( sound, hitseg, 0, hitpt, 0, F1_0 );
880 #ifdef NETWORK
881                                                 if (Game_mode & GM_MULTI)
882                                                         multi_send_play_sound(sound, F1_0);
883 #endif
884                                         }
885
886                                         #ifdef COMPACT_SEGS
887                                                 get_side_normal(&Segments[hitseg], higside, 0, &hit_dir );      
888                                         #else
889                                                 hit_dir = Segments[hitseg].sides[hitside].normals[0];
890                                         #endif
891                         
892                                         make_random_vector(&rand_vec);
893                                         vm_vec_scale_add2(&hit_dir, &rand_vec, F1_0/8);
894                                         vm_vec_normalize_quick(&hit_dir);
895                                         bump_one_object(obj, &hit_dir, F1_0*8);
896                                 }
897
898                                 //@@} else {
899                                 //@@    //what scrape sound
900                                 //@@    //PLAY_SOUND( SOUND_PLAYER_SCRAPE_WALL );
901                                 //@@}
902                 
903                         }
904
905                         break;
906
907                 //these two kinds of objects below shouldn't really slide, so
908                 //if this scrape routine gets called (which it might if the
909                 //object (such as a fusion blob) was created already poking
910                 //through the wall) call the collide routine.
911
912                 case OBJ_WEAPON:
913                         collide_weapon_and_wall(obj,0,hitseg,hitside,hitpt); 
914                         break;
915
916                 case OBJ_DEBRIS:                
917                         collide_debris_and_wall(obj,0,hitseg,hitside,hitpt); 
918                         break;
919         }
920
921 }
922
923 //if an effect is hit, and it can blow up, then blow it up
924 //returns true if it blew up
925 int check_effect_blowup(segment *seg,int side,vms_vector *pnt, object *blower, int force_blowup_flag)
926 {
927         int tm,tmf,ec,db;
928
929         db=0;
930
931         //      If this wall has a trigger and the blower-upper is not the player or the buddy, abort!
932         {
933                 int     ok_to_blow = 0;
934
935                 if (blower->ctype.laser_info.parent_type == OBJ_ROBOT)
936                         if (Robot_info[Objects[blower->ctype.laser_info.parent_num].id].companion)
937                                 ok_to_blow = 1;
938
939                 if (!(ok_to_blow || (blower->ctype.laser_info.parent_type == OBJ_PLAYER))) {
940                         int     trigger_num, wall_num;
941
942                         wall_num = seg->sides[side].wall_num;
943                         if ( wall_num != -1 ) {
944                                 trigger_num = Walls[wall_num].trigger;
945
946                                 if (trigger_num != -1)
947                                         return 0;
948                         }
949                 }
950         }
951
952
953         if ((tm=seg->sides[side].tmap_num2) != 0) {
954
955                 tmf = tm&0xc000;                //tm flags
956                 tm &= 0x3fff;                   //tm without flags
957
958                 //check if it's an animation (monitor) or casts light
959                 if ((((ec=TmapInfo[tm].eclip_num)!=-1) && ((db=Effects[ec].dest_bm_num)!=-1 && !(Effects[ec].flags&EF_ONE_SHOT))) ||    (ec==-1 && (TmapInfo[tm].destroyed!=-1))) {
960                         fix u,v;
961                         grs_bitmap *bm = &GameBitmaps[Textures[tm].index];
962                         int x=0,y=0,t;
963
964                         PIGGY_PAGE_IN(Textures[tm]);
965
966                         //this can be blown up...did we hit it?
967
968                         if (!force_blowup_flag) {
969                                 find_hitpoint_uv(&u,&v,NULL,pnt,seg,side,0);    //evil: always say face zero
970
971                                 x = ((unsigned) f2i(u*bm->bm_w)) % bm->bm_w;
972                                 y = ((unsigned) f2i(v*bm->bm_h)) % bm->bm_h;
973
974                                 switch (tmf) {          //adjust for orientation of paste-on
975                                         case 0x0000:    break;
976                                         case 0x4000:    t=y; y=x; x=bm->bm_w-t-1; break;
977                                         case 0x8000:    y=bm->bm_h-y-1; x=bm->bm_w-x-1; break;
978                                         case 0xc000:    t=x; x=y; y=bm->bm_h-t-1; break;
979                                 }
980
981                                 //mprintf((0,"u,v = %x,%x   x,y=%x,%x",u,v,x,y));
982                         
983                                 if (bm->bm_flags & BM_FLAG_RLE)
984                                         bm = rle_expand_texture(bm);
985                         }
986
987                         if (force_blowup_flag || (bm->bm_data[y*bm->bm_w+x] != TRANSPARENCY_COLOR)) {           //not trans, thus on effect
988                                 int vc,sound_num;
989                                 fix dest_size;
990
991
992 #ifdef NETWORK
993                                 if ((Game_mode & GM_MULTI) && Netgame.AlwaysLighting)
994                                 if (!(ec!=-1 && db!=-1 && !(Effects[ec].flags&EF_ONE_SHOT)))
995                                         return(0);
996 #endif
997
998                                 //mprintf((0,"  HIT!\n"));
999
1000                                 //note: this must get called before the texture changes, 
1001                                 //because we use the light value of the texture to change
1002                                 //the static light in the segment
1003                                 subtract_light(seg-Segments,side);
1004
1005                                 if (Newdemo_state == ND_STATE_RECORDING)
1006                                         newdemo_record_effect_blowup( seg-Segments, side, pnt);
1007
1008                                 if (ec!=-1) {
1009                                         dest_size = Effects[ec].dest_size;
1010                                         vc = Effects[ec].dest_vclip;
1011                                 } else {
1012                                         dest_size = i2f(20);
1013                                         vc = 3;
1014                                 }
1015
1016                                 object_create_explosion( seg-Segments, pnt, dest_size, vc );
1017
1018                                 if (ec!=-1 && db!=-1 && !(Effects[ec].flags&EF_ONE_SHOT)) {
1019
1020                                         if ((sound_num = Vclip[vc].sound_num) != -1)
1021                                                 digi_link_sound_to_pos( sound_num, seg-Segments, 0, pnt,  0, F1_0 );
1022
1023                                         if ((sound_num=Effects[ec].sound_num)!=-1)              //kill sound
1024                                                 digi_kill_sound_linked_to_segment(seg-Segments,side,sound_num);
1025
1026                                         if (Effects[ec].dest_eclip!=-1 && Effects[Effects[ec].dest_eclip].segnum==-1) {
1027                                                 int bm_num;
1028                                                 eclip *new_ec;
1029                                         
1030                                                 new_ec = &Effects[Effects[ec].dest_eclip];
1031                                                 bm_num = new_ec->changing_wall_texture;
1032
1033                                                 mprintf((0,"bm_num = %d\n",bm_num));
1034
1035                                                 new_ec->time_left = new_ec->vc.frame_time;
1036                                                 new_ec->frame_count = 0;
1037                                                 new_ec->segnum = seg-Segments;
1038                                                 new_ec->sidenum = side;
1039                                                 new_ec->flags |= EF_ONE_SHOT;
1040                                                 new_ec->dest_bm_num = Effects[ec].dest_bm_num;
1041
1042                                                 Assert(bm_num!=0 && seg->sides[side].tmap_num2!=0);
1043                                                 seg->sides[side].tmap_num2 = bm_num | tmf;              //replace with destoyed
1044
1045                                         }
1046                                         else {
1047                                                 Assert(db!=0 && seg->sides[side].tmap_num2!=0);
1048                                                 seg->sides[side].tmap_num2 = db | tmf;          //replace with destoyed
1049                                         }
1050                                 }
1051                                 else {
1052                                         seg->sides[side].tmap_num2 = TmapInfo[tm].destroyed | tmf;
1053
1054                                         //assume this is a light, and play light sound
1055                                         digi_link_sound_to_pos( SOUND_LIGHT_BLOWNUP, seg-Segments, 0, pnt,  0, F1_0 );
1056                                 }
1057
1058
1059                                 return 1;               //blew up!
1060                         }
1061                 }
1062         }
1063
1064         return 0;               //didn't blow up
1065 }
1066
1067 //      Copied from laser.c!
1068 #define MIN_OMEGA_BLOBS         3                               //      No matter how close the obstruction, at this many blobs created.
1069 #define MIN_OMEGA_DIST                  (F1_0*3)                //      At least this distance between blobs, unless doing so would violate MIN_OMEGA_BLOBS
1070 #define DESIRED_OMEGA_DIST      (F1_0*5)                //      This is the desired distance between blobs.  For distances > MIN_OMEGA_BLOBS*DESIRED_OMEGA_DIST, but not very large, this will apply.
1071 #define MAX_OMEGA_BLOBS         16                              //      No matter how far away the obstruction, this is the maximum number of blobs.
1072 #define MAX_OMEGA_DIST                  (MAX_OMEGA_BLOBS * DESIRED_OMEGA_DIST)          //      Maximum extent of lightning blobs.
1073
1074 //      -------------------------------------------------
1075 //      Return true if ok to do Omega damage.
1076 int ok_to_do_omega_damage(object *weapon)
1077 {
1078         int     parent_sig = weapon->ctype.laser_info.parent_signature;
1079         int     parent_num = weapon->ctype.laser_info.parent_num;
1080
1081         if (!(Game_mode & GM_MULTI))
1082                 return 1;
1083
1084         if (Objects[parent_num].signature != parent_sig)
1085                 mprintf((0, "Parent of omega blob not consistent with object information.\n"));
1086         else {
1087                 fix     dist = vm_vec_dist_quick(&Objects[parent_num].pos, &weapon->pos);
1088
1089                 if (dist > MAX_OMEGA_DIST) {
1090                         // -- mprintf((0, "Not doing damage in frame %i, too far away.\n", FrameCount));
1091                         return 0;
1092                 } else
1093                         ; // -- mprintf((0, "*** Doing damage in frame %i ***\n", FrameCount));
1094         }
1095
1096         return 1;
1097 }
1098
1099 //these gets added to the weapon's values when the weapon hits a volitle wall
1100 #define VOLATILE_WALL_EXPL_STRENGTH i2f(10)
1101 #define VOLATILE_WALL_IMPACT_SIZE       i2f(3)
1102 #define VOLATILE_WALL_DAMAGE_FORCE      i2f(5)
1103 #define VOLATILE_WALL_DAMAGE_RADIUS     i2f(30)
1104
1105 // int Show_seg_and_side = 0;
1106
1107 void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
1108 {
1109         segment *seg = &Segments[hitseg];
1110         int blew_up;
1111         int wall_type;
1112         int playernum;
1113         int     robot_escort;
1114
1115         if (weapon->id == OMEGA_ID)
1116                 if (!ok_to_do_omega_damage(weapon))
1117                         return;
1118
1119         //      If this is a guided missile and it strikes fairly directly, clear bounce flag.
1120         if (weapon->id == GUIDEDMISS_ID) {
1121                 fix     dot;
1122
1123                 dot = vm_vec_dot(&weapon->orient.fvec, &Segments[hitseg].sides[hitwall].normals[0]);
1124                 mprintf((0, "Guided missile dot = %7.3f\n", f2fl(dot)));
1125                 if (dot < -F1_0/6) {
1126                         mprintf((0, "Guided missile loses bounciness.\n"));
1127                         weapon->mtype.phys_info.flags &= ~PF_BOUNCE;
1128                 }
1129         }
1130
1131         //if an energy weapon hits a forcefield, let it bounce
1132         if ((TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_FORCE_FIELD) &&
1133                  !(weapon->type == OBJ_WEAPON && Weapon_info[weapon->id].energy_usage==0)) {
1134
1135                 //make sound
1136                 digi_link_sound_to_pos( SOUND_FORCEFIELD_BOUNCE_WEAPON, hitseg, 0, hitpt, 0, f1_0 );
1137 #ifdef NETWORK
1138                 if (Game_mode & GM_MULTI)
1139                         multi_send_play_sound(SOUND_FORCEFIELD_BOUNCE_WEAPON, f1_0);
1140 #endif
1141
1142                 return; //bail here. physics code will bounce this object
1143         }
1144
1145         #ifndef NDEBUG
1146         if (keyd_pressed[KEY_LAPOSTRO])
1147                 if (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum) {
1148                         //      MK: Real pain when you need to know a seg:side and you've got quad lasers.
1149                         mprintf((0, "Your laser hit at segment = %i, side = %i\n", hitseg, hitwall));
1150                         HUD_init_message("Hit at segment = %i, side = %i", hitseg, hitwall);
1151                         if (weapon->id < 4)
1152                                 subtract_light(hitseg, hitwall);
1153                         else if (weapon->id == FLARE_ID)
1154                                 add_light(hitseg, hitwall);
1155                 }
1156
1157                 //@@#ifdef EDITOR
1158                 //@@Cursegp = &Segments[hitseg];
1159                 //@@Curside = hitwall;
1160                 //@@#endif
1161         #endif
1162
1163         if ((weapon->mtype.phys_info.velocity.x == 0) && (weapon->mtype.phys_info.velocity.y == 0) && (weapon->mtype.phys_info.velocity.z == 0)) {
1164                 Int3(); //      Contact Matt: This is impossible.  A weapon with 0 velocity hit a wall, which doesn't move.
1165                 return;
1166         }
1167
1168         blew_up = check_effect_blowup(seg,hitwall,hitpt, weapon, 0);
1169
1170         //if ((seg->sides[hitwall].tmap_num2==0) && (TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_VOLATILE)) {
1171
1172         if ((weapon->ctype.laser_info.parent_type == OBJ_ROBOT) && (Robot_info[Objects[weapon->ctype.laser_info.parent_num].id].companion==1)) {
1173                 robot_escort = 1;
1174
1175                 if (Game_mode & GM_MULTI)
1176                  {
1177                          Int3();  // Get Jason!
1178                     return;
1179             }   
1180
1181
1182                 playernum = Player_num;         //if single player, he's the player's buddy
1183         }
1184         else {
1185                 robot_escort = 0;
1186
1187                 if (Objects[weapon->ctype.laser_info.parent_num].type == OBJ_PLAYER)
1188                         playernum = Objects[weapon->ctype.laser_info.parent_num].id;
1189                 else
1190                         playernum = -1;         //not a player (thus a robot)
1191         }
1192
1193         if (blew_up) {          //could be a wall switch
1194                 //for wall triggers, always say that the player shot it out.  This is
1195                 //because robots can shoot out wall triggers, and so the trigger better
1196                 //take effect  
1197                 //      NO -- Changed by MK, 10/18/95.  We don't want robots blowing puzzles.  Only player or buddy can open!
1198                 check_trigger(seg,hitwall,weapon->ctype.laser_info.parent_num,1);
1199         }
1200
1201         if (weapon->id == EARTHSHAKER_ID)
1202                 smega_rock_stuff();
1203
1204         wall_type = wall_hit_process( seg, hitwall, weapon->shields, playernum, weapon );
1205
1206         // Wall is volatile if either tmap 1 or 2 is volatile
1207         if ((TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_VOLATILE) || (seg->sides[hitwall].tmap_num2 && (TmapInfo[seg->sides[hitwall].tmap_num2&0x3fff].flags & TMI_VOLATILE))) {
1208                 weapon_info *wi = &Weapon_info[weapon->id];
1209                 int vclip;
1210
1211                 //we've hit a volatile wall
1212
1213                 digi_link_sound_to_pos( SOUND_VOLATILE_WALL_HIT,hitseg, 0, hitpt, 0, F1_0 );
1214
1215                 //for most weapons, use volatile wall hit.  For mega, use its special vclip
1216                 vclip = (weapon->id == MEGA_ID)?Weapon_info[weapon->id].robot_hit_vclip:VCLIP_VOLATILE_WALL_HIT;
1217
1218                 //      New by MK: If powerful badass, explode as badass, not due to lava, fixes megas being wimpy in lava.
1219                 if (wi->damage_radius >= VOLATILE_WALL_DAMAGE_RADIUS/2) {
1220                         // -- mprintf((0, "Big weapon doing badass in lava instead.\n"));
1221                         explode_badass_weapon(weapon,hitpt);
1222                 } else {
1223                         object_create_badass_explosion( weapon, hitseg, hitpt, 
1224                                 wi->impact_size + VOLATILE_WALL_IMPACT_SIZE,
1225                                 vclip,
1226                                 wi->strength[Difficulty_level]/4+VOLATILE_WALL_EXPL_STRENGTH,   //      diminished by mk on 12/08/94, i was doing 70 damage hitting lava on lvl 1.
1227                                 wi->damage_radius+VOLATILE_WALL_DAMAGE_RADIUS,
1228                                 wi->strength[Difficulty_level]/2+VOLATILE_WALL_DAMAGE_FORCE,
1229                                 weapon->ctype.laser_info.parent_num );
1230                 }
1231
1232                 weapon->flags |= OF_SHOULD_BE_DEAD;             //make flares die in lava
1233
1234         }
1235         else if ((TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_WATER) || (seg->sides[hitwall].tmap_num2 && (TmapInfo[seg->sides[hitwall].tmap_num2&0x3fff].flags & TMI_WATER))) {
1236                 weapon_info *wi = &Weapon_info[weapon->id];
1237
1238                 //we've hit water
1239
1240                 //      MK: 09/13/95: Badass in water is 1/2 normal intensity.
1241                 if ( Weapon_info[weapon->id].matter ) {
1242
1243                         digi_link_sound_to_pos( SOUND_MISSILE_HIT_WATER,hitseg, 0, hitpt, 0, F1_0 );
1244
1245                         if ( Weapon_info[weapon->id].damage_radius ) {
1246
1247                                 digi_link_sound_to_object(SOUND_BADASS_EXPLOSION, weapon-Objects, 0, F1_0);
1248
1249                                 //      MK: 09/13/95: Badass in water is 1/2 normal intensity.
1250                                 object_create_badass_explosion( weapon, hitseg, hitpt, 
1251                                         wi->impact_size/2,
1252                                         wi->robot_hit_vclip, 
1253                                         wi->strength[Difficulty_level]/4,
1254                                         wi->damage_radius,
1255                                         wi->strength[Difficulty_level]/2,
1256                                         weapon->ctype.laser_info.parent_num );
1257                         }
1258                         else
1259                                 object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].wall_hit_vclip );
1260
1261                 } else {
1262                         digi_link_sound_to_pos( SOUND_LASER_HIT_WATER,hitseg, 0, hitpt, 0, F1_0 );
1263                         object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, VCLIP_WATER_HIT );
1264                 }
1265
1266                 weapon->flags |= OF_SHOULD_BE_DEAD;             //make flares die in water
1267
1268         }
1269         else {
1270
1271                 if (weapon->mtype.phys_info.flags & PF_BOUNCE) {
1272
1273                         //do special bound sound & effect
1274
1275                 }
1276                 else {
1277
1278                         //if it's not the player's weapon, or it is the player's and there
1279                         //is no wall, and no blowing up monitor, then play sound
1280                         if ((weapon->ctype.laser_info.parent_type != OBJ_PLAYER) ||     ((seg->sides[hitwall].wall_num == -1 || wall_type==WHP_NOT_SPECIAL) && !blew_up))
1281                                 if ((Weapon_info[weapon->id].wall_hit_sound > -1 ) && (!(weapon->flags & OF_SILENT)))
1282                                 digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound,weapon->segnum, 0, &weapon->pos, 0, F1_0 );
1283                 
1284                         if ( Weapon_info[weapon->id].wall_hit_vclip > -1 )      {
1285                                 if ( Weapon_info[weapon->id].damage_radius )
1286                                         explode_badass_weapon(weapon,hitpt);
1287                                 else
1288                                         object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].wall_hit_vclip );
1289                         }
1290                 }
1291         }
1292
1293         //      If weapon fired by player or companion...
1294         if (( weapon->ctype.laser_info.parent_type== OBJ_PLAYER ) || robot_escort) {
1295
1296                 if (!(weapon->flags & OF_SILENT) && (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum))
1297                         create_awareness_event(weapon, PA_WEAPON_WALL_COLLISION);                       // object "weapon" can attract attention to player
1298         
1299 //              if (weapon->id != FLARE_ID) {
1300 //      We now allow flares to open doors.
1301                 {
1302
1303                         if (((weapon->id != FLARE_ID) || (weapon->ctype.laser_info.parent_type != OBJ_PLAYER)) && !(weapon->mtype.phys_info.flags & PF_BOUNCE))
1304                                 weapon->flags |= OF_SHOULD_BE_DEAD;
1305
1306                         //don't let flares stick in force fields
1307                         if ((weapon->id == FLARE_ID) && (TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_FORCE_FIELD))
1308                                 weapon->flags |= OF_SHOULD_BE_DEAD;
1309
1310                         if (!(weapon->flags & OF_SILENT)) {
1311                                 switch (wall_type) {
1312
1313                                         case WHP_NOT_SPECIAL:
1314                                                 //should be handled above
1315                                                 //digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
1316                                                 break;
1317
1318                                         case WHP_NO_KEY:
1319                                                 //play special hit door sound (if/when we get it)
1320                                                 digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
1321 #ifdef NETWORK
1322                                  if (Game_mode & GM_MULTI)
1323                                                         multi_send_play_sound( SOUND_WEAPON_HIT_DOOR, F1_0 );
1324 #endif
1325
1326                                                 break;
1327
1328                                         case WHP_BLASTABLE:
1329                                                 //play special blastable wall sound (if/when we get it)
1330                                                 if ((Weapon_info[weapon->id].wall_hit_sound > -1 ) && (!(weapon->flags & OF_SILENT)))
1331                                                         digi_link_sound_to_pos( SOUND_WEAPON_HIT_BLASTABLE, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
1332                                                 break;
1333
1334                                         case WHP_DOOR:
1335                                                 //don't play anything, since door open sound will play
1336                                                 break;
1337                                 }
1338                         } // else
1339                                 //mprintf((0, "Weapon %i hits wall, but has silent bit set.\n", weapon-Objects));
1340                 } // else {
1341                         //      if (weapon->lifeleft <= 0)
1342                         //      weapon->flags |= OF_SHOULD_BE_DEAD;
1343                 // }
1344
1345         } else {
1346                 // This is a robot's laser
1347                 if (!(weapon->mtype.phys_info.flags & PF_BOUNCE))
1348                         weapon->flags |= OF_SHOULD_BE_DEAD;
1349         }
1350
1351         return;
1352 }
1353
1354 //##void collide_camera_and_wall( object * camera, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)       {
1355 //##    return;
1356 //##}
1357
1358 //##void collide_powerup_and_wall( object * powerup, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)     {
1359 //##    return;
1360 //##}
1361
1362 void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)   {       
1363         explode_object(debris,0);
1364         return;
1365 }
1366
1367 //##void collide_fireball_and_fireball( object * fireball1, object * fireball2, vms_vector *collision_point ) {
1368 //##    return; 
1369 //##}
1370
1371 //##void collide_fireball_and_robot( object * fireball, object * robot, vms_vector *collision_point ) {
1372 //##    return; 
1373 //##}
1374
1375 //##void collide_fireball_and_hostage( object * fireball, object * hostage, vms_vector *collision_point ) {
1376 //##    return; 
1377 //##}
1378
1379 //##void collide_fireball_and_player( object * fireball, object * player, vms_vector *collision_point ) {
1380 //##    return; 
1381 //##}
1382
1383 //##void collide_fireball_and_weapon( object * fireball, object * weapon, vms_vector *collision_point ) { 
1384 //##    //weapon->flags |= OF_SHOULD_BE_DEAD;
1385 //##    return; 
1386 //##}
1387
1388 //##void collide_fireball_and_camera( object * fireball, object * camera, vms_vector *collision_point ) { 
1389 //##    return; 
1390 //##}
1391
1392 //##void collide_fireball_and_powerup( object * fireball, object * powerup, vms_vector *collision_point ) { 
1393 //##    return; 
1394 //##}
1395
1396 //##void collide_fireball_and_debris( object * fireball, object * debris, vms_vector *collision_point ) { 
1397 //##    return; 
1398 //##}
1399
1400 //      -------------------------------------------------------------------------------------------------------------------
1401 void collide_robot_and_robot( object * robot1, object * robot2, vms_vector *collision_point ) { 
1402 //      mprintf((0, "Coll: [%2i %4i %4i %4i] [%2i %4i %4i %4i] at [%4i %4i %4i]", 
1403 //              robot1-Objects, f2i(robot1->pos.x), f2i(robot1->pos.y), f2i(robot1->pos.z),
1404 //              robot2-Objects, f2i(robot2->pos.x), f2i(robot2->pos.y), f2i(robot2->pos.z),
1405 //              f2i(collision_point->x), f2i(collision_point->y), f2i(collision_point->z)));
1406
1407         bump_two_objects(robot1, robot2, 1);
1408         return; 
1409 }
1410
1411 void collide_robot_and_controlcen( object * obj1, object * obj2, vms_vector *collision_point )
1412 {
1413
1414         if (obj1->type == OBJ_ROBOT) {
1415                 vms_vector      hitvec;
1416                 vm_vec_normalize_quick(vm_vec_sub(&hitvec, &obj2->pos, &obj1->pos));
1417                 bump_one_object(obj1, &hitvec, 0);
1418         } else {
1419                 vms_vector      hitvec;
1420                 vm_vec_normalize_quick(vm_vec_sub(&hitvec, &obj1->pos, &obj2->pos));
1421                 bump_one_object(obj2, &hitvec, 0);
1422         }
1423
1424 }
1425
1426 //##void collide_robot_and_hostage( object * robot, object * hostage, vms_vector *collision_point ) { 
1427 //##    return; 
1428 //##}
1429
1430 fix Last_thief_hit_time;
1431
1432 void collide_robot_and_player( object * robot, object * playerobj, vms_vector *collision_point )
1433
1434         int     steal_attempt = 0;
1435         int     collision_seg;
1436
1437         if (robot->flags&OF_EXPLODING)
1438                 return;
1439
1440         collision_seg = find_point_seg(collision_point, playerobj->segnum);
1441         if (collision_seg != -1)
1442                 object_create_explosion( collision_seg, collision_point, Weapon_info[0].impact_size, Weapon_info[0].wall_hit_vclip );
1443
1444         if (playerobj->id == Player_num) {
1445                 if (Robot_info[robot->id].companion)    //      Player and companion don't collide.
1446                         return;
1447                 if (Robot_info[robot->id].kamikaze) {
1448                         apply_damage_to_robot(robot, robot->shields+1, playerobj-Objects);
1449                         if (playerobj == ConsoleObject)
1450                                 add_points_to_score(Robot_info[robot->id].score_value);
1451                 }
1452
1453                 if (Robot_info[robot->id].thief) {
1454                         if (Ai_local_info[robot-Objects].mode == AIM_THIEF_ATTACK) {
1455                                 Last_thief_hit_time = GameTime;
1456                                 attempt_to_steal_item(robot, playerobj->id);
1457                                 steal_attempt = 1;
1458                         } else if (GameTime - Last_thief_hit_time < F1_0*2)
1459                                 return;         //      ZOUNDS!  BRILLIANT!  Thief not collide with player if not stealing!
1460                                                                 // NO!  VERY DUMB!  makes thief look very stupid if player hits him while cloaked! -AP
1461                         else
1462                                 Last_thief_hit_time = GameTime;
1463                 }
1464
1465                 create_awareness_event(playerobj, PA_PLAYER_COLLISION);                 // object robot can attract attention to player
1466                 do_ai_robot_hit_attack(robot, playerobj, collision_point);
1467                 do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION);
1468         } 
1469 #ifdef NETWORK
1470         else
1471                 multi_robot_request_change(robot, playerobj->id);
1472 #endif
1473
1474         // added this if to remove the bump sound if it's the thief.
1475         // A "steal" sound was added and it was getting obscured by the bump. -AP 10/3/95
1476         //      Changed by MK to make this sound unless the robot stole.
1477         if ((!steal_attempt) && !Robot_info[robot->id].energy_drain)
1478                 digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, playerobj->segnum, 0, collision_point, 0, F1_0 );
1479
1480         bump_two_objects(robot, playerobj, 1);
1481         return; 
1482 }
1483
1484 // Provide a way for network message to instantly destroy the control center
1485 // without awarding points or anything.
1486
1487 //      if controlcen == NULL, that means don't do the explosion because the control center
1488 //      was actually in another object.
1489 void net_destroy_controlcen(object *controlcen)
1490 {
1491         if (Control_center_destroyed != 1) {
1492
1493                 do_controlcen_destroyed_stuff(controlcen);
1494
1495                 if ((controlcen != NULL) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED))) {
1496                         digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 );
1497                         explode_object(controlcen,0);
1498                 }
1499         }
1500
1501 }
1502
1503 //      -----------------------------------------------------------------------------
1504 void apply_damage_to_controlcen(object *controlcen, fix damage, short who)
1505 {
1506         int     whotype;
1507
1508         //      Only allow a player to damage the control center.
1509
1510         if ((who < 0) || (who > Highest_object_index))
1511                 return;
1512
1513         whotype = Objects[who].type;
1514         if (whotype != OBJ_PLAYER) {
1515                 mprintf((0, "Damage to control center by object of type %i prevented by MK!\n", whotype));
1516                 return;
1517         }
1518
1519         #ifdef NETWORK
1520         if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) && (Players[Player_num].time_level < Netgame.control_invul_time))
1521         {
1522                 if (Objects[who].id == Player_num) {
1523                         int secs = f2i(Netgame.control_invul_time-Players[Player_num].time_level) % 60;
1524                         int mins = f2i(Netgame.control_invul_time-Players[Player_num].time_level) / 60;
1525                         HUD_init_message("%s %d:%02d.", TXT_CNTRLCEN_INVUL, mins, secs);
1526                 }
1527                 return;
1528         }
1529         #endif
1530
1531         if (Objects[who].id == Player_num) {
1532                 Control_center_been_hit = 1;
1533                 ai_do_cloak_stuff();
1534         }
1535
1536         if ( controlcen->shields >= 0 )
1537                 controlcen->shields -= damage;
1538
1539         if ( (controlcen->shields < 0) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED)) ) {
1540
1541                 do_controlcen_destroyed_stuff(controlcen);
1542
1543                 #ifdef NETWORK
1544                 if (Game_mode & GM_MULTI) {
1545                         if (who == Players[Player_num].objnum)
1546                                 add_points_to_score(CONTROL_CEN_SCORE);
1547                         multi_send_destroy_controlcen((ushort)(controlcen-Objects), Objects[who].id );
1548                 }
1549                 #endif
1550
1551                 if (!(Game_mode & GM_MULTI))
1552                         add_points_to_score(CONTROL_CEN_SCORE);
1553
1554                 digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 );
1555
1556                 explode_object(controlcen,0);
1557         }
1558 }
1559
1560 void collide_player_and_controlcen( object * controlcen, object * playerobj, vms_vector *collision_point )
1561
1562         if (playerobj->id == Player_num) {
1563                 Control_center_been_hit = 1;
1564                 ai_do_cloak_stuff();                            //      In case player cloaked, make control center know where he is.
1565         }
1566
1567         digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, playerobj->segnum, 0, collision_point, 0, F1_0 );
1568         bump_two_objects(controlcen, playerobj, 1);
1569
1570         return; 
1571 }
1572
1573 void collide_player_and_marker( object * marker, object * playerobj, vms_vector *collision_point )
1574
1575    mprintf ((0,"Collided with marker %d!\n",marker->id));
1576
1577         if (playerobj->id==Player_num) {
1578                 int drawn;
1579
1580                 if (Game_mode & GM_MULTI)
1581                 {
1582                         drawn = HUD_init_message ("MARKER %s: %s",Players[marker->id/2].callsign,MarkerMessage[marker->id]);
1583                 }
1584                 else
1585                 {
1586                         if (MarkerMessage[marker->id][0])
1587                                 drawn = HUD_init_message("MARKER %d: %s", marker->id+1,MarkerMessage[marker->id]);
1588                         else
1589                                 drawn = HUD_init_message("MARKER %d", marker->id+1);
1590            }
1591
1592                 if (drawn)
1593                         digi_play_sample( SOUND_MARKER_HIT, F1_0 );
1594
1595                 detect_escort_goal_accomplished(marker-Objects);
1596    }
1597 }
1598
1599 //      If a persistent weapon and other object is not a weapon, weaken it, else kill it.
1600 //      If both objects are weapons, weaken the weapon.
1601 void maybe_kill_weapon(object *weapon, object *other_obj)
1602 {
1603         if ((weapon->id == PROXIMITY_ID) || (weapon->id == SUPERPROX_ID) || (weapon->id == PMINE_ID)) {
1604                 weapon->flags |= OF_SHOULD_BE_DEAD;
1605                 return;
1606         }
1607
1608         //      Changed, 10/12/95, MK: Make weapon-weapon collisions always kill both weapons if not persistent.
1609         //      Reason: Otherwise you can't use proxbombs to detonate incoming homing missiles (or mega missiles).
1610         if (weapon->mtype.phys_info.flags & PF_PERSISTENT) {
1611                 //      Weapons do a lot of damage to weapons, other objects do much less.
1612                 if (!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) {
1613                         if (other_obj->type == OBJ_WEAPON)
1614                                 weapon->shields -= other_obj->shields/2;
1615                         else
1616                                 weapon->shields -= other_obj->shields/4;
1617
1618                         if (weapon->shields <= 0) {
1619                                 weapon->shields = 0;
1620                                 weapon->flags |= OF_SHOULD_BE_DEAD;     // weapon->lifeleft = 1;
1621                         }
1622                 }
1623         } else
1624                 weapon->flags |= OF_SHOULD_BE_DEAD;     // weapon->lifeleft = 1;
1625
1626 // --   if ((weapon->mtype.phys_info.flags & PF_PERSISTENT) || (other_obj->type == OBJ_WEAPON)) {
1627 // --           //      Weapons do a lot of damage to weapons, other objects do much less.
1628 // --           if (!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) {
1629 // --                   if (other_obj->type == OBJ_WEAPON)
1630 // --                           weapon->shields -= other_obj->shields/2;
1631 // --                   else
1632 // --                           weapon->shields -= other_obj->shields/4;
1633 // -- 
1634 // --                   if (weapon->shields <= 0) {
1635 // --                           weapon->shields = 0;
1636 // --                           weapon->flags |= OF_SHOULD_BE_DEAD;
1637 // --                   }
1638 // --           }
1639 // --   } else
1640 // --           weapon->flags |= OF_SHOULD_BE_DEAD;
1641 }
1642
1643 void collide_weapon_and_controlcen( object * weapon, object *controlcen, vms_vector *collision_point  )
1644 {
1645
1646         if (weapon->id == OMEGA_ID)
1647                 if (!ok_to_do_omega_damage(weapon))
1648                         return;
1649
1650         if (weapon->ctype.laser_info.parent_type == OBJ_PLAYER) {
1651                 fix     damage = weapon->shields;
1652
1653                 if (Objects[weapon->ctype.laser_info.parent_num].id == Player_num)
1654                         Control_center_been_hit = 1;
1655
1656                 if ( Weapon_info[weapon->id].damage_radius )
1657                         explode_badass_weapon(weapon,collision_point);
1658                 else
1659                         object_create_explosion( controlcen->segnum, collision_point, controlcen->size*3/20, VCLIP_SMALL_EXPLOSION );
1660
1661                 digi_link_sound_to_pos( SOUND_CONTROL_CENTER_HIT, controlcen->segnum, 0, collision_point, 0, F1_0 );
1662
1663                 damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
1664
1665                 apply_damage_to_controlcen(controlcen, damage, weapon->ctype.laser_info.parent_num);
1666
1667                 maybe_kill_weapon(weapon,controlcen);
1668         } else {        //      If robot weapon hits control center, blow it up, make it go away, but do no damage to control center.
1669                 object_create_explosion( controlcen->segnum, collision_point, controlcen->size*3/20, VCLIP_SMALL_EXPLOSION );
1670                 maybe_kill_weapon(weapon,controlcen);
1671         }
1672
1673 }
1674
1675 void collide_weapon_and_clutter( object * weapon, object *clutter, vms_vector *collision_point  )       {
1676         short exp_vclip = VCLIP_SMALL_EXPLOSION;
1677
1678         if ( clutter->shields >= 0 )
1679                 clutter->shields -= weapon->shields;
1680
1681         digi_link_sound_to_pos( SOUND_LASER_HIT_CLUTTER, weapon->segnum, 0, collision_point, 0, F1_0 );
1682  
1683         object_create_explosion( clutter->segnum, collision_point, ((clutter->size/3)*3)/4, exp_vclip );
1684
1685         if ( (clutter->shields < 0) && !(clutter->flags&(OF_EXPLODING|OF_DESTROYED)))
1686                 explode_object(clutter,STANDARD_EXPL_DELAY);
1687
1688         maybe_kill_weapon(weapon,clutter);
1689 }
1690
1691 //--mk, 121094 -- extern void spin_robot(object *robot, vms_vector *collision_point);
1692
1693 extern object *explode_badass_object(object *objp, fix damage, fix distance, fix force);
1694
1695 int     Final_boss_is_dead = 0;
1696 fix     Final_boss_countdown_time = 0;
1697
1698 //      ------------------------------------------------------------------------------------------------------
1699 void do_final_boss_frame(void)
1700 {
1701
1702         if (!Final_boss_is_dead)
1703                 return;
1704
1705         if (!Control_center_destroyed)
1706                 return;
1707
1708         if (Final_boss_countdown_time == 0)
1709                 Final_boss_countdown_time = F1_0*2;
1710
1711         Final_boss_countdown_time -= FrameTime;
1712         if (Final_boss_countdown_time > 0)
1713                 return;
1714
1715         gr_palette_fade_out( gr_palette, 256, 0 );
1716         start_endlevel_sequence();              //pretend we hit the exit trigger
1717
1718 }
1719
1720 //      ------------------------------------------------------------------------------------------------------
1721 //      This is all the ugly stuff we do when you kill the final boss so that you don't die or something
1722 //      which would ruin the logic of the cut sequence.
1723 void do_final_boss_hacks(void)
1724 {
1725         if (Player_is_dead) {
1726                 Int3();         //      Uh-oh, player is dead.  Try to rescue him.
1727                 Player_is_dead = 0;
1728         }
1729
1730         if (Players[Player_num].shields <= 0)
1731                 Players[Player_num].shields = 1;
1732
1733         //      If you're not invulnerable, get invulnerable!
1734         if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) {
1735                 Players[Player_num].invulnerable_time = GameTime;
1736                 Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE;
1737         }
1738         if (!(Game_mode & GM_MULTI))
1739                 buddy_message("Nice job, %s!", Players[Player_num].callsign);
1740
1741         Final_boss_is_dead = 1;
1742 }
1743
1744 extern int Buddy_dude_cheat;
1745 extern int multi_all_players_alive();
1746 void multi_send_finish_game ();
1747
1748 //      ------------------------------------------------------------------------------------------------------
1749 //      Return 1 if robot died, else return 0
1750 int apply_damage_to_robot(object *robot, fix damage, int killer_objnum)
1751 {
1752 #ifdef NETWORK
1753    char isthief;
1754         char i,temp_stolen[MAX_STOLEN_ITEMS];   
1755 #endif
1756         
1757         if ( robot->flags&OF_EXPLODING) return 0;
1758
1759         if (robot->shields < 0 ) return 0;      //robot already dead...
1760
1761         if (Robot_info[robot->id].boss_flag)
1762                 Boss_hit_time = GameTime;
1763
1764         //      Buddy invulnerable on level 24 so he can give you his important messages.  Bah.
1765         //      Also invulnerable if his cheat for firing weapons is in effect.
1766         if (Robot_info[robot->id].companion) {
1767 //              if ((Current_mission_num == Builtin_mission_num && Current_level_num == Last_level) || Buddy_dude_cheat)
1768 #ifdef NETWORK
1769                 if ((Current_mission_num == Builtin_mission_num && Current_level_num == Last_level) )
1770                         return 0;
1771 #endif
1772         }
1773
1774 //      if (robot->control_type == CT_REMOTE)
1775 //              return 0; // Can't damange a robot controlled by another player
1776
1777 // -- MK, 10/21/95, unused! --  if (Robot_info[robot->id].boss_flag)
1778 //              Boss_been_hit = 1;
1779
1780         robot->shields -= damage;
1781
1782         //      Do unspeakable hacks to make sure player doesn't die after killing boss.  Or before, sort of.
1783         if (Robot_info[robot->id].boss_flag)
1784 #ifdef NETWORK
1785                 if ((Current_mission_num == Builtin_mission_num) && Current_level_num == Last_level)
1786 #endif
1787                         if (robot->shields < 0)
1788                          {
1789 #ifdef NETWORK
1790                                 if (Game_mode & GM_MULTI)
1791                                   {
1792                                          if (!multi_all_players_alive()) // everyones gotta be alive
1793                                            robot->shields=1;
1794                                          else
1795                                           {
1796                                             multi_send_finish_game();
1797                                             do_final_boss_hacks();
1798                                           }             
1799                                   
1800                                         }               
1801                                 else
1802 #endif
1803                                   {     // NOTE LINK TO ABOVE!!!
1804                                         if ((Players[Player_num].shields < 0) || Player_is_dead)
1805                                                 robot->shields = 1;             //      Sorry, we can't allow you to kill the final boss after you've died.  Rough luck.
1806                                         else
1807                                                 do_final_boss_hacks();
1808                                   }
1809                           }
1810
1811         if (robot->shields < 0) {
1812 #ifdef NETWORK
1813                 if (Game_mode & GM_MULTI) {
1814                  if (Robot_info[robot->id].thief)       
1815                         isthief=1;
1816                  else
1817                         isthief=0;
1818
1819                  if (isthief)
1820                         for (i=0;i<MAX_STOLEN_ITEMS;i++)
1821                          temp_stolen[(int)i]=Stolen_items[(int)i];
1822                                 
1823                         if (multi_explode_robot_sub(robot-Objects, killer_objnum,Robot_info[robot->id].thief))
1824                         {
1825                          if (isthief)   
1826                         for (i=0;i<MAX_STOLEN_ITEMS;i++)
1827                                   Stolen_items[(int)i]=temp_stolen[(int)i];
1828                                         
1829                                 multi_send_robot_explode(robot-Objects, killer_objnum,Robot_info[robot->id].thief);
1830
1831                    if (isthief) 
1832                                 for (i=0;i<MAX_STOLEN_ITEMS;i++)
1833                                           Stolen_items[(int)i]=255;
1834
1835                                 return 1;
1836                         }
1837                         else
1838                                 return 0;
1839                 }
1840 #endif
1841
1842                 Players[Player_num].num_kills_level++;
1843                 Players[Player_num].num_kills_total++;
1844
1845                 if (Robot_info[robot->id].boss_flag) {
1846                         start_boss_death_sequence(robot);       //do_controlcen_destroyed_stuff(NULL);
1847                 } else if (Robot_info[robot->id].death_roll) {
1848                         start_robot_death_sequence(robot);      //do_controlcen_destroyed_stuff(NULL);
1849                 } else {
1850                         if (robot->id == SPECIAL_REACTOR_ROBOT)
1851                                 special_reactor_stuff();
1852                         //if (Robot_info[robot->id].smart_blobs)
1853                         //      create_smart_children(robot, Robot_info[robot->id].smart_blobs);
1854                         //if (Robot_info[robot->id].badass)
1855                         //      explode_badass_object(robot, F1_0*Robot_info[robot->id].badass, F1_0*40, F1_0*150);
1856                         if (Robot_info[robot->id].kamikaze)
1857                                 explode_object(robot,1);                //      Kamikaze, explode right away, IN YOUR FACE!
1858                         else
1859                                 explode_object(robot,STANDARD_EXPL_DELAY);
1860                 }
1861                 return 1;
1862         } else
1863                 return 0;
1864 }
1865
1866 extern int boss_spew_robot(object *objp, vms_vector *pos);
1867
1868 //--ubyte       Boss_teleports[NUM_D2_BOSSES] =                                 {1,1,1,1,1,1};          // Set byte if this boss can teleport
1869 //--ubyte       Boss_cloaks[NUM_D2_BOSSES] =                                    {1,1,1,1,1,1};          // Set byte if this boss can cloak
1870 //--ubyte       Boss_spews_bots_energy[NUM_D2_BOSSES] =         {1,1,0,0,1,1};          //      Set byte if boss spews bots when hit by energy weapon.
1871 //--ubyte       Boss_spews_bots_matter[NUM_D2_BOSSES] =         {0,0,1,0,1,1};          //      Set byte if boss spews bots when hit by matter weapon.
1872 //--ubyte       Boss_invulnerable_energy[NUM_D2_BOSSES] = {0,0,1,1,0,0};                //      Set byte if boss is invulnerable to energy weapons.
1873 //--ubyte       Boss_invulnerable_matter[NUM_D2_BOSSES] = {0,0,0,1,0,0};                //      Set byte if boss is invulnerable to matter weapons.
1874 //--ubyte       Boss_invulnerable_spot[NUM_D2_BOSSES] =         {0,0,0,0,1,1};          //      Set byte if boss is invulnerable in all but a certain spot.  (Dot product fvec|vec_to_collision < BOSS_INVULNERABLE_DOT)
1875
1876 //#define       BOSS_INVULNERABLE_DOT   0               //      If a boss is invulnerable over most of his body, fvec(dot)vec_to_collision must be less than this for damage to occur.
1877 int     Boss_invulnerable_dot = 0;
1878
1879 int     Buddy_gave_hint_count = 5;
1880 fix     Last_time_buddy_gave_hint = 0;
1881
1882 //      ------------------------------------------------------------------------------------------------------
1883 //      Return true if damage done to boss, else return false.
1884 int do_boss_weapon_collision(object *robot, object *weapon, vms_vector *collision_point)
1885 {
1886         int     d2_boss_index;
1887         int     damage_flag;
1888
1889         damage_flag = 1;
1890
1891         d2_boss_index = Robot_info[robot->id].boss_flag - BOSS_D2;
1892
1893         Assert((d2_boss_index >= 0) && (d2_boss_index < NUM_D2_BOSSES));
1894
1895         //      See if should spew a bot.
1896         if (weapon->ctype.laser_info.parent_type == OBJ_PLAYER)
1897                 if ((Weapon_info[weapon->id].matter && Boss_spews_bots_matter[d2_boss_index]) || (!Weapon_info[weapon->id].matter && Boss_spews_bots_energy[d2_boss_index])) {
1898                         if (Boss_spew_more[d2_boss_index])
1899                                 if (d_rand() > 16384) {
1900                                         if (boss_spew_robot(robot, collision_point) != -1)
1901                                                 Last_gate_time = GameTime - Gate_interval - 1;  //      Force allowing spew of another bot.
1902                                 }
1903                         boss_spew_robot(robot, collision_point);
1904                 }
1905
1906         if (Boss_invulnerable_spot[d2_boss_index]) {
1907                 fix                     dot;
1908                 vms_vector      tvec1;
1909
1910                 //      Boss only vulnerable in back.  See if hit there.
1911                 vm_vec_sub(&tvec1, collision_point, &robot->pos);
1912                 vm_vec_normalize_quick(&tvec1); //      Note, if BOSS_INVULNERABLE_DOT is close to F1_0 (in magnitude), then should probably use non-quick version.
1913                 dot = vm_vec_dot(&tvec1, &robot->orient.fvec);
1914                 mprintf((0, "Boss hit vec dot = %7.3f\n", f2fl(dot)));
1915
1916                 if (dot > Boss_invulnerable_dot) {
1917                         int     new_obj;
1918                         int     segnum;
1919
1920                         segnum = find_point_seg(collision_point, robot->segnum);
1921                         digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, segnum, 0, collision_point, 0, F1_0);
1922                         damage_flag = 0;
1923
1924                         if (Last_time_buddy_gave_hint == 0)
1925                                 Last_time_buddy_gave_hint = d_rand()*32 + F1_0*16;
1926
1927                         if (Buddy_gave_hint_count) {
1928                                 if (Last_time_buddy_gave_hint + F1_0*20 < GameTime) {
1929                                         int     sval;
1930
1931                                         Buddy_gave_hint_count--;
1932                                         Last_time_buddy_gave_hint = GameTime;
1933                                         sval = (d_rand()*4) >> 15;
1934                                         switch (sval) {
1935                                                 case 0: buddy_message("Hit him in the back!");  break;
1936                                                 case 1: buddy_message("He's invulnerable there!");      break;
1937                                                 case 2: buddy_message("Get behind him and fire!");      break;
1938                                                 case 3:
1939                                                 default:
1940                                                                         buddy_message("Hit the glowing spot!"); break;
1941                                         }
1942                                 }
1943                         }
1944
1945                         //      Cause weapon to bounce.
1946                         //      Make a copy of this weapon, because the physics wants to destroy it.
1947                         if (!Weapon_info[weapon->id].matter) {
1948                                 new_obj = obj_create(weapon->type, weapon->id, weapon->segnum, &weapon->pos,
1949                                         &weapon->orient, weapon->size, weapon->control_type, weapon->movement_type, weapon->render_type);
1950
1951                                 if (new_obj != -1) {
1952                                         vms_vector      vec_to_point;
1953                                         vms_vector      weap_vec;
1954                                         fix                     speed;
1955
1956                                         if (weapon->render_type == RT_POLYOBJ) {
1957                                                 Objects[new_obj].rtype.pobj_info.model_num = Weapon_info[Objects[new_obj].id].model_num;
1958                                                 Objects[new_obj].size = fixdiv(Polygon_models[Objects[new_obj].rtype.pobj_info.model_num].rad,Weapon_info[Objects[new_obj].id].po_len_to_width_ratio);
1959                                         }
1960
1961                                         Objects[new_obj].mtype.phys_info.mass = Weapon_info[weapon->type].mass;
1962                                         Objects[new_obj].mtype.phys_info.drag = Weapon_info[weapon->type].drag;
1963                                         vm_vec_zero(&Objects[new_obj].mtype.phys_info.thrust);
1964
1965                                         vm_vec_sub(&vec_to_point, collision_point, &robot->pos);
1966                                         vm_vec_normalize_quick(&vec_to_point);
1967                                         weap_vec = weapon->mtype.phys_info.velocity;
1968                                         speed = vm_vec_normalize_quick(&weap_vec);
1969                                         vm_vec_scale_add2(&vec_to_point, &weap_vec, -F1_0*2);
1970                                         vm_vec_scale(&vec_to_point, speed/4);
1971                                         Objects[new_obj].mtype.phys_info.velocity = vec_to_point;
1972                                 }
1973                         }
1974                 }
1975         } else if ((Weapon_info[weapon->id].matter && Boss_invulnerable_matter[d2_boss_index]) || (!Weapon_info[weapon->id].matter && Boss_invulnerable_energy[d2_boss_index])) {
1976                 int     segnum;
1977
1978                 segnum = find_point_seg(collision_point, robot->segnum);
1979                 digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, segnum, 0, collision_point, 0, F1_0);
1980                 damage_flag = 0;
1981         }
1982
1983         return damage_flag;
1984 }
1985
1986 extern int Robots_kill_robots_cheat;
1987
1988 //      ------------------------------------------------------------------------------------------------------
1989 void collide_robot_and_weapon( object * robot, object * weapon, vms_vector *collision_point )
1990
1991         int     damage_flag=1;
1992         int     boss_invul_flag=0;
1993
1994         if (weapon->id == OMEGA_ID)
1995                 if (!ok_to_do_omega_damage(weapon))
1996                         return;
1997
1998         if (Robot_info[robot->id].boss_flag) {
1999                 Boss_hit_time = GameTime;
2000                 if (Robot_info[robot->id].boss_flag >= BOSS_D2) {
2001                         damage_flag = do_boss_weapon_collision(robot, weapon, collision_point);
2002                         boss_invul_flag = !damage_flag;
2003                 }
2004         }
2005
2006         //      Put in at request of Jasen (and Adam) because the Buddy-Bot gets in their way.
2007         //      MK has so much fun whacking his butt around the mine he never cared...
2008         if ((Robot_info[robot->id].companion) && ((weapon->ctype.laser_info.parent_type != OBJ_ROBOT) && !Robots_kill_robots_cheat))
2009                 return;
2010
2011         if (weapon->id == EARTHSHAKER_ID)
2012                 smega_rock_stuff();
2013
2014         //      If a persistent weapon hit robot most recently, quick abort, else we cream the same robot many times,
2015         //      depending on frame rate.
2016         if (weapon->mtype.phys_info.flags & PF_PERSISTENT) {
2017                 if (weapon->ctype.laser_info.last_hitobj == robot-Objects)
2018                         return;
2019                 else
2020                         weapon->ctype.laser_info.last_hitobj = robot-Objects;
2021
2022                 // mprintf((0, "weapon #%i with power %i hits robot #%i.\n", weapon - Objects, f2i(weapon->shields), robot - Objects));
2023         }
2024
2025         if (weapon->ctype.laser_info.parent_signature == robot->signature)
2026                 return;
2027
2028         //      Changed, 10/04/95, put out blobs based on skill level and power of weapon doing damage.
2029         //      Also, only a weapon hit from a player weapon causes smart blobs.
2030         if ((weapon->ctype.laser_info.parent_type == OBJ_PLAYER) && (Robot_info[robot->id].energy_blobs))
2031                 if ((robot->shields > 0) && Weapon_is_energy[weapon->id]) {
2032                         fix     probval;
2033                         int     num_blobs;
2034
2035                         probval = (Difficulty_level+2) * min(weapon->shields, robot->shields);
2036                         probval = Robot_info[robot->id].energy_blobs * probval/(NDL*32);
2037
2038                         num_blobs = probval >> 16;
2039                         if (2*d_rand() < (probval & 0xffff))
2040                                 num_blobs++;
2041
2042                         if (num_blobs)
2043                                 create_smart_children(robot, num_blobs);
2044                 }
2045
2046         //      Note: If weapon hits an invulnerable boss, it will still do badass damage, including to the boss,
2047         //      unless this is trapped elsewhere.
2048         if ( Weapon_info[weapon->id].damage_radius )
2049         {
2050                 if (boss_invul_flag) {                  //don't make badass sound
2051                         weapon_info *wi = &Weapon_info[weapon->id];
2052
2053                         //this code copied from explode_badass_weapon()
2054                 
2055                         object_create_badass_explosion( weapon, weapon->segnum, collision_point, 
2056                                                         wi->impact_size, 
2057                                                         wi->robot_hit_vclip, 
2058                                                         wi->strength[Difficulty_level], 
2059                                                         wi->damage_radius,wi->strength[Difficulty_level],
2060                                                         weapon->ctype.laser_info.parent_num );
2061                 
2062                 }
2063                 else            //normal badass explosion
2064                         explode_badass_weapon(weapon,collision_point);
2065         }
2066
2067         if ( ((weapon->ctype.laser_info.parent_type==OBJ_PLAYER) || Robots_kill_robots_cheat) && !(robot->flags & OF_EXPLODING) )       {       
2068                 object *expl_obj=NULL;
2069
2070                 if (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum) {
2071                         create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION);                      // object "weapon" can attract attention to player
2072                         do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION);
2073                 }
2074 #ifdef NETWORK
2075                 else
2076                         multi_robot_request_change(robot, Objects[weapon->ctype.laser_info.parent_num].id);
2077 #endif
2078
2079                 if ( Robot_info[robot->id].exp1_vclip_num > -1 )
2080                         expl_obj = object_create_explosion( weapon->segnum, collision_point, (robot->size/2*3)/4, Robot_info[robot->id].exp1_vclip_num );
2081                 else if ( Weapon_info[weapon->id].robot_hit_vclip > -1 )
2082                         expl_obj = object_create_explosion( weapon->segnum, collision_point, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].robot_hit_vclip );
2083
2084                 if (expl_obj)
2085                         obj_attach(robot,expl_obj);
2086
2087                 if ( damage_flag && (Robot_info[robot->id].exp1_sound_num > -1 ))
2088                         digi_link_sound_to_pos( Robot_info[robot->id].exp1_sound_num, robot->segnum, 0, collision_point, 0, F1_0 );
2089
2090                 if (!(weapon->flags & OF_HARMLESS)) {
2091                         fix     damage = weapon->shields;
2092
2093                         if (damage_flag)
2094                                 damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
2095                         else
2096                                 damage = 0;
2097
2098                         //      Cut Gauss damage on bosses because it just breaks the game.  Bosses are so easy to
2099                         //      hit, and missing a robot is what prevents the Gauss from being game-breaking.
2100                         if (weapon->id == GAUSS_ID)
2101                                 if (Robot_info[robot->id].boss_flag)
2102                                         damage = damage * (2*NDL-Difficulty_level)/(2*NDL);
2103
2104                         if (! apply_damage_to_robot(robot, damage, weapon->ctype.laser_info.parent_num))
2105                                 bump_two_objects(robot, weapon, 0);             //only bump if not dead. no damage from bump
2106                         else if (weapon->ctype.laser_info.parent_signature == ConsoleObject->signature) {
2107                                 add_points_to_score(Robot_info[robot->id].score_value);
2108                                 detect_escort_goal_accomplished(robot-Objects);
2109                         }
2110                 }
2111
2112
2113                 //      If Gauss Cannon, spin robot.
2114                 if ((robot != NULL) && (!Robot_info[robot->id].companion) && (!Robot_info[robot->id].boss_flag) && (weapon->id == GAUSS_ID)) {
2115                         ai_static       *aip = &robot->ctype.ai_info;
2116
2117                         if (aip->SKIP_AI_COUNT * FrameTime < F1_0) {
2118                                 aip->SKIP_AI_COUNT++;
2119                                 robot->mtype.phys_info.rotthrust.x = fixmul((d_rand() - 16384), FrameTime * aip->SKIP_AI_COUNT);
2120                                 robot->mtype.phys_info.rotthrust.y = fixmul((d_rand() - 16384), FrameTime * aip->SKIP_AI_COUNT);
2121                                 robot->mtype.phys_info.rotthrust.z = fixmul((d_rand() - 16384), FrameTime * aip->SKIP_AI_COUNT);
2122                                 robot->mtype.phys_info.flags |= PF_USES_THRUST;
2123
2124                         }
2125                 }
2126
2127         }
2128
2129         maybe_kill_weapon(weapon,robot);
2130
2131         return; 
2132 }
2133
2134 //##void collide_robot_and_camera( object * robot, object * camera, vms_vector *collision_point ) { 
2135 //##    return; 
2136 //##}
2137
2138 //##void collide_robot_and_powerup( object * robot, object * powerup, vms_vector *collision_point ) { 
2139 //##    return; 
2140 //##}
2141
2142 //##void collide_robot_and_debris( object * robot, object * debris, vms_vector *collision_point ) { 
2143 //##    return; 
2144 //##}
2145
2146 //##void collide_hostage_and_hostage( object * hostage1, object * hostage2, vms_vector *collision_point ) { 
2147 //##    return; 
2148 //##}
2149
2150 void collide_hostage_and_player( object * hostage, object * player, vms_vector *collision_point ) { 
2151         // Give player points, etc.
2152         if ( player == ConsoleObject )  {
2153                 detect_escort_goal_accomplished(hostage-Objects);
2154                 add_points_to_score(HOSTAGE_SCORE);
2155
2156                 // Do effect
2157                 hostage_rescue(hostage->id);
2158
2159                 // Remove the hostage object.
2160                 hostage->flags |= OF_SHOULD_BE_DEAD;
2161
2162                 #ifdef NETWORK  
2163                 if (Game_mode & GM_MULTI)
2164                         multi_send_remobj(hostage-Objects);
2165                 #endif
2166         }
2167         return; 
2168 }
2169
2170 //--unused-- void collide_hostage_and_weapon( object * hostage, object * weapon, vms_vector *collision_point )
2171 //--unused-- { 
2172 //--unused--    //      Cannot kill hostages, as per Matt's edict!
2173 //--unused--    //      (A fine edict, but in contradiction to the milestone: "Robots attack hostages.")
2174 //--unused--    hostage->shields -= weapon->shields/2;
2175 //--unused-- 
2176 //--unused--    create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION);                      // object "weapon" can attract attention to player
2177 //--unused-- 
2178 //--unused--    //PLAY_SOUND_3D( SOUND_HOSTAGE_KILLED, collision_point, hostage->segnum );
2179 //--unused--    digi_link_sound_to_pos( SOUND_HOSTAGE_KILLED, hostage->segnum , 0, collision_point, 0, F1_0 );
2180 //--unused-- 
2181 //--unused-- 
2182 //--unused--    if (hostage->shields <= 0) {
2183 //--unused--            explode_object(hostage,0);
2184 //--unused--            hostage->flags |= OF_SHOULD_BE_DEAD;
2185 //--unused--    }
2186 //--unused-- 
2187 //--unused--    if ( Weapon_info[weapon->id].damage_radius )
2188 //--unused--            explode_badass_weapon(weapon);
2189 //--unused-- 
2190 //--unused--    maybe_kill_weapon(weapon,hostage);
2191 //--unused-- 
2192 //--unused-- }
2193
2194 //##void collide_hostage_and_camera( object * hostage, object * camera, vms_vector *collision_point ) { 
2195 //##    return; 
2196 //##}
2197
2198 //##void collide_hostage_and_powerup( object * hostage, object * powerup, vms_vector *collision_point ) { 
2199 //##    return; 
2200 //##}
2201
2202 //##void collide_hostage_and_debris( object * hostage, object * debris, vms_vector *collision_point ) { 
2203 //##    return; 
2204 //##}
2205
2206 void collide_player_and_player( object * player1, object * player2, vms_vector *collision_point ) { 
2207         digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player1->segnum, 0, collision_point, 0, F1_0 );
2208         bump_two_objects(player1, player2, 1);
2209         return;
2210 }
2211
2212 int maybe_drop_primary_weapon_egg(object *playerobj, int weapon_index)
2213 {
2214         int weapon_flag = HAS_FLAG(weapon_index);
2215         int powerup_num;
2216
2217         powerup_num = Primary_weapon_to_powerup[weapon_index];
2218
2219         if (Players[playerobj->id].primary_weapon_flags & weapon_flag)
2220                 return call_object_create_egg(playerobj, 1, OBJ_POWERUP, powerup_num);
2221         else
2222                 return -1;
2223 }
2224
2225 void maybe_drop_secondary_weapon_egg(object *playerobj, int weapon_index, int count)
2226 {
2227         int weapon_flag = HAS_FLAG(weapon_index);
2228         int powerup_num;
2229
2230         powerup_num = Secondary_weapon_to_powerup[weapon_index];
2231
2232         if (Players[playerobj->id].secondary_weapon_flags & weapon_flag) {
2233                 int     i, max_count;
2234
2235                 max_count = min(count, 3);
2236                 for (i=0; i<max_count; i++)
2237                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, powerup_num);
2238         }
2239 }
2240
2241 void drop_missile_1_or_4(object *playerobj,int missile_index)
2242 {
2243         int num_missiles,powerup_id;
2244
2245         num_missiles = Players[playerobj->id].secondary_ammo[missile_index];
2246         powerup_id = Secondary_weapon_to_powerup[missile_index];
2247
2248         if (num_missiles > 10)
2249                 num_missiles = 10;
2250
2251         call_object_create_egg(playerobj, num_missiles/4, OBJ_POWERUP, powerup_id+1);
2252         call_object_create_egg(playerobj, num_missiles%4, OBJ_POWERUP, powerup_id);
2253 }
2254
2255 // -- int       Items_destroyed = 0;
2256
2257 void drop_player_eggs(object *playerobj)
2258 {
2259 //      mprintf((0, "In drop_player_eggs...\n"));
2260
2261         if ((playerobj->type == OBJ_PLAYER) || (playerobj->type == OBJ_GHOST)) {
2262                 int     rthresh;
2263                 int     pnum = playerobj->id;
2264                 int     objnum;
2265                 int     vulcan_ammo=0;
2266                 vms_vector      randvec;
2267
2268                 // -- Items_destroyed = 0;
2269
2270                 // Seed the random number generator so in net play the eggs will always
2271                 // drop the same way
2272                 #ifdef NETWORK
2273                 if (Game_mode & GM_MULTI) 
2274                 {
2275                         Net_create_loc = 0;
2276                         d_srand(5483L);
2277                 }
2278                 #endif
2279
2280                 //      If the player had smart mines, maybe arm one of them.
2281                 rthresh = 30000;
2282                 while ((Players[playerobj->id].secondary_ammo[SMART_MINE_INDEX]%4==1) && (d_rand() < rthresh)) {
2283                         int                     newseg;
2284                         vms_vector      tvec;
2285
2286                         make_random_vector(&randvec);
2287                         rthresh /= 2;
2288                         vm_vec_add(&tvec, &playerobj->pos, &randvec);
2289                         newseg = find_point_seg(&tvec, playerobj->segnum);
2290                         if (newseg != -1)
2291                                 Laser_create_new(&randvec, &tvec, newseg, playerobj-Objects, SUPERPROX_ID, 0);
2292                 }
2293
2294                 //      If the player had proximity bombs, maybe arm one of them.
2295
2296                 if ((Game_mode & GM_MULTI) && !(Game_mode & GM_HOARD))
2297                 {
2298                         rthresh = 30000;
2299                         while ((Players[playerobj->id].secondary_ammo[PROXIMITY_INDEX]%4==1) && (d_rand() < rthresh)) {
2300                                 int                     newseg;
2301                                 vms_vector      tvec;
2302         
2303                                 make_random_vector(&randvec);
2304                                 rthresh /= 2;
2305                                 vm_vec_add(&tvec, &playerobj->pos, &randvec);
2306                                 newseg = find_point_seg(&tvec, playerobj->segnum);
2307                                 if (newseg != -1)
2308                                         Laser_create_new(&randvec, &tvec, newseg, playerobj-Objects, PROXIMITY_ID, 0);
2309         
2310                         }
2311                 }
2312
2313                 //      If the player dies and he has powerful lasers, create the powerups here.
2314
2315                 if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2316                         call_object_create_egg(playerobj, Players[pnum].laser_level-MAX_LASER_LEVEL, OBJ_POWERUP, POW_SUPER_LASER);
2317                 else if (Players[pnum].laser_level >= 1)
2318                         call_object_create_egg(playerobj, Players[pnum].laser_level, OBJ_POWERUP, POW_LASER);   // Note: laser_level = 0 for laser level 1.
2319
2320                 //      Drop quad laser if appropos
2321                 if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2322                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_QUAD_FIRE);
2323
2324                 if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2325                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_CLOAK);
2326
2327                 if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2328                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_FULL_MAP);
2329
2330                 if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2331                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_AFTERBURNER);
2332
2333                 if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2334                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_AMMO_RACK);
2335
2336                 if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2337                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_CONVERTER);
2338
2339                 if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2340                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_HEADLIGHT);
2341
2342                 // drop the other enemies flag if you have it
2343
2344 #ifdef NETWORK
2345                 if ((Game_mode & GM_CAPTURE) && (Players[pnum].flags & PLAYER_FLAGS_FLAG))
2346                 {
2347                  if ((get_team (pnum)==TEAM_RED))
2348                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_FLAG_BLUE);
2349                  else
2350                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_FLAG_RED);
2351                 }
2352
2353         
2354                 if (Game_mode & GM_HOARD)
2355                 {
2356                         // Drop hoard orbs
2357                         
2358                         int max_count,i;
2359
2360                         mprintf ((0,"HOARD MODE: Dropping %d orbs\n",Players[pnum].secondary_ammo[PROXIMITY_INDEX]));
2361         
2362                         max_count = min(Players[pnum].secondary_ammo[PROXIMITY_INDEX], 12);
2363                         for (i=0; i<max_count; i++)
2364                                 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_HOARD_ORB);
2365                 }
2366 #endif
2367
2368                 //Drop the vulcan, gauss, and ammo
2369                 vulcan_ammo = Players[pnum].primary_ammo[VULCAN_INDEX];
2370                 if ((Players[pnum].primary_weapon_flags & HAS_FLAG(VULCAN_INDEX)) && (Players[pnum].primary_weapon_flags & HAS_FLAG(GAUSS_INDEX)))
2371                         vulcan_ammo /= 2;               //if both vulcan & gauss, each gets half
2372                 if (vulcan_ammo < VULCAN_AMMO_AMOUNT)
2373                         vulcan_ammo = VULCAN_AMMO_AMOUNT;       //make sure gun has at least as much as a powerup
2374                 objnum = maybe_drop_primary_weapon_egg(playerobj, VULCAN_INDEX);
2375                 if (objnum!=-1)
2376                         Objects[objnum].ctype.powerup_info.count = vulcan_ammo;
2377                 objnum = maybe_drop_primary_weapon_egg(playerobj, GAUSS_INDEX);
2378                 if (objnum!=-1)
2379                         Objects[objnum].ctype.powerup_info.count = vulcan_ammo;
2380
2381                 //      Drop the rest of the primary weapons
2382                 maybe_drop_primary_weapon_egg(playerobj, SPREADFIRE_INDEX);
2383                 maybe_drop_primary_weapon_egg(playerobj, PLASMA_INDEX);
2384                 maybe_drop_primary_weapon_egg(playerobj, FUSION_INDEX);
2385
2386                 maybe_drop_primary_weapon_egg(playerobj, HELIX_INDEX);
2387                 maybe_drop_primary_weapon_egg(playerobj, PHOENIX_INDEX);
2388
2389                 objnum = maybe_drop_primary_weapon_egg(playerobj, OMEGA_INDEX);
2390                 if (objnum!=-1)
2391                         Objects[objnum].ctype.powerup_info.count = (playerobj->id==Player_num)?Omega_charge:MAX_OMEGA_CHARGE;
2392
2393                 //      Drop the secondary weapons
2394                 //      Note, proximity weapon only comes in packets of 4.  So drop n/2, but a max of 3 (handled inside maybe_drop..)  Make sense?
2395                 
2396                 if (!(Game_mode & GM_HOARD))
2397                         maybe_drop_secondary_weapon_egg(playerobj, PROXIMITY_INDEX, (Players[playerobj->id].secondary_ammo[PROXIMITY_INDEX])/4);
2398
2399                 maybe_drop_secondary_weapon_egg(playerobj, SMART_INDEX, Players[playerobj->id].secondary_ammo[SMART_INDEX]);
2400                 maybe_drop_secondary_weapon_egg(playerobj, MEGA_INDEX, Players[playerobj->id].secondary_ammo[MEGA_INDEX]);
2401
2402                 maybe_drop_secondary_weapon_egg(playerobj, SMART_MINE_INDEX,(Players[playerobj->id].secondary_ammo[SMART_MINE_INDEX])/4);
2403                 maybe_drop_secondary_weapon_egg(playerobj, SMISSILE5_INDEX, Players[playerobj->id].secondary_ammo[SMISSILE5_INDEX]);
2404
2405                 //      Drop the player's missiles in packs of 1 and/or 4
2406                 drop_missile_1_or_4(playerobj,HOMING_INDEX);
2407                 drop_missile_1_or_4(playerobj,GUIDED_INDEX);
2408                 drop_missile_1_or_4(playerobj,CONCUSSION_INDEX);
2409                 drop_missile_1_or_4(playerobj,SMISSILE1_INDEX);
2410                 drop_missile_1_or_4(playerobj,SMISSILE4_INDEX);
2411
2412                 //      If player has vulcan ammo, but no vulcan cannon, drop the ammo.
2413                 if (!(Players[playerobj->id].primary_weapon_flags & HAS_VULCAN_FLAG)) {
2414                         int     amount = Players[playerobj->id].primary_ammo[VULCAN_INDEX];
2415                         if (amount > 200) {
2416                                 mprintf((0, "Surprising amount of vulcan ammo: %i bullets.\n", amount));
2417                                 amount = 200;
2418                         }
2419                         while (amount > 0) {
2420                                 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_VULCAN_AMMO);
2421                                 amount -= VULCAN_AMMO_AMOUNT;
2422                         }
2423                 }
2424
2425                 //      Always drop a shield and energy powerup.
2426                 if (Game_mode & GM_MULTI) {
2427                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_SHIELD_BOOST);
2428                         call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_ENERGY);
2429                 }
2430
2431 //--            //      Drop all the keys.
2432 //--            if (Players[Player_num].flags & PLAYER_FLAGS_BLUE_KEY) {
2433 //--                    playerobj->contains_count = 1;
2434 //--                    playerobj->contains_type = OBJ_POWERUP;
2435 //--                    playerobj->contains_id = POW_KEY_BLUE;
2436 //--                    object_create_egg(playerobj);
2437 //--            }
2438 //--            if (Players[Player_num].flags & PLAYER_FLAGS_RED_KEY) {
2439 //--                    playerobj->contains_count = 1;
2440 //--                    playerobj->contains_type = OBJ_POWERUP;
2441 //--                    playerobj->contains_id = POW_KEY_RED;
2442 //--                    object_create_egg(playerobj);
2443 //--            }
2444 //--            if (Players[Player_num].flags & PLAYER_FLAGS_GOLD_KEY) {
2445 //--                    playerobj->contains_count = 1;
2446 //--                    playerobj->contains_type = OBJ_POWERUP;
2447 //--                    playerobj->contains_id = POW_KEY_GOLD;
2448 //--                    object_create_egg(playerobj);
2449 //--            }
2450
2451 // --           if (Items_destroyed) {
2452 // --                   if (Items_destroyed == 1)
2453 // --                           HUD_init_message("%i item was destroyed.", Items_destroyed);
2454 // --                   else
2455 // --                           HUD_init_message("%i items were destroyed.", Items_destroyed);
2456 // --                   Items_destroyed = 0;
2457 // --           }
2458         }
2459
2460 }
2461
2462 // -- removed, 09/06/95, MK -- void destroy_primary_weapon(int weapon_index)
2463 // -- removed, 09/06/95, MK -- {
2464 // -- removed, 09/06/95, MK --  if (weapon_index == MAX_PRIMARY_WEAPONS) {
2465 // -- removed, 09/06/95, MK --          HUD_init_message("Quad lasers destroyed!");
2466 // -- removed, 09/06/95, MK --          Players[Player_num].flags &= ~PLAYER_FLAGS_QUAD_LASERS;
2467 // -- removed, 09/06/95, MK --          update_laser_weapon_info();
2468 // -- removed, 09/06/95, MK --  } else if (weapon_index == 0) {
2469 // -- removed, 09/06/95, MK --          Assert(Players[Player_num].laser_level > 0);
2470 // -- removed, 09/06/95, MK --          HUD_init_message("%s degraded!", Text_string[104+weapon_index]);                //      Danger! Danger! Use of literal!  Danger!
2471 // -- removed, 09/06/95, MK --          Players[Player_num].laser_level--;
2472 // -- removed, 09/06/95, MK --          update_laser_weapon_info();
2473 // -- removed, 09/06/95, MK --  } else {
2474 // -- removed, 09/06/95, MK --          HUD_init_message("%s destroyed!", Text_string[104+weapon_index]);               //      Danger! Danger! Use of literal!  Danger!
2475 // -- removed, 09/06/95, MK --          Players[Player_num].primary_weapon_flags &= ~(1 << weapon_index);
2476 // -- removed, 09/06/95, MK --          auto_select_weapon(0);
2477 // -- removed, 09/06/95, MK --  }
2478 // -- removed, 09/06/95, MK -- 
2479 // -- removed, 09/06/95, MK -- }
2480 // -- removed, 09/06/95, MK -- 
2481 // -- removed, 09/06/95, MK -- void destroy_secondary_weapon(int weapon_index)
2482 // -- removed, 09/06/95, MK -- {
2483 // -- removed, 09/06/95, MK --  if (Players[Player_num].secondary_ammo <= 0)
2484 // -- removed, 09/06/95, MK --          return;
2485 // -- removed, 09/06/95, MK -- 
2486 // -- removed, 09/06/95, MK --  HUD_init_message("%s destroyed!", Text_string[114+weapon_index]);               //      Danger! Danger! Use of literal!  Danger!
2487 // -- removed, 09/06/95, MK --  if (--Players[Player_num].secondary_ammo[weapon_index] == 0)
2488 // -- removed, 09/06/95, MK --          auto_select_weapon(1);
2489 // -- removed, 09/06/95, MK -- 
2490 // -- removed, 09/06/95, MK -- }
2491 // -- removed, 09/06/95, MK -- 
2492 // -- removed, 09/06/95, MK -- #define  LOSE_WEAPON_THRESHOLD   (F1_0*30)
2493
2494 extern fix Buddy_sorry_time;
2495
2496 void apply_damage_to_player(object *playerobj, object *killer, fix damage)
2497 {
2498         if (Player_is_dead)
2499                 return;
2500
2501         if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
2502                 return;
2503
2504         if (Endlevel_sequence)
2505                 return;
2506
2507         //for the player, the 'real' shields are maintained in the Players[]
2508         //array.  The shields value in the player's object are, I think, not
2509         //used anywhere.  This routine, however, sets the objects shields to
2510         //be a mirror of the value in the Player structure. 
2511
2512         if (playerobj->id == Player_num) {              //is this the local player?
2513
2514                 //      MK: 08/14/95: This code can never be reached.  See the return about 12 lines up.
2515 // --           if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) {
2516 // -- 
2517 // --                   //invincible, so just do blue flash
2518 // -- 
2519 // --                   PALETTE_FLASH_ADD(0,0,f2i(damage)*4);   //flash blue
2520 // -- 
2521 // --           } 
2522 // --           else {          //take damage, do red flash
2523
2524                         Players[Player_num].shields -= damage;
2525
2526                         PALETTE_FLASH_ADD(f2i(damage)*4,-f2i(damage/2),-f2i(damage/2)); //flash red
2527
2528 // --           }
2529
2530                 if (Players[Player_num].shields < 0)    {
2531
2532                         Players[Player_num].killer_objnum = killer-Objects;
2533                         
2534 //                      if ( killer && (killer->type == OBJ_PLAYER))
2535 //                              Players[Player_num].killer_objnum = killer-Objects;
2536
2537                         playerobj->flags |= OF_SHOULD_BE_DEAD;
2538
2539                         if (Buddy_objnum != -1)
2540                                 if (killer && (killer->type == OBJ_ROBOT) && (Robot_info[killer->id].companion))
2541                                         Buddy_sorry_time = GameTime;
2542                 }
2543 // -- removed, 09/06/95, MK --  else if (Players[Player_num].shields < LOSE_WEAPON_THRESHOLD) {
2544 // -- removed, 09/06/95, MK --                  int     randnum = d_rand();
2545 // -- removed, 09/06/95, MK -- 
2546 // -- removed, 09/06/95, MK --                  if (fixmul(Players[Player_num].shields, randnum) < damage/4) {
2547 // -- removed, 09/06/95, MK --                          if (d_rand() > 20000) {
2548 // -- removed, 09/06/95, MK --                                  destroy_secondary_weapon(Secondary_weapon);
2549 // -- removed, 09/06/95, MK --                          } else if (Primary_weapon == 0) {
2550 // -- removed, 09/06/95, MK --                                  if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)
2551 // -- removed, 09/06/95, MK --                                          destroy_primary_weapon(MAX_PRIMARY_WEAPONS);    //      This means to destroy quad laser.
2552 // -- removed, 09/06/95, MK --                                  else if (Players[Player_num].laser_level > 0)
2553 // -- removed, 09/06/95, MK --                                          destroy_primary_weapon(Primary_weapon);
2554 // -- removed, 09/06/95, MK --                          } else
2555 // -- removed, 09/06/95, MK --                                  destroy_primary_weapon(Primary_weapon);
2556 // -- removed, 09/06/95, MK --                  } else
2557 // -- removed, 09/06/95, MK --                          ; // mprintf((0, "%8x > %8x, so don't lose weapon.\n", fixmul(Players[Player_num].shields, randnum), damage/4));
2558 // -- removed, 09/06/95, MK --          }
2559
2560                 playerobj->shields = Players[Player_num].shields;               //mirror
2561
2562         }
2563 }
2564
2565 void collide_player_and_weapon( object * playerobj, object * weapon, vms_vector *collision_point )
2566 {
2567         fix             damage = weapon->shields;
2568         object * killer=NULL;
2569
2570         //      In multiplayer games, only do damage to another player if in first frame.
2571         //      This is necessary because in multiplayer, due to varying framerates, omega blobs actually
2572         //      have a bit of a lifetime.  But they start out with a lifetime of ONE_FRAME_TIME, and this
2573         //      gets bashed to 1/4 second in laser_do_weapon_sequence.  This bashing occurs for visual purposes only.
2574         if (weapon->id == OMEGA_ID)
2575                 if (!ok_to_do_omega_damage(weapon))
2576                         return;
2577
2578         //      Don't collide own smart mines unless direct hit.
2579         if (weapon->id == SUPERPROX_ID)
2580                 if (playerobj-Objects == weapon->ctype.laser_info.parent_num)
2581                         if (vm_vec_dist_quick(collision_point, &playerobj->pos) > playerobj->size)
2582                                 return;
2583
2584         if (weapon->id == EARTHSHAKER_ID)
2585                 smega_rock_stuff();
2586
2587         damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
2588 #ifndef SHAREWARE
2589         if (Game_mode & GM_MULTI)
2590                 damage = fixmul(damage, Weapon_info[weapon->id].multi_damage_scale);
2591 #endif
2592
2593         if (weapon->mtype.phys_info.flags & PF_PERSISTENT)
2594         {
2595                 if (weapon->ctype.laser_info.last_hitobj == playerobj-Objects)
2596                         return;
2597                 else
2598                         weapon->ctype.laser_info.last_hitobj = playerobj-Objects;
2599         }
2600
2601         if (playerobj->id == Player_num)
2602         {
2603                 if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2604                 {
2605                         digi_link_sound_to_pos( SOUND_PLAYER_GOT_HIT, playerobj->segnum, 0, collision_point, 0, F1_0 );
2606                         #ifdef NETWORK
2607                         if (Game_mode & GM_MULTI)
2608                                 multi_send_play_sound(SOUND_PLAYER_GOT_HIT, F1_0);
2609                         #endif
2610                 }
2611                 else
2612                 {
2613                         digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, playerobj->segnum, 0, collision_point, 0, F1_0);
2614                         #ifdef NETWORK
2615                         if (Game_mode & GM_MULTI)
2616                                 multi_send_play_sound(SOUND_WEAPON_HIT_DOOR, F1_0);
2617                         #endif
2618                 }
2619         }
2620
2621         object_create_explosion( playerobj->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT );
2622         if ( Weapon_info[weapon->id].damage_radius )
2623                 explode_badass_weapon(weapon,collision_point);
2624
2625         maybe_kill_weapon(weapon,playerobj);
2626
2627         bump_two_objects(playerobj, weapon, 0); //no damage from bump
2628
2629         if ( !Weapon_info[weapon->id].damage_radius ) {
2630                 if ( weapon->ctype.laser_info.parent_num > -1 )
2631                         killer = &Objects[weapon->ctype.laser_info.parent_num];
2632
2633 //              if (weapon->id == SMART_HOMING_ID)
2634 //                      damage /= 4;
2635
2636                 if (!(weapon->flags & OF_HARMLESS))
2637                         apply_damage_to_player( playerobj, killer, damage);
2638         }
2639
2640         //      Robots become aware of you if you get hit.
2641         ai_do_cloak_stuff();
2642
2643         return; 
2644 }
2645
2646 //      Nasty robots are the ones that attack you by running into you and doing lots of damage.
2647 void collide_player_and_nasty_robot( object * playerobj, object * robot, vms_vector *collision_point )
2648 {
2649 //      if (!(Robot_info[robot->id].energy_drain && Players[playerobj->id].energy))
2650                 digi_link_sound_to_pos( Robot_info[robot->id].claw_sound, playerobj->segnum, 0, collision_point, 0, F1_0 );
2651
2652         object_create_explosion( playerobj->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT );
2653
2654         bump_two_objects(playerobj, robot, 0);  //no damage from bump
2655
2656         apply_damage_to_player( playerobj, robot, F1_0*(Difficulty_level+1));
2657
2658         return; 
2659 }
2660
2661 void collide_player_and_materialization_center(object *objp)
2662 {
2663         int     side;
2664         vms_vector      exit_dir;
2665         segment *segp = &Segments[objp->segnum];
2666
2667         digi_link_sound_to_pos(SOUND_PLAYER_GOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0);
2668 //      digi_play_sample( SOUND_PLAYER_GOT_HIT, F1_0 );
2669
2670         object_create_explosion( objp->segnum, &objp->pos, i2f(10)/2, VCLIP_PLAYER_HIT );
2671
2672         if (objp->id != Player_num)
2673                 return;
2674
2675         for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
2676                 if (WALL_IS_DOORWAY(segp, side) & WID_FLY_FLAG) {
2677                         vms_vector      exit_point, rand_vec;
2678
2679                         compute_center_point_on_side(&exit_point, segp, side);
2680                         vm_vec_sub(&exit_dir, &exit_point, &objp->pos);
2681                         vm_vec_normalize_quick(&exit_dir);
2682                         make_random_vector(&rand_vec);
2683                         rand_vec.x /= 4;        rand_vec.y /= 4;        rand_vec.z /= 4;
2684                         vm_vec_add2(&exit_dir, &rand_vec);
2685                         vm_vec_normalize_quick(&exit_dir);
2686                 }
2687
2688         bump_one_object(objp, &exit_dir, 64*F1_0);
2689
2690         apply_damage_to_player( objp, objp, 4*F1_0);    //      Changed, MK, 2/19/96, make killer the player, so if you die in matcen, will say you killed yourself
2691
2692         return; 
2693
2694 }
2695
2696 void collide_robot_and_materialization_center(object *objp)
2697 {
2698         int     side;
2699         vms_vector      exit_dir;
2700         segment *segp=&Segments[objp->segnum];
2701
2702         digi_link_sound_to_pos(SOUND_ROBOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0);
2703 //      digi_play_sample( SOUND_ROBOT_HIT, F1_0 );
2704
2705         if ( Robot_info[objp->id].exp1_vclip_num > -1 )
2706                 object_create_explosion( objp->segnum, &objp->pos, (objp->size/2*3)/4, Robot_info[objp->id].exp1_vclip_num );
2707
2708         for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
2709                 if (WALL_IS_DOORWAY(segp, side) & WID_FLY_FLAG) {
2710                         vms_vector      exit_point;
2711
2712                         compute_center_point_on_side(&exit_point, segp, side);
2713                         vm_vec_sub(&exit_dir, &exit_point, &objp->pos);
2714                         vm_vec_normalize_quick(&exit_dir);
2715                 }
2716
2717         bump_one_object(objp, &exit_dir, 8*F1_0);
2718
2719         apply_damage_to_robot( objp, F1_0, -1);
2720
2721         return; 
2722
2723 }
2724
2725 //##void collide_player_and_camera( object * playerobj, object * camera, vms_vector *collision_point ) { 
2726 //##    return; 
2727 //##}
2728
2729 extern int Network_got_powerup; // HACK!!!
2730
2731 void collide_player_and_powerup( object * playerobj, object * powerup, vms_vector *collision_point ) { 
2732         if (!Endlevel_sequence && !Player_is_dead && (playerobj->id == Player_num )) {
2733                 int powerup_used;
2734
2735                 powerup_used = do_powerup(powerup);
2736                 
2737                 if (powerup_used)       {
2738                         powerup->flags |= OF_SHOULD_BE_DEAD;
2739                         #ifdef NETWORK
2740                         if (Game_mode & GM_MULTI)
2741                                 multi_send_remobj(powerup-Objects);
2742                         #endif
2743                 }
2744         }
2745 #ifndef SHAREWARE
2746         else if ((Game_mode & GM_MULTI_COOP) && (playerobj->id != Player_num))
2747         {
2748                 switch (powerup->id) {
2749                         case POW_KEY_BLUE:      
2750                                 Players[playerobj->id].flags |= PLAYER_FLAGS_BLUE_KEY;
2751                                 break;
2752                         case POW_KEY_RED:       
2753                                 Players[playerobj->id].flags |= PLAYER_FLAGS_RED_KEY;
2754                                 break;
2755                         case POW_KEY_GOLD:      
2756                                 Players[playerobj->id].flags |= PLAYER_FLAGS_GOLD_KEY;
2757                                 break;
2758                         default:
2759                                 break;
2760                 }
2761         }
2762 #endif
2763         return; 
2764 }
2765
2766 //##void collide_player_and_debris( object * playerobj, object * debris, vms_vector *collision_point ) { 
2767 //##    return; 
2768 //##}
2769
2770 void collide_player_and_clutter( object * playerobj, object * clutter, vms_vector *collision_point ) { 
2771         digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, playerobj->segnum, 0, collision_point, 0, F1_0 );
2772         bump_two_objects(clutter, playerobj, 1);
2773         return; 
2774 }
2775
2776 //      See if weapon1 creates a badass explosion.  If so, create the explosion
2777 //      Return true if weapon does proximity (as opposed to only contact) damage when it explodes.
2778 int maybe_detonate_weapon(object *weapon1, object *weapon2, vms_vector *collision_point)
2779 {
2780         if ( Weapon_info[weapon1->id].damage_radius ) {
2781                 fix     dist;
2782
2783                 dist = vm_vec_dist_quick(&weapon1->pos, &weapon2->pos);
2784                 if (dist < F1_0*5) {
2785                         maybe_kill_weapon(weapon1,weapon2);
2786                         if (weapon1->flags & OF_SHOULD_BE_DEAD) {
2787                                 explode_badass_weapon(weapon1,collision_point);
2788                                 digi_link_sound_to_pos( Weapon_info[weapon1->id].robot_hit_sound, weapon1->segnum , 0, collision_point, 0, F1_0 );
2789                         }
2790                         return 1;
2791                 } else {
2792                         weapon1->lifeleft = min(dist/64, F1_0);
2793                         return 1;
2794                 }
2795         } else
2796                 return 0;
2797 }
2798
2799 void collide_weapon_and_weapon( object * weapon1, object * weapon2, vms_vector *collision_point )
2800
2801         // -- Does this look buggy??:  if (weapon1->id == PMINE_ID && weapon1->id == PMINE_ID)
2802         if (weapon1->id == PMINE_ID && weapon2->id == PMINE_ID)
2803                 return;         //these can't blow each other up  
2804
2805         if (weapon1->id == OMEGA_ID) {
2806                 if (!ok_to_do_omega_damage(weapon1))
2807                         return;
2808         } else if (weapon2->id == OMEGA_ID) {
2809                 if (!ok_to_do_omega_damage(weapon2))
2810                         return;
2811         }
2812
2813         if ((Weapon_info[weapon1->id].destroyable) || (Weapon_info[weapon2->id].destroyable)) {
2814
2815                 //      Bug reported by Adam Q. Pletcher on September 9, 1994, smart bomb homing missiles were toasting each other.
2816                 if ((weapon1->id == weapon2->id) && (weapon1->ctype.laser_info.parent_num == weapon2->ctype.laser_info.parent_num))
2817                         return;
2818
2819                 if (Weapon_info[weapon1->id].destroyable)
2820                         if (maybe_detonate_weapon(weapon1, weapon2, collision_point))
2821                                 maybe_detonate_weapon(weapon2,weapon1, collision_point);
2822
2823                 if (Weapon_info[weapon2->id].destroyable)
2824                         if (maybe_detonate_weapon(weapon2, weapon1, collision_point))
2825                                 maybe_detonate_weapon(weapon1,weapon2, collision_point);
2826
2827         }
2828
2829 }
2830
2831 //##void collide_weapon_and_camera( object * weapon, object * camera, vms_vector *collision_point ) { 
2832 //##    return; 
2833 //##}
2834
2835 //##void collide_weapon_and_powerup( object * weapon, object * powerup, vms_vector *collision_point ) { 
2836 //##    return; 
2837 //##}
2838
2839 void collide_weapon_and_debris( object * weapon, object * debris, vms_vector *collision_point ) { 
2840
2841         //      Hack!  Prevent debris from causing bombs spewed at player death to detonate!
2842         if ((weapon->id == PROXIMITY_ID) || (weapon->id == SUPERPROX_ID)) {
2843                 if (weapon->ctype.laser_info.creation_time + F1_0/2 > GameTime)
2844                         return;
2845         }
2846
2847         if ( (weapon->ctype.laser_info.parent_type==OBJ_PLAYER) && !(debris->flags & OF_EXPLODING) )    {       
2848                 digi_link_sound_to_pos( SOUND_ROBOT_HIT, weapon->segnum , 0, collision_point, 0, F1_0 );
2849
2850                 explode_object(debris,0);
2851                 if ( Weapon_info[weapon->id].damage_radius )
2852                         explode_badass_weapon(weapon,collision_point);
2853                 maybe_kill_weapon(weapon,debris);
2854                 weapon->flags |= OF_SHOULD_BE_DEAD;
2855         }
2856         return; 
2857 }
2858
2859 //##void collide_camera_and_camera( object * camera1, object * camera2, vms_vector *collision_point ) { 
2860 //##    return; 
2861 //##}
2862
2863 //##void collide_camera_and_powerup( object * camera, object * powerup, vms_vector *collision_point ) { 
2864 //##    return; 
2865 //##}
2866
2867 //##void collide_camera_and_debris( object * camera, object * debris, vms_vector *collision_point ) { 
2868 //##    return; 
2869 //##}
2870
2871 //##void collide_powerup_and_powerup( object * powerup1, object * powerup2, vms_vector *collision_point ) { 
2872 //##    return; 
2873 //##}
2874
2875 //##void collide_powerup_and_debris( object * powerup, object * debris, vms_vector *collision_point ) { 
2876 //##    return; 
2877 //##}
2878
2879 //##void collide_debris_and_debris( object * debris1, object * debris2, vms_vector *collision_point ) { 
2880 //##    return; 
2881 //##}
2882
2883
2884 /* DPH: Put these macros on one long line to avoid CR/LF problems on linux */
2885 #define COLLISION_OF(a,b) (((a)<<8) + (b))
2886
2887 #define DO_COLLISION(type1,type2,collision_function)    case COLLISION_OF( (type1), (type2) ):  (collision_function)( (A), (B), collision_point ); break;   case COLLISION_OF( (type2), (type1) ):  (collision_function)( (B), (A), collision_point );  break;
2888
2889 #define DO_SAME_COLLISION(type1,type2,collision_function)    case COLLISION_OF( (type1), (type1) ):  (collision_function)( (A), (B), collision_point ); break;
2890
2891 //these next two macros define a case that does nothing
2892 #define NO_COLLISION(type1,type2,collision_function)    case COLLISION_OF( (type1), (type2) ):  break;  case COLLISION_OF( (type2), (type1) ):  break;
2893
2894 #define NO_SAME_COLLISION(type1,type2,collision_function)    case COLLISION_OF( (type1), (type1) ):    break;
2895
2896 /* DPH: These ones are never used so I'm not going to bother */
2897 #ifndef __GNUC__
2898 #define IGNORE_COLLISION(type1,type2,collision_function)                                        \
2899         case COLLISION_OF( (type1), (type2) ):                                                                          \
2900                 break;                                                                                                                                                  \
2901         case COLLISION_OF( (type2), (type1) ):                                                                          \
2902                 break;
2903
2904 #define ERROR_COLLISION(type1,type2,collision_function)                                 \
2905         case COLLISION_OF( (type1), (type2) ):                                                                          \
2906                 Error( "Error in collision type!" );                                                                    \
2907                 break;                                                                                                                                                  \
2908         case COLLISION_OF( (type2), (type1) ):                                                                          \
2909                 Error( "Error in collision type!" );                                                                    \
2910                 break;
2911 #endif
2912
2913 void collide_two_objects( object * A, object * B, vms_vector *collision_point )
2914 {
2915         int collision_type;     
2916                 
2917         collision_type = COLLISION_OF(A->type,B->type);
2918
2919         //mprintf( (0, "Object %d of type %d collided with object %d of type %d\n", A-Objects,A->type, B-Objects, B->type ));
2920
2921         switch( collision_type )        {
2922         NO_SAME_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL,   collide_fireball_and_fireball )
2923         DO_SAME_COLLISION( OBJ_ROBOT, OBJ_ROBOT, collide_robot_and_robot )
2924         NO_SAME_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE,  collide_hostage_and_hostage )
2925         DO_SAME_COLLISION( OBJ_PLAYER, OBJ_PLAYER,  collide_player_and_player )
2926         DO_SAME_COLLISION( OBJ_WEAPON, OBJ_WEAPON,  collide_weapon_and_weapon )
2927         NO_SAME_COLLISION( OBJ_CAMERA, OBJ_CAMERA, collide_camera_and_camera )
2928         NO_SAME_COLLISION( OBJ_POWERUP, OBJ_POWERUP,  collide_powerup_and_powerup )
2929         NO_SAME_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS,  collide_debris_and_debris )
2930         NO_SAME_COLLISION( OBJ_MARKER, OBJ_MARKER,  NULL )
2931         NO_COLLISION( OBJ_FIREBALL, OBJ_ROBOT,   collide_fireball_and_robot )
2932         NO_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE, collide_fireball_and_hostage )
2933         NO_COLLISION( OBJ_FIREBALL, OBJ_PLAYER,  collide_fireball_and_player )
2934         NO_COLLISION( OBJ_FIREBALL, OBJ_WEAPON,  collide_fireball_and_weapon )
2935         NO_COLLISION( OBJ_FIREBALL, OBJ_CAMERA,  collide_fireball_and_camera )
2936         NO_COLLISION( OBJ_FIREBALL, OBJ_POWERUP, collide_fireball_and_powerup )
2937         NO_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS,  collide_fireball_and_debris )
2938         NO_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE, collide_robot_and_hostage )
2939         DO_COLLISION( OBJ_ROBOT, OBJ_PLAYER,  collide_robot_and_player )
2940         DO_COLLISION( OBJ_ROBOT, OBJ_WEAPON,  collide_robot_and_weapon )
2941         NO_COLLISION( OBJ_ROBOT, OBJ_CAMERA,  collide_robot_and_camera )
2942         NO_COLLISION( OBJ_ROBOT, OBJ_POWERUP, collide_robot_and_powerup )
2943         NO_COLLISION( OBJ_ROBOT, OBJ_DEBRIS,  collide_robot_and_debris )
2944         DO_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER,  collide_hostage_and_player )
2945         NO_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON,  collide_hostage_and_weapon )
2946         NO_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA,  collide_hostage_and_camera )
2947         NO_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP, collide_hostage_and_powerup )
2948         NO_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS,  collide_hostage_and_debris )
2949         DO_COLLISION( OBJ_PLAYER, OBJ_WEAPON,  collide_player_and_weapon )
2950         NO_COLLISION( OBJ_PLAYER, OBJ_CAMERA,  collide_player_and_camera )
2951         DO_COLLISION( OBJ_PLAYER, OBJ_POWERUP, collide_player_and_powerup )
2952         NO_COLLISION( OBJ_PLAYER, OBJ_DEBRIS,  collide_player_and_debris )
2953         DO_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN, collide_player_and_controlcen )
2954         DO_COLLISION( OBJ_PLAYER, OBJ_CLUTTER, collide_player_and_clutter )
2955         NO_COLLISION( OBJ_WEAPON, OBJ_CAMERA,  collide_weapon_and_camera )
2956         NO_COLLISION( OBJ_WEAPON, OBJ_POWERUP, collide_weapon_and_powerup )
2957         DO_COLLISION( OBJ_WEAPON, OBJ_DEBRIS,  collide_weapon_and_debris )
2958         NO_COLLISION( OBJ_CAMERA, OBJ_POWERUP, collide_camera_and_powerup )
2959         NO_COLLISION( OBJ_CAMERA, OBJ_DEBRIS,  collide_camera_and_debris )
2960         NO_COLLISION( OBJ_POWERUP, OBJ_DEBRIS,  collide_powerup_and_debris )
2961         DO_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN, collide_weapon_and_controlcen )
2962         DO_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN, collide_robot_and_controlcen )
2963         DO_COLLISION( OBJ_WEAPON, OBJ_CLUTTER, collide_weapon_and_clutter )
2964
2965         DO_COLLISION( OBJ_MARKER, OBJ_PLAYER,  collide_player_and_marker)
2966         NO_COLLISION( OBJ_MARKER, OBJ_ROBOT,   NULL)
2967         NO_COLLISION( OBJ_MARKER, OBJ_HOSTAGE, NULL)
2968         NO_COLLISION( OBJ_MARKER, OBJ_WEAPON,  NULL)
2969         NO_COLLISION( OBJ_MARKER, OBJ_CAMERA,  NULL)
2970         NO_COLLISION( OBJ_MARKER, OBJ_POWERUP, NULL)
2971         NO_COLLISION( OBJ_MARKER, OBJ_DEBRIS,  NULL)
2972
2973         default:
2974                 Int3(); //Error( "Unhandled collision_type in collide.c!\n" );
2975         }
2976 }
2977
2978 #define ENABLE_COLLISION(type1,type2)                                   \
2979         CollisionResult[type1][type2] = RESULT_CHECK;   \
2980         CollisionResult[type2][type1] = RESULT_CHECK;
2981
2982 #define DISABLE_COLLISION(type1,type2)                                  \
2983         CollisionResult[type1][type2] = RESULT_NOTHING; \
2984         CollisionResult[type2][type1] = RESULT_NOTHING;
2985
2986 void collide_init()     {
2987         int i, j;
2988
2989         for (i=0; i < MAX_OBJECT_TYPES; i++ )
2990                 for (j=0; j < MAX_OBJECT_TYPES; j++ )
2991                         CollisionResult[i][j] = RESULT_NOTHING;
2992
2993         ENABLE_COLLISION( OBJ_WALL, OBJ_ROBOT );
2994         ENABLE_COLLISION( OBJ_WALL, OBJ_WEAPON );
2995         ENABLE_COLLISION( OBJ_WALL, OBJ_PLAYER  );
2996         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL );
2997
2998         ENABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT );
2999 //      DISABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT );      //      ALERT: WARNING: HACK: MK = RESPONSIBLE! TESTING!!
3000
3001         DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE );
3002         ENABLE_COLLISION( OBJ_PLAYER, OBJ_PLAYER );
3003         ENABLE_COLLISION( OBJ_WEAPON, OBJ_WEAPON );
3004         DISABLE_COLLISION( OBJ_CAMERA, OBJ_CAMERA );
3005         DISABLE_COLLISION( OBJ_POWERUP, OBJ_POWERUP );
3006         DISABLE_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS );
3007         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_ROBOT );
3008         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE );
3009         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_PLAYER );
3010         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_WEAPON );
3011         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_CAMERA );
3012         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_POWERUP );
3013         DISABLE_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS );
3014         DISABLE_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE );
3015         ENABLE_COLLISION( OBJ_ROBOT, OBJ_PLAYER );
3016         ENABLE_COLLISION( OBJ_ROBOT, OBJ_WEAPON );
3017         DISABLE_COLLISION( OBJ_ROBOT, OBJ_CAMERA );
3018         DISABLE_COLLISION( OBJ_ROBOT, OBJ_POWERUP );
3019         DISABLE_COLLISION( OBJ_ROBOT, OBJ_DEBRIS );
3020         ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER );
3021         ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON );
3022         DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA );
3023         DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP );
3024         DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS );
3025         ENABLE_COLLISION( OBJ_PLAYER, OBJ_WEAPON );
3026         DISABLE_COLLISION( OBJ_PLAYER, OBJ_CAMERA );
3027         ENABLE_COLLISION( OBJ_PLAYER, OBJ_POWERUP );
3028         DISABLE_COLLISION( OBJ_PLAYER, OBJ_DEBRIS );
3029         DISABLE_COLLISION( OBJ_WEAPON, OBJ_CAMERA );
3030         DISABLE_COLLISION( OBJ_WEAPON, OBJ_POWERUP );
3031         ENABLE_COLLISION( OBJ_WEAPON, OBJ_DEBRIS );
3032         DISABLE_COLLISION( OBJ_CAMERA, OBJ_POWERUP );
3033         DISABLE_COLLISION( OBJ_CAMERA, OBJ_DEBRIS );
3034         DISABLE_COLLISION( OBJ_POWERUP, OBJ_DEBRIS );
3035         ENABLE_COLLISION( OBJ_POWERUP, OBJ_WALL );
3036         ENABLE_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN )
3037         ENABLE_COLLISION( OBJ_WEAPON, OBJ_CLUTTER )
3038         ENABLE_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN )
3039         ENABLE_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN )
3040         ENABLE_COLLISION( OBJ_PLAYER, OBJ_CLUTTER )
3041
3042         ENABLE_COLLISION( OBJ_PLAYER, OBJ_MARKER );
3043
3044 }
3045
3046 void collide_object_with_wall( object * A, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt )
3047 {
3048
3049         switch( A->type )       {
3050         case OBJ_NONE:
3051                 Error( "A object of type NONE hit a wall!\n");
3052                 break;
3053         case OBJ_PLAYER:                collide_player_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
3054         case OBJ_WEAPON:                collide_weapon_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
3055         case OBJ_DEBRIS:                collide_debris_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
3056
3057         case OBJ_FIREBALL:      break;          //collide_fireball_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
3058         case OBJ_ROBOT:         collide_robot_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
3059         case OBJ_HOSTAGE:               break;          //collide_hostage_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
3060         case OBJ_CAMERA:                break;          //collide_camera_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
3061         case OBJ_POWERUP:               break;          //collide_powerup_and_wall(A,hitspeed,hitseg,hitwall,hitpt); 
3062         case OBJ_GHOST:         break;  //do nothing
3063
3064         default:
3065                 Error( "Unhandled object type hit wall in collide.c\n" );
3066         }
3067 }
3068
3069