/* * $Logfile: /DescentIII/Main/physics/Collide.cpp $ * $Revision: 239 $ * $Date: 9/20/01 5:33p $ * $Author: Matt $ * * Descent III collision code * * $Log: /DescentIII/Main/physics/Collide.cpp $ * * 239 9/20/01 5:33p Matt * Fixed weird omega cannon bugs (I hope) by only letting the omega * particles collide from inside AquireElectricalTarget(). * * 238 11/04/99 5:35p Chris * Levels with forcefields with a custom bouce sound don't cause damage * * 237 10/20/99 5:40p Chris * Added the Red Guidebot * * 236 10/08/99 4:29p Chris * Added the forcefield and glass breaking override options * * 235 5/24/99 1:26a Matt * Correctly deal with hit_info == NULL being passed to collision * routines. * * 234 5/21/99 2:55a Matt * When an object is bounced-out and needs to be killed, call * DestroyObject() if it's already dying. Before the code just set the * dead flag, which caused robots to disappear if they bumped into * something while dying. * * 233 5/20/99 9:03p Matt * Changed trigger system so that collisions with rendered portals don't * set off triggers on the portals. * * 232 5/19/99 1:23p Matt * Fixed (hopefully) yet more collision problems introduced by my recent * changes. * * 231 5/18/99 10:15p Matt * Fixed bug with weapon spawning that I introduced last night. * * 230 5/18/99 10:57a Chris * Various bug fixes * * 229 5/17/99 9:09p Matt * Made objects with lava behave like walls with lava; flares don't stick, * player catches on fire. * * 228 5/17/99 6:07p Chris * GB doesn't damage players - PF_LOCK_MASK objects always do... * * 227 5/11/99 5:50p Chris * Buildings don't collide with each other * * 226 5/08/99 4:27p Chris * Hearing code * * 225 5/08/99 3:31p Matt * Deal with weapons hitting water. * * 224 5/07/99 10:56p Chris * GB avoids forcefields, lava, and volatile surfaces... If he accidently * hits one of these, he ignores the collision (i.e. no effects). It make * him look smarter. * * 223 4/30/99 3:28p Matt * Weapons now make a special sound when colliding with lava & volatile * surfaces, instead of the standard hit-wall sound. * * 222 4/29/99 6:48p Matt * Made volatile surfaces apply damage and lava surfaces catch the player * on fire. Both now generate the steam puff effect. * * 221 4/29/99 2:17a Samir * adjusted some sound priority stuff * * 220 4/23/99 6:44p Matt * Changed weapons to keep going after breaking glass. * * 219 4/21/99 4:27p Chris * * 218 4/21/99 3:45p Chris * * 217 4/21/99 3:43p Chris * * 216 4/21/99 2:56p Chris * Made player-player collisions almost complete in-elastic * * 215 4/21/99 1:30p Matt * Make breakable glass use the new breakable flag, instead of * piggybacking on the destroyable flag. * * 214 4/21/99 11:06a Kevin * new ps_rand and ps_srand to replace rand & srand * * 213 4/21/99 10:12a Chris * Tweaked robot/player damage * * 212 4/21/99 3:33a Chris * Collisions between robots and players cause damage to both robots and * players (robots get more damage) * * 211 4/19/99 12:03p Jason * added checking for fireball collisions * * 210 4/19/99 4:02a Jeff * fixed min/max for Linux * * 209 4/18/99 10:55p Chris * Added ignore own concussive blasts * * 208 4/16/99 8:18p Jason * make impact spawning weapons work with doors * * 207 4/14/99 1:42a Jeff * fixed case mismatched #includes * * 206 4/12/99 6:15p Samir * Sound priorities pass 1 * * 205 4/06/99 6:24p Jason * various fixes for multiplayer * * 204 3/23/99 4:10p Jason * more tweaks for line sparks * * 203 3/23/99 12:50p Jason * added line sparks * * 202 3/22/99 6:41p Jason * fixed client side weapons not reacting correctly to bouncing code * * 201 3/22/99 1:47p Matt * Moved breaking glass code from collide.cpp to damage.cpp * * 200 3/16/99 4:16p Matt * Made mass driver spin the victim more. (Jason had reduced it from 0.25 * to 0.05; I've moved it back up to 0.12 at Andy's request.) * * 199 3/12/99 7:46p Jeff * record wall hit collisions to demo file * * 198 3/11/99 5:55p Jason * fixed player spin with mass driver * * 197 3/05/99 2:12p Matt * Fixed bug (in a slightly hacky way) where energy weapons would cause * glass to switch to the damaged texture. For a real fix, we need a * separate breakable glass flag for textures. * * 196 3/03/99 10:52a Chris * Energy weapons push again * * 195 3/03/99 5:44a Chris * Max secondary burn time of 10 seconds * * 194 3/01/99 3:18p Jason * made powerups work correctly in multiplayer * * 193 2/28/99 11:29p Chris * Improved robot-wall reactions * * 192 2/22/99 2:03p Jason * added different damages for players and generics * * 191 2/21/99 4:35p Chris * Improving the level goal system... Not done. * * 190 2/20/99 10:31a Kevin * OEM Beta 1 fixs * * 189 2/19/99 12:35p Chris * Player can fly through markers * * 188 2/17/99 4:50p Jason * fixed destroyable face/breakable glass bug * * 187 2/17/99 1:26p Matt * Fixed the die angle system for weapons (changing it around a little in * the process: now all non-weapons (which don't use the system) should * have dot == -1, weapons that die at any angle have dot == 0, and * setting dot == 1 means it never dies). * * 186 2/16/99 8:16a Chris * Fixed a bug - THANKS! * * 185 2/10/99 1:48p Matt * Changed object handle symbolic constants * * 184 2/09/99 2:38p Jason * added destroyable faces * * 183 2/02/99 8:44a Chris * I made buildings with AI work correctly (ie really big robots should be * buildings) * anim to and from states are now shorts instead of bytes * * 182 1/31/99 7:26p Matt * Renamed a bunch of functions to have HUD capitalized * * 181 1/29/99 5:09p Chris * Made changes for ROCKS * * 180 1/28/99 6:17p Jason * added markers * * 179 1/26/99 6:39p Jason * added wall effects code * * 178 1/25/99 5:59p Matt * Patched the masses of objects * * 177 1/24/99 8:18p Chris * Updated AI and OSIRIS. Externalized fireball constants for spew and * sparks. Added CreateRandomSparks to OSIRIS, renamed a bunch of AI * Notify names to use underscores. Fixed a memory access leak in the * matcen effect code. * * 176 1/23/99 5:16p Chris * Bounds fixed acos and asin stuff (-1.0000000000001 could cause really * bad things to happen with rot. vels) * * 175 1/20/99 10:50a Jason * added new terrain * * 174 1/20/99 2:13a Chris * It is now possible for robots to have special immunities, resistances, * and vunerabilities * * 173 1/18/99 12:12a Jeff * removed weapon collide event, combined it in general collide event. * general collide event handles more collides. Added a room collide * event * * 172 1/15/99 3:59a Jeff * added two new multiplayer DLL events for weapon collisions. Added two * new fields to DLLInfo data, point and normal, which are filled out for * collision events. * * 170 1/10/99 7:35p Matt * Added missing break to DO_COLLISION macor * * 169 1/10/99 6:49a Jeff * Some initial work to get linux version to compile * * 168 1/08/99 2:56p Samir * Ripped out OSIRIS1. * * 167 1/01/99 4:10p Chris * Added some const parameters, improved ray cast object collide/rejection * code * * 166 12/21/98 10:50a Chris * You can now push walking objects * * 165 12/17/98 12:08p Jeff * first checkin of new implementation of OSIRIS (old OSIRIS no longer * works) * * 164 11/19/98 3:54p Chris * * 163 11/19/98 3:51p Chris * Shooting dying robots makes them blow up faster (but now not as * quickly) * * 162 11/13/98 4:25p Jason * changes for better weapon effects * * 161 11/13/98 1:00p Chris * Fixed a math problem with the new collision response code. Zero rad * particles where causing i1 or i2 to be zero. c1 = c1/i1 -> it was * going to infinity. So, I made a floor threshold for i1 and i2 * * 160 11/11/98 2:46p Kevin * Demo recording system work * * 159 11/10/98 5:17p Jeff * peppered in some more forcefeedback effects * * 158 10/30/98 5:17p Chris * Players only get 1/4 the rotational velocity of an impulse * * 157 10/29/98 1:45p Chris * Checked in the better collision response code * * 156 10/22/98 12:57p Chris * Added sounds to player/player and player/robot collisions * * 155 10/20/98 1:26p Jason * took out spawning on direct hits * * 154 10/20/98 12:10p Chris * * 153 10/19/98 8:38p Matt * Don't make a sound when colliding with lava, since the lava will start * you on fire, which will make sound. * * 152 10/19/98 7:19p Matt * Added system to support different types of damage to the player and * have these different types make different sounds. * * 151 10/18/98 2:09p Matt * Made the backquote/flare thing go away in release versions, and made it * work for terrain cells. * * 150 10/17/98 12:25p Chris * Fixed attached flares * * 149 10/16/98 5:25p Chris * Fixed sticky code * * 148 10/16/98 4:33p Chris * * 147 10/16/98 4:18p Chris * Fixed the 'flare thing' * * 146 10/16/98 3:39p Chris * Improved the object linking system and AI and physics * * 145 10/15/98 4:51p Chris * Speed up dying for player too * * 144 10/15/98 4:49p Chris * Speed up dying if the robot is getting hit * * 143 10/12/98 2:27p Matt * Fixed code to print room:face when backquote/tilde held down and flare * hits the wall. * * 142 10/12/98 10:04a Chris * Wall hits cannot kill the player * * 141 10/09/98 7:57p Chris * Added the flare room/wall cheat * * 140 10/09/98 7:47p Chris * Added ObjSetDeadFlag * * 139 10/08/98 12:00p Kevin * Demo system work * * 138 10/05/98 7:23p Jason * implemented destroyable lights (first draft) * * 137 10/01/98 6:56p Jason * turned off energy weapon hit effects if the object getting hit is the * viewer - this helps cut down on the general clutter in heavy combat * * 136 9/29/98 4:48p Chris * Working on multiplayer collisions * * 135 9/23/98 5:04p Chris * Raised the collide wall damage threshold * * 134 9/23/98 3:47p Chris * Increased the speed to cause damage from wall hits * * 133 9/22/98 12:23p Chris * Further improvements to wall hitting * * 132 9/21/98 8:32p Chris * Another improvement to the forcefield stuff * * 131 9/21/98 8:19p Chris * Improved volatile and forcefield hits * * 130 9/21/98 1:08p Chris * Improved lava handling * * 129 9/21/98 1:04p Chris * * 128 9/21/98 1:03p Chris * * 127 9/21/98 1:01p Chris * Fixed more volatile problems * * 126 9/21/98 11:44a Chris * Fixed the volatile terrain crash bug * * 125 9/18/98 7:45p Chris * Lava works - needs tweaking. * * 124 8/25/98 7:27p Chris * Improved the scorch code * * 123 8/25/98 7:23p Chris * Made weapons explode even if they break glass * * 122 8/25/98 12:35p Chris * Fixed a small reversed normal bug * * 121 8/19/98 2:48p Jason * fixed some weapon firing and weapon exploding bugs * * 120 8/18/98 7:12p Chris * Improved FUSION behavior. * * 119 8/12/98 12:26p Chris * * 118 8/05/98 11:16a Matt * Added trigger checks when weapons and the player collide with walls. * * 117 8/03/98 5:56p Jason * got fusion cannon working correctly * * 116 7/31/98 11:52a Chris * Weapons can be persistent. Added ability for objects to be manually * set for no object collisions. * * 115 7/30/98 11:09a Jason * added weapons that freeze and deform terrain * * 114 7/22/98 4:36p Jason * took out bugs from observer mode * * 113 7/17/98 10:12a Chris * * 112 7/01/98 12:56p Jason * more changes for countermeasures * * 111 7/01/98 12:12p Jason * added countermeasures * * 110 6/24/98 3:56p Jason * added code for new omega cannon * * 109 6/15/98 3:23p Chris * Single point walker update * * 108 6/15/98 7:53a Chris * Fixed a comment'ed out variable * * 107 6/15/98 7:52a Chris * Removed the new "cool" physics * * 106 6/11/98 12:48p Jason * added better spewing weapons * * 105 6/04/98 12:00p Matt * Took out Napalm Rocket hack that I added for the E3 demo. * * 104 6/02/98 10:43p Chris * Multipoint collision detection enabled * * 103 6/01/98 9:23p Chris * Fixed a bunch of collision problems * * 102 5/27/98 6:18p Matt * Super hack to reduce impact damage of napalm rocket (for E3 only) * * 101 5/27/98 6:08p Chris * Added weapon to generic sound * * 100 5/26/98 4:17p Jason * made scripts/dlls not collide every single frame * * 99 5/26/98 3:58p Matt * Only matter weapons now break glass. * * 98 5/25/98 8:36p Matt * Added code to set different sizes for different weapon scorch marks. * Also, don't leave scorch marks on lights. * * 97 5/22/98 12:34p Matt * Added scorch mark/bullet hole system. * * 96 5/22/98 11:59a Chris * Fixed improper uses of FindSoundName and made the proper static sounds * * 95 5/19/98 4:42a Chris * Added shockwave's -- enjoy. :) * * 94 5/07/98 2:52p Chris * Removed a bounce mprintf * * 93 5/07/98 2:40p Chris * Added death_dot and bounce sound for weapons * * 92 5/07/98 2:22p Chris * Hit die dot * * 91 5/06/98 7:07p Samir * when player is completely dead, don't call script too. * * 90 5/05/98 3:42p Chris * Code cleanup and fixed the collide_XXX_with_wall code. The wall_normal * was know by fvi; so, it is passed to the function (instead of * generating it again) * * 89 5/04/98 3:51p Matt * Finished (for now) with breaking glass. * * 88 5/04/98 1:00p Jason * changed the way weapon explosions work * * 87 5/04/98 12:47p Matt * Improvements to the breaking glass system, though I don't consider it * anywhere near done yet. * * 86 5/03/98 10:24p Matt * Partially completed breaking glass code, checked in so Chris can fix a * bug * * 85 4/23/98 7:14p Chris * Changed non-moving objects to player collisions * * 84 4/22/98 9:43p Chris * More AI improvements * * 83 4/22/98 3:25p Jason * changes for multiplayer debugging * * 82 4/20/98 4:47p Chris * Made collision stuff more accurate * * 81 4/17/98 2:00p Jason * added cool object effects * * 80 4/15/98 12:56p Chris * Reformatted some code * * 79 4/09/98 5:18p Jason * got guided working in multiplayer * * 78 4/09/98 12:05p Chris * Added parenting for all object types. :) * * 77 4/08/98 11:16a Chris * Fixed powerup pickup bug * * 76 4/07/98 4:25p Chris * Added support for buddy bot * * 75 4/06/98 11:59a Chris * Fixed powerup/powerup hack * * 74 3/31/98 5:56p Jason * changes for multiplay * * 73 3/30/98 5:12p Jason * more changes for game/dll integration * * 72 3/20/98 9:34p Jason * added SetObjectDeadFlag inlined function * * 71 3/20/98 6:39p Jason * 100.0 to 1.0 for volume * * 70 3/20/98 3:54p Chris * Working on adding sounds to the game. :) * * 69 3/20/98 3:21p Chris * Added player hit by weapon sound. * * 68 3/20/98 2:59p Chris * Added a wall hit sound for the player and added support for a base * volume for 3d sounds * * 67 3/19/98 7:15p Jason * more changes for multiplayer * * 66 3/19/98 3:44p Chris * Multiplayer enchancement for collisions * * 65 3/19/98 3:27p Chris * Did some collision code for multiplayer. * * 64 3/18/98 5:45p Jason * more multiplayer script integration * * 63 3/17/98 6:17p Jason * added gamemode collide stuff * * 62 3/17/98 11:27a Chris * Added object bump notifies for AI * * 61 3/13/98 5:55p Chris * Added the new collision spheres * * 60 2/23/98 5:46p Chris * Removed some old code. * * 59 2/18/98 11:48a Craig * * 58 2/11/98 4:10p Jason * got spawning impact weapons working * * 57 2/05/98 2:54p Jason * changes for explosions * * 56 2/05/98 2:02p Chris * Fixed the hitseg and hitwall in collide_object_with_wall and * scrape_object_with_wall * * 55 2/04/98 6:09p Matt * Changed object room number to indicate a terrain cell via a flag. Got * rid of the object flag which used to indicate terrain. * * 54 1/30/98 2:54p Matt * Took script calls out of bump_two_objects, since they alread existed in * collide_two_objects * * 53 1/29/98 5:48p Matt * Got rid of marker objects * * 52 1/29/98 4:16p Matt * Fixed some problems from my last changes * * 51 1/29/98 3:11p Matt * Clean up a bit: deleted commented-out code, removed leftover D1/D2 * stuff, removed references to hostage objects * * 50 1/28/98 12:00p Jason * more changes for multiplayer * * 49 1/26/98 11:01a Jason * incremental checkin for multiplayer * * 48 1/23/98 11:21a Jason * incremental multiplayer checkin * * 47 1/21/98 6:09p Jason * Got player deaths working in multiplayer * * 46 1/21/98 3:05p Samir * Changed a function call to StartPlayerExplosion * * 45 1/21/98 1:11p Jason * incremental checkin for multiplayer * * 44 1/20/98 12:10p Jason * implemented vis effect system * * 43 1/19/98 10:04a Matt * Added new object handle system * * 42 1/14/98 7:57p Chris * Improving the awareness system * * 41 1/14/98 1:23p Jason * made ApplyDamageToGeneric send the weapons parent as the killer * * 40 1/09/98 4:13p Chris * Reformatted some code * * 39 1/09/98 4:11p Chris * Removed a mprintf * * 38 12/22/97 6:19p Chris * Moved weapon battery firing sound off the projectile (weapon) and into * the weapon battery. * * 37 12/15/97 11:03a Jason * make sparks only when successfully hit * * 36 12/12/97 6:13p Jason * added sparks * * 35 12/10/97 2:36p Jason * added random small explosions * * 34 12/04/97 12:15p Jason * gave designers the ability to set their own weapon-to-wall hit vclips * * 33 12/01/97 9:54a Chris * Added support for concussive forces, generalized robot collisions to * generic collisions * * 32 11/20/97 1:38p Chris * No rotation is applied to player objects * * 31 11/13/97 5:06p Chris * Added support for clutter to weapon collisions * * 30 11/05/97 6:42p Jason * took out stupid blast ring * * 29 10/29/97 1:29p Chris * Added PF_STICK for weapons * * 28 10/24/97 2:30p Jason * more changes for explosions * * 27 10/23/97 11:14a Jason * changed some fireball DEFINEs * * 26 10/22/97 7:26p Samir * Player death mostly working. Damn hangup still occurs. Freaky. * * 25 10/22/97 4:30p Chris * We can now slew between the mine and the terrain * * 24 10/22/97 11:44a Jason * changes for explosion system * * 23 10/21/97 4:15p Chris * Incremental integration of the fvi/physics/collide code * * 22 10/20/97 4:46p Jason * changes for explosions * * 21 10/20/97 11:55a Chris * Added some support for the new collide system. * * 20 10/16/97 3:46p Chris * Incremental improvements * * 19 10/03/97 3:47p Chris * Moved script calls to bump two objects (so building can have scripts) * * 18 10/03/97 3:45p Chris * Added some bumping force by weapons * * 17 10/03/97 3:18p Samir * Added script hook to bump_this_object * * 16 10/02/97 11:34a Chris * Added support for external room collisions * * 15 10/01/97 4:51p Samir * Include damage.h * * 14 9/19/97 9:37p Chris * Attempted to fix door collisions -- almost there, but not quite * * 13 9/15/97 5:17a Chris * Removed the Explosion Vclips since they do not play correctly in * Hardware * Added support for building collisons. * working on SPhere to non-moving sphere collisions * * 12 9/12/97 6:36p Chris * Added building collisions * * 11 9/05/97 12:27p Samir * Player takes damage and set death if needed. * * 10 9/04/97 12:03p Matt * Got rid of warnings * * 9 9/03/97 2:13p Chris * Working on improving the debris system and partical explosions * * 8 8/21/97 7:53p Chris * * 7 8/21/97 7:52p Chris * * 6 8/18/97 1:46a Chris * Allowed for robot damage and destoyable objects. * Also, allowed weapons to bounce * * 5 8/14/97 11:44a Samir * Don't kill powerups. Let script do it. * * 4 8/12/97 3:32p Samir * collisions call script code now too. * * 3 8/11/97 1:54p Matt * Ripped out robot & powerup pages, and added generic page * * 2 7/28/97 1:16p Chris * Allow for player and robots to be hit by weapons and correct parenting * of weapons. * * 16 5/19/97 5:39 PM Jeremy * removed "we hit a robot" mprintf * * 15 5/15/97 6:09p Chris * * 14 5/13/97 5:52p Chris * Added ability to exit and enter mine. Also did some * incremental improvements. * * 13 5/05/97 5:41a Chris * Added some better polygon collision code. It is still rough though. * * 12 4/29/97 8:03a Chris * Improved the sound code. High-level sound now * fully uses the flags in the sound page and it * resulted in a simpilier coding interface :) * * 11 4/24/97 5:42p Jason * got fireball vclips working * * 10 4/24/97 12:28p Jason * added sound when weapon hits a wall * * 9 4/24/97 3:25a Chris * // Added some more support for 3d sounds * * 8 4/23/97 6:34p Chris * // Incremental collision stuff. * * 7 4/23/97 6:06p Jason * made player ship and weapons work correctly together (first pass) * * 6 4/17/97 3:10p Chris * Added edge of world object delete. Also did some incremental * improvements. * * 5 4/11/97 3:05a Chris * Allowed robot sphere collision * * 4 3/15/97 1:29p Chris * * $NoKeywords: $ */ #include #include #include "collide.h" #include "PHYSICS.H" #include "pserror.h" #include "mono.h" #include "object.h" #include "player.h" #include "hlsoundlib.h" #include "weapon.h" #include "damage.h" #include "fireball.h" #include "sounds.h" #include "AIMain.h" #include "multi.h" #include "game.h" #include "soundload.h" #include "game2dll.h" #include "scorch.h" #include "ddio.h" #include "vecmat.h" #include "trigger.h" #include "lighting.h" #include "hud.h" #include "D3ForceFeedback.h" #include "demofile.h" #include "osiris_dll.h" #include "marker.h" #include "hud.h" #include "levelgoal.h" #include "psrand.h" #ifdef __LINUX__ #define max(a,b) ((a>b)?a:b) #endif #define PLAYER_ROTATION_BY_FORCE_SCALAR 0.12f #define NONPLAYER_ROTATION_BY_FORCE_SCALAR 1.0f ubyte CollisionResult[MAX_OBJECT_TYPES][MAX_OBJECT_TYPES]; ubyte CollisionRayResult[MAX_OBJECT_TYPES]; bool IsOKToApplyForce(object *objp) { if(Game_mode & GM_MULTI) { if(objp->type == OBJ_PLAYER) { if(objp != Player_object) return false; } else { if(objp->type!=OBJ_WEAPON && objp->type!=OBJ_POWERUP && Netgame.local_role != LR_SERVER) return false; } } if (objp->mtype.phys_info.mass == 0.0) return false; if (objp->movement_type != MT_PHYSICS && objp->movement_type != MT_WALKING) return false; if(objp->mtype.phys_info.flags & PF_PERSISTENT) return false; if (objp->mtype.phys_info.flags & PF_LOCK_MASK) // Not done! return false; return true; } // ----------------------------------------------------------------------------- void bump_this_object(object *objp, object *other_objp, vector *force, vector *collision_pnt, int damage_flag) { // float force_mag; if(objp->type == OBJ_PLAYER) { if((Game_mode & GM_MULTI) && (objp != Player_object)) return; phys_apply_force(objp,force); } else { if((Game_mode & GM_MULTI) && (objp->type != OBJ_PLAYER && objp->type!=OBJ_POWERUP) && (Netgame.local_role != LR_SERVER)) return; phys_apply_force(objp,force); phys_apply_rot(objp,force); } // if (! (objp->mtype.phys_info.flags & PF_PERSISTENT)) // if (objp->type == OBJ_PLAYER) { // vector force2; // force2 = forcex/4; // phys_apply_force(objp,&force2); // if (damage_flag && ((other_objp->type != OBJ_ROBOT) || !Robot_info[other_objp->id].companion)) { // force_mag = vm_vec_mag_quick(&force2); // apply_force_damage(objp, force_mag, other_objp); // } // } else if ((objp->type == OBJ_ROBOT) || (objp->type == OBJ_CLUTTER) || (objp->type == OBJ_CNTRLCEN)) { // if (!Robot_info[objp->id].boss_flag) { // vector force2; // force2.x = force->x/(4 + Difficulty_level); // force2.y = force->y/(4 + Difficulty_level); // force2.z = force->z/(4 + Difficulty_level); // phys_apply_force(objp, force); // phys_apply_rot(objp, &force2); // if (damage_flag) { // force_mag = vm_vec_mag_quick(force); // apply_force_damage(objp, force_mag, other_objp); // } // } // } } /* void bump_one_object(object *obj0, vector *hit_dir, float damage) { vector hit_vec; hit_vec = *hit_dir; vm_vec_scale(&hit_vec, damage); phys_apply_force(obj0,&hit_vec); } */ //#define DAMAGE_SCALE 128 // Was 32 before 8:55 am on Thursday, September 15, changed by MK, walls were hurting me more than robots! //#define DAMAGE_THRESHOLD (F1_0/3) //#define WALL_LOUDNESS_SCALE (20) //float force_force = 50.0; typedef struct v{ float i,j; } vec2d; #define cross(v0,v1) (((v0)->i * (v1)->j) - ((v0)->j * (v1)->i)) //finds the uv coords of the given point on the given seg & side //fills in u & v. if l is non-NULL fills it in also void FindHitpointUV(float *u,float *v,vector *point,room *rp,int facenum) { face *fp = &rp->faces[facenum]; int ii,jj; vec2d pnt[3],checkp,vec0,vec1; float *t; float k0,k1; int i; //1. find what plane to project this wall onto to make it a 2d case GetIJ(&fp->normal,&ii,&jj); //2. compute u,v of intersection point //Copy face points into 2d verts array for (i=0;i<3;i++) { t = &rp->verts[fp->face_verts[i]].x; pnt[i].i = t[ii]; pnt[i].j = t[jj]; } t = &point->x; checkp.i = t[ii]; checkp.j = t[jj]; //vec from 1 -> 0 vec0.i = pnt[0].i - pnt[1].i; vec0.j = pnt[0].j - pnt[1].j; //vec from 1 -> 2 vec1.i = pnt[2].i - pnt[1].i; vec1.j = pnt[2].j - pnt[1].j; k1 = -((cross(&checkp,&vec0) + cross(&vec0,&pnt[1])) / cross(&vec0,&vec1)); if (abs(vec0.i) > abs(vec0.j)) k0 = ((-k1 * vec1.i) + checkp.i - pnt[1].i) / vec0.i; else k0 = ((-k1 * vec1.j) + checkp.j - pnt[1].j) / vec0.j; //mprintf(0," k0,k1 = %x,%x\n",k0,k1); *u = fp->face_uvls[1].u + (k0 * (fp->face_uvls[0].u - fp->face_uvls[1].u)) + (k1 * (fp->face_uvls[2].u - fp->face_uvls[1].u)); *v = fp->face_uvls[1].v + (k0 * (fp->face_uvls[0].v - fp->face_uvls[1].v)) + (k1 * (fp->face_uvls[2].v - fp->face_uvls[1].v)); //mprintf(0," u,v = %x,%x\n",*u,*v); } // Creates some effects where a weapon has collided with a wall void DoWallEffects (object *weapon,int surface_tmap) { texture *texp = &GameTextures[surface_tmap]; if (texp->flags & (TF_VOLATILE+TF_LAVA+TF_WATER)) { // Create some lava steam if ((texp->flags & TF_WATER) || ((ps_rand()%4)==0)) { int visnum=VisEffectCreate (VIS_FIREBALL,MED_SMOKE_INDEX,weapon->roomnum,&weapon->pos); if (visnum>=0) { vis_effect *vis=&VisEffects[visnum]; vis->lifetime=.9f; vis->lifeleft=.9f; vis->movement_type=MT_PHYSICS; vis->size=3.0; vm_MakeZero (&vis->velocity); vis->velocity.y=10; } } } else if (texp->flags & TF_RUBBLE) { if ((ps_rand()%4)==0) { int num_rubble=(ps_rand()%3)+1; int bm_handle=GetTextureBitmap(texp-GameTextures,0); ushort *data=bm_data(bm_handle,0); ushort color=data[(bm_w(bm_handle,0)*(bm_h(bm_handle,0)/2))+(bm_w(bm_handle,0)/2)]; for (int i=0;iroomnum,&weapon->pos); if (visnum>=0) { vis_effect *vis=&VisEffects[visnum]; vis->movement_type=MT_PHYSICS; vis->mass=100; vis->drag=.1f; vis->phys_flags|=PF_GRAVITY|PF_NO_COLLIDE; if ((ps_rand()%3)==0) { vis->velocity.x=(ps_rand()%100)-50; vis->velocity.y=-((ps_rand()%200)-30); vis->velocity.z=(ps_rand()%100)-50; } else { vis->velocity.x=(ps_rand()%300)-50; vis->velocity.y=-((ps_rand()%200)-30); vis->velocity.z=(ps_rand()%300)-50; } vm_NormalizeVectorFast (&vis->velocity); vis->velocity*=4+(ps_rand()%20); vis->size=.5+(((ps_rand()%11)-5)*.05); vis->flags|=VF_USES_LIFELEFT; float lifetime=1.0+(((ps_rand()%11)-5)*.1); vis->lifeleft=lifetime; vis->lifetime=lifetime; vis->lighting_color=color; } } } } } #define FORCEFIELD_DAMAGE 5.0f void DeformTerrain (vector *pos,int depth,float size); //Check for lava, volatile, or water surface. If contact, make special sound & kill the weapon void check_for_special_surface(object *weapon,int surface_tmap,vector *surface_normal,float hit_dot) { bool f_forcefield,f_volatile,f_lava,f_water; f_forcefield = (GameTextures[surface_tmap].flags & TF_FORCEFIELD) != 0; f_volatile = (GameTextures[surface_tmap].flags & TF_VOLATILE) != 0; f_lava = (GameTextures[surface_tmap].flags & TF_LAVA) != 0; f_water = (GameTextures[surface_tmap].flags & TF_WATER) != 0; //Kill the weapon if the surface is volatile, lava, or water if (f_volatile || f_lava || f_water) { int snd; ain_hear hear; hear.f_directly_player = false; if (f_water) { snd = SOUND_WEAPON_HIT_WATER; hear.hostile_level = 0.2f; hear.curiosity_level = 0.3f; } else if (f_volatile || f_lava) { snd = SOUND_WEAPON_HIT_LAVA; hear.hostile_level = 0.1f; hear.curiosity_level = 0.5f; } else Int3(); hear.max_dist = Sounds[snd].max_distance; Sound_system.Play3dSound(snd, SND_PRIORITY_NORMAL, weapon); AINotify(weapon, AIN_HEAR_NOISE, (void *)&hear); if (! f_water) DoWeaponExploded (weapon, surface_normal); SetObjectDeadFlag (weapon); } } //Process a collision between a weapon and a wall //Returns true if the weapon hits the wall, and false if should keep going though the wall (for breakable glass) bool collide_weapon_and_wall( object * weapon, fix hitspeed, int hitseg, int hitwall, vector * hitpnt, vector *wall_normal, float hit_dot) { bool f_forcefield; bool f_volatile,f_lava,f_water; //mprintf((0, "Weapon hit wall, how nice.\n")); //#ifndef RELEASE if ((stricmp(Weapons[weapon->id].name,"Yellow flare") == 0) && (weapon->parent_handle == Player_object->handle) && (KEY_STATE(KEY_LAPOSTRO))) if (ROOMNUM_OUTSIDE(hitseg)) AddHUDMessage("Terrain cell %d",CELLNUM(hitseg)); else AddHUDMessage("Room %d face %d",hitseg,hitwall); //#endif //Check if forcefield int tmap; if (!ROOMNUM_OUTSIDE(hitseg)) //Make sure we've hit a wall, and not terrain { tmap = Rooms[hitseg].faces[hitwall].tmap; } else { tmap = Terrain_tex_seg[Terrain_seg[CELLNUM(hitseg)].texseg_index].tex_index; } f_forcefield = (GameTextures[tmap].flags & TF_FORCEFIELD) != 0; f_volatile = (GameTextures[tmap].flags & TF_VOLATILE) != 0; f_lava = (GameTextures[tmap].flags & TF_LAVA) != 0; f_water = (GameTextures[tmap].flags & TF_WATER) != 0; if(f_forcefield && !(Weapons[weapon->id].flags & WF_MATTER_WEAPON)) { ain_hear hear; hear.f_directly_player = false; hear.hostile_level = 0.9f; hear.curiosity_level = 0.1f; if(sound_override_force_field == -1) hear.max_dist = Sounds[SOUND_FORCEFIELD_BOUNCE].max_distance; else hear.max_dist = Sounds[sound_override_force_field].max_distance; AINotify(weapon, AIN_HEAR_NOISE, (void *)&hear); if(sound_override_force_field == -1) Sound_system.Play3dSound(SOUND_FORCEFIELD_BOUNCE,SND_PRIORITY_HIGH,weapon); else Sound_system.Play3dSound(sound_override_force_field,SND_PRIORITY_HIGH,weapon); return true; } //Check for destroyable or breakable face if (! ROOMNUM_OUTSIDE(hitseg)) //First, make sure we've hit a wall, and not terrain { room *rp = &Rooms[hitseg]; face *fp = &rp->faces[hitwall]; //Check for a trigger on this wall CheckTrigger(hitseg,hitwall,weapon,TT_COLLIDE); // Check for a destroyable face if ((GameTextures[fp->tmap].flags & TF_DESTROYABLE) && !(fp->flags & FF_DESTROYED)) { int visnum=CreateFireball (hitpnt,SHATTER_INDEX+(ps_rand()%2),hitseg,VISUAL_FIREBALL); if (visnum>=0) { // Alter the size of this explosion based on the face size vector verts[MAX_VERTS_PER_FACE]; vector center; for (int t=0;tnum_verts;t++) verts[t]=rp->verts[fp->face_verts[t]]; float size=sqrt(vm_GetCentroid (¢er,verts,fp->num_verts)); VisEffects[visnum].size=(size/2); } CreateRandomSparks (20,hitpnt,hitseg); if(sound_override_glass_breaking == -1) Sound_system.Play3dSound(SOUND_BREAKING_GLASS,SND_PRIORITY_HIGH,weapon); else Sound_system.Play3dSound(sound_override_glass_breaking,SND_PRIORITY_HIGH,weapon); fp->flags|=FF_DESTROYED; } //Check for a breakable face: If the texture is breakable and it's on a portal //and hit with a matter weapon, break it if ((fp->portal_num != -1) && (GameTextures[fp->tmap].flags & TF_BREAKABLE) && (Weapons[weapon->id].flags & WF_MATTER_WEAPON)) { //Do the breaking glass stuff if (!((Game_mode & GM_MULTI) && Netgame.local_role==LR_CLIENT)) BreakGlassFace(rp,hitwall,hitpnt,&weapon->mtype.phys_info.velocity); ain_hear hear; hear.f_directly_player = false; hear.hostile_level = 0.9f; hear.curiosity_level = 1.0f; if(sound_override_glass_breaking == -1) hear.max_dist = Sounds[SOUND_BREAKING_GLASS].max_distance; else hear.max_dist = Sounds[sound_override_glass_breaking].max_distance; AINotify(weapon, AIN_HEAR_NOISE, (void *)&hear); return false; } } //Add a scorch if ((Weapons[weapon->id].scorch_handle != -1) && !f_water && !f_volatile && !f_lava) AddScorch(hitseg,hitwall,hitpnt,Weapons[weapon->id].scorch_handle,Weapons[weapon->id].scorch_size); if (ROOMNUM_OUTSIDE(hitseg)) { if (Weapons[weapon->id].terrain_damage_size>0 && Weapons[weapon->id].terrain_damage_depth>0) { DeformTerrain (&weapon->pos,Weapons[weapon->id].terrain_damage_depth,Weapons[weapon->id].terrain_damage_size); } } //Do special smoke, etc. DoWallEffects (weapon,tmap); //look for lava, volatile, water check_for_special_surface(weapon,tmap,wall_normal,hit_dot); //If dead, we're done if (weapon->flags & OF_DEAD) return true; //If done bouncing, kill the weapon if ((weapon->mtype.phys_info.num_bounces <= 0) && !(weapon->mtype.phys_info.flags & PF_STICK) && (hit_dot > weapon->mtype.phys_info.hit_die_dot)) { int snd; ain_hear hear; hear.f_directly_player = false; snd = Weapons[weapon->id].sounds[WSI_IMPACT_WALL]; hear.hostile_level = 0.9f; hear.curiosity_level = 0.1f; if (snd != SOUND_NONE_INDEX) { hear.max_dist = Sounds[snd].max_distance; Sound_system.Play3dSound(snd, SND_PRIORITY_NORMAL, weapon); AINotify(weapon, AIN_HEAR_NOISE, (void *)&hear); } // Check to see if we should spawn if ((Weapons[weapon->id].flags & WF_SPAWNS_IMPACT) && Weapons[weapon->id].spawn_count>0 && Weapons[weapon->id].spawn_handle>=0) CreateImpactSpawnFromWeapon (weapon, wall_normal); if ((Weapons[weapon->id].flags & WF_SPAWNS_ROBOT) && (Weapons[weapon->id].flags & WF_COUNTERMEASURE) && Weapons[weapon->id].robot_spawn_handle>=0) CreateRobotSpawnFromWeapon (weapon); DoWeaponExploded (weapon, wall_normal); SetObjectDeadFlag (weapon); } else { //weapon is bouncing if (Weapons[weapon->id].sounds[WSI_BOUNCE]!=SOUND_NONE_INDEX) { Sound_system.Play3dSound(Weapons[weapon->id].sounds[WSI_BOUNCE], SND_PRIORITY_HIGH, weapon); if(Weapons[weapon->id].sounds[WSI_BOUNCE] > -1) { ain_hear hear; hear.f_directly_player = false; hear.hostile_level = 0.20f; hear.curiosity_level = 0.6f; hear.max_dist = Sounds[Weapons[weapon->id].sounds[WSI_BOUNCE]].max_distance; AINotify(weapon, AIN_HEAR_NOISE, (void *)&hear); } } } return true; } // Prints out a marker hud message if needed void collide_player_and_marker( object * playerobj, object * marker_obj, vector *collision_point, vector *collision_normal, bool f_reverse_normal, fvi_info *hit_info ) { if (playerobj->id==Player_num) { char str[100]; sprintf (str,"Marker: %s",MarkerMessages[marker_obj->id]); AddHUDMessage (str); } } #define MIN_WALL_HIT_SOUND_VEL 40.0f #define MAX_WALL_HIT_SOUND_VEL 120.0f #define MIN_PLAYER_WALL_SOUND_TIME .1f #define WALL_DAMAGE 0.5f #define MIN_WALL_HIT_DAMAGE_SHIELDS 5 #define MIN_WALL_DAMAGE_SPEED 65.0 #define VOLATILE_DAMAGE 7.0f //damage per hit void collide_player_and_wall( object * playerobj, float hitspeed, int hitseg, int hitwall, vector * hitpt, vector *wall_normal, float hit_dot) { float volume = MAX_GAME_VOLUME; bool f_volatile,f_lava; bool f_forcefield; int tmap; if(playerobj->flags & OF_DYING) playerobj->ctype.dying_info.delay_time *= 0.9f; //Check for a trigger on this wall if (! ROOMNUM_OUTSIDE(hitseg)) //Make sure we've hit a wall, and not terrain { CheckTrigger(hitseg,hitwall,playerobj,TT_COLLIDE); tmap = Rooms[hitseg].faces[hitwall].tmap; } else { tmap = Terrain_tex_seg[Terrain_seg[CELLNUM(hitseg)].texseg_index].tex_index; } f_lava = (GameTextures[tmap].flags & TF_LAVA) != 0; f_volatile = (GameTextures[tmap].flags & TF_VOLATILE) != 0; f_forcefield = (GameTextures[tmap].flags & TF_FORCEFIELD) != 0; if(f_lava) { if(!((Game_mode & GM_MULTI) && (Netgame.local_role==LR_CLIENT))) { int id = FindWeaponName("NapalmBlob"); if(id >= 0) SetNapalmDamageEffect(playerobj,NULL,id); else Int3(); } } //If volatile, make the sound & apply damage if (f_volatile) { if(playerobj == Player_object) { if ((!(Game_mode & GM_MULTI)) || Netgame.local_role==LR_SERVER) ApplyDamageToPlayer (playerobj, playerobj, PD_VOLATILE_HISS, VOLATILE_DAMAGE); else { Multi_requested_damage_type = PD_VOLATILE_HISS; Multi_requested_damage_amount+=(VOLATILE_DAMAGE); } } } if(f_forcefield) { if(playerobj == Player_object && sound_override_force_field == -1) { if ((!(Game_mode & GM_MULTI)) || Netgame.local_role==LR_SERVER) ApplyDamageToPlayer (playerobj, playerobj, PD_ENERGY_WEAPON, FORCEFIELD_DAMAGE); else { Multi_requested_damage_type = PD_ENERGY_WEAPON; Multi_requested_damage_amount+=(FORCEFIELD_DAMAGE); } } if(sound_override_force_field == -1) Sound_system.Play3dSound(SOUND_FORCEFIELD_BOUNCE, SND_PRIORITY_HIGH, playerobj, MAX_GAME_VOLUME); else Sound_system.Play3dSound(sound_override_force_field, SND_PRIORITY_HIGH, playerobj, MAX_GAME_VOLUME); } if(f_forcefield || f_lava || f_volatile) { ain_hear hear; hear.f_directly_player = true; hear.hostile_level = 0.90f; hear.curiosity_level = 0.6f; if(sound_override_force_field == -1) hear.max_dist = Sounds[SOUND_FORCEFIELD_BOUNCE].max_distance; else hear.max_dist = Sounds[sound_override_force_field].max_distance; AINotify(playerobj, AIN_HEAR_NOISE, (void *)&hear); } // Do sound stuff when a player hits a wall if(!f_forcefield && !f_volatile && !f_lava && hitspeed > MIN_WALL_HIT_SOUND_VEL && Players[playerobj->id].last_hit_wall_sound_time + MIN_PLAYER_WALL_SOUND_TIME < Gametime) { if(hitspeed < MAX_WALL_HIT_SOUND_VEL) { volume = MAX_GAME_VOLUME * (hitspeed - MIN_WALL_HIT_SOUND_VEL)/(MAX_WALL_HIT_SOUND_VEL - MIN_WALL_HIT_SOUND_VEL); } if(hitspeed > MIN_WALL_DAMAGE_SPEED) { if(playerobj == Player_object && playerobj->shields >= MIN_WALL_HIT_DAMAGE_SHIELDS) { if ((!(Game_mode & GM_MULTI)) || Netgame.local_role==LR_SERVER) ApplyDamageToPlayer (playerobj, playerobj, PD_WALL_HIT, WALL_DAMAGE); else { Multi_requested_damage_type = PD_WALL_HIT; Multi_requested_damage_amount+=(WALL_DAMAGE); } } } Sound_system.Play3dSound(SOUND_PLAYER_HIT_WALL, SND_PRIORITY_NORMAL, playerobj, volume); if(Demo_flags==DF_RECORDING) DemoWrite3DSound(SOUND_PLAYER_HIT_WALL,OBJNUM(playerobj),1,volume); ain_hear hear; hear.f_directly_player = true; hear.hostile_level = 0.10f; hear.curiosity_level = 0.5f; hear.max_dist = Sounds[SOUND_PLAYER_HIT_WALL].max_distance * volume; AINotify(playerobj, AIN_HEAR_NOISE, (void *)&hear); Players[playerobj->id].last_hit_wall_sound_time = Gametime; } if (Players[playerobj->id].flags & PLAYER_FLAGS_DYING) StartPlayerExplosion(playerobj->id); //Do ForceFeedback //---------------- if(playerobj->id == Player_num && ForceIsEnabled() ) { DoForceForWall(playerobj,hitspeed,hitseg,hitwall,wall_normal); } return; } void collide_generic_and_wall( object * genericobj, float hitspeed, int hitseg, int hitwall, vector * hitpt, vector *wall_normal, float hit_dot) { bool f_volatile,f_lava; bool f_forcefield; float volume = MAX_GAME_VOLUME; //Check for a trigger on this wall int tmap; if (! ROOMNUM_OUTSIDE(hitseg)) //Make sure we've hit a wall, and not terrain { CheckTrigger(hitseg,hitwall,genericobj,TT_COLLIDE); tmap = Rooms[hitseg].faces[hitwall].tmap; } else { tmap = Terrain_tex_seg[Terrain_seg[CELLNUM(hitseg)].texseg_index].tex_index; } f_forcefield = (GameTextures[tmap].flags & TF_FORCEFIELD) != 0; f_volatile = (GameTextures[tmap].flags & TF_VOLATILE) != 0; f_lava = (GameTextures[tmap].flags & TF_LAVA) != 0; if(IS_GUIDEBOT(genericobj)) { f_forcefield = false; f_volatile = false; f_lava = false; } if(f_lava) { if(!((Game_mode & GM_MULTI) && (Netgame.local_role==LR_CLIENT))) { int id = FindWeaponName("NapalmBlob"); if(id >= 0) SetNapalmDamageEffect(genericobj,NULL,id); else Int3(); } } //If volatile, make the sound & apply damage if (f_volatile && !((Game_mode & GM_MULTI) && (Netgame.local_role==LR_CLIENT))) { ApplyDamageToGeneric(genericobj, genericobj, GD_VOLATILE_HISS, VOLATILE_DAMAGE); Sound_system.Play3dSound(SOUND_VOLATILE_HISS, SND_PRIORITY_HIGHEST, genericobj, MAX_GAME_VOLUME); } if(f_forcefield && !((Game_mode & GM_MULTI) && (Netgame.local_role==LR_CLIENT))) { if(sound_override_force_field == -1) { Sound_system.Play3dSound(SOUND_FORCEFIELD_BOUNCE, SND_PRIORITY_LOW, genericobj, MAX_GAME_VOLUME); ApplyDamageToGeneric(genericobj, genericobj, GD_ENERGY, FORCEFIELD_DAMAGE); } else { Sound_system.Play3dSound(sound_override_force_field, SND_PRIORITY_LOW, genericobj, MAX_GAME_VOLUME); } } if(genericobj->control_type != CT_AI) { if(!f_forcefield && !f_volatile && !f_lava && hitspeed > MIN_WALL_HIT_SOUND_VEL) { if(hitspeed < MAX_WALL_HIT_SOUND_VEL) { volume = MAX_GAME_VOLUME * (hitspeed - MIN_WALL_HIT_SOUND_VEL)/(MAX_WALL_HIT_SOUND_VEL - MIN_WALL_HIT_SOUND_VEL); } if(hitspeed > MIN_WALL_DAMAGE_SPEED) { if ((!(Game_mode & GM_MULTI)) || Netgame.local_role==LR_SERVER) { ApplyDamageToGeneric(genericobj, genericobj, GD_PHYSICS, WALL_DAMAGE); } } Sound_system.Play3dSound(SOUND_PLAYER_HIT_WALL, SND_PRIORITY_LOW, genericobj, volume); if(Demo_flags==DF_RECORDING) DemoWrite3DSound(SOUND_PLAYER_HIT_WALL,OBJNUM(genericobj),1,volume); } } return; } float Last_volatile_scrape_sound_time = 0; //this gets called when an object is scraping along the wall void scrape_object_on_wall(object *obj, int hitseg, int hitwall, vector * hitpt, vector *wall_normal ) { /* switch (obj->type) { case OBJ_PLAYER: if (obj->id==Player_num) { int type; //mprintf((0, "Scraped segment #%3i, side #%i\n", hitseg, hitside)); if ((type=check_volatile_wall(obj,hitseg,hitside,hitpt))!=0) { vector hit_dir, rand_vec; if ((GameTime > Last_volatile_scrape_sound_time + F1_0/4) || (GameTime < Last_volatile_scrape_sound_time)) { int sound = (type==1)?SOUND_VOLATILE_WALL_HISS:SOUND_SHIP_IN_WATER; Last_volatile_scrape_sound_time = GameTime; digi_link_sound_to_pos( sound, hitseg, 0, hitpt, 0, F1_0 ); if (Game_mode & GM_MULTI) multi_send_play_sound(sound, F1_0); } #ifdef COMPACT_SEGS get_side_normal(&Segments[hitseg], higside, 0, &hit_dir ); #else hit_dir = Segments[hitseg].sides[hitside].normals[0]; #endif make_random_vector(&rand_vec); vm_vec_scale_add2(&hit_dir, &rand_vec, F1_0/8); vm_vec_normalize_quick(&hit_dir); bump_one_object(obj, &hit_dir, F1_0*8); } //@@} else { //@@ //what scrape sound //@@ //PLAY_SOUND( SOUND_PLAYER_SCRAPE_WALL ); //@@} } break; //these two kinds of objects below shouldn't really slide, so //if this scrape routine gets called (which it might if the //object (such as a fusion blob) was created already poking //through the wall) call the collide routine. case OBJ_WEAPON: collide_weapon_and_wall(obj,0,hitseg,hitside,hitpt); break; case OBJ_DEBRIS: collide_debris_and_wall(obj,0,hitseg,hitside,hitpt); break; } */ } /* void apply_damage_to_player(object *playerobj, object *killer, float damage) { if (Player_is_dead) return; if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) return; if (Endlevel_sequence) return; //for the player, the 'real' shields are maintained in the Players[] //array. The shields value in the player's object are, I think, not //used anywhere. This routine, however, sets the objects shields to //be a mirror of the value in the Player structure. if (playerobj->id == Player_num) { //is this the local player? // MK: 08/14/95: This code can never be reached. See the return about 12 lines up. // -- if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) { // -- // -- //invincible, so just do blue flash // -- // -- PALETTE_FLASH_ADD(0,0,f2i(damage)*4); //flash blue // -- // -- } // -- else { //take damage, do red flash Players[Player_num].shields -= damage; PALETTE_FLASH_ADD(f2i(damage)*4,-f2i(damage/2),-f2i(damage/2)); //flash red // -- } if (Players[Player_num].shields < 0) { Players[Player_num].killer_objnum = killer-Objects; // if ( killer && (killer->type == OBJ_PLAYER)) // Players[Player_num].killer_objnum = killer-Objects; playerobj->flags |= OF_DEAD; if (Buddy_objnum != -1) if ((killer->type == OBJ_ROBOT) && (Robot_info[killer->id].companion)) Buddy_sorry_time = GameTime; } // -- removed, 09/06/95, MK -- else if (Players[Player_num].shields < LOSE_WEAPON_THRESHOLD) { // -- removed, 09/06/95, MK -- int randnum = ps_rand(); // -- removed, 09/06/95, MK -- // -- removed, 09/06/95, MK -- if (floatmul(Players[Player_num].shields, randnum) < damage/4) { // -- removed, 09/06/95, MK -- if (ps_rand() > 20000) { // -- removed, 09/06/95, MK -- destroy_secondary_weapon(Secondary_weapon); // -- removed, 09/06/95, MK -- } else if (Primary_weapon == 0) { // -- removed, 09/06/95, MK -- if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS) // -- removed, 09/06/95, MK -- destroy_primary_weapon(MAX_PRIMARY_WEAPONS); // This means to destroy quad laser. // -- removed, 09/06/95, MK -- else if (Players[Player_num].laser_level > 0) // -- removed, 09/06/95, MK -- destroy_primary_weapon(Primary_weapon); // -- removed, 09/06/95, MK -- } else // -- removed, 09/06/95, MK -- destroy_primary_weapon(Primary_weapon); // -- removed, 09/06/95, MK -- } else // -- removed, 09/06/95, MK -- ; // mprintf((0, "%8x > %8x, so don't lose weapon.\n", floatmul(Players[Player_num].shields, randnum), damage/4)); // -- removed, 09/06/95, MK -- } playerobj->shields = Players[Player_num].shields; //mirror } } */ void CollideAnglesToMatrix(matrix *m, float p, float h, float b) { float sinp,cosp,sinb,cosb,sinh,cosh; sinp = sin(p); cosp = cos(p); sinb = sin(b); cosb = cos(b); sinh = sin(h); cosh = cos(h); m->rvec.x = cosb*cosh; m->rvec.y = cosb*sinp*sinh - cosp*sinb; m->rvec.z = cosb*cosp*sinh + sinb*sinp; m->uvec.x = cosh*sinb; m->uvec.y = sinb*sinp*sinh + cosp*cosb; m->uvec.z = sinb*cosp*sinh - cosb*sinp; m->fvec.x = -sinh; m->fvec.y = sinp*cosh; m->fvec.z = cosp*cosh; } vector *CollideExtractAnglesFromMatrix(vector *a,matrix *m) { float sinh,cosh,sinp,sinb; sinh = -m->fvec.x; if(sinh < -1.0f) sinh = -1.0f; else if(sinh > 1.0f) sinh = 1.0f; a->y = asin(sinh); cosh = cos(a->y); ASSERT(cosh != 0.0); sinp = m->fvec.y/cosh; if(sinp < -1.0f) sinp = -1.0f; else if(sinp > 1.0f) sinp = 1.0f; sinb = m->uvec.x/cosh; if(sinb < -1.0f) sinb = -1.0f; else if(sinb > 1.0f) sinb = 1.0f; a->x = asin(sinp); a->z = asin(sinb); return a; } void ConvertEulerToAxisAmount(vector *e, vector *n, float *w) { float rotspeed = vm_GetMagnitude(e); matrix rotmat; vector e_n; float scale = rotspeed/.0001f; // If there isn't a rotation, return something valid if(rotspeed == 0.0f || scale == 0.0f) { *n = Zero_vector; n->y = 1.0f; *w = 0.0f; return; } e_n = *e / scale; // vector f; CollideAnglesToMatrix(&rotmat, e_n.x, e_n.y, e_n.z); // mprintf((0, "F %f, %f, %f\n", XYZ(&rotmat.fvec))); // mprintf((0, "R %f, %f, %f\n", XYZ(&rotmat.rvec))); // mprintf((0, "U %f, %f, %f\n", XYZ(&rotmat.uvec))); // CollideExtractAnglesFromMatrix(&f, &rotmat); // mprintf((0, "Before %f, %f, %f\n", XYZ(&e_n))); // mprintf((0, "After %f, %f, %f\n", XYZ(&f))); // This is from Graphics Gems 1 p.467 I am converting from a angle vector // to the normal of that rotation (you can also get the angle about that normal, but // we don't need it) n->x = rotmat.uvec.z - rotmat.fvec.y; n->y = rotmat.fvec.x - rotmat.rvec.z; n->z = rotmat.rvec.y - rotmat.uvec.x; if(*n != Zero_vector) { vm_NormalizeVector(n); float ct = (rotmat.rvec.x + rotmat.uvec.y + rotmat.fvec.z - 1.0f)/2.0f; if(ct < -1.0f) ct = -1.0f; else if(ct > 1.0f) ct = 1.0f; float v = acos(ct); float z = sin(v); // if(v < 0.0) // *w = -rotspeed; // else *w = rotspeed * ((2.0f * PI)/(65535.0f)); if(z >= 0.0f) *n *= -1.0f; } else { *w = 0.0f; } } void ConvertAxisAmountToEuler(vector *n, float *w, vector *e) { float s; float c; float t; float scale = *w/.0001f; float w_n = .0001f; vector s_result; if(*w == 0.0f) { *e = Zero_vector; return; } s = sin(.0001); c = cos(.0001); t = 1.0f - c; matrix rotmat; const float sx = s * n->x; const float sy = s * n->y; const float sz = s * n->z; const float txy = t * n->x * n->y; const float txz = t * n->x * n->z; const float tyz = t * n->y * n->z; const float txx = t * n->x * n->x; const float tyy = t * n->y * n->y; const float tzz = t * n->z * n->z; rotmat.rvec.x = txx + c; rotmat.rvec.y = txy - sz; rotmat.rvec.z = txz + sy; rotmat.uvec.x = txy + sz; rotmat.uvec.y = tyy + c; rotmat.uvec.z = tyz - sx; rotmat.fvec.x = txz - sy; rotmat.fvec.y = tyz + sx; rotmat.fvec.z = tzz + c; CollideExtractAnglesFromMatrix(&s_result, &rotmat); e->x = (s_result.x) * scale * (65535.0f/(2.0*PI)); e->y = (s_result.y) * scale * (65535.0f/(2.0*PI)); e->z = (s_result.z) * scale * (65535.0f/(2.0*PI)); } void bump_obj_against_fixed(object *obj, vector *collision_point, vector *collision_normal) { ASSERT(_finite(obj->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(obj->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(obj->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(obj->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(obj->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(obj->mtype.phys_info.velocity.z) != 0); if(!IsOKToApplyForce(obj)) return; vector r1 = *collision_point - obj->pos; vector w1; vector n1; float temp1; float j; matrix o_t1 = obj->orient; vm_TransposeMatrix(&o_t1); vector cmp1 = obj->mtype.phys_info.rotvel * o_t1; ConvertEulerToAxisAmount(&cmp1, &n1, &temp1); n1 *= temp1; if(temp1 != 0.0f) { vm_CrossProduct(&w1, &n1, &r1); } else { w1 = Zero_vector; } vector p1 = obj->mtype.phys_info.velocity + w1; float v_rel; float m1 = obj->mtype.phys_info.mass; ASSERT(m1 != 0.0f); if(m1 <= 0.0f) m1 = 0.00000001f; v_rel = *collision_normal * (p1); float e = obj->mtype.phys_info.coeff_restitution; vector c1; vector cc1; float cv1; // matrix i1; // matrix i2; float i1 = (2.0f/5.0f)*m1*obj->size*obj->size; if(i1 < .0000001) i1 = .0000001f; vm_CrossProduct(&c1, &r1, collision_normal); c1 = c1/i1; vm_CrossProduct(&cc1, &c1, &r1); cv1 = (*collision_normal)*c1; j = (-(1.0f + e))*v_rel; j /= (1/m1 + cv1); obj->mtype.phys_info.velocity += ((j*(*collision_normal))/m1); vector jcn = j * (*collision_normal); vm_CrossProduct(&c1, &r1, &jcn); n1 = (c1)/i1; temp1 = vm_NormalizeVector(&n1); vector txx1; ConvertAxisAmountToEuler(&n1, &temp1, &txx1); obj->mtype.phys_info.rotvel += (txx1*obj->orient); ASSERT(_finite(obj->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(obj->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(obj->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(obj->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(obj->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(obj->mtype.phys_info.velocity.z) != 0); //hack rotvel /* vector v = obj->mtype.phys_info.velocity; vector c = *collision_normal; if(v != Zero_vector) { vm_NormalizeVector(&v); if(v != c) { float rad = vm_VectorDistance(&obj->pos, collision_point); float rotvel = vm_GetMagnitude(&obj->mtype.phys_info.velocity)*((2*PI*rad)); vector r; vector e; vm_CrossProduct(&r, &v, &c); vm_NormalizeVector(&r); ConvertAxisAmountToEuler(&r, &rotvel, &e); matrix rrr = obj->orient; // vm_TransposeMatrix(&rrr); obj->mtype.phys_info.rotvel = rrr * r; } else { obj->mtype.phys_info.rotvel = Zero_vector; } } else { obj->mtype.phys_info.rotvel = Zero_vector; }*/ } void bump_two_objects(object *object0, object *object1, vector *collision_point, vector *collision_normal, int damage_flag) { // vector force; //dv, object *t = NULL; object *other = NULL; // Determine if a moving object hits a non-moving object if((object0->movement_type != MT_PHYSICS && object0->movement_type != MT_WALKING) || (object0->movement_type == MT_PHYSICS && object0->mtype.phys_info.velocity == Zero_vector && (object0->mtype.phys_info.flags & PF_LOCK_MASK) && (object0->mtype.phys_info.flags & PF_POINT_COLLIDE_WALLS))) { t = object1; other = object0; *collision_normal *= -1.0f; } if((object1->movement_type != MT_PHYSICS && object1->movement_type != MT_WALKING) || (object1->movement_type == MT_PHYSICS && object1->mtype.phys_info.velocity == Zero_vector && (object1->mtype.phys_info.flags & PF_LOCK_MASK) && (object1->mtype.phys_info.flags & PF_POINT_COLLIDE_WALLS))) { t = object0; other = object1; } // If we hit a non-moving object... if (t) { // chrishack -- walker hack if(t->movement_type != MT_PHYSICS && t->movement_type != MT_WALKING) { t->mtype.phys_info.velocity = Zero_vector; return; } if(t->mtype.phys_info.flags & PF_PERSISTENT) return; vector moved_v; float wall_part; float luke_test; if(t->type == OBJ_PLAYER) { luke_test = vm_GetMagnitude(&t->mtype.phys_info.velocity); } if (!(t->flags & OF_DEAD)) { // bump_obj_against_fixed(t, collision_point, collision_normal); // } ///* // Find hit speed moved_v = t->pos - t->last_pos; wall_part = *collision_normal * t->mtype.phys_info.velocity; if (t->mtype.phys_info.flags & PF_BOUNCE) { wall_part *= 2.0; //Subtract out wall part twice to achieve bounce // New bounceness code if ((t->mtype.phys_info.flags & PF_BOUNCE) && (t->mtype.phys_info.num_bounces != PHYSICS_UNLIMITED_BOUNCE)) { if(t->mtype.phys_info.num_bounces == 0) { ASSERT (t->type!=OBJ_PLAYER); if (t->flags & OF_DYING) { ASSERT((t->control_type == CT_DYING) || (t->control_type == CT_DYING_AND_AI)); DestroyObject(t,50.0,t->ctype.dying_info.death_flags); } else SetObjectDeadFlag (t); } } t->mtype.phys_info.num_bounces--; t->mtype.phys_info.velocity += *collision_normal * (wall_part * -1.0f); if(t->mtype.phys_info.coeff_restitution != 1.0f) t->mtype.phys_info.velocity -= (t->mtype.phys_info.velocity * (1.0f - t->mtype.phys_info.coeff_restitution)); } else { float wall_force; wall_force = t->mtype.phys_info.thrust * *collision_normal; t->mtype.phys_info.thrust += *collision_normal * (wall_force * -1.001); // 1.001 so that we are not quite tangential // Update velocity from wall hit. t->mtype.phys_info.velocity += *collision_normal * (wall_part * -1.001); // 1.001 so that we are not quite tangential if(t->type == OBJ_PLAYER) { float real_vel; real_vel = vm_NormalizeVector(&t->mtype.phys_info.velocity); t->mtype.phys_info.velocity *= ((real_vel + luke_test)/2.0f); //obj->mtype.phys_info.velocity *= (luke_test); } } // Weapons should face their new heading. This is so missiles are pointing in the correct direct. if (t->type == OBJ_WEAPON && (t->mtype.phys_info.flags & (PF_BOUNCE | PF_GRAVITY | PF_WIND ))) vm_VectorToMatrix(&t->orient, &t->mtype.phys_info.velocity, &t->orient.uvec, NULL); } // Return it to the original direction if(object0->movement_type != MT_PHYSICS && object0->movement_type != MT_WALKING) { *collision_normal *= -1.0f; } //Do ForceFeedback stuff for non-moving objects //----------------------------------------- if(ForceIsEnabled()){ if(object0->type==OBJ_PLAYER && object0->id==Player_num){ } } //*/ return; } // force = object0->mtype.phys_info.velocity - object1->mtype.phys_info.velocity; // force *= 2*(object0->mtype.phys_info.mass * object1->mtype.phys_info.mass)/(object0->mtype.phys_info.mass + object1->mtype.phys_info.mass); // if(!(object1->mtype.phys_info.flags & PF_PERSISTENT)) // bump_this_object(object1, object0, &force, collision_point, damage_flag); // // force = -force; // // if(!(object0->mtype.phys_info.flags & PF_PERSISTENT)) // bump_this_object(object0, object1, &force, collision_point, damage_flag); // vector r_vel = object0->mtype.phys_info.velocity - object1->mtype.phys_info.velocity; //Add this back ASSERT(_finite(object1->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(object1->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(object1->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(object1->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(object1->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(object1->mtype.phys_info.velocity.z) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.z) != 0); vector r1 = *collision_point - object0->pos; vector r2 = *collision_point - object1->pos; vector w1; vector w2; vector n1; vector n2; float temp1; float temp2; float j; matrix o_t1 = object0->orient; matrix o_t2 = object1->orient; vm_TransposeMatrix(&o_t1); vm_TransposeMatrix(&o_t2); vector cmp1 = object0->mtype.phys_info.rotvel * o_t1; vector cmp2 = object1->mtype.phys_info.rotvel * o_t2; ConvertEulerToAxisAmount(&cmp1, &n1, &temp1); ConvertEulerToAxisAmount(&cmp2, &n2, &temp2); n1 *= temp1; n2 *= temp2; if(temp1 != 0.0f) { vm_CrossProduct(&w1, &n1, &r1); } else { w1 = Zero_vector; } if(temp2 != 0.0f) { vm_CrossProduct(&w2, &n2, &r2); } else { w2 = Zero_vector; } vector p1 = object0->mtype.phys_info.velocity + w1; vector p2 = object1->mtype.phys_info.velocity + w2; float v_rel; float m1 = object0->mtype.phys_info.mass; float m2 = object1->mtype.phys_info.mass; bool f_force_1 = IsOKToApplyForce(object0); bool f_force_2 = IsOKToApplyForce(object1); ASSERT(m1 != 0.0f && m2 != 0.0f); if(m1 <= 0.0f) m1 = 0.00000001f; if(m2 <= 0.0f) m2 = 0.00000001f; v_rel = *collision_normal * (p1 - p2); float e; if(object0->type == OBJ_PLAYER && object1->type == OBJ_PLAYER) e = 0.015f; else if((object0->type == OBJ_WEAPON || object1->type == OBJ_WEAPON) && (object0->type != OBJ_PLAYER && object1->type != OBJ_PLAYER)) e = 1.0f; else if((object0->type == OBJ_CLUTTER && object1->type == OBJ_PLAYER) || (object0->type == OBJ_PLAYER && object1->type == OBJ_CLUTTER)) e = 0.5f; else e = 0.1f; vector c1; vector c2; vector cc1; vector cc2; float cv1; float cv2; // matrix i1; // matrix i2; float i1 = (2.0f/5.0f)*m1*object0->size*object0->size; float i2 = (2.0f/5.0f)*m2*object1->size*object1->size; if(i1 < .0000001) i1 = .0000001f; if(i2 < .0000001) i2 = .0000001f; vm_CrossProduct(&c1, &r1, collision_normal); vm_CrossProduct(&c2, &r2, collision_normal); c1 = c1/i1; c2 = c2/i2; vm_CrossProduct(&cc1, &c1, &r1); vm_CrossProduct(&cc2, &c2, &r2); cv1 = (*collision_normal)*c1; cv2 = (*collision_normal)*c2; j = (-(1.0f + e))*v_rel; j /= (1/m1 + 1/m2 + cv1 + cv2); if(f_force_1) object0->mtype.phys_info.velocity += ((j*(*collision_normal))/m1); if(f_force_2) object1->mtype.phys_info.velocity -= ((j*(*collision_normal))/m2); vector jcn = j * (*collision_normal); vm_CrossProduct(&c1, &r1, &jcn); vm_CrossProduct(&c2, &r2, &jcn); n1 = (c1)/i1; n2 = (c2)/i2; temp1 = vm_NormalizeVector(&n1); temp2 = vm_NormalizeVector(&n2); vector txx1; vector txx2; ConvertAxisAmountToEuler(&n1, &temp1, &txx1); ConvertAxisAmountToEuler(&n2, &temp2, &txx2); float rotscale1, rotscale2; if(object0->type == OBJ_PLAYER) rotscale1 = PLAYER_ROTATION_BY_FORCE_SCALAR; else rotscale1 = NONPLAYER_ROTATION_BY_FORCE_SCALAR; if(object1->type == OBJ_PLAYER) rotscale2 = PLAYER_ROTATION_BY_FORCE_SCALAR; else rotscale2 = NONPLAYER_ROTATION_BY_FORCE_SCALAR; if(f_force_1) object0->mtype.phys_info.rotvel += (txx1*object0->orient) * rotscale1; if(f_force_2) object1->mtype.phys_info.rotvel += (txx2*object1->orient) * rotscale2; ASSERT(_finite(object1->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(object1->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(object1->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(object1->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(object1->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(object1->mtype.phys_info.velocity.z) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.z) != 0); //Do ForceFeedback stuff for moving objects //----------------------------------------- if(ForceIsEnabled()){ if(object0->type==OBJ_PLAYER && object0->id==Player_num){ //v is the force vector vector v; v = -1.0 * v_rel * (*collision_normal); //Was it weapon->player collide switch(object1->type){ case OBJ_WEAPON: //Do force effect for player/weapon collision DoForceForWeapon(object0,object1,&v); break; default: break; } } } // Catch things on fire if possible if (object0->effect_info && object1->effect_info) { // One of these objects must be burning if ((object0->effect_info->type_flags & EF_NAPALMED) || (object1->effect_info->type_flags & EF_NAPALMED)) { // Both cannot be burning if (!(object0->effect_info->type_flags & EF_NAPALMED) || !(object1->effect_info->type_flags & EF_NAPALMED)) { object *src_obj,*dest_obj; if (object0->effect_info->type_flags & EF_NAPALMED) { src_obj=object0; dest_obj=object1; } else { src_obj=object1; dest_obj=object0; } dest_obj->effect_info->type_flags|=EF_NAPALMED; dest_obj->effect_info->damage_time=max(1.0,src_obj->effect_info->damage_time/3.0); dest_obj->effect_info->damage_per_second=src_obj->effect_info->damage_per_second; // We need this cap (as the gb burns forever if(dest_obj->effect_info->damage_time > 10.0f) { dest_obj->effect_info->damage_time = 10.0f; } dest_obj->effect_info->last_damage_time=0; dest_obj->effect_info->damage_handle=src_obj->handle; if (dest_obj->effect_info->sound_handle == SOUND_NONE_INDEX) dest_obj->effect_info->sound_handle = Sound_system.Play3dSound(SOUND_PLAYER_BURNING, SND_PRIORITY_HIGHEST, dest_obj); } } } } void collide_player_and_player( object * p1, object * p2, vector *collision_point, vector *collision_normal, bool f_reverse_normal, fvi_info *hit_info ) { if(f_reverse_normal) *collision_normal *= -1.0f; vector rvel = p1->mtype.phys_info.velocity - p2->mtype.phys_info.velocity; float speed = vm_NormalizeVector(&rvel); float scalar; if(speed <= MIN_WALL_HIT_SOUND_VEL) { scalar = 0.0f; } else if(speed >= MAX_WALL_HIT_SOUND_VEL) { scalar = 1.0f; } else { scalar = (speed - MIN_WALL_HIT_SOUND_VEL)/(MAX_WALL_HIT_SOUND_VEL - MIN_WALL_HIT_SOUND_VEL); } if(scalar > .01) { pos_state cur_pos; cur_pos.position = collision_point; cur_pos.orient = &p1->orient; cur_pos.roomnum = p1->roomnum; Sound_system.Play3dSound(SOUND_PLAYER_HIT_WALL, SND_PRIORITY_HIGHEST, &cur_pos, MAX_GAME_VOLUME * scalar); } bump_two_objects(p1, p2, collision_point, collision_normal, 1); } #include "polymodel.h" void collide_generic_and_player( object * robotobj, object * playerobj, vector *collision_point, vector *collision_normal, bool f_reverse_normal, fvi_info *hit_info ) { if(f_reverse_normal) *collision_normal *= -1.0f; vector rvel; if(robotobj->movement_type == MT_PHYSICS || robotobj->movement_type == MT_WALKING) { rvel = robotobj->mtype.phys_info.velocity; } else { rvel = Zero_vector; } rvel -= playerobj->mtype.phys_info.velocity; float speed = vm_NormalizeVector(&rvel); float scalar; if(speed <= MIN_WALL_HIT_SOUND_VEL) { scalar = 0.0f; } else if(speed >= MAX_WALL_HIT_SOUND_VEL) { scalar = 1.0f; } else { scalar = (speed - MIN_WALL_HIT_SOUND_VEL)/(MAX_WALL_HIT_SOUND_VEL - MIN_WALL_HIT_SOUND_VEL); } //Check for lava surface on an object if ((robotobj->type == OBJ_BUILDING) && hit_info) { poly_model *pm = GetPolymodelPointer(robotobj->rtype.pobj_info.model_num); int tmap = pm->textures[pm->submodel[hit_info->hit_subobject[0]].faces[hit_info->hit_face[0]].texnum]; if (GameTextures[tmap].flags & TF_LAVA) { if(!((Game_mode & GM_MULTI) && (Netgame.local_role==LR_CLIENT))) { int id = FindWeaponName("NapalmBlob"); if(id >= 0) SetNapalmDamageEffect(playerobj,NULL,id); else Int3(); } scalar = 0; //don't make collide sound } } if(scalar > .01 || (robotobj->mtype.phys_info.flags & PF_LOCK_MASK)) { pos_state cur_pos; cur_pos.position = collision_point; cur_pos.orient = &playerobj->orient; cur_pos.roomnum = playerobj->roomnum; Sound_system.Play3dSound(SOUND_PLAYER_HIT_WALL, SND_PRIORITY_HIGHEST, &cur_pos, MAX_GAME_VOLUME * scalar); ain_hear hear; hear.f_directly_player = true; hear.hostile_level = 0.10f; hear.curiosity_level = 0.5f; hear.max_dist = Sounds[SOUND_PLAYER_HIT_WALL].max_distance * scalar; AINotify(playerobj, AIN_HEAR_NOISE, (void *)&hear); if((scalar > .25f && (robotobj->movement_type == MT_WALKING || robotobj->movement_type == MT_PHYSICS)) || ((robotobj->mtype.phys_info.flags & PF_LOCK_MASK) && (robotobj->mtype.phys_info.flags & PF_POINT_COLLIDE_WALLS))) { if(!(IS_GUIDEBOT(robotobj))) { if(robotobj->shields <= 1.0f) { ApplyDamageToGeneric(robotobj, playerobj, GD_PHYSICS, 2.0f); } else { ApplyDamageToGeneric(robotobj, playerobj, GD_PHYSICS, 5.0f * Frametime * scalar); } if(scalar < 1.0f && (robotobj->mtype.phys_info.flags & PF_LOCK_MASK) && (robotobj->mtype.phys_info.flags & PF_POINT_COLLIDE_WALLS)) scalar = 1.0f; ApplyDamageToPlayer(playerobj, playerobj, PD_WALL_HIT, 2.0f * Frametime * scalar); } } } //mprintf((0, "We hit a robot\n")); if(robotobj->control_type == CT_AI) { AINotify(robotobj, AIN_BUMPED_OBJ, (void *)playerobj); } /* if((GameTextures[Rooms[hitseg].faces[hitwall].tmap].flags & TF_VOLATILE) && !((Game_mode & GM_MULTI) && (Netgame.local_role==LR_CLIENT))) { int id = FindWeaponName("NapalmBlob"); if(id >= 0) { int objnum = ObjCreate(OBJ_WEAPON, id, playerobj->roomnum, &playerobj->pos, NULL, playerobj->handle); if(objnum >= 0) { object *weapon = &Objects[objnum]; float damage_to_apply = Weapons[weapon->id].damage; // Factor in multiplier damage_to_apply *= weapon->ctype.laser_info.multiplier; ApplyDamageToPlayer(playerobj, weapon, 0); SetObjectDeadFlag(objnum); } } } */ bump_two_objects(robotobj, playerobj, collision_point, collision_normal, 1); } void MakeWeaponStick(object *weapon, object *parent, fvi_info *hit_info) { weapon->mtype.obj_link_info.parent_handle = parent->handle; weapon->mtype.obj_link_info.fvec = hit_info->hit_subobj_fvec; weapon->mtype.obj_link_info.uvec = hit_info->hit_subobj_uvec; weapon->mtype.obj_link_info.pos = hit_info->hit_subobj_pos; weapon->mtype.obj_link_info.sobj_index = hit_info->hit_subobject[0]; weapon->movement_type = MT_OBJ_LINKED; } void collide_generic_and_weapon( object * robotobj, object * weapon, vector *collision_point, vector *collision_normal, bool f_reverse_normal, fvi_info *hit_info ) { object *parent_obj; float damage_to_apply; ubyte electrical= (Weapons[weapon->id].flags & WF_ELECTRICAL)?1:0; bool f_stick = ((weapon->mtype.phys_info.flags & PF_STICK) != 0); bool f_energy = ((Weapons[weapon->id].flags & WF_MATTER_WEAPON) == 0); int damage_type; //Check for lava & volatile surfaces on an object if ((robotobj->type == OBJ_BUILDING) && hit_info) { poly_model *pm = GetPolymodelPointer(robotobj->rtype.pobj_info.model_num); int tmap = pm->textures[pm->submodel[hit_info->hit_subobject[0]].faces[hit_info->hit_face[0]].texnum]; vector *normal = &hit_info->hit_wallnorm[0]; DoWallEffects (weapon,tmap); check_for_special_surface(weapon,tmap,normal,1.0); //If object died, stop processing if (weapon->flags & OF_DEAD) return; } if(Weapons[weapon->id].flags & WF_NAPALM) damage_type = GD_FIRE; else if(Weapons[weapon->id].flags & WF_MATTER_WEAPON) damage_type = GD_MATTER; else if(Weapons[weapon->id].flags & WF_ELECTRICAL) damage_type = GD_ELECTRIC; else damage_type = GD_ENERGY; if(f_reverse_normal) *collision_normal *= -1.0f; if(robotobj->flags & OF_DYING) robotobj->ctype.dying_info.delay_time *= 0.975f; if (Weapons[weapon->id].sounds[WSI_IMPACT_WALL]!=SOUND_NONE_INDEX) { Sound_system.Play3dSound(Weapons[weapon->id].sounds[WSI_IMPACT_WALL], SND_PRIORITY_HIGH, weapon); ain_hear hear; hear.f_directly_player = false; if(robotobj->control_type == CT_AI) { hear.hostile_level = 1.0f; hear.curiosity_level = 0.1f; } else if(robotobj->type == OBJ_DOOR) { hear.hostile_level = 0.5f; hear.curiosity_level = 1.0f; } else { hear.hostile_level = .9f; hear.curiosity_level = 0.5f; } hear.max_dist = Sounds[Weapons[weapon->id].sounds[WSI_IMPACT_WALL]].max_distance; AINotify(weapon, AIN_HEAR_NOISE, (void *)&hear); } // Do weapon explosion stuff DoWeaponExploded (weapon,collision_normal,collision_point); // Check to see if we should spawn if (robotobj->type==OBJ_DOOR && !(Game_mode & GM_MULTI)) { if ((Weapons[weapon->id].flags & WF_SPAWNS_IMPACT) && Weapons[weapon->id].spawn_count>0 && Weapons[weapon->id].spawn_handle>=0) CreateImpactSpawnFromWeapon (weapon,collision_normal); } if ((Weapons[weapon->id].flags & WF_SPAWNS_ROBOT) && (Weapons[weapon->id].flags & WF_COUNTERMEASURE) && Weapons[weapon->id].robot_spawn_handle>=0) CreateRobotSpawnFromWeapon (weapon); parent_obj = ObjGet(weapon->parent_handle); if((parent_obj) && (parent_obj->control_type == CT_AI)) { AINotify(parent_obj, AIN_WHIT_OBJECT, (void *)robotobj); } if(robotobj->control_type == CT_AI) { AINotify(robotobj, AIN_HIT_BY_WEAPON, (void *)weapon); } if (electrical) { damage_to_apply=Weapons[weapon->id].generic_damage*Frametime; } else damage_to_apply=Weapons[weapon->id].generic_damage; // Factor in multiplier damage_to_apply*=weapon->ctype.laser_info.multiplier; if (ApplyDamageToGeneric(robotobj, weapon, damage_type, damage_to_apply)) { if (Weapons[weapon->id].sounds[WSI_IMPACT_ROBOT]!=SOUND_NONE_INDEX) { Sound_system.Play3dSound(Weapons[weapon->id].sounds[WSI_IMPACT_ROBOT], SND_PRIORITY_HIGHEST, weapon); } if (!electrical) { light_info *li=&Weapons[weapon->id].lighting_info; ushort color=GR_RGB16(li->red_light2*255,li->green_light2*255,li->blue_light2*255); CreateRandomLineSparks (3+ps_rand()%6,&weapon->pos,weapon->roomnum,color); } } #if 0 if(Demo_flags == DF_RECORDING) { DemoWriteCollideGenericWeapon( robotobj, weapon, collision_point, collision_normal, f_reverse_normal, hit_info ); } else if(Demo_flags == DF_PLAYBACK) { //During playback we don't need the code below (actually it won't work) return; } #endif if (!electrical) { bump_two_objects(robotobj, weapon, collision_point, collision_normal, 0); if(!f_stick || (hit_info == NULL)) { if((robotobj->lighting_render_type == LRT_LIGHTMAPS) || !(weapon->mtype.phys_info.flags & PF_PERSISTENT)) SetObjectDeadFlag (weapon); } else { MakeWeaponStick(weapon, robotobj, hit_info); } } } void collide_player_and_weapon( object * playerobj, object * weapon, vector *collision_point, vector *collision_normal, bool f_reverse_normal, fvi_info *hit_info ) { object *parent_obj; float damage_to_apply; ubyte electrical=Weapons[weapon->id].flags & WF_ELECTRICAL?1:0; bool f_stick = ((weapon->mtype.phys_info.flags & PF_STICK) != 0); if(f_reverse_normal) *collision_normal *= -1.0f; parent_obj = ObjGet(weapon->parent_handle); if((parent_obj) && (parent_obj->control_type == CT_AI)) { AINotify(parent_obj, AIN_WHIT_OBJECT, (void *)playerobj); } // Do weapon explosion stuff DoWeaponExploded (weapon,collision_normal,collision_point,playerobj); // Check to see if we should spawn /*if ((Weapons[weapon->id].flags & WF_SPAWNS_IMPACT) && Weapons[weapon->id].spawn_count>0 && Weapons[weapon->id].spawn_handle>=0) CreateImpactSpawnFromWeapon (weapon,collision_normal);*/ if ((Weapons[weapon->id].flags & WF_SPAWNS_ROBOT) && (Weapons[weapon->id].flags & WF_COUNTERMEASURE) && Weapons[weapon->id].robot_spawn_handle>=0) CreateRobotSpawnFromWeapon (weapon); if (electrical) damage_to_apply=Weapons[weapon->id].player_damage*Frametime; else damage_to_apply=Weapons[weapon->id].player_damage; // Factor in multiplier damage_to_apply*=weapon->ctype.laser_info.multiplier; int damage_type = electrical ? PD_ENERGY_WEAPON : PD_MATTER_WEAPON; if (ApplyDamageToPlayer(playerobj, weapon, damage_type, damage_to_apply)) { // we were damaged! if (Weapons[weapon->id].sounds[WSI_IMPACT_ROBOT]!=SOUND_NONE_INDEX) Sound_system.Play3dSound(Weapons[weapon->id].sounds[WSI_IMPACT_ROBOT], SND_PRIORITY_NORMAL, weapon); } #if 0 if(Demo_flags == DF_RECORDING) { DemoWriteCollidePlayerWeapon( playerobj, weapon, collision_point, collision_normal, f_reverse_normal, hit_info ); } else if(Demo_flags == DF_PLAYBACK) { //During playback we don't need the code below (actually it won't work) return; } #endif if (!electrical) { bump_two_objects(playerobj, weapon, collision_point, collision_normal, 0); if(!f_stick || (hit_info == NULL)) { if(!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) SetObjectDeadFlag (weapon); } else { MakeWeaponStick(weapon, playerobj, hit_info); } } } #define COLLISION_OF(a,b) (((a)<<8) + (b)) #define DO_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type2) ): (collision_function)( (A), (B), collision_point, collision_normal, false, hit_info); break; case COLLISION_OF( (type2), (type1) ): (collision_function)( (B), (A), collision_point, collision_normal, true, hit_info); break; #define DO_SAME_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type1) ): (collision_function)( (A), (B), collision_point, collision_normal, false, hit_info); break; #define NO_COLLISION(type1,type2) case COLLISION_OF( (type1), (type2) ): case COLLISION_OF( (type2), (type1) ): break; void check_lg_inform(object *A, object *B) { if(A->flags & (OF_INFORM_PLAYER_COLLIDE_TO_LG | OF_INFORM_PLAYER_WEAPON_COLLIDE_TO_LG)) { if(B->type == OBJ_PLAYER) { bool f_pwc = (A->flags & OF_INFORM_PLAYER_WEAPON_COLLIDE_TO_LG) != 0; int type; if(f_pwc) { type = OF_INFORM_PLAYER_WEAPON_COLLIDE_TO_LG; } else { type = OF_INFORM_PLAYER_COLLIDE_TO_LG; } Level_goals.Inform(LIT_OBJECT, type, A->handle); } } if(A->flags & OF_INFORM_PLAYER_WEAPON_COLLIDE_TO_LG) { if(B->type == OBJ_WEAPON) { object *parent = ObjGetUltimateParent(B); if(parent && parent->type == OBJ_PLAYER) { Level_goals.Inform(LIT_OBJECT, OF_INFORM_PLAYER_WEAPON_COLLIDE_TO_LG, A->handle); } } } } void collide_two_objects( object * A, object * B, vector *collision_point, vector *collision_normal, fvi_info *hit_info) { int collision_type; int a_num=A-Objects; int b_num=B-Objects; ubyte a_good=0,b_good=0; ubyte a_hittime_good=1,b_hittime_good=1; //Only do omega particle collisions if specifically allowed extern bool Enable_omega_collions; if (((A->type == OBJ_WEAPON) && (A->id == OMEGA_INDEX)) || ((B->type == OBJ_WEAPON) && (B->id == OMEGA_INDEX))) if (! Enable_omega_collions) return; ASSERT(CollisionResult[A->type][B->type] != RESULT_NOTHING); collision_type = COLLISION_OF(A->type,B->type); check_lg_inform(A, B); check_lg_inform(B, A); //mprintf( (0, "Object %d of type %d collided with object %d of type %d\n", A-Objects,A->type, B-Objects, B->type )); // COLLISION SCRIPT HOOK if (Game_mode & GM_MULTI) { ASSERT (!(A->flags & OF_DEAD)); ASSERT (!(B->flags & OF_DEAD)); // Make sure we have good scripts to call if (A->type==OBJ_PLAYER || A->type==OBJ_ROBOT || A->type==OBJ_POWERUP || A->type==OBJ_WEAPON || A->type==OBJ_BUILDING || A->type==OBJ_DOOR || A->type==OBJ_CLUTTER) a_good=1; if (B->type==OBJ_PLAYER || B->type==OBJ_ROBOT || B->type==OBJ_POWERUP || B->type==OBJ_WEAPON || B->type==OBJ_BUILDING || B->type==OBJ_DOOR || B->type==OBJ_CLUTTER) b_good=1; if (A->type==OBJ_PLAYER && (Players[A->id].flags & (PLAYER_FLAGS_DYING|PLAYER_FLAGS_DEAD))) a_good=0; if (B->type==OBJ_PLAYER && (Players[B->id].flags & (PLAYER_FLAGS_DYING|PLAYER_FLAGS_DEAD))) b_good=0; if (A->type==OBJ_POWERUP && A->effect_info->last_object_hit==b_num && (Gametime-A->effect_info->last_object_hit_time)<1) { a_good = 0; a_hittime_good=0; } if (B->type==OBJ_POWERUP && B->effect_info->last_object_hit==a_num && (Gametime-B->effect_info->last_object_hit_time)<1) { b_good = 0; b_hittime_good=0; } if (a_good && b_good) { DLLInfo.me_handle=A->handle; DLLInfo.it_handle=B->handle; DLLInfo.collide_info.point.x = collision_point->x; DLLInfo.collide_info.point.y = collision_point->y; DLLInfo.collide_info.point.z = collision_point->z; DLLInfo.collide_info.normal.x = collision_normal->x; DLLInfo.collide_info.normal.y = collision_normal->y; DLLInfo.collide_info.normal.z = collision_normal->z; CallGameDLL (EVT_GAMECOLLIDE,&DLLInfo); DLLInfo.me_handle=B->handle; DLLInfo.it_handle=A->handle; CallGameDLL (EVT_GAMECOLLIDE,&DLLInfo); // Update static variables if (A->type==OBJ_POWERUP) { A->effect_info->last_object_hit=b_num; A->effect_info->last_object_hit_time=Gametime; } if (B->type==OBJ_POWERUP) { B->effect_info->last_object_hit=a_num; B->effect_info->last_object_hit_time=Gametime; } } } // Call script only if its ok to int ok_to_call_script=1; if (A->type==OBJ_PLAYER && (Players[A->id].flags & (PLAYER_FLAGS_DYING|PLAYER_FLAGS_DEAD))) ok_to_call_script=0; if (B->type==OBJ_PLAYER && (Players[B->id].flags & (PLAYER_FLAGS_DYING|PLAYER_FLAGS_DEAD))) ok_to_call_script=0; // Check to see if we should call the script if ((Game_mode & GM_MULTI)) { if ((A->type==OBJ_POWERUP || B->type==OBJ_POWERUP) && (a_hittime_good==0 || b_hittime_good==0)) ok_to_call_script=0; } if (ok_to_call_script) { if (!(Game_mode & GM_MULTI)) { ASSERT (!(A->flags & OF_DEAD)); ASSERT (!(B->flags & OF_DEAD)); } tOSIRISEventInfo ei; ei.evt_collide.it_handle = B->handle; Osiris_CallEvent(A,EVT_COLLIDE,&ei); ei.evt_collide.it_handle = A->handle; Osiris_CallEvent(B,EVT_COLLIDE,&ei); } switch( collision_type ) { DO_COLLISION( OBJ_PLAYER, OBJ_WEAPON, collide_player_and_weapon ) DO_COLLISION( OBJ_PLAYER, OBJ_MARKER, collide_player_and_marker ) DO_COLLISION( OBJ_ROBOT, OBJ_PLAYER, collide_generic_and_player ) DO_COLLISION( OBJ_BUILDING, OBJ_PLAYER, collide_generic_and_player ) DO_COLLISION( OBJ_DOOR, OBJ_PLAYER, collide_generic_and_player ) DO_COLLISION( OBJ_ROOM, OBJ_VIEWER, collide_generic_and_player ) DO_COLLISION( OBJ_ROOM, OBJ_PLAYER, collide_generic_and_player ) DO_COLLISION( OBJ_CLUTTER, OBJ_PLAYER, collide_generic_and_player ) DO_COLLISION( OBJ_ROBOT, OBJ_WEAPON, collide_generic_and_weapon ) DO_COLLISION( OBJ_CLUTTER, OBJ_WEAPON, collide_generic_and_weapon ) DO_COLLISION( OBJ_BUILDING, OBJ_WEAPON, collide_generic_and_weapon ) DO_COLLISION( OBJ_ROOM, OBJ_WEAPON, collide_generic_and_weapon ) DO_COLLISION( OBJ_DOOR, OBJ_WEAPON, collide_generic_and_weapon ) DO_SAME_COLLISION(OBJ_PLAYER, OBJ_PLAYER, collide_player_and_player ) //Handled by the script, so no code NO_COLLISION( OBJ_PLAYER, OBJ_POWERUP ) NO_COLLISION (OBJ_POWERUP, OBJ_WEAPON) default: bump_two_objects(A, B, collision_point, collision_normal, 1); } if((A->type == OBJ_PLAYER && B->type == OBJ_POWERUP && (B->flags & OF_DEAD)) || (B->type == OBJ_PLAYER && A->type == OBJ_POWERUP && (A->flags & OF_DEAD))) { ain_hear hear; hear.f_directly_player = true; hear.hostile_level = 0.05f; hear.curiosity_level = 1.0f; hear.max_dist = Sounds[SOUND_POWERUP_PICKUP].max_distance; if(A->type == OBJ_PLAYER) AINotify(A, AIN_HEAR_NOISE, (void *)&hear); else AINotify(B, AIN_HEAR_NOISE, (void *)&hear); } } #define ENABLE_COLLISION_SPHERE_SPHERE(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_SPHERE_SPHERE; CollisionResult[type2][type1] = RESULT_CHECK_SPHERE_SPHERE; #define ENABLE_COLLISION_SPHERE_POLY(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_SPHERE_POLY; CollisionResult[type2][type1] = RESULT_CHECK_POLY_SPHERE; #define ENABLE_COLLISION_POLY_SPHERE(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_POLY_SPHERE; CollisionResult[type2][type1] = RESULT_CHECK_SPHERE_POLY; #define ENABLE_COLLISION_BBOX_POLY(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_BBOX_POLY; CollisionResult[type2][type1] = RESULT_CHECK_POLY_BBOX; #define ENABLE_COLLISION_POLY_BBOX(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_POLY_BBOX; CollisionResult[type2][type1] = RESULT_CHECK_BBOX_POLY; #define ENABLE_COLLISION_BBOX_BBOX(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_BBOX_BBOX; CollisionResult[type2][type1] = RESULT_CHECK_BBOX_BBOX; #define ENABLE_COLLISION_BBOX_SPHERE(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_BBOX_SPHERE; CollisionResult[type2][type1] = RESULT_CHECK_SPHERE_BBOX; #define ENABLE_COLLISION_SPHERE_BBOX(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_SPHERE_BBOX; CollisionResult[type2][type1] = RESULT_CHECK_BBOX_SPHERE; #define ENABLE_COLLISION_SPHERE_ROOM(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_SPHERE_ROOM; CollisionResult[type2][type1] = RESULT_CHECK_SPHERE_ROOM; #define ENABLE_COLLISION_BBOX_ROOM(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK_BBOX_ROOM; CollisionResult[type2][type1] = RESULT_CHECK_BBOX_ROOM; #define DISABLE_COLLISION(type1,type2) CollisionResult[type1][type2] = RESULT_NOTHING; CollisionResult[type2][type1] = RESULT_NOTHING; void CollideInit() { int i, j; for (i=0; i < MAX_OBJECT_TYPES; i++ ) for (j=0; j < MAX_OBJECT_TYPES; j++ ) { CollisionResult[i][j] = RESULT_NOTHING; } for (i=0; i < MAX_OBJECT_TYPES; i++ ) { CollisionRayResult[i] = RESULT_NOTHING; } CollisionRayResult[OBJ_ROBOT] = RESULT_CHECK_SPHERE_POLY; CollisionRayResult[OBJ_PLAYER] = RESULT_CHECK_SPHERE_POLY; CollisionRayResult[OBJ_WEAPON] = RESULT_CHECK_SPHERE_POLY; CollisionRayResult[OBJ_POWERUP] = RESULT_CHECK_SPHERE_POLY; CollisionRayResult[OBJ_CLUTTER] = RESULT_CHECK_SPHERE_POLY; CollisionRayResult[OBJ_BUILDING] = RESULT_CHECK_SPHERE_POLY; CollisionRayResult[OBJ_DOOR] = RESULT_CHECK_SPHERE_POLY; CollisionRayResult[OBJ_ROOM] = RESULT_CHECK_SPHERE_POLY; for(i=0; i < MAX_OBJECT_TYPES; i++) { ENABLE_COLLISION_SPHERE_ROOM( i, OBJ_ROOM ) } ENABLE_COLLISION_POLY_SPHERE( OBJ_WALL, OBJ_ROBOT ) ENABLE_COLLISION_POLY_SPHERE( OBJ_WALL, OBJ_WEAPON ) ENABLE_COLLISION_POLY_SPHERE( OBJ_WALL, OBJ_PLAYER ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_ROBOT, OBJ_ROBOT ) // ENABLE_COLLISION_SPHERE_SPHERE( OBJ_BUILDING, OBJ_BUILDING ) ENABLE_COLLISION_POLY_SPHERE( OBJ_PLAYER, OBJ_FIREBALL ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_PLAYER, OBJ_PLAYER ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_PLAYER, OBJ_MARKER ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_MARKER, OBJ_PLAYER ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_WEAPON, OBJ_WEAPON ) ENABLE_COLLISION_POLY_SPHERE( OBJ_ROBOT, OBJ_PLAYER ) // ENABLE_COLLISION_SPHERE_SPHERE( OBJ_ROBOT, OBJ_PLAYER ) ENABLE_COLLISION_POLY_SPHERE( OBJ_ROBOT, OBJ_WEAPON ) ENABLE_COLLISION_POLY_SPHERE( OBJ_PLAYER, OBJ_WEAPON ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_PLAYER, OBJ_POWERUP ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_POWERUP, OBJ_WALL ) ENABLE_COLLISION_SPHERE_POLY( OBJ_WEAPON, OBJ_CLUTTER ) ENABLE_COLLISION_SPHERE_POLY( OBJ_PLAYER, OBJ_CLUTTER ) ENABLE_COLLISION_SPHERE_SPHERE( OBJ_CLUTTER, OBJ_CLUTTER ) ENABLE_COLLISION_SPHERE_POLY( OBJ_ROBOT, OBJ_CLUTTER ) ENABLE_COLLISION_SPHERE_POLY( OBJ_PLAYER, OBJ_BUILDING ) ENABLE_COLLISION_SPHERE_POLY( OBJ_ROBOT, OBJ_BUILDING ) ENABLE_COLLISION_SPHERE_POLY( OBJ_WEAPON, OBJ_BUILDING ) ENABLE_COLLISION_SPHERE_POLY( OBJ_CLUTTER, OBJ_BUILDING ) ENABLE_COLLISION_SPHERE_POLY( OBJ_CLUTTER, OBJ_DOOR ) ENABLE_COLLISION_SPHERE_POLY( OBJ_BUILDING, OBJ_DOOR ) ENABLE_COLLISION_SPHERE_ROOM( OBJ_PLAYER, OBJ_ROOM ) ENABLE_COLLISION_SPHERE_ROOM( OBJ_ROBOT, OBJ_ROOM ) ENABLE_COLLISION_SPHERE_ROOM( OBJ_WEAPON, OBJ_ROOM ) ENABLE_COLLISION_SPHERE_ROOM( OBJ_VIEWER, OBJ_ROOM ) ENABLE_COLLISION_SPHERE_POLY( OBJ_PLAYER, OBJ_DOOR ) ENABLE_COLLISION_SPHERE_POLY( OBJ_ROBOT, OBJ_DOOR ) ENABLE_COLLISION_SPHERE_POLY( OBJ_WEAPON, OBJ_DOOR ) DISABLE_COLLISION( OBJ_POWERUP, OBJ_POWERUP ) } //Process a collision between an object and a wall //Returns true if the object hits the wall, and false if should keep going though the wall (for breakable glass) bool collide_object_with_wall( object * A, float hitspeed, int hitseg, int hitwall, vector * hitpt, vector *wall_normal, float hit_dot ) { ubyte do_event = 0; bool ret = true; switch( A->type ) { case OBJ_NONE: Error( "A object of type NONE hit a wall!\n"); break; case OBJ_PLAYER: collide_player_and_wall(A,hitspeed,hitseg,hitwall,hitpt, wall_normal, hit_dot); do_event = 1; break; case OBJ_WEAPON: ret = collide_weapon_and_wall(A,hitspeed,hitseg,hitwall,hitpt, wall_normal, hit_dot); do_event = 1; break; case OBJ_DEBRIS: break; // chrishack -- collide_debris_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break; case OBJ_FIREBALL: break; //collide_fireball_and_wall(A,hitspeed,hitseg,hitwall,hitpt); case OBJ_CLUTTER: case OBJ_BUILDING: case OBJ_ROBOT: collide_generic_and_wall(A,hitspeed,hitseg,hitwall,hitpt, wall_normal, hit_dot); do_event = 1; break; case OBJ_VIEWER: break; //collide_camera_and_wall(A,hitspeed,hitseg,hitwall,hitpt); case OBJ_POWERUP: break; //collide_powerup_and_wall(A,hitspeed,hitseg,hitwall,hitpt); case OBJ_GHOST: break; //do nothing case OBJ_OBSERVER: break; // do nothing case OBJ_SPLINTER: break; case OBJ_MARKER: break; case OBJ_SHARD: if(sound_override_glass_breaking == -1) Sound_system.Play3dSound(SOUND_BREAKING_GLASS,SND_PRIORITY_NORMAL,A,MAX_GAME_VOLUME/10); else Sound_system.Play3dSound(sound_override_glass_breaking,SND_PRIORITY_NORMAL,A,MAX_GAME_VOLUME/10); break; default: mprintf((0, "Unhandled collision of object type %d and wall\n", A->type)); // Error( "Unhandled object type hit wall in collide.c\n" ); } if(do_event && (Game_mode&GM_MULTI)) { //call multiplayer event DLLInfo.me_handle=A->handle; DLLInfo.it_handle=OBJECT_HANDLE_NONE; DLLInfo.collide_info.point.x = hitpt->x; DLLInfo.collide_info.point.y = hitpt->y; DLLInfo.collide_info.point.z = hitpt->z; DLLInfo.collide_info.normal.x = wall_normal->x; DLLInfo.collide_info.normal.y = wall_normal->y; DLLInfo.collide_info.normal.z = wall_normal->z; DLLInfo.collide_info.hitspeed = hitspeed; DLLInfo.collide_info.hit_dot = hit_dot; DLLInfo.collide_info.hitseg = hitseg; DLLInfo.collide_info.hitwall = hitwall; CallGameDLL (EVT_GAMEWALLCOLLIDE,&DLLInfo); } return ret; }