Descent3/physics/Collide.cpp

3076 lines
88 KiB
C++
Raw Normal View History

2024-04-16 03:43:29 +00:00
/*
* $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 <stdlib.h>
#include <stdio.h>
#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((int)vec0.i) > abs((int)vec0.j))
2024-04-16 03:43:29 +00:00
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;i<num_rubble;i++)
{
int visnum;
visnum=VisEffectCreate (VIS_FIREBALL,RUBBLE1_INDEX+(ps_rand()%2),weapon->roomnum,&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;t<fp->num_verts;t++)
verts[t]=rp->verts[fp->face_verts[t]];
float size=sqrt(vm_GetCentroid (&center,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;
}