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