2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 * $Source: /cvs/cvsroot/d2x/main/collide.c,v $
18 * $Date: 2001-11-08 10:30:27 $
20 * FIXME: put description here
22 * $Log: not supported by cvs2svn $
23 * Revision 1.8 2001/10/25 02:15:55 bradleyb
24 * conditionalize including multi.h and network.h, fix backslashes
26 * Revision 1.7 2001/10/18 00:01:00 bradleyb
27 * RCS headers added/changed
36 #include <string.h> // for memset
98 #include "editor/editor.h"
103 #define STANDARD_EXPL_DELAY (f1_0/4)
105 //##void collide_fireball_and_wall(object *fireball,fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) {
109 // -------------------------------------------------------------------------------------------------------------
110 // The only reason this routine is called (as of 10/12/94) is so Brain guys can open doors.
111 void collide_robot_and_wall( object * robot, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
113 ai_local *ailp = &Ai_local_info[robot-Objects];
115 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)) {
116 int wall_num = Segments[hitseg].sides[hitwall].wall_num;
117 if (wall_num != -1) {
118 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)) {
119 // -- mprintf((0, "Trying to open door at segment %i, side %i\n", hitseg, hitwall));
120 wall_open_door(&Segments[hitseg], hitwall);
121 // -- Changed from this, 10/19/95, MK: Don't want buddy getting stranded from player
122 //-- } 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)) {
123 } else if ((Robot_info[robot->id].companion == 1) && (Walls[wall_num].type == WALL_DOOR)) {
124 if ((ailp->mode == AIM_GOTO_PLAYER) || (Escort_special_goal == ESCORT_GOAL_SCRAM)) {
125 if (Walls[wall_num].keys != KEY_NONE) {
126 if (Walls[wall_num].keys & Players[Player_num].flags)
127 wall_open_door(&Segments[hitseg], hitwall);
128 } else if (!(Walls[wall_num].flags & WALL_DOOR_LOCKED))
129 wall_open_door(&Segments[hitseg], hitwall);
131 } else if (Robot_info[robot->id].thief) { // Thief allowed to go through doors to which player has key.
132 if (Walls[wall_num].keys != KEY_NONE)
133 if (Walls[wall_num].keys & Players[Player_num].flags)
134 wall_open_door(&Segments[hitseg], hitwall);
142 //##void collide_hostage_and_wall( object * hostage, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) {
146 // -------------------------------------------------------------------------------------------------------------
148 int apply_damage_to_clutter(object *clutter, fix damage)
150 if ( clutter->flags&OF_EXPLODING) return 0;
152 if (clutter->shields < 0 ) return 0; //clutter already dead...
154 clutter->shields -= damage;
156 if (clutter->shields < 0) {
157 explode_object(clutter,0);
163 char Monster_mode = 0; // A cheat. Do massive damage when collide.
165 //given the specified force, apply damage from that force to an object
166 void apply_force_damage(object *obj,fix force,object *other_obj)
171 if (obj->flags & (OF_EXPLODING|OF_SHOULD_BE_DEAD))
172 return; //already exploding or dead
174 damage = fixdiv(force,obj->mtype.phys_info.mass) / 8;
176 if ((other_obj->type == OBJ_PLAYER) && Monster_mode)
179 //mprintf((0,"obj %d, damage=%x\n",obj-Objects,damage));
185 if (Robot_info[obj->id].attack_type == 1) {
186 if (other_obj->type == OBJ_WEAPON)
187 result = apply_damage_to_robot(obj,damage/4, other_obj->ctype.laser_info.parent_num);
189 result = apply_damage_to_robot(obj,damage/4, other_obj-Objects);
192 if (other_obj->type == OBJ_WEAPON)
193 result = apply_damage_to_robot(obj,damage/2, other_obj->ctype.laser_info.parent_num);
195 result = apply_damage_to_robot(obj,damage/2, other_obj-Objects);
198 if (result && (other_obj->ctype.laser_info.parent_signature == ConsoleObject->signature))
199 add_points_to_score(Robot_info[obj->id].score_value);
204 // If colliding with a claw type robot, do damage proportional to FrameTime because you can collide with those
205 // bots every frame since they don't move.
206 if ( (other_obj->type == OBJ_ROBOT) && (Robot_info[other_obj->id].attack_type) )
207 damage = fixmul(damage, FrameTime*2);
209 // Make trainee easier.
210 if (Difficulty_level == 0)
213 apply_damage_to_player(obj,other_obj,damage);
218 apply_damage_to_clutter(obj,damage);
223 apply_damage_to_controlcen(obj,damage, other_obj-Objects);
228 break; //weapons don't take damage
237 // -----------------------------------------------------------------------------
238 void bump_this_object(object *objp, object *other_objp, vms_vector *force, int damage_flag)
242 if (! (objp->mtype.phys_info.flags & PF_PERSISTENT))
244 if (objp->type == OBJ_PLAYER) {
246 force2.x = force->x/4;
247 force2.y = force->y/4;
248 force2.z = force->z/4;
249 phys_apply_force(objp,&force2);
250 if (damage_flag && ((other_objp->type != OBJ_ROBOT) || !Robot_info[other_objp->id].companion)) {
251 force_mag = vm_vec_mag_quick(&force2);
252 apply_force_damage(objp, force_mag, other_objp);
254 } else if ((objp->type == OBJ_ROBOT) || (objp->type == OBJ_CLUTTER) || (objp->type == OBJ_CNTRLCEN)) {
255 if (!Robot_info[objp->id].boss_flag) {
257 force2.x = force->x/(4 + Difficulty_level);
258 force2.y = force->y/(4 + Difficulty_level);
259 force2.z = force->z/(4 + Difficulty_level);
261 phys_apply_force(objp, force);
262 phys_apply_rot(objp, &force2);
264 force_mag = vm_vec_mag_quick(force);
265 apply_force_damage(objp, force_mag, other_objp);
272 // -----------------------------------------------------------------------------
273 //deal with two objects bumping into each other. Apply force from collision
274 //to each robot. The flags tells whether the objects should take damage from
276 void bump_two_objects(object *obj0,object *obj1,int damage_flag)
281 if (obj0->movement_type != MT_PHYSICS)
283 else if (obj1->movement_type != MT_PHYSICS)
287 Assert(t->movement_type == MT_PHYSICS);
288 vm_vec_copy_scale(&force,&t->mtype.phys_info.velocity,-t->mtype.phys_info.mass);
289 phys_apply_force(t,&force);
293 vm_vec_sub(&force,&obj0->mtype.phys_info.velocity,&obj1->mtype.phys_info.velocity);
294 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));
296 bump_this_object(obj1, obj0, &force, damage_flag);
297 vm_vec_negate(&force);
298 bump_this_object(obj0, obj1, &force, damage_flag);
302 void bump_one_object(object *obj0, vms_vector *hit_dir, fix damage)
307 vm_vec_scale(&hit_vec, damage);
309 phys_apply_force(obj0,&hit_vec);
313 #define DAMAGE_SCALE 128 // Was 32 before 8:55 am on Thursday, September 15, changed by MK, walls were hurting me more than robots!
314 #define DAMAGE_THRESHOLD (F1_0/3)
315 #define WALL_LOUDNESS_SCALE (20)
317 fix force_force = i2f(50);
319 void collide_player_and_wall( object * playerobj, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
322 char ForceFieldHit=0;
323 int tmap_num,tmap_num2;
325 if (playerobj->id != Player_num) // Execute only for local player
328 tmap_num = Segments[hitseg].sides[hitwall].tmap_num;
330 // If this wall does damage, don't make *BONK* sound, we'll be making another sound.
331 if (TmapInfo[tmap_num].damage > 0)
334 if (TmapInfo[tmap_num].flags & TMI_FORCE_FIELD) {
337 PALETTE_FLASH_ADD(0, 0, 60); //flash blue
339 //knock player around
340 force.x = 40*(d_rand() - 16384);
341 force.y = 40*(d_rand() - 16384);
342 force.z = 40*(d_rand() - 16384);
343 phys_apply_rot(playerobj, &force);
347 Tactile_apply_force (&force,&playerobj->orient);
351 digi_link_sound_to_pos( SOUND_FORCEFIELD_BOUNCE_PLAYER, hitseg, 0, hitpt, 0, f1_0 );
353 if (Game_mode & GM_MULTI)
354 multi_send_play_sound(SOUND_FORCEFIELD_BOUNCE_PLAYER, f1_0);
363 force.x = -playerobj->mtype.phys_info.velocity.x;
364 force.y = -playerobj->mtype.phys_info.velocity.y;
365 force.z = -playerobj->mtype.phys_info.velocity.z;
366 Tactile_do_collide(&force, &playerobj->orient);
370 wall_hit_process( &Segments[hitseg], hitwall, 20, playerobj->id, playerobj );
373 // ** Damage from hitting wall **
374 // If the player has less than 10% shields, don't take damage from bump
375 // Note: Does quad damage if hit a force field - JL
376 damage = (hitspeed / DAMAGE_SCALE) * (ForceFieldHit*8 + 1);
378 tmap_num2 = Segments[hitseg].sides[hitwall].tmap_num2;
380 //don't do wall damage and sound if hit lava or water
381 if ((TmapInfo[tmap_num].flags & (TMI_WATER|TMI_VOLATILE)) || (tmap_num2 && (TmapInfo[tmap_num2&0x3fff].flags & (TMI_WATER|TMI_VOLATILE))))
384 if (damage >= DAMAGE_THRESHOLD) {
386 volume = (hitspeed-(DAMAGE_SCALE*DAMAGE_THRESHOLD)) / WALL_LOUDNESS_SCALE ;
388 create_awareness_event(playerobj, PA_WEAPON_WALL_COLLISION);
392 if (volume > 0 && !ForceFieldHit) { // uhhhgly hack
393 digi_link_sound_to_pos( SOUND_PLAYER_HIT_WALL, hitseg, 0, hitpt, 0, volume );
395 if (Game_mode & GM_MULTI)
396 multi_send_play_sound(SOUND_PLAYER_HIT_WALL, volume);
400 if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
401 if ( Players[Player_num].shields > f1_0*10 || ForceFieldHit)
402 apply_damage_to_player( playerobj, playerobj, damage );
404 // -- No point in doing this unless we compute a reasonable hitpt. Currently it is just the player's position. --MK, 01/18/96
405 // -- if (!(TmapInfo[Segments[hitseg].sides[hitwall].tmap_num].flags & TMI_FORCE_FIELD)) {
406 // -- vms_vector hitpt1;
409 // -- vm_vec_avg(&hitpt1, hitpt, &Objects[Players[Player_num].objnum].pos);
410 // -- hitseg1 = find_point_seg(&hitpt1, Objects[Players[Player_num].objnum].segnum);
411 // -- if (hitseg1 != -1)
412 // -- object_create_explosion( hitseg, hitpt, Weapon_info[0].impact_size, Weapon_info[0].wall_hit_vclip );
420 fix Last_volatile_scrape_sound_time = 0;
422 void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt);
423 void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt);
425 //see if wall is volatile or water
426 //if volatile, cause damage to player
427 //returns 1=lava, 2=water
428 int check_volatile_wall(object *obj,int segnum,int sidenum,vms_vector *hitpt)
430 fix tmap_num,d,water;
432 Assert(obj->type==OBJ_PLAYER);
434 tmap_num = Segments[segnum].sides[sidenum].tmap_num;
436 d = TmapInfo[tmap_num].damage;
437 water = (TmapInfo[tmap_num].flags & TMI_WATER);
439 if (d > 0 || water) {
441 if (obj->id == Player_num) {
444 fix damage = fixmul(d,FrameTime);
446 if (Difficulty_level == 0)
449 if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
450 apply_damage_to_player( obj, obj, damage );
454 Tactile_Xvibrate (50,25);
457 PALETTE_FLASH_ADD(f2i(damage*4), 0, 0); //flash red
460 obj->mtype.phys_info.rotvel.x = (d_rand() - 16384)/2;
461 obj->mtype.phys_info.rotvel.z = (d_rand() - 16384)/2;
469 if (TactileStick && !(FrameCount & 15))
470 Tactile_Xvibrate_clear ();
477 //this gets called when an object is scraping along the wall
478 void scrape_object_on_wall(object *obj, short hitseg, short hitside, vms_vector * hitpt )
484 if (obj->id==Player_num) {
487 //mprintf((0, "Scraped segment #%3i, side #%i\n", hitseg, hitside));
489 if ((type=check_volatile_wall(obj,hitseg,hitside,hitpt))!=0) {
490 vms_vector hit_dir, rand_vec;
492 if ((GameTime > Last_volatile_scrape_sound_time + F1_0/4) || (GameTime < Last_volatile_scrape_sound_time)) {
493 int sound = (type==1)?SOUND_VOLATILE_WALL_HISS:SOUND_SHIP_IN_WATER;
495 Last_volatile_scrape_sound_time = GameTime;
497 digi_link_sound_to_pos( sound, hitseg, 0, hitpt, 0, F1_0 );
499 if (Game_mode & GM_MULTI)
500 multi_send_play_sound(sound, F1_0);
505 get_side_normal(&Segments[hitseg], higside, 0, &hit_dir );
507 hit_dir = Segments[hitseg].sides[hitside].normals[0];
510 make_random_vector(&rand_vec);
511 vm_vec_scale_add2(&hit_dir, &rand_vec, F1_0/8);
512 vm_vec_normalize_quick(&hit_dir);
513 bump_one_object(obj, &hit_dir, F1_0*8);
517 //@@ //what scrape sound
518 //@@ //PLAY_SOUND( SOUND_PLAYER_SCRAPE_WALL );
525 //these two kinds of objects below shouldn't really slide, so
526 //if this scrape routine gets called (which it might if the
527 //object (such as a fusion blob) was created already poking
528 //through the wall) call the collide routine.
531 collide_weapon_and_wall(obj,0,hitseg,hitside,hitpt);
535 collide_debris_and_wall(obj,0,hitseg,hitside,hitpt);
541 //if an effect is hit, and it can blow up, then blow it up
542 //returns true if it blew up
543 int check_effect_blowup(segment *seg,int side,vms_vector *pnt, object *blower, int force_blowup_flag)
549 // If this wall has a trigger and the blower-upper is not the player or the buddy, abort!
553 if (blower->ctype.laser_info.parent_type == OBJ_ROBOT)
554 if (Robot_info[Objects[blower->ctype.laser_info.parent_num].id].companion)
557 if (!(ok_to_blow || (blower->ctype.laser_info.parent_type == OBJ_PLAYER))) {
558 int trigger_num, wall_num;
560 wall_num = seg->sides[side].wall_num;
561 if ( wall_num != -1 ) {
562 trigger_num = Walls[wall_num].trigger;
564 if (trigger_num != -1)
571 if ((tm=seg->sides[side].tmap_num2) != 0) {
573 tmf = tm&0xc000; //tm flags
574 tm &= 0x3fff; //tm without flags
576 //check if it's an animation (monitor) or casts light
577 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))) {
579 grs_bitmap *bm = &GameBitmaps[Textures[tm].index];
582 PIGGY_PAGE_IN(Textures[tm]);
584 //this can be blown up...did we hit it?
586 if (!force_blowup_flag) {
587 find_hitpoint_uv(&u,&v,NULL,pnt,seg,side,0); //evil: always say face zero
589 x = ((unsigned) f2i(u*bm->bm_w)) % bm->bm_w;
590 y = ((unsigned) f2i(v*bm->bm_h)) % bm->bm_h;
592 switch (tmf) { //adjust for orientation of paste-on
594 case 0x4000: t=y; y=x; x=bm->bm_w-t-1; break;
595 case 0x8000: y=bm->bm_h-y-1; x=bm->bm_w-x-1; break;
596 case 0xc000: t=x; x=y; y=bm->bm_h-t-1; break;
599 //mprintf((0,"u,v = %x,%x x,y=%x,%x",u,v,x,y));
601 if (bm->bm_flags & BM_FLAG_RLE)
602 bm = rle_expand_texture(bm);
605 if (force_blowup_flag || (bm->bm_data[y*bm->bm_w+x] != TRANSPARENCY_COLOR)) { //not trans, thus on effect
611 if ((Game_mode & GM_MULTI) && Netgame.AlwaysLighting)
612 if (!(ec!=-1 && db!=-1 && !(Effects[ec].flags&EF_ONE_SHOT)))
616 //mprintf((0," HIT!\n"));
618 //note: this must get called before the texture changes,
619 //because we use the light value of the texture to change
620 //the static light in the segment
621 subtract_light(seg-Segments,side);
623 if (Newdemo_state == ND_STATE_RECORDING)
624 newdemo_record_effect_blowup( seg-Segments, side, pnt);
627 dest_size = Effects[ec].dest_size;
628 vc = Effects[ec].dest_vclip;
634 object_create_explosion( seg-Segments, pnt, dest_size, vc );
636 if (ec!=-1 && db!=-1 && !(Effects[ec].flags&EF_ONE_SHOT)) {
638 if ((sound_num = Vclip[vc].sound_num) != -1)
639 digi_link_sound_to_pos( sound_num, seg-Segments, 0, pnt, 0, F1_0 );
641 if ((sound_num=Effects[ec].sound_num)!=-1) //kill sound
642 digi_kill_sound_linked_to_segment(seg-Segments,side,sound_num);
644 if (Effects[ec].dest_eclip!=-1 && Effects[Effects[ec].dest_eclip].segnum==-1) {
648 new_ec = &Effects[Effects[ec].dest_eclip];
649 bm_num = new_ec->changing_wall_texture;
651 mprintf((0,"bm_num = %d\n",bm_num));
653 new_ec->time_left = new_ec->vc.frame_time;
654 new_ec->frame_count = 0;
655 new_ec->segnum = seg-Segments;
656 new_ec->sidenum = side;
657 new_ec->flags |= EF_ONE_SHOT;
658 new_ec->dest_bm_num = Effects[ec].dest_bm_num;
660 Assert(bm_num!=0 && seg->sides[side].tmap_num2!=0);
661 seg->sides[side].tmap_num2 = bm_num | tmf; //replace with destoyed
665 Assert(db!=0 && seg->sides[side].tmap_num2!=0);
666 seg->sides[side].tmap_num2 = db | tmf; //replace with destoyed
670 seg->sides[side].tmap_num2 = TmapInfo[tm].destroyed | tmf;
672 //assume this is a light, and play light sound
673 digi_link_sound_to_pos( SOUND_LIGHT_BLOWNUP, seg-Segments, 0, pnt, 0, F1_0 );
682 return 0; //didn't blow up
685 // Copied from laser.c!
686 #define MIN_OMEGA_BLOBS 3 // No matter how close the obstruction, at this many blobs created.
687 #define MIN_OMEGA_DIST (F1_0*3) // At least this distance between blobs, unless doing so would violate MIN_OMEGA_BLOBS
688 #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.
689 #define MAX_OMEGA_BLOBS 16 // No matter how far away the obstruction, this is the maximum number of blobs.
690 #define MAX_OMEGA_DIST (MAX_OMEGA_BLOBS * DESIRED_OMEGA_DIST) // Maximum extent of lightning blobs.
692 // -------------------------------------------------
693 // Return true if ok to do Omega damage.
694 int ok_to_do_omega_damage(object *weapon)
696 int parent_sig = weapon->ctype.laser_info.parent_signature;
697 int parent_num = weapon->ctype.laser_info.parent_num;
699 if (!(Game_mode & GM_MULTI))
702 if (Objects[parent_num].signature != parent_sig)
703 mprintf((0, "Parent of omega blob not consistent with object information.\n"));
705 fix dist = vm_vec_dist_quick(&Objects[parent_num].pos, &weapon->pos);
707 if (dist > MAX_OMEGA_DIST) {
708 // -- mprintf((0, "Not doing damage in frame %i, too far away.\n", FrameCount));
711 ; // -- mprintf((0, "*** Doing damage in frame %i ***\n", FrameCount));
717 //these gets added to the weapon's values when the weapon hits a volitle wall
718 #define VOLATILE_WALL_EXPL_STRENGTH i2f(10)
719 #define VOLATILE_WALL_IMPACT_SIZE i2f(3)
720 #define VOLATILE_WALL_DAMAGE_FORCE i2f(5)
721 #define VOLATILE_WALL_DAMAGE_RADIUS i2f(30)
723 // int Show_seg_and_side = 0;
725 void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt)
727 segment *seg = &Segments[hitseg];
733 if (weapon->id == OMEGA_ID)
734 if (!ok_to_do_omega_damage(weapon))
737 // If this is a guided missile and it strikes fairly directly, clear bounce flag.
738 if (weapon->id == GUIDEDMISS_ID) {
741 dot = vm_vec_dot(&weapon->orient.fvec, &Segments[hitseg].sides[hitwall].normals[0]);
742 mprintf((0, "Guided missile dot = %7.3f\n", f2fl(dot)));
744 mprintf((0, "Guided missile loses bounciness.\n"));
745 weapon->mtype.phys_info.flags &= ~PF_BOUNCE;
749 //if an energy weapon hits a forcefield, let it bounce
750 if ((TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_FORCE_FIELD) &&
751 !(weapon->type == OBJ_WEAPON && Weapon_info[weapon->id].energy_usage==0)) {
754 digi_link_sound_to_pos( SOUND_FORCEFIELD_BOUNCE_WEAPON, hitseg, 0, hitpt, 0, f1_0 );
756 if (Game_mode & GM_MULTI)
757 multi_send_play_sound(SOUND_FORCEFIELD_BOUNCE_WEAPON, f1_0);
760 return; //bail here. physics code will bounce this object
764 if (keyd_pressed[KEY_LAPOSTRO])
765 if (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum) {
766 // MK: Real pain when you need to know a seg:side and you've got quad lasers.
767 mprintf((0, "Your laser hit at segment = %i, side = %i\n", hitseg, hitwall));
768 HUD_init_message("Hit at segment = %i, side = %i", hitseg, hitwall);
770 subtract_light(hitseg, hitwall);
771 else if (weapon->id == FLARE_ID)
772 add_light(hitseg, hitwall);
776 //@@Cursegp = &Segments[hitseg];
777 //@@Curside = hitwall;
781 if ((weapon->mtype.phys_info.velocity.x == 0) && (weapon->mtype.phys_info.velocity.y == 0) && (weapon->mtype.phys_info.velocity.z == 0)) {
782 Int3(); // Contact Matt: This is impossible. A weapon with 0 velocity hit a wall, which doesn't move.
786 blew_up = check_effect_blowup(seg,hitwall,hitpt, weapon, 0);
788 //if ((seg->sides[hitwall].tmap_num2==0) && (TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_VOLATILE)) {
790 if ((weapon->ctype.laser_info.parent_type == OBJ_ROBOT) && (Robot_info[Objects[weapon->ctype.laser_info.parent_num].id].companion==1)) {
793 if (Game_mode & GM_MULTI)
795 Int3(); // Get Jason!
800 playernum = Player_num; //if single player, he's the player's buddy
805 if (Objects[weapon->ctype.laser_info.parent_num].type == OBJ_PLAYER)
806 playernum = Objects[weapon->ctype.laser_info.parent_num].id;
808 playernum = -1; //not a player (thus a robot)
811 if (blew_up) { //could be a wall switch
812 //for wall triggers, always say that the player shot it out. This is
813 //because robots can shoot out wall triggers, and so the trigger better
815 // NO -- Changed by MK, 10/18/95. We don't want robots blowing puzzles. Only player or buddy can open!
816 check_trigger(seg,hitwall,weapon->ctype.laser_info.parent_num,1);
819 if (weapon->id == EARTHSHAKER_ID)
822 wall_type = wall_hit_process( seg, hitwall, weapon->shields, playernum, weapon );
824 // Wall is volatile if either tmap 1 or 2 is volatile
825 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))) {
826 weapon_info *wi = &Weapon_info[weapon->id];
829 //we've hit a volatile wall
831 digi_link_sound_to_pos( SOUND_VOLATILE_WALL_HIT,hitseg, 0, hitpt, 0, F1_0 );
833 //for most weapons, use volatile wall hit. For mega, use its special vclip
834 vclip = (weapon->id == MEGA_ID)?Weapon_info[weapon->id].robot_hit_vclip:VCLIP_VOLATILE_WALL_HIT;
836 // New by MK: If powerful badass, explode as badass, not due to lava, fixes megas being wimpy in lava.
837 if (wi->damage_radius >= VOLATILE_WALL_DAMAGE_RADIUS/2) {
838 // -- mprintf((0, "Big weapon doing badass in lava instead.\n"));
839 explode_badass_weapon(weapon,hitpt);
841 object_create_badass_explosion( weapon, hitseg, hitpt,
842 wi->impact_size + VOLATILE_WALL_IMPACT_SIZE,
844 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.
845 wi->damage_radius+VOLATILE_WALL_DAMAGE_RADIUS,
846 wi->strength[Difficulty_level]/2+VOLATILE_WALL_DAMAGE_FORCE,
847 weapon->ctype.laser_info.parent_num );
850 weapon->flags |= OF_SHOULD_BE_DEAD; //make flares die in lava
853 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))) {
854 weapon_info *wi = &Weapon_info[weapon->id];
858 // MK: 09/13/95: Badass in water is 1/2 normal intensity.
859 if ( Weapon_info[weapon->id].matter ) {
861 digi_link_sound_to_pos( SOUND_MISSILE_HIT_WATER,hitseg, 0, hitpt, 0, F1_0 );
863 if ( Weapon_info[weapon->id].damage_radius ) {
865 digi_link_sound_to_object(SOUND_BADASS_EXPLOSION, weapon-Objects, 0, F1_0);
867 // MK: 09/13/95: Badass in water is 1/2 normal intensity.
868 object_create_badass_explosion( weapon, hitseg, hitpt,
871 wi->strength[Difficulty_level]/4,
873 wi->strength[Difficulty_level]/2,
874 weapon->ctype.laser_info.parent_num );
877 object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].wall_hit_vclip );
880 digi_link_sound_to_pos( SOUND_LASER_HIT_WATER,hitseg, 0, hitpt, 0, F1_0 );
881 object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, VCLIP_WATER_HIT );
884 weapon->flags |= OF_SHOULD_BE_DEAD; //make flares die in water
889 if (weapon->mtype.phys_info.flags & PF_BOUNCE) {
891 //do special bound sound & effect
896 //if it's not the player's weapon, or it is the player's and there
897 //is no wall, and no blowing up monitor, then play sound
898 if ((weapon->ctype.laser_info.parent_type != OBJ_PLAYER) || ((seg->sides[hitwall].wall_num == -1 || wall_type==WHP_NOT_SPECIAL) && !blew_up))
899 if ((Weapon_info[weapon->id].wall_hit_sound > -1 ) && (!(weapon->flags & OF_SILENT)))
900 digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound,weapon->segnum, 0, &weapon->pos, 0, F1_0 );
902 if ( Weapon_info[weapon->id].wall_hit_vclip > -1 ) {
903 if ( Weapon_info[weapon->id].damage_radius )
904 explode_badass_weapon(weapon,hitpt);
906 object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].wall_hit_vclip );
911 // If weapon fired by player or companion...
912 if (( weapon->ctype.laser_info.parent_type== OBJ_PLAYER ) || robot_escort) {
914 if (!(weapon->flags & OF_SILENT) && (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum))
915 create_awareness_event(weapon, PA_WEAPON_WALL_COLLISION); // object "weapon" can attract attention to player
917 // if (weapon->id != FLARE_ID) {
918 // We now allow flares to open doors.
921 if (((weapon->id != FLARE_ID) || (weapon->ctype.laser_info.parent_type != OBJ_PLAYER)) && !(weapon->mtype.phys_info.flags & PF_BOUNCE))
922 weapon->flags |= OF_SHOULD_BE_DEAD;
924 //don't let flares stick in force fields
925 if ((weapon->id == FLARE_ID) && (TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_FORCE_FIELD))
926 weapon->flags |= OF_SHOULD_BE_DEAD;
928 if (!(weapon->flags & OF_SILENT)) {
931 case WHP_NOT_SPECIAL:
932 //should be handled above
933 //digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
937 //play special hit door sound (if/when we get it)
938 digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
940 if (Game_mode & GM_MULTI)
941 multi_send_play_sound( SOUND_WEAPON_HIT_DOOR, F1_0 );
947 //play special blastable wall sound (if/when we get it)
948 if ((Weapon_info[weapon->id].wall_hit_sound > -1 ) && (!(weapon->flags & OF_SILENT)))
949 digi_link_sound_to_pos( SOUND_WEAPON_HIT_BLASTABLE, weapon->segnum, 0, &weapon->pos, 0, F1_0 );
953 //don't play anything, since door open sound will play
957 //mprintf((0, "Weapon %i hits wall, but has silent bit set.\n", weapon-Objects));
959 // if (weapon->lifeleft <= 0)
960 // weapon->flags |= OF_SHOULD_BE_DEAD;
964 // This is a robot's laser
965 if (!(weapon->mtype.phys_info.flags & PF_BOUNCE))
966 weapon->flags |= OF_SHOULD_BE_DEAD;
972 //##void collide_camera_and_wall( object * camera, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) {
976 //##void collide_powerup_and_wall( object * powerup, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) {
980 void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) {
981 explode_object(debris,0);
985 //##void collide_fireball_and_fireball( object * fireball1, object * fireball2, vms_vector *collision_point ) {
989 //##void collide_fireball_and_robot( object * fireball, object * robot, vms_vector *collision_point ) {
993 //##void collide_fireball_and_hostage( object * fireball, object * hostage, vms_vector *collision_point ) {
997 //##void collide_fireball_and_player( object * fireball, object * player, vms_vector *collision_point ) {
1001 //##void collide_fireball_and_weapon( object * fireball, object * weapon, vms_vector *collision_point ) {
1002 //## //weapon->flags |= OF_SHOULD_BE_DEAD;
1006 //##void collide_fireball_and_camera( object * fireball, object * camera, vms_vector *collision_point ) {
1010 //##void collide_fireball_and_powerup( object * fireball, object * powerup, vms_vector *collision_point ) {
1014 //##void collide_fireball_and_debris( object * fireball, object * debris, vms_vector *collision_point ) {
1018 // -------------------------------------------------------------------------------------------------------------------
1019 void collide_robot_and_robot( object * robot1, object * robot2, vms_vector *collision_point ) {
1020 // mprintf((0, "Coll: [%2i %4i %4i %4i] [%2i %4i %4i %4i] at [%4i %4i %4i]",
1021 // robot1-Objects, f2i(robot1->pos.x), f2i(robot1->pos.y), f2i(robot1->pos.z),
1022 // robot2-Objects, f2i(robot2->pos.x), f2i(robot2->pos.y), f2i(robot2->pos.z),
1023 // f2i(collision_point->x), f2i(collision_point->y), f2i(collision_point->z)));
1025 bump_two_objects(robot1, robot2, 1);
1029 void collide_robot_and_controlcen( object * obj1, object * obj2, vms_vector *collision_point )
1032 if (obj1->type == OBJ_ROBOT) {
1034 vm_vec_normalize_quick(vm_vec_sub(&hitvec, &obj2->pos, &obj1->pos));
1035 bump_one_object(obj1, &hitvec, 0);
1038 vm_vec_normalize_quick(vm_vec_sub(&hitvec, &obj1->pos, &obj2->pos));
1039 bump_one_object(obj2, &hitvec, 0);
1044 //##void collide_robot_and_hostage( object * robot, object * hostage, vms_vector *collision_point ) {
1048 fix Last_thief_hit_time;
1050 void collide_robot_and_player( object * robot, object * playerobj, vms_vector *collision_point )
1052 int steal_attempt = 0;
1055 if (robot->flags&OF_EXPLODING)
1058 collision_seg = find_point_seg(collision_point, playerobj->segnum);
1059 if (collision_seg != -1)
1060 object_create_explosion( collision_seg, collision_point, Weapon_info[0].impact_size, Weapon_info[0].wall_hit_vclip );
1062 if (playerobj->id == Player_num) {
1063 if (Robot_info[robot->id].companion) // Player and companion don't collide.
1065 if (Robot_info[robot->id].kamikaze) {
1066 apply_damage_to_robot(robot, robot->shields+1, playerobj-Objects);
1067 if (playerobj == ConsoleObject)
1068 add_points_to_score(Robot_info[robot->id].score_value);
1071 if (Robot_info[robot->id].thief) {
1072 if (Ai_local_info[robot-Objects].mode == AIM_THIEF_ATTACK) {
1073 Last_thief_hit_time = GameTime;
1074 attempt_to_steal_item(robot, playerobj->id);
1076 } else if (GameTime - Last_thief_hit_time < F1_0*2)
1077 return; // ZOUNDS! BRILLIANT! Thief not collide with player if not stealing!
1078 // NO! VERY DUMB! makes thief look very stupid if player hits him while cloaked! -AP
1080 Last_thief_hit_time = GameTime;
1083 create_awareness_event(playerobj, PA_PLAYER_COLLISION); // object robot can attract attention to player
1084 do_ai_robot_hit_attack(robot, playerobj, collision_point);
1085 do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION);
1089 multi_robot_request_change(robot, playerobj->id);
1092 // added this if to remove the bump sound if it's the thief.
1093 // A "steal" sound was added and it was getting obscured by the bump. -AP 10/3/95
1094 // Changed by MK to make this sound unless the robot stole.
1095 if ((!steal_attempt) && !Robot_info[robot->id].energy_drain)
1096 digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, playerobj->segnum, 0, collision_point, 0, F1_0 );
1098 bump_two_objects(robot, playerobj, 1);
1102 // Provide a way for network message to instantly destroy the control center
1103 // without awarding points or anything.
1105 // if controlcen == NULL, that means don't do the explosion because the control center
1106 // was actually in another object.
1107 void net_destroy_controlcen(object *controlcen)
1109 if (Control_center_destroyed != 1) {
1111 do_controlcen_destroyed_stuff(controlcen);
1113 if ((controlcen != NULL) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED))) {
1114 digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 );
1115 explode_object(controlcen,0);
1121 // -----------------------------------------------------------------------------
1122 void apply_damage_to_controlcen(object *controlcen, fix damage, short who)
1126 // Only allow a player to damage the control center.
1128 if ((who < 0) || (who > Highest_object_index))
1131 whotype = Objects[who].type;
1132 if (whotype != OBJ_PLAYER) {
1133 mprintf((0, "Damage to control center by object of type %i prevented by MK!\n", whotype));
1138 if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) && (Players[Player_num].time_level < Netgame.control_invul_time))
1140 if (Objects[who].id == Player_num) {
1141 int secs = f2i(Netgame.control_invul_time-Players[Player_num].time_level) % 60;
1142 int mins = f2i(Netgame.control_invul_time-Players[Player_num].time_level) / 60;
1143 HUD_init_message("%s %d:%02d.", TXT_CNTRLCEN_INVUL, mins, secs);
1149 if (Objects[who].id == Player_num) {
1150 Control_center_been_hit = 1;
1151 ai_do_cloak_stuff();
1154 if ( controlcen->shields >= 0 )
1155 controlcen->shields -= damage;
1157 if ( (controlcen->shields < 0) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED)) ) {
1159 do_controlcen_destroyed_stuff(controlcen);
1162 if (Game_mode & GM_MULTI) {
1163 if (who == Players[Player_num].objnum)
1164 add_points_to_score(CONTROL_CEN_SCORE);
1165 multi_send_destroy_controlcen((ushort)(controlcen-Objects), Objects[who].id );
1169 if (!(Game_mode & GM_MULTI))
1170 add_points_to_score(CONTROL_CEN_SCORE);
1172 digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 );
1174 explode_object(controlcen,0);
1178 void collide_player_and_controlcen( object * controlcen, object * playerobj, vms_vector *collision_point )
1180 if (playerobj->id == Player_num) {
1181 Control_center_been_hit = 1;
1182 ai_do_cloak_stuff(); // In case player cloaked, make control center know where he is.
1185 digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, playerobj->segnum, 0, collision_point, 0, F1_0 );
1186 bump_two_objects(controlcen, playerobj, 1);
1191 void collide_player_and_marker( object * marker, object * playerobj, vms_vector *collision_point )
1193 mprintf ((0,"Collided with marker %d!\n",marker->id));
1195 if (playerobj->id==Player_num) {
1198 if (Game_mode & GM_MULTI)
1200 drawn = HUD_init_message ("MARKER %s: %s",Players[marker->id/2].callsign,MarkerMessage[marker->id]);
1204 if (MarkerMessage[marker->id][0])
1205 drawn = HUD_init_message("MARKER %d: %s", marker->id+1,MarkerMessage[marker->id]);
1207 drawn = HUD_init_message("MARKER %d", marker->id+1);
1211 digi_play_sample( SOUND_MARKER_HIT, F1_0 );
1213 detect_escort_goal_accomplished(marker-Objects);
1217 // If a persistent weapon and other object is not a weapon, weaken it, else kill it.
1218 // If both objects are weapons, weaken the weapon.
1219 void maybe_kill_weapon(object *weapon, object *other_obj)
1221 if ((weapon->id == PROXIMITY_ID) || (weapon->id == SUPERPROX_ID) || (weapon->id == PMINE_ID)) {
1222 weapon->flags |= OF_SHOULD_BE_DEAD;
1226 // Changed, 10/12/95, MK: Make weapon-weapon collisions always kill both weapons if not persistent.
1227 // Reason: Otherwise you can't use proxbombs to detonate incoming homing missiles (or mega missiles).
1228 if (weapon->mtype.phys_info.flags & PF_PERSISTENT) {
1229 // Weapons do a lot of damage to weapons, other objects do much less.
1230 if (!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) {
1231 if (other_obj->type == OBJ_WEAPON)
1232 weapon->shields -= other_obj->shields/2;
1234 weapon->shields -= other_obj->shields/4;
1236 if (weapon->shields <= 0) {
1237 weapon->shields = 0;
1238 weapon->flags |= OF_SHOULD_BE_DEAD; // weapon->lifeleft = 1;
1242 weapon->flags |= OF_SHOULD_BE_DEAD; // weapon->lifeleft = 1;
1244 // -- if ((weapon->mtype.phys_info.flags & PF_PERSISTENT) || (other_obj->type == OBJ_WEAPON)) {
1245 // -- // Weapons do a lot of damage to weapons, other objects do much less.
1246 // -- if (!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) {
1247 // -- if (other_obj->type == OBJ_WEAPON)
1248 // -- weapon->shields -= other_obj->shields/2;
1250 // -- weapon->shields -= other_obj->shields/4;
1252 // -- if (weapon->shields <= 0) {
1253 // -- weapon->shields = 0;
1254 // -- weapon->flags |= OF_SHOULD_BE_DEAD;
1258 // -- weapon->flags |= OF_SHOULD_BE_DEAD;
1261 void collide_weapon_and_controlcen( object * weapon, object *controlcen, vms_vector *collision_point )
1264 if (weapon->id == OMEGA_ID)
1265 if (!ok_to_do_omega_damage(weapon))
1268 if (weapon->ctype.laser_info.parent_type == OBJ_PLAYER) {
1269 fix damage = weapon->shields;
1271 if (Objects[weapon->ctype.laser_info.parent_num].id == Player_num)
1272 Control_center_been_hit = 1;
1274 if ( Weapon_info[weapon->id].damage_radius )
1275 explode_badass_weapon(weapon,collision_point);
1277 object_create_explosion( controlcen->segnum, collision_point, controlcen->size*3/20, VCLIP_SMALL_EXPLOSION );
1279 digi_link_sound_to_pos( SOUND_CONTROL_CENTER_HIT, controlcen->segnum, 0, collision_point, 0, F1_0 );
1281 damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
1283 apply_damage_to_controlcen(controlcen, damage, weapon->ctype.laser_info.parent_num);
1285 maybe_kill_weapon(weapon,controlcen);
1286 } else { // If robot weapon hits control center, blow it up, make it go away, but do no damage to control center.
1287 object_create_explosion( controlcen->segnum, collision_point, controlcen->size*3/20, VCLIP_SMALL_EXPLOSION );
1288 maybe_kill_weapon(weapon,controlcen);
1293 void collide_weapon_and_clutter( object * weapon, object *clutter, vms_vector *collision_point ) {
1294 short exp_vclip = VCLIP_SMALL_EXPLOSION;
1296 if ( clutter->shields >= 0 )
1297 clutter->shields -= weapon->shields;
1299 digi_link_sound_to_pos( SOUND_LASER_HIT_CLUTTER, weapon->segnum, 0, collision_point, 0, F1_0 );
1301 object_create_explosion( clutter->segnum, collision_point, ((clutter->size/3)*3)/4, exp_vclip );
1303 if ( (clutter->shields < 0) && !(clutter->flags&(OF_EXPLODING|OF_DESTROYED)))
1304 explode_object(clutter,STANDARD_EXPL_DELAY);
1306 maybe_kill_weapon(weapon,clutter);
1309 //--mk, 121094 -- extern void spin_robot(object *robot, vms_vector *collision_point);
1311 extern object *explode_badass_object(object *objp, fix damage, fix distance, fix force);
1313 int Final_boss_is_dead = 0;
1314 fix Final_boss_countdown_time = 0;
1316 // ------------------------------------------------------------------------------------------------------
1317 void do_final_boss_frame(void)
1320 if (!Final_boss_is_dead)
1323 if (!Control_center_destroyed)
1326 if (Final_boss_countdown_time == 0)
1327 Final_boss_countdown_time = F1_0*2;
1329 Final_boss_countdown_time -= FrameTime;
1330 if (Final_boss_countdown_time > 0)
1333 gr_palette_fade_out( gr_palette, 256, 0 );
1334 start_endlevel_sequence(); //pretend we hit the exit trigger
1338 // ------------------------------------------------------------------------------------------------------
1339 // This is all the ugly stuff we do when you kill the final boss so that you don't die or something
1340 // which would ruin the logic of the cut sequence.
1341 void do_final_boss_hacks(void)
1343 if (Player_is_dead) {
1344 Int3(); // Uh-oh, player is dead. Try to rescue him.
1348 if (Players[Player_num].shields <= 0)
1349 Players[Player_num].shields = 1;
1351 // If you're not invulnerable, get invulnerable!
1352 if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) {
1353 Players[Player_num].invulnerable_time = GameTime;
1354 Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE;
1356 if (!(Game_mode & GM_MULTI))
1357 buddy_message("Nice job, %s!", Players[Player_num].callsign);
1359 Final_boss_is_dead = 1;
1362 extern int Buddy_dude_cheat;
1363 extern int multi_all_players_alive();
1364 void multi_send_finish_game ();
1366 // ------------------------------------------------------------------------------------------------------
1367 // Return 1 if robot died, else return 0
1368 int apply_damage_to_robot(object *robot, fix damage, int killer_objnum)
1372 char i,temp_stolen[MAX_STOLEN_ITEMS];
1375 if ( robot->flags&OF_EXPLODING) return 0;
1377 if (robot->shields < 0 ) return 0; //robot already dead...
1379 if (Robot_info[robot->id].boss_flag)
1380 Boss_hit_time = GameTime;
1382 // Buddy invulnerable on level 24 so he can give you his important messages. Bah.
1383 // Also invulnerable if his cheat for firing weapons is in effect.
1384 if (Robot_info[robot->id].companion) {
1385 // if ((Current_mission_num == 0 && Current_level_num == Last_level) || Buddy_dude_cheat)
1387 if ((Current_mission_num == 0 && Current_level_num == Last_level) )
1392 // if (robot->control_type == CT_REMOTE)
1393 // return 0; // Can't damange a robot controlled by another player
1395 // -- MK, 10/21/95, unused! -- if (Robot_info[robot->id].boss_flag)
1396 // Boss_been_hit = 1;
1398 robot->shields -= damage;
1400 // Do unspeakable hacks to make sure player doesn't die after killing boss. Or before, sort of.
1401 if (Robot_info[robot->id].boss_flag)
1403 if ((Current_mission_num == 0) && Current_level_num == Last_level)
1405 if (robot->shields < 0)
1408 if (Game_mode & GM_MULTI)
1410 if (!multi_all_players_alive()) // everyones gotta be alive
1414 multi_send_finish_game();
1415 do_final_boss_hacks();
1421 { // NOTE LINK TO ABOVE!!!
1422 if ((Players[Player_num].shields < 0) || Player_is_dead)
1423 robot->shields = 1; // Sorry, we can't allow you to kill the final boss after you've died. Rough luck.
1425 do_final_boss_hacks();
1429 if (robot->shields < 0) {
1431 if (Game_mode & GM_MULTI) {
1432 if (Robot_info[robot->id].thief)
1438 for (i=0;i<MAX_STOLEN_ITEMS;i++)
1439 temp_stolen[(int)i]=Stolen_items[(int)i];
1441 if (multi_explode_robot_sub(robot-Objects, killer_objnum,Robot_info[robot->id].thief))
1444 for (i=0;i<MAX_STOLEN_ITEMS;i++)
1445 Stolen_items[(int)i]=temp_stolen[(int)i];
1447 multi_send_robot_explode(robot-Objects, killer_objnum,Robot_info[robot->id].thief);
1450 for (i=0;i<MAX_STOLEN_ITEMS;i++)
1451 Stolen_items[(int)i]=255;
1460 Players[Player_num].num_kills_level++;
1461 Players[Player_num].num_kills_total++;
1463 if (Robot_info[robot->id].boss_flag) {
1464 start_boss_death_sequence(robot); //do_controlcen_destroyed_stuff(NULL);
1465 } else if (Robot_info[robot->id].death_roll) {
1466 start_robot_death_sequence(robot); //do_controlcen_destroyed_stuff(NULL);
1468 if (robot->id == SPECIAL_REACTOR_ROBOT)
1469 special_reactor_stuff();
1470 //if (Robot_info[robot->id].smart_blobs)
1471 // create_smart_children(robot, Robot_info[robot->id].smart_blobs);
1472 //if (Robot_info[robot->id].badass)
1473 // explode_badass_object(robot, F1_0*Robot_info[robot->id].badass, F1_0*40, F1_0*150);
1474 if (Robot_info[robot->id].kamikaze)
1475 explode_object(robot,1); // Kamikaze, explode right away, IN YOUR FACE!
1477 explode_object(robot,STANDARD_EXPL_DELAY);
1484 extern int boss_spew_robot(object *objp, vms_vector *pos);
1486 //--ubyte Boss_teleports[NUM_D2_BOSSES] = {1,1,1,1,1,1}; // Set byte if this boss can teleport
1487 //--ubyte Boss_cloaks[NUM_D2_BOSSES] = {1,1,1,1,1,1}; // Set byte if this boss can cloak
1488 //--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.
1489 //--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.
1490 //--ubyte Boss_invulnerable_energy[NUM_D2_BOSSES] = {0,0,1,1,0,0}; // Set byte if boss is invulnerable to energy weapons.
1491 //--ubyte Boss_invulnerable_matter[NUM_D2_BOSSES] = {0,0,0,1,0,0}; // Set byte if boss is invulnerable to matter weapons.
1492 //--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)
1494 //#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.
1495 int Boss_invulnerable_dot = 0;
1497 int Buddy_gave_hint_count = 5;
1498 fix Last_time_buddy_gave_hint = 0;
1500 // ------------------------------------------------------------------------------------------------------
1501 // Return true if damage done to boss, else return false.
1502 int do_boss_weapon_collision(object *robot, object *weapon, vms_vector *collision_point)
1509 d2_boss_index = Robot_info[robot->id].boss_flag - BOSS_D2;
1511 Assert((d2_boss_index >= 0) && (d2_boss_index < NUM_D2_BOSSES));
1513 // See if should spew a bot.
1514 if (weapon->ctype.laser_info.parent_type == OBJ_PLAYER)
1515 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])) {
1516 if (Boss_spew_more[d2_boss_index])
1517 if (d_rand() > 16384) {
1518 if (boss_spew_robot(robot, collision_point) != -1)
1519 Last_gate_time = GameTime - Gate_interval - 1; // Force allowing spew of another bot.
1521 boss_spew_robot(robot, collision_point);
1524 if (Boss_invulnerable_spot[d2_boss_index]) {
1528 // Boss only vulnerable in back. See if hit there.
1529 vm_vec_sub(&tvec1, collision_point, &robot->pos);
1530 vm_vec_normalize_quick(&tvec1); // Note, if BOSS_INVULNERABLE_DOT is close to F1_0 (in magnitude), then should probably use non-quick version.
1531 dot = vm_vec_dot(&tvec1, &robot->orient.fvec);
1532 mprintf((0, "Boss hit vec dot = %7.3f\n", f2fl(dot)));
1534 if (dot > Boss_invulnerable_dot) {
1538 segnum = find_point_seg(collision_point, robot->segnum);
1539 digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, segnum, 0, collision_point, 0, F1_0);
1542 if (Last_time_buddy_gave_hint == 0)
1543 Last_time_buddy_gave_hint = d_rand()*32 + F1_0*16;
1545 if (Buddy_gave_hint_count) {
1546 if (Last_time_buddy_gave_hint + F1_0*20 < GameTime) {
1549 Buddy_gave_hint_count--;
1550 Last_time_buddy_gave_hint = GameTime;
1551 sval = (d_rand()*4) >> 15;
1553 case 0: buddy_message("Hit him in the back!"); break;
1554 case 1: buddy_message("He's invulnerable there!"); break;
1555 case 2: buddy_message("Get behind him and fire!"); break;
1558 buddy_message("Hit the glowing spot!"); break;
1563 // Cause weapon to bounce.
1564 // Make a copy of this weapon, because the physics wants to destroy it.
1565 if (!Weapon_info[weapon->id].matter) {
1566 new_obj = obj_create(weapon->type, weapon->id, weapon->segnum, &weapon->pos,
1567 &weapon->orient, weapon->size, weapon->control_type, weapon->movement_type, weapon->render_type);
1569 if (new_obj != -1) {
1570 vms_vector vec_to_point;
1571 vms_vector weap_vec;
1574 if (weapon->render_type == RT_POLYOBJ) {
1575 Objects[new_obj].rtype.pobj_info.model_num = Weapon_info[Objects[new_obj].id].model_num;
1576 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);
1579 Objects[new_obj].mtype.phys_info.mass = Weapon_info[weapon->type].mass;
1580 Objects[new_obj].mtype.phys_info.drag = Weapon_info[weapon->type].drag;
1581 vm_vec_zero(&Objects[new_obj].mtype.phys_info.thrust);
1583 vm_vec_sub(&vec_to_point, collision_point, &robot->pos);
1584 vm_vec_normalize_quick(&vec_to_point);
1585 weap_vec = weapon->mtype.phys_info.velocity;
1586 speed = vm_vec_normalize_quick(&weap_vec);
1587 vm_vec_scale_add2(&vec_to_point, &weap_vec, -F1_0*2);
1588 vm_vec_scale(&vec_to_point, speed/4);
1589 Objects[new_obj].mtype.phys_info.velocity = vec_to_point;
1593 } else if ((Weapon_info[weapon->id].matter && Boss_invulnerable_matter[d2_boss_index]) || (!Weapon_info[weapon->id].matter && Boss_invulnerable_energy[d2_boss_index])) {
1596 segnum = find_point_seg(collision_point, robot->segnum);
1597 digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, segnum, 0, collision_point, 0, F1_0);
1604 extern int Robots_kill_robots_cheat;
1606 // ------------------------------------------------------------------------------------------------------
1607 void collide_robot_and_weapon( object * robot, object * weapon, vms_vector *collision_point )
1610 int boss_invul_flag=0;
1612 if (weapon->id == OMEGA_ID)
1613 if (!ok_to_do_omega_damage(weapon))
1616 if (Robot_info[robot->id].boss_flag) {
1617 Boss_hit_time = GameTime;
1618 if (Robot_info[robot->id].boss_flag >= BOSS_D2) {
1619 damage_flag = do_boss_weapon_collision(robot, weapon, collision_point);
1620 boss_invul_flag = !damage_flag;
1624 // Put in at request of Jasen (and Adam) because the Buddy-Bot gets in their way.
1625 // MK has so much fun whacking his butt around the mine he never cared...
1626 if ((Robot_info[robot->id].companion) && ((weapon->ctype.laser_info.parent_type != OBJ_ROBOT) && !Robots_kill_robots_cheat))
1629 if (weapon->id == EARTHSHAKER_ID)
1632 // If a persistent weapon hit robot most recently, quick abort, else we cream the same robot many times,
1633 // depending on frame rate.
1634 if (weapon->mtype.phys_info.flags & PF_PERSISTENT) {
1635 if (weapon->ctype.laser_info.last_hitobj == robot-Objects)
1638 weapon->ctype.laser_info.last_hitobj = robot-Objects;
1640 // mprintf((0, "weapon #%i with power %i hits robot #%i.\n", weapon - Objects, f2i(weapon->shields), robot - Objects));
1643 if (weapon->ctype.laser_info.parent_signature == robot->signature)
1646 // Changed, 10/04/95, put out blobs based on skill level and power of weapon doing damage.
1647 // Also, only a weapon hit from a player weapon causes smart blobs.
1648 if ((weapon->ctype.laser_info.parent_type == OBJ_PLAYER) && (Robot_info[robot->id].energy_blobs))
1649 if ((robot->shields > 0) && Weapon_is_energy[weapon->id]) {
1653 probval = (Difficulty_level+2) * min(weapon->shields, robot->shields);
1654 probval = Robot_info[robot->id].energy_blobs * probval/(NDL*32);
1656 num_blobs = probval >> 16;
1657 if (2*d_rand() < (probval & 0xffff))
1661 create_smart_children(robot, num_blobs);
1664 // Note: If weapon hits an invulnerable boss, it will still do badass damage, including to the boss,
1665 // unless this is trapped elsewhere.
1666 if ( Weapon_info[weapon->id].damage_radius )
1668 if (boss_invul_flag) { //don't make badass sound
1669 weapon_info *wi = &Weapon_info[weapon->id];
1671 //this code copied from explode_badass_weapon()
1673 object_create_badass_explosion( weapon, weapon->segnum, collision_point,
1675 wi->robot_hit_vclip,
1676 wi->strength[Difficulty_level],
1677 wi->damage_radius,wi->strength[Difficulty_level],
1678 weapon->ctype.laser_info.parent_num );
1681 else //normal badass explosion
1682 explode_badass_weapon(weapon,collision_point);
1685 if ( ((weapon->ctype.laser_info.parent_type==OBJ_PLAYER) || Robots_kill_robots_cheat) && !(robot->flags & OF_EXPLODING) ) {
1686 object *expl_obj=NULL;
1688 if (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum) {
1689 create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION); // object "weapon" can attract attention to player
1690 do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION);
1694 multi_robot_request_change(robot, Objects[weapon->ctype.laser_info.parent_num].id);
1697 if ( Robot_info[robot->id].exp1_vclip_num > -1 )
1698 expl_obj = object_create_explosion( weapon->segnum, collision_point, (robot->size/2*3)/4, Robot_info[robot->id].exp1_vclip_num );
1699 else if ( Weapon_info[weapon->id].robot_hit_vclip > -1 )
1700 expl_obj = object_create_explosion( weapon->segnum, collision_point, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].robot_hit_vclip );
1703 obj_attach(robot,expl_obj);
1705 if ( damage_flag && (Robot_info[robot->id].exp1_sound_num > -1 ))
1706 digi_link_sound_to_pos( Robot_info[robot->id].exp1_sound_num, robot->segnum, 0, collision_point, 0, F1_0 );
1708 if (!(weapon->flags & OF_HARMLESS)) {
1709 fix damage = weapon->shields;
1712 damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
1716 // Cut Gauss damage on bosses because it just breaks the game. Bosses are so easy to
1717 // hit, and missing a robot is what prevents the Gauss from being game-breaking.
1718 if (weapon->id == GAUSS_ID)
1719 if (Robot_info[robot->id].boss_flag)
1720 damage = damage * (2*NDL-Difficulty_level)/(2*NDL);
1722 if (! apply_damage_to_robot(robot, damage, weapon->ctype.laser_info.parent_num))
1723 bump_two_objects(robot, weapon, 0); //only bump if not dead. no damage from bump
1724 else if (weapon->ctype.laser_info.parent_signature == ConsoleObject->signature) {
1725 add_points_to_score(Robot_info[robot->id].score_value);
1726 detect_escort_goal_accomplished(robot-Objects);
1731 // If Gauss Cannon, spin robot.
1732 if ((robot != NULL) && (!Robot_info[robot->id].companion) && (!Robot_info[robot->id].boss_flag) && (weapon->id == GAUSS_ID)) {
1733 ai_static *aip = &robot->ctype.ai_info;
1735 if (aip->SKIP_AI_COUNT * FrameTime < F1_0) {
1736 aip->SKIP_AI_COUNT++;
1737 robot->mtype.phys_info.rotthrust.x = fixmul((d_rand() - 16384), FrameTime * aip->SKIP_AI_COUNT);
1738 robot->mtype.phys_info.rotthrust.y = fixmul((d_rand() - 16384), FrameTime * aip->SKIP_AI_COUNT);
1739 robot->mtype.phys_info.rotthrust.z = fixmul((d_rand() - 16384), FrameTime * aip->SKIP_AI_COUNT);
1740 robot->mtype.phys_info.flags |= PF_USES_THRUST;
1747 maybe_kill_weapon(weapon,robot);
1752 //##void collide_robot_and_camera( object * robot, object * camera, vms_vector *collision_point ) {
1756 //##void collide_robot_and_powerup( object * robot, object * powerup, vms_vector *collision_point ) {
1760 //##void collide_robot_and_debris( object * robot, object * debris, vms_vector *collision_point ) {
1764 //##void collide_hostage_and_hostage( object * hostage1, object * hostage2, vms_vector *collision_point ) {
1768 void collide_hostage_and_player( object * hostage, object * player, vms_vector *collision_point ) {
1769 // Give player points, etc.
1770 if ( player == ConsoleObject ) {
1771 detect_escort_goal_accomplished(hostage-Objects);
1772 add_points_to_score(HOSTAGE_SCORE);
1775 hostage_rescue(hostage->id);
1777 // Remove the hostage object.
1778 hostage->flags |= OF_SHOULD_BE_DEAD;
1781 if (Game_mode & GM_MULTI)
1782 multi_send_remobj(hostage-Objects);
1788 //--unused-- void collide_hostage_and_weapon( object * hostage, object * weapon, vms_vector *collision_point )
1790 //--unused-- // Cannot kill hostages, as per Matt's edict!
1791 //--unused-- // (A fine edict, but in contradiction to the milestone: "Robots attack hostages.")
1792 //--unused-- hostage->shields -= weapon->shields/2;
1794 //--unused-- create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION); // object "weapon" can attract attention to player
1796 //--unused-- //PLAY_SOUND_3D( SOUND_HOSTAGE_KILLED, collision_point, hostage->segnum );
1797 //--unused-- digi_link_sound_to_pos( SOUND_HOSTAGE_KILLED, hostage->segnum , 0, collision_point, 0, F1_0 );
1800 //--unused-- if (hostage->shields <= 0) {
1801 //--unused-- explode_object(hostage,0);
1802 //--unused-- hostage->flags |= OF_SHOULD_BE_DEAD;
1805 //--unused-- if ( Weapon_info[weapon->id].damage_radius )
1806 //--unused-- explode_badass_weapon(weapon);
1808 //--unused-- maybe_kill_weapon(weapon,hostage);
1812 //##void collide_hostage_and_camera( object * hostage, object * camera, vms_vector *collision_point ) {
1816 //##void collide_hostage_and_powerup( object * hostage, object * powerup, vms_vector *collision_point ) {
1820 //##void collide_hostage_and_debris( object * hostage, object * debris, vms_vector *collision_point ) {
1824 void collide_player_and_player( object * player1, object * player2, vms_vector *collision_point ) {
1825 digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player1->segnum, 0, collision_point, 0, F1_0 );
1826 bump_two_objects(player1, player2, 1);
1830 int maybe_drop_primary_weapon_egg(object *playerobj, int weapon_index)
1832 int weapon_flag = HAS_FLAG(weapon_index);
1835 powerup_num = Primary_weapon_to_powerup[weapon_index];
1837 if (Players[playerobj->id].primary_weapon_flags & weapon_flag)
1838 return call_object_create_egg(playerobj, 1, OBJ_POWERUP, powerup_num);
1843 void maybe_drop_secondary_weapon_egg(object *playerobj, int weapon_index, int count)
1845 int weapon_flag = HAS_FLAG(weapon_index);
1848 powerup_num = Secondary_weapon_to_powerup[weapon_index];
1850 if (Players[playerobj->id].secondary_weapon_flags & weapon_flag) {
1853 max_count = min(count, 3);
1854 for (i=0; i<max_count; i++)
1855 call_object_create_egg(playerobj, 1, OBJ_POWERUP, powerup_num);
1859 void drop_missile_1_or_4(object *playerobj,int missile_index)
1861 int num_missiles,powerup_id;
1863 num_missiles = Players[playerobj->id].secondary_ammo[missile_index];
1864 powerup_id = Secondary_weapon_to_powerup[missile_index];
1866 if (num_missiles > 10)
1869 call_object_create_egg(playerobj, num_missiles/4, OBJ_POWERUP, powerup_id+1);
1870 call_object_create_egg(playerobj, num_missiles%4, OBJ_POWERUP, powerup_id);
1873 // -- int Items_destroyed = 0;
1875 void drop_player_eggs(object *playerobj)
1877 // mprintf((0, "In drop_player_eggs...\n"));
1879 if ((playerobj->type == OBJ_PLAYER) || (playerobj->type == OBJ_GHOST)) {
1881 int pnum = playerobj->id;
1886 // -- Items_destroyed = 0;
1888 // Seed the random number generator so in net play the eggs will always
1889 // drop the same way
1891 if (Game_mode & GM_MULTI)
1898 // If the player had smart mines, maybe arm one of them.
1900 while ((Players[playerobj->id].secondary_ammo[SMART_MINE_INDEX]%4==1) && (d_rand() < rthresh)) {
1904 make_random_vector(&randvec);
1906 vm_vec_add(&tvec, &playerobj->pos, &randvec);
1907 newseg = find_point_seg(&tvec, playerobj->segnum);
1909 Laser_create_new(&randvec, &tvec, newseg, playerobj-Objects, SUPERPROX_ID, 0);
1912 // If the player had proximity bombs, maybe arm one of them.
1914 if ((Game_mode & GM_MULTI) && !(Game_mode & GM_HOARD))
1917 while ((Players[playerobj->id].secondary_ammo[PROXIMITY_INDEX]%4==1) && (d_rand() < rthresh)) {
1921 make_random_vector(&randvec);
1923 vm_vec_add(&tvec, &playerobj->pos, &randvec);
1924 newseg = find_point_seg(&tvec, playerobj->segnum);
1926 Laser_create_new(&randvec, &tvec, newseg, playerobj-Objects, PROXIMITY_ID, 0);
1931 // If the player dies and he has powerful lasers, create the powerups here.
1933 if (Players[pnum].laser_level > MAX_LASER_LEVEL)
1934 call_object_create_egg(playerobj, Players[pnum].laser_level-MAX_LASER_LEVEL, OBJ_POWERUP, POW_SUPER_LASER);
1935 else if (Players[pnum].laser_level >= 1)
1936 call_object_create_egg(playerobj, Players[pnum].laser_level, OBJ_POWERUP, POW_LASER); // Note: laser_level = 0 for laser level 1.
1938 // Drop quad laser if appropos
1939 if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
1940 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_QUAD_FIRE);
1942 if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
1943 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_CLOAK);
1945 if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
1946 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_FULL_MAP);
1948 if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
1949 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_AFTERBURNER);
1951 if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
1952 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_AMMO_RACK);
1954 if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
1955 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_CONVERTER);
1957 if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
1958 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_HEADLIGHT);
1960 // drop the other enemies flag if you have it
1963 if ((Game_mode & GM_CAPTURE) && (Players[pnum].flags & PLAYER_FLAGS_FLAG))
1965 if ((get_team (pnum)==TEAM_RED))
1966 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_FLAG_BLUE);
1968 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_FLAG_RED);
1972 if (Game_mode & GM_HOARD)
1978 mprintf ((0,"HOARD MODE: Dropping %d orbs\n",Players[pnum].secondary_ammo[PROXIMITY_INDEX]));
1980 max_count = min(Players[pnum].secondary_ammo[PROXIMITY_INDEX], 12);
1981 for (i=0; i<max_count; i++)
1982 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_HOARD_ORB);
1986 //Drop the vulcan, gauss, and ammo
1987 vulcan_ammo = Players[pnum].primary_ammo[VULCAN_INDEX];
1988 if ((Players[pnum].primary_weapon_flags & HAS_FLAG(VULCAN_INDEX)) && (Players[pnum].primary_weapon_flags & HAS_FLAG(GAUSS_INDEX)))
1989 vulcan_ammo /= 2; //if both vulcan & gauss, each gets half
1990 if (vulcan_ammo < VULCAN_AMMO_AMOUNT)
1991 vulcan_ammo = VULCAN_AMMO_AMOUNT; //make sure gun has at least as much as a powerup
1992 objnum = maybe_drop_primary_weapon_egg(playerobj, VULCAN_INDEX);
1994 Objects[objnum].ctype.powerup_info.count = vulcan_ammo;
1995 objnum = maybe_drop_primary_weapon_egg(playerobj, GAUSS_INDEX);
1997 Objects[objnum].ctype.powerup_info.count = vulcan_ammo;
1999 // Drop the rest of the primary weapons
2000 maybe_drop_primary_weapon_egg(playerobj, SPREADFIRE_INDEX);
2001 maybe_drop_primary_weapon_egg(playerobj, PLASMA_INDEX);
2002 maybe_drop_primary_weapon_egg(playerobj, FUSION_INDEX);
2004 maybe_drop_primary_weapon_egg(playerobj, HELIX_INDEX);
2005 maybe_drop_primary_weapon_egg(playerobj, PHOENIX_INDEX);
2007 objnum = maybe_drop_primary_weapon_egg(playerobj, OMEGA_INDEX);
2009 Objects[objnum].ctype.powerup_info.count = (playerobj->id==Player_num)?Omega_charge:MAX_OMEGA_CHARGE;
2011 // Drop the secondary weapons
2012 // Note, proximity weapon only comes in packets of 4. So drop n/2, but a max of 3 (handled inside maybe_drop..) Make sense?
2014 if (!(Game_mode & GM_HOARD))
2015 maybe_drop_secondary_weapon_egg(playerobj, PROXIMITY_INDEX, (Players[playerobj->id].secondary_ammo[PROXIMITY_INDEX])/4);
2017 maybe_drop_secondary_weapon_egg(playerobj, SMART_INDEX, Players[playerobj->id].secondary_ammo[SMART_INDEX]);
2018 maybe_drop_secondary_weapon_egg(playerobj, MEGA_INDEX, Players[playerobj->id].secondary_ammo[MEGA_INDEX]);
2020 maybe_drop_secondary_weapon_egg(playerobj, SMART_MINE_INDEX,(Players[playerobj->id].secondary_ammo[SMART_MINE_INDEX])/4);
2021 maybe_drop_secondary_weapon_egg(playerobj, SMISSILE5_INDEX, Players[playerobj->id].secondary_ammo[SMISSILE5_INDEX]);
2023 // Drop the player's missiles in packs of 1 and/or 4
2024 drop_missile_1_or_4(playerobj,HOMING_INDEX);
2025 drop_missile_1_or_4(playerobj,GUIDED_INDEX);
2026 drop_missile_1_or_4(playerobj,CONCUSSION_INDEX);
2027 drop_missile_1_or_4(playerobj,SMISSILE1_INDEX);
2028 drop_missile_1_or_4(playerobj,SMISSILE4_INDEX);
2030 // If player has vulcan ammo, but no vulcan cannon, drop the ammo.
2031 if (!(Players[playerobj->id].primary_weapon_flags & HAS_VULCAN_FLAG)) {
2032 int amount = Players[playerobj->id].primary_ammo[VULCAN_INDEX];
2034 mprintf((0, "Surprising amount of vulcan ammo: %i bullets.\n", amount));
2037 while (amount > 0) {
2038 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_VULCAN_AMMO);
2039 amount -= VULCAN_AMMO_AMOUNT;
2043 // Always drop a shield and energy powerup.
2044 if (Game_mode & GM_MULTI) {
2045 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_SHIELD_BOOST);
2046 call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_ENERGY);
2049 //-- // Drop all the keys.
2050 //-- if (Players[Player_num].flags & PLAYER_FLAGS_BLUE_KEY) {
2051 //-- playerobj->contains_count = 1;
2052 //-- playerobj->contains_type = OBJ_POWERUP;
2053 //-- playerobj->contains_id = POW_KEY_BLUE;
2054 //-- object_create_egg(playerobj);
2056 //-- if (Players[Player_num].flags & PLAYER_FLAGS_RED_KEY) {
2057 //-- playerobj->contains_count = 1;
2058 //-- playerobj->contains_type = OBJ_POWERUP;
2059 //-- playerobj->contains_id = POW_KEY_RED;
2060 //-- object_create_egg(playerobj);
2062 //-- if (Players[Player_num].flags & PLAYER_FLAGS_GOLD_KEY) {
2063 //-- playerobj->contains_count = 1;
2064 //-- playerobj->contains_type = OBJ_POWERUP;
2065 //-- playerobj->contains_id = POW_KEY_GOLD;
2066 //-- object_create_egg(playerobj);
2069 // -- if (Items_destroyed) {
2070 // -- if (Items_destroyed == 1)
2071 // -- HUD_init_message("%i item was destroyed.", Items_destroyed);
2073 // -- HUD_init_message("%i items were destroyed.", Items_destroyed);
2074 // -- Items_destroyed = 0;
2080 // -- removed, 09/06/95, MK -- void destroy_primary_weapon(int weapon_index)
2081 // -- removed, 09/06/95, MK -- {
2082 // -- removed, 09/06/95, MK -- if (weapon_index == MAX_PRIMARY_WEAPONS) {
2083 // -- removed, 09/06/95, MK -- HUD_init_message("Quad lasers destroyed!");
2084 // -- removed, 09/06/95, MK -- Players[Player_num].flags &= ~PLAYER_FLAGS_QUAD_LASERS;
2085 // -- removed, 09/06/95, MK -- update_laser_weapon_info();
2086 // -- removed, 09/06/95, MK -- } else if (weapon_index == 0) {
2087 // -- removed, 09/06/95, MK -- Assert(Players[Player_num].laser_level > 0);
2088 // -- removed, 09/06/95, MK -- HUD_init_message("%s degraded!", Text_string[104+weapon_index]); // Danger! Danger! Use of literal! Danger!
2089 // -- removed, 09/06/95, MK -- Players[Player_num].laser_level--;
2090 // -- removed, 09/06/95, MK -- update_laser_weapon_info();
2091 // -- removed, 09/06/95, MK -- } else {
2092 // -- removed, 09/06/95, MK -- HUD_init_message("%s destroyed!", Text_string[104+weapon_index]); // Danger! Danger! Use of literal! Danger!
2093 // -- removed, 09/06/95, MK -- Players[Player_num].primary_weapon_flags &= ~(1 << weapon_index);
2094 // -- removed, 09/06/95, MK -- auto_select_weapon(0);
2095 // -- removed, 09/06/95, MK -- }
2096 // -- removed, 09/06/95, MK --
2097 // -- removed, 09/06/95, MK -- }
2098 // -- removed, 09/06/95, MK --
2099 // -- removed, 09/06/95, MK -- void destroy_secondary_weapon(int weapon_index)
2100 // -- removed, 09/06/95, MK -- {
2101 // -- removed, 09/06/95, MK -- if (Players[Player_num].secondary_ammo <= 0)
2102 // -- removed, 09/06/95, MK -- return;
2103 // -- removed, 09/06/95, MK --
2104 // -- removed, 09/06/95, MK -- HUD_init_message("%s destroyed!", Text_string[114+weapon_index]); // Danger! Danger! Use of literal! Danger!
2105 // -- removed, 09/06/95, MK -- if (--Players[Player_num].secondary_ammo[weapon_index] == 0)
2106 // -- removed, 09/06/95, MK -- auto_select_weapon(1);
2107 // -- removed, 09/06/95, MK --
2108 // -- removed, 09/06/95, MK -- }
2109 // -- removed, 09/06/95, MK --
2110 // -- removed, 09/06/95, MK -- #define LOSE_WEAPON_THRESHOLD (F1_0*30)
2112 extern fix Buddy_sorry_time;
2114 void apply_damage_to_player(object *playerobj, object *killer, fix damage)
2119 if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
2122 if (Endlevel_sequence)
2125 //for the player, the 'real' shields are maintained in the Players[]
2126 //array. The shields value in the player's object are, I think, not
2127 //used anywhere. This routine, however, sets the objects shields to
2128 //be a mirror of the value in the Player structure.
2130 if (playerobj->id == Player_num) { //is this the local player?
2132 // MK: 08/14/95: This code can never be reached. See the return about 12 lines up.
2133 // -- if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) {
2135 // -- //invincible, so just do blue flash
2137 // -- PALETTE_FLASH_ADD(0,0,f2i(damage)*4); //flash blue
2140 // -- else { //take damage, do red flash
2142 Players[Player_num].shields -= damage;
2144 PALETTE_FLASH_ADD(f2i(damage)*4,-f2i(damage/2),-f2i(damage/2)); //flash red
2148 if (Players[Player_num].shields < 0) {
2150 Players[Player_num].killer_objnum = killer-Objects;
2152 // if ( killer && (killer->type == OBJ_PLAYER))
2153 // Players[Player_num].killer_objnum = killer-Objects;
2155 playerobj->flags |= OF_SHOULD_BE_DEAD;
2157 if (Buddy_objnum != -1)
2158 if (killer && (killer->type == OBJ_ROBOT) && (Robot_info[killer->id].companion))
2159 Buddy_sorry_time = GameTime;
2161 // -- removed, 09/06/95, MK -- else if (Players[Player_num].shields < LOSE_WEAPON_THRESHOLD) {
2162 // -- removed, 09/06/95, MK -- int randnum = d_rand();
2163 // -- removed, 09/06/95, MK --
2164 // -- removed, 09/06/95, MK -- if (fixmul(Players[Player_num].shields, randnum) < damage/4) {
2165 // -- removed, 09/06/95, MK -- if (d_rand() > 20000) {
2166 // -- removed, 09/06/95, MK -- destroy_secondary_weapon(Secondary_weapon);
2167 // -- removed, 09/06/95, MK -- } else if (Primary_weapon == 0) {
2168 // -- removed, 09/06/95, MK -- if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)
2169 // -- removed, 09/06/95, MK -- destroy_primary_weapon(MAX_PRIMARY_WEAPONS); // This means to destroy quad laser.
2170 // -- removed, 09/06/95, MK -- else if (Players[Player_num].laser_level > 0)
2171 // -- removed, 09/06/95, MK -- destroy_primary_weapon(Primary_weapon);
2172 // -- removed, 09/06/95, MK -- } else
2173 // -- removed, 09/06/95, MK -- destroy_primary_weapon(Primary_weapon);
2174 // -- removed, 09/06/95, MK -- } else
2175 // -- removed, 09/06/95, MK -- ; // mprintf((0, "%8x > %8x, so don't lose weapon.\n", fixmul(Players[Player_num].shields, randnum), damage/4));
2176 // -- removed, 09/06/95, MK -- }
2178 playerobj->shields = Players[Player_num].shields; //mirror
2183 void collide_player_and_weapon( object * playerobj, object * weapon, vms_vector *collision_point )
2185 fix damage = weapon->shields;
2186 object * killer=NULL;
2188 // In multiplayer games, only do damage to another player if in first frame.
2189 // This is necessary because in multiplayer, due to varying framerates, omega blobs actually
2190 // have a bit of a lifetime. But they start out with a lifetime of ONE_FRAME_TIME, and this
2191 // gets bashed to 1/4 second in laser_do_weapon_sequence. This bashing occurs for visual purposes only.
2192 if (weapon->id == OMEGA_ID)
2193 if (!ok_to_do_omega_damage(weapon))
2196 // Don't collide own smart mines unless direct hit.
2197 if (weapon->id == SUPERPROX_ID)
2198 if (playerobj-Objects == weapon->ctype.laser_info.parent_num)
2199 if (vm_vec_dist_quick(collision_point, &playerobj->pos) > playerobj->size)
2202 if (weapon->id == EARTHSHAKER_ID)
2205 damage = fixmul(damage, weapon->ctype.laser_info.multiplier);
2207 if (Game_mode & GM_MULTI)
2208 damage = fixmul(damage, Weapon_info[weapon->id].multi_damage_scale);
2211 if (weapon->mtype.phys_info.flags & PF_PERSISTENT)
2213 if (weapon->ctype.laser_info.last_hitobj == playerobj-Objects)
2216 weapon->ctype.laser_info.last_hitobj = playerobj-Objects;
2219 if (playerobj->id == Player_num)
2221 if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2223 digi_link_sound_to_pos( SOUND_PLAYER_GOT_HIT, playerobj->segnum, 0, collision_point, 0, F1_0 );
2225 if (Game_mode & GM_MULTI)
2226 multi_send_play_sound(SOUND_PLAYER_GOT_HIT, F1_0);
2231 digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, playerobj->segnum, 0, collision_point, 0, F1_0);
2233 if (Game_mode & GM_MULTI)
2234 multi_send_play_sound(SOUND_WEAPON_HIT_DOOR, F1_0);
2239 object_create_explosion( playerobj->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT );
2240 if ( Weapon_info[weapon->id].damage_radius )
2241 explode_badass_weapon(weapon,collision_point);
2243 maybe_kill_weapon(weapon,playerobj);
2245 bump_two_objects(playerobj, weapon, 0); //no damage from bump
2247 if ( !Weapon_info[weapon->id].damage_radius ) {
2248 if ( weapon->ctype.laser_info.parent_num > -1 )
2249 killer = &Objects[weapon->ctype.laser_info.parent_num];
2251 // if (weapon->id == SMART_HOMING_ID)
2254 if (!(weapon->flags & OF_HARMLESS))
2255 apply_damage_to_player( playerobj, killer, damage);
2258 // Robots become aware of you if you get hit.
2259 ai_do_cloak_stuff();
2264 // Nasty robots are the ones that attack you by running into you and doing lots of damage.
2265 void collide_player_and_nasty_robot( object * playerobj, object * robot, vms_vector *collision_point )
2267 // if (!(Robot_info[robot->id].energy_drain && Players[playerobj->id].energy))
2268 digi_link_sound_to_pos( Robot_info[robot->id].claw_sound, playerobj->segnum, 0, collision_point, 0, F1_0 );
2270 object_create_explosion( playerobj->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT );
2272 bump_two_objects(playerobj, robot, 0); //no damage from bump
2274 apply_damage_to_player( playerobj, robot, F1_0*(Difficulty_level+1));
2279 void collide_player_and_materialization_center(object *objp)
2282 vms_vector exit_dir;
2283 segment *segp = &Segments[objp->segnum];
2285 digi_link_sound_to_pos(SOUND_PLAYER_GOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0);
2286 // digi_play_sample( SOUND_PLAYER_GOT_HIT, F1_0 );
2288 object_create_explosion( objp->segnum, &objp->pos, i2f(10)/2, VCLIP_PLAYER_HIT );
2290 if (objp->id != Player_num)
2293 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
2294 if (WALL_IS_DOORWAY(segp, side) & WID_FLY_FLAG) {
2295 vms_vector exit_point, rand_vec;
2297 compute_center_point_on_side(&exit_point, segp, side);
2298 vm_vec_sub(&exit_dir, &exit_point, &objp->pos);
2299 vm_vec_normalize_quick(&exit_dir);
2300 make_random_vector(&rand_vec);
2301 rand_vec.x /= 4; rand_vec.y /= 4; rand_vec.z /= 4;
2302 vm_vec_add2(&exit_dir, &rand_vec);
2303 vm_vec_normalize_quick(&exit_dir);
2306 bump_one_object(objp, &exit_dir, 64*F1_0);
2308 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
2314 void collide_robot_and_materialization_center(object *objp)
2317 vms_vector exit_dir;
2318 segment *segp=&Segments[objp->segnum];
2320 digi_link_sound_to_pos(SOUND_ROBOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0);
2321 // digi_play_sample( SOUND_ROBOT_HIT, F1_0 );
2323 if ( Robot_info[objp->id].exp1_vclip_num > -1 )
2324 object_create_explosion( objp->segnum, &objp->pos, (objp->size/2*3)/4, Robot_info[objp->id].exp1_vclip_num );
2326 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
2327 if (WALL_IS_DOORWAY(segp, side) & WID_FLY_FLAG) {
2328 vms_vector exit_point;
2330 compute_center_point_on_side(&exit_point, segp, side);
2331 vm_vec_sub(&exit_dir, &exit_point, &objp->pos);
2332 vm_vec_normalize_quick(&exit_dir);
2335 bump_one_object(objp, &exit_dir, 8*F1_0);
2337 apply_damage_to_robot( objp, F1_0, -1);
2343 //##void collide_player_and_camera( object * playerobj, object * camera, vms_vector *collision_point ) {
2347 extern int Network_got_powerup; // HACK!!!
2349 void collide_player_and_powerup( object * playerobj, object * powerup, vms_vector *collision_point ) {
2350 if (!Endlevel_sequence && !Player_is_dead && (playerobj->id == Player_num )) {
2353 powerup_used = do_powerup(powerup);
2356 powerup->flags |= OF_SHOULD_BE_DEAD;
2358 if (Game_mode & GM_MULTI)
2359 multi_send_remobj(powerup-Objects);
2364 else if ((Game_mode & GM_MULTI_COOP) && (playerobj->id != Player_num))
2366 switch (powerup->id) {
2368 Players[playerobj->id].flags |= PLAYER_FLAGS_BLUE_KEY;
2371 Players[playerobj->id].flags |= PLAYER_FLAGS_RED_KEY;
2374 Players[playerobj->id].flags |= PLAYER_FLAGS_GOLD_KEY;
2384 //##void collide_player_and_debris( object * playerobj, object * debris, vms_vector *collision_point ) {
2388 void collide_player_and_clutter( object * playerobj, object * clutter, vms_vector *collision_point ) {
2389 digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, playerobj->segnum, 0, collision_point, 0, F1_0 );
2390 bump_two_objects(clutter, playerobj, 1);
2394 // See if weapon1 creates a badass explosion. If so, create the explosion
2395 // Return true if weapon does proximity (as opposed to only contact) damage when it explodes.
2396 int maybe_detonate_weapon(object *weapon1, object *weapon2, vms_vector *collision_point)
2398 if ( Weapon_info[weapon1->id].damage_radius ) {
2401 dist = vm_vec_dist_quick(&weapon1->pos, &weapon2->pos);
2402 if (dist < F1_0*5) {
2403 maybe_kill_weapon(weapon1,weapon2);
2404 if (weapon1->flags & OF_SHOULD_BE_DEAD) {
2405 explode_badass_weapon(weapon1,collision_point);
2406 digi_link_sound_to_pos( Weapon_info[weapon1->id].robot_hit_sound, weapon1->segnum , 0, collision_point, 0, F1_0 );
2410 weapon1->lifeleft = min(dist/64, F1_0);
2417 void collide_weapon_and_weapon( object * weapon1, object * weapon2, vms_vector *collision_point )
2419 // -- Does this look buggy??: if (weapon1->id == PMINE_ID && weapon1->id == PMINE_ID)
2420 if (weapon1->id == PMINE_ID && weapon2->id == PMINE_ID)
2421 return; //these can't blow each other up
2423 if (weapon1->id == OMEGA_ID) {
2424 if (!ok_to_do_omega_damage(weapon1))
2426 } else if (weapon2->id == OMEGA_ID) {
2427 if (!ok_to_do_omega_damage(weapon2))
2431 if ((Weapon_info[weapon1->id].destroyable) || (Weapon_info[weapon2->id].destroyable)) {
2433 // Bug reported by Adam Q. Pletcher on September 9, 1994, smart bomb homing missiles were toasting each other.
2434 if ((weapon1->id == weapon2->id) && (weapon1->ctype.laser_info.parent_num == weapon2->ctype.laser_info.parent_num))
2437 if (Weapon_info[weapon1->id].destroyable)
2438 if (maybe_detonate_weapon(weapon1, weapon2, collision_point))
2439 maybe_detonate_weapon(weapon2,weapon1, collision_point);
2441 if (Weapon_info[weapon2->id].destroyable)
2442 if (maybe_detonate_weapon(weapon2, weapon1, collision_point))
2443 maybe_detonate_weapon(weapon1,weapon2, collision_point);
2449 //##void collide_weapon_and_camera( object * weapon, object * camera, vms_vector *collision_point ) {
2453 //##void collide_weapon_and_powerup( object * weapon, object * powerup, vms_vector *collision_point ) {
2457 void collide_weapon_and_debris( object * weapon, object * debris, vms_vector *collision_point ) {
2459 // Hack! Prevent debris from causing bombs spewed at player death to detonate!
2460 if ((weapon->id == PROXIMITY_ID) || (weapon->id == SUPERPROX_ID)) {
2461 if (weapon->ctype.laser_info.creation_time + F1_0/2 > GameTime)
2465 if ( (weapon->ctype.laser_info.parent_type==OBJ_PLAYER) && !(debris->flags & OF_EXPLODING) ) {
2466 digi_link_sound_to_pos( SOUND_ROBOT_HIT, weapon->segnum , 0, collision_point, 0, F1_0 );
2468 explode_object(debris,0);
2469 if ( Weapon_info[weapon->id].damage_radius )
2470 explode_badass_weapon(weapon,collision_point);
2471 maybe_kill_weapon(weapon,debris);
2472 weapon->flags |= OF_SHOULD_BE_DEAD;
2477 //##void collide_camera_and_camera( object * camera1, object * camera2, vms_vector *collision_point ) {
2481 //##void collide_camera_and_powerup( object * camera, object * powerup, vms_vector *collision_point ) {
2485 //##void collide_camera_and_debris( object * camera, object * debris, vms_vector *collision_point ) {
2489 //##void collide_powerup_and_powerup( object * powerup1, object * powerup2, vms_vector *collision_point ) {
2493 //##void collide_powerup_and_debris( object * powerup, object * debris, vms_vector *collision_point ) {
2497 //##void collide_debris_and_debris( object * debris1, object * debris2, vms_vector *collision_point ) {
2502 /* DPH: Put these macros on one long line to avoid CR/LF problems on linux */
2503 #define COLLISION_OF(a,b) (((a)<<8) + (b))
2505 #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;
2507 #define DO_SAME_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type1) ): (collision_function)( (A), (B), collision_point ); break;
2509 //these next two macros define a case that does nothing
2510 #define NO_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type2) ): break; case COLLISION_OF( (type2), (type1) ): break;
2512 #define NO_SAME_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type1) ): break;
2514 /* DPH: These ones are never used so I'm not going to bother */
2516 #define IGNORE_COLLISION(type1,type2,collision_function) \
2517 case COLLISION_OF( (type1), (type2) ): \
2519 case COLLISION_OF( (type2), (type1) ): \
2522 #define ERROR_COLLISION(type1,type2,collision_function) \
2523 case COLLISION_OF( (type1), (type2) ): \
2524 Error( "Error in collision type!" ); \
2526 case COLLISION_OF( (type2), (type1) ): \
2527 Error( "Error in collision type!" ); \
2531 void collide_two_objects( object * A, object * B, vms_vector *collision_point )
2535 collision_type = COLLISION_OF(A->type,B->type);
2537 //mprintf( (0, "Object %d of type %d collided with object %d of type %d\n", A-Objects,A->type, B-Objects, B->type ));
2539 switch( collision_type ) {
2540 NO_SAME_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL, collide_fireball_and_fireball )
2541 DO_SAME_COLLISION( OBJ_ROBOT, OBJ_ROBOT, collide_robot_and_robot )
2542 NO_SAME_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE, collide_hostage_and_hostage )
2543 DO_SAME_COLLISION( OBJ_PLAYER, OBJ_PLAYER, collide_player_and_player )
2544 DO_SAME_COLLISION( OBJ_WEAPON, OBJ_WEAPON, collide_weapon_and_weapon )
2545 NO_SAME_COLLISION( OBJ_CAMERA, OBJ_CAMERA, collide_camera_and_camera )
2546 NO_SAME_COLLISION( OBJ_POWERUP, OBJ_POWERUP, collide_powerup_and_powerup )
2547 NO_SAME_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS, collide_debris_and_debris )
2548 NO_SAME_COLLISION( OBJ_MARKER, OBJ_MARKER, NULL )
2549 NO_COLLISION( OBJ_FIREBALL, OBJ_ROBOT, collide_fireball_and_robot )
2550 NO_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE, collide_fireball_and_hostage )
2551 NO_COLLISION( OBJ_FIREBALL, OBJ_PLAYER, collide_fireball_and_player )
2552 NO_COLLISION( OBJ_FIREBALL, OBJ_WEAPON, collide_fireball_and_weapon )
2553 NO_COLLISION( OBJ_FIREBALL, OBJ_CAMERA, collide_fireball_and_camera )
2554 NO_COLLISION( OBJ_FIREBALL, OBJ_POWERUP, collide_fireball_and_powerup )
2555 NO_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS, collide_fireball_and_debris )
2556 NO_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE, collide_robot_and_hostage )
2557 DO_COLLISION( OBJ_ROBOT, OBJ_PLAYER, collide_robot_and_player )
2558 DO_COLLISION( OBJ_ROBOT, OBJ_WEAPON, collide_robot_and_weapon )
2559 NO_COLLISION( OBJ_ROBOT, OBJ_CAMERA, collide_robot_and_camera )
2560 NO_COLLISION( OBJ_ROBOT, OBJ_POWERUP, collide_robot_and_powerup )
2561 NO_COLLISION( OBJ_ROBOT, OBJ_DEBRIS, collide_robot_and_debris )
2562 DO_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER, collide_hostage_and_player )
2563 NO_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON, collide_hostage_and_weapon )
2564 NO_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA, collide_hostage_and_camera )
2565 NO_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP, collide_hostage_and_powerup )
2566 NO_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS, collide_hostage_and_debris )
2567 DO_COLLISION( OBJ_PLAYER, OBJ_WEAPON, collide_player_and_weapon )
2568 NO_COLLISION( OBJ_PLAYER, OBJ_CAMERA, collide_player_and_camera )
2569 DO_COLLISION( OBJ_PLAYER, OBJ_POWERUP, collide_player_and_powerup )
2570 NO_COLLISION( OBJ_PLAYER, OBJ_DEBRIS, collide_player_and_debris )
2571 DO_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN, collide_player_and_controlcen )
2572 DO_COLLISION( OBJ_PLAYER, OBJ_CLUTTER, collide_player_and_clutter )
2573 NO_COLLISION( OBJ_WEAPON, OBJ_CAMERA, collide_weapon_and_camera )
2574 NO_COLLISION( OBJ_WEAPON, OBJ_POWERUP, collide_weapon_and_powerup )
2575 DO_COLLISION( OBJ_WEAPON, OBJ_DEBRIS, collide_weapon_and_debris )
2576 NO_COLLISION( OBJ_CAMERA, OBJ_POWERUP, collide_camera_and_powerup )
2577 NO_COLLISION( OBJ_CAMERA, OBJ_DEBRIS, collide_camera_and_debris )
2578 NO_COLLISION( OBJ_POWERUP, OBJ_DEBRIS, collide_powerup_and_debris )
2579 DO_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN, collide_weapon_and_controlcen )
2580 DO_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN, collide_robot_and_controlcen )
2581 DO_COLLISION( OBJ_WEAPON, OBJ_CLUTTER, collide_weapon_and_clutter )
2583 DO_COLLISION( OBJ_MARKER, OBJ_PLAYER, collide_player_and_marker)
2584 NO_COLLISION( OBJ_MARKER, OBJ_ROBOT, NULL)
2585 NO_COLLISION( OBJ_MARKER, OBJ_HOSTAGE, NULL)
2586 NO_COLLISION( OBJ_MARKER, OBJ_WEAPON, NULL)
2587 NO_COLLISION( OBJ_MARKER, OBJ_CAMERA, NULL)
2588 NO_COLLISION( OBJ_MARKER, OBJ_POWERUP, NULL)
2589 NO_COLLISION( OBJ_MARKER, OBJ_DEBRIS, NULL)
2592 Int3(); //Error( "Unhandled collision_type in collide.c!\n" );
2596 #define ENABLE_COLLISION(type1,type2) \
2597 CollisionResult[type1][type2] = RESULT_CHECK; \
2598 CollisionResult[type2][type1] = RESULT_CHECK;
2600 #define DISABLE_COLLISION(type1,type2) \
2601 CollisionResult[type1][type2] = RESULT_NOTHING; \
2602 CollisionResult[type2][type1] = RESULT_NOTHING;
2604 void collide_init() {
2607 for (i=0; i < MAX_OBJECT_TYPES; i++ )
2608 for (j=0; j < MAX_OBJECT_TYPES; j++ )
2609 CollisionResult[i][j] = RESULT_NOTHING;
2611 ENABLE_COLLISION( OBJ_WALL, OBJ_ROBOT );
2612 ENABLE_COLLISION( OBJ_WALL, OBJ_WEAPON );
2613 ENABLE_COLLISION( OBJ_WALL, OBJ_PLAYER );
2614 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL );
2616 ENABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT );
2617 // DISABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT ); // ALERT: WARNING: HACK: MK = RESPONSIBLE! TESTING!!
2619 DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE );
2620 ENABLE_COLLISION( OBJ_PLAYER, OBJ_PLAYER );
2621 ENABLE_COLLISION( OBJ_WEAPON, OBJ_WEAPON );
2622 DISABLE_COLLISION( OBJ_CAMERA, OBJ_CAMERA );
2623 DISABLE_COLLISION( OBJ_POWERUP, OBJ_POWERUP );
2624 DISABLE_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS );
2625 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_ROBOT );
2626 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE );
2627 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_PLAYER );
2628 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_WEAPON );
2629 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_CAMERA );
2630 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_POWERUP );
2631 DISABLE_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS );
2632 DISABLE_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE );
2633 ENABLE_COLLISION( OBJ_ROBOT, OBJ_PLAYER );
2634 ENABLE_COLLISION( OBJ_ROBOT, OBJ_WEAPON );
2635 DISABLE_COLLISION( OBJ_ROBOT, OBJ_CAMERA );
2636 DISABLE_COLLISION( OBJ_ROBOT, OBJ_POWERUP );
2637 DISABLE_COLLISION( OBJ_ROBOT, OBJ_DEBRIS );
2638 ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER );
2639 ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON );
2640 DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA );
2641 DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP );
2642 DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS );
2643 ENABLE_COLLISION( OBJ_PLAYER, OBJ_WEAPON );
2644 DISABLE_COLLISION( OBJ_PLAYER, OBJ_CAMERA );
2645 ENABLE_COLLISION( OBJ_PLAYER, OBJ_POWERUP );
2646 DISABLE_COLLISION( OBJ_PLAYER, OBJ_DEBRIS );
2647 DISABLE_COLLISION( OBJ_WEAPON, OBJ_CAMERA );
2648 DISABLE_COLLISION( OBJ_WEAPON, OBJ_POWERUP );
2649 ENABLE_COLLISION( OBJ_WEAPON, OBJ_DEBRIS );
2650 DISABLE_COLLISION( OBJ_CAMERA, OBJ_POWERUP );
2651 DISABLE_COLLISION( OBJ_CAMERA, OBJ_DEBRIS );
2652 DISABLE_COLLISION( OBJ_POWERUP, OBJ_DEBRIS );
2653 ENABLE_COLLISION( OBJ_POWERUP, OBJ_WALL );
2654 ENABLE_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN )
2655 ENABLE_COLLISION( OBJ_WEAPON, OBJ_CLUTTER )
2656 ENABLE_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN )
2657 ENABLE_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN )
2658 ENABLE_COLLISION( OBJ_PLAYER, OBJ_CLUTTER )
2660 ENABLE_COLLISION( OBJ_PLAYER, OBJ_MARKER );
2664 void collide_object_with_wall( object * A, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt )
2669 Error( "A object of type NONE hit a wall!\n");
2671 case OBJ_PLAYER: collide_player_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
2672 case OBJ_WEAPON: collide_weapon_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
2673 case OBJ_DEBRIS: collide_debris_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
2675 case OBJ_FIREBALL: break; //collide_fireball_and_wall(A,hitspeed,hitseg,hitwall,hitpt);
2676 case OBJ_ROBOT: collide_robot_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break;
2677 case OBJ_HOSTAGE: break; //collide_hostage_and_wall(A,hitspeed,hitseg,hitwall,hitpt);
2678 case OBJ_CAMERA: break; //collide_camera_and_wall(A,hitspeed,hitseg,hitwall,hitpt);
2679 case OBJ_POWERUP: break; //collide_powerup_and_wall(A,hitspeed,hitseg,hitwall,hitpt);
2680 case OBJ_GHOST: break; //do nothing
2683 Error( "Unhandled object type hit wall in collide.c\n" );