2021-09-15 17:20:42 +03:00
# include "framework.h"
2021-12-22 16:23:57 +03:00
# include "Game/control/los.h"
2021-12-24 03:32:19 +03:00
2021-12-22 16:23:57 +03:00
# include "Game/animation.h"
2022-03-14 15:18:11 +11:00
# include "Game/collision/collide_room.h"
2021-12-22 16:23:57 +03:00
# include "Game/effects/tomb4fx.h"
# include "Game/effects/debris.h"
# include "Game/items.h"
2021-12-24 03:32:19 +03:00
# include "Game/Lara/lara_fire.h"
# include "Game/Lara/lara_one_gun.h"
2021-12-19 05:24:12 +03:00
# include "Objects/Generic/Object/objects.h"
2021-12-24 03:32:19 +03:00
# include "Objects/Generic/Switches/switch.h"
# include "Sound/sound.h"
# include "Specific/input.h"
2021-12-22 16:23:57 +03:00
# include "Specific/setup.h"
2021-09-25 11:27:47 +02:00
2021-09-15 17:20:42 +03:00
int NumberLosRooms ;
short LosRooms [ 20 ] ;
int ClosestItem ;
int ClosestDist ;
PHD_VECTOR ClosestCoord ;
2022-02-13 23:23:36 +11:00
bool ClipTarget ( GAME_VECTOR * start , GAME_VECTOR * target )
2021-09-15 17:20:42 +03:00
{
int x , y , z , wx , wy , wz ;
2022-02-13 23:23:36 +11:00
short roomNumber = target - > roomNumber ;
if ( target - > y > GetFloorHeight ( GetFloor ( target - > x , target - > y , target - > z , & roomNumber ) , target - > x , target - > y , target - > z ) )
2021-09-15 17:20:42 +03:00
{
x = ( 7 * ( target - > x - start - > x ) > > 3 ) + start - > x ;
y = ( 7 * ( target - > y - start - > y ) > > 3 ) + start - > y ;
z = ( 7 * ( target - > z - start - > z ) > > 3 ) + start - > z ;
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
for ( int i = 3 ; i > 0 ; - - i )
{
wx = ( ( target - > x - x ) * i > > 2 ) + x ;
wy = ( ( target - > y - y ) * i > > 2 ) + y ;
wz = ( ( target - > z - z ) * i > > 2 ) + z ;
2022-02-13 23:23:36 +11:00
if ( wy < GetFloorHeight ( GetFloor ( wx , wy , wz , & roomNumber ) , wx , wy , wz ) )
2021-09-15 17:20:42 +03:00
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
target - > x = wx ;
target - > y = wy ;
target - > z = wz ;
2022-02-13 23:23:36 +11:00
target - > roomNumber = roomNumber ;
return false ;
2021-09-15 17:20:42 +03:00
}
2022-02-13 23:23:36 +11:00
roomNumber = target - > roomNumber ;
if ( target - > y < GetCeiling ( GetFloor ( target - > x , target - > y , target - > z , & roomNumber ) , target - > x , target - > y , target - > z ) )
2021-09-15 17:20:42 +03:00
{
x = ( 7 * ( target - > x - start - > x ) > > 3 ) + start - > x ;
y = ( 7 * ( target - > y - start - > y ) > > 3 ) + start - > y ;
z = ( 7 * ( target - > z - start - > z ) > > 3 ) + start - > z ;
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
for ( int i = 3 ; i > 0 ; - - i )
{
wx = ( ( target - > x - x ) * i > > 2 ) + x ;
wy = ( ( target - > y - y ) * i > > 2 ) + y ;
wz = ( ( target - > z - z ) * i > > 2 ) + z ;
2022-02-13 23:23:36 +11:00
if ( wy > GetCeiling ( GetFloor ( wx , wy , wz , & roomNumber ) , wx , wy , wz ) )
2021-09-15 17:20:42 +03:00
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
target - > x = wx ;
target - > y = wy ;
target - > z = wz ;
2022-02-13 23:23:36 +11:00
target - > roomNumber = roomNumber ;
return false ;
2021-09-15 17:20:42 +03:00
}
2022-02-13 23:23:36 +11:00
return true ;
2021-09-15 17:20:42 +03:00
}
2022-03-14 01:20:51 +11:00
bool GetTargetOnLOS ( GAME_VECTOR * src , GAME_VECTOR * dest , int drawTarget , bool firing )
2021-09-15 17:20:42 +03:00
{
Vector3 direction = Vector3 ( dest - > x , dest - > y , dest - > z ) - Vector3 ( src - > x , src - > y , src - > z ) ;
direction . Normalize ( ) ;
2022-02-13 23:23:36 +11:00
GAME_VECTOR target = { dest - > x , dest - > y , dest - > z } ;
int result = LOS ( src , & target ) ;
2021-09-15 17:20:42 +03:00
GetFloor ( target . x , target . y , target . z , & target . roomNumber ) ;
if ( firing & & LaserSight )
{
2022-03-09 17:04:19 +11:00
Lara . Control . Weapon . HasFired = true ;
Lara . Control . Weapon . Fired = true ;
2021-09-15 17:20:42 +03:00
2022-03-09 20:37:26 +11:00
if ( Lara . Control . Weapon . GunType = = LaraWeaponType : : Revolver )
2021-09-15 17:20:42 +03:00
SoundEffect ( SFX_TR4_DESSERT_EAGLE_FIRE , NULL , 0 ) ;
}
2022-02-13 23:23:36 +11:00
bool hit = false ;
MESH_INFO * mesh ;
PHD_VECTOR vector ;
int itemNumber = ObjectOnLOS2 ( src , dest , & vector , & mesh ) ;
2021-09-15 17:20:42 +03:00
if ( itemNumber ! = NO_LOS_ITEM )
{
target . x = vector . x - ( vector . x - src - > x > > 5 ) ;
target . y = vector . y - ( vector . y - src - > y > > 5 ) ;
target . z = vector . z - ( vector . z - src - > z > > 5 ) ;
GetFloor ( target . x , target . y , target . z , & target . roomNumber ) ;
// TODO: for covering scientist
// if ((itemNumber >= 0) && (BaddieSlots[itemNumber].itemNum != NO_ITEM)) // BUGFIX: ensure target has AI. No more pistol desync and camera wobble when shooting non-AI movable objects.
// Lara.target = &g_Level.Items[itemNumber];
// this is crashing and it's not really doing anything..
if ( firing )
{
2022-03-09 20:37:26 +11:00
if ( Lara . Control . Weapon . GunType ! = LaraWeaponType : : Crossbow )
2021-09-15 17:20:42 +03:00
{
if ( itemNumber < 0 )
{
if ( StaticObjects [ mesh - > staticNumber ] . shatterType ! = SHT_NONE )
{
ShatterImpactData . impactDirection = direction ;
ShatterImpactData . impactLocation = Vector3 ( mesh - > pos . xPos , mesh - > pos . yPos , mesh - > pos . zPos ) ;
ShatterObject ( NULL , mesh , 128 , target . roomNumber , 0 ) ;
SmashedMeshRoom [ SmashedMeshCount ] = target . roomNumber ;
SmashedMesh [ SmashedMeshCount ] = mesh ;
+ + SmashedMeshCount ;
mesh - > flags & = ~ StaticMeshFlags : : SM_VISIBLE ;
SoundEffect ( GetShatterSound ( mesh - > staticNumber ) , ( PHD_3DPOS * ) mesh , 0 ) ;
}
2022-02-13 23:23:36 +11:00
2022-02-09 16:55:46 +11:00
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 3 , 0 ) ;
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 3 , 0 ) ;
2021-09-15 17:20:42 +03:00
}
else
{
2022-02-14 17:05:52 +11:00
auto * item = & g_Level . Items [ itemNumber ] ;
2022-02-09 16:55:46 +11:00
if ( item - > ObjectNumber < ID_SHOOT_SWITCH1 | | item - > ObjectNumber > ID_SHOOT_SWITCH4 )
2021-09-15 17:20:42 +03:00
{
2022-02-13 23:23:36 +11:00
if ( ( Objects [ item - > ObjectNumber ] . explodableMeshbits & ShatterItem . bit ) & &
LaserSight )
2021-09-15 17:20:42 +03:00
{
//if (!Objects[item->objectNumber].intelligent)
//{
2022-02-09 16:55:46 +11:00
item - > MeshBits & = ~ ShatterItem . bit ;
2021-09-15 17:20:42 +03:00
ShatterImpactData . impactDirection = direction ;
ShatterImpactData . impactLocation = Vector3 ( ShatterItem . sphere . x , ShatterItem . sphere . y , ShatterItem . sphere . z ) ;
ShatterObject ( & ShatterItem , 0 , 128 , target . roomNumber , 0 ) ;
2022-02-09 16:55:46 +11:00
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 3 , 0 ) ;
2021-09-15 17:20:42 +03:00
/*}
else
{
if ( item - > objectNumber ! = ID_GUARD_LASER )
{
2022-02-09 16:55:46 +11:00
item - > HitPoints - = 30 ;
if ( item - > HitPoints < 0 )
item - > HitPoints = 0 ;
2021-09-15 17:20:42 +03:00
HitTarget ( item , & target , Weapons [ Lara . gunType ] . damage , 0 ) ;
}
else
{
angle = phd_atan ( LaraItem - > pos . zPos - item - > pos . zPos , LaraItem - > pos . xPos - item - > pos . xPos ) - item - > pos . yRot ;
if ( angle > - ANGLE ( 90 ) & & angle < ANGLE ( 90 ) )
{
2022-02-09 16:55:46 +11:00
item - > HitPoints = 0 ;
2021-09-15 17:20:42 +03:00
HitTarget ( item , & target , Weapons [ Lara . gunType ] . damage , 0 ) ;
}
}
} */
}
else
{
2022-03-09 20:37:26 +11:00
if ( drawTarget & & ( Lara . Control . Weapon . GunType = = LaraWeaponType : : Revolver | |
Lara . Control . Weapon . GunType = = LaraWeaponType : : HK ) )
2021-09-15 17:20:42 +03:00
{
2022-02-09 16:55:46 +11:00
if ( Objects [ item - > ObjectNumber ] . intelligent )
2022-03-09 20:37:26 +11:00
HitTarget ( LaraItem , item , & target , Weapons [ ( int ) Lara . Control . Weapon . GunType ] . Damage , 0 ) ;
2021-09-15 17:20:42 +03:00
else
{
// TR5
2022-02-09 16:55:46 +11:00
if ( Objects [ item - > ObjectNumber ] . hitEffect = = HIT_RICOCHET )
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 3 , 0 ) ;
2021-09-15 17:20:42 +03:00
}
}
else
{
2022-02-09 16:55:46 +11:00
if ( item - > ObjectNumber > = ID_SMASH_OBJECT1 & & item - > ObjectNumber < = ID_SMASH_OBJECT8 )
2021-09-15 17:20:42 +03:00
SmashObject ( itemNumber ) ;
else
{
2022-02-09 16:55:46 +11:00
if ( Objects [ item - > ObjectNumber ] . hitEffect = = HIT_BLOOD )
DoBloodSplat ( target . x , target . y , target . z , ( GetRandomControl ( ) & 3 ) + 3 , item - > Position . yRot , item - > RoomNumber ) ;
else if ( Objects [ item - > ObjectNumber ] . hitEffect = = HIT_SMOKE )
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 3 , - 5 ) ;
else if ( Objects [ item - > ObjectNumber ] . hitEffect = = HIT_RICOCHET )
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 3 , 0 ) ;
2022-02-13 23:23:36 +11:00
2022-02-09 16:55:46 +11:00
item - > HitStatus = true ;
if ( ! Objects [ item - > ObjectNumber ] . undead )
2022-03-09 20:37:26 +11:00
item - > HitPoints - = Weapons [ ( int ) Lara . Control . Weapon . GunType ] . Damage ;
2021-09-15 17:20:42 +03:00
}
}
}
}
else
{
2022-02-09 16:55:46 +11:00
if ( ShatterItem . bit = = 1 < < Objects [ item - > ObjectNumber ] . nmeshes - 1 )
2021-09-15 17:20:42 +03:00
{
2022-02-09 16:55:46 +11:00
if ( ! ( item - > Flags & 0x40 ) )
2021-09-15 17:20:42 +03:00
{
2022-02-09 16:55:46 +11:00
if ( item - > ObjectNumber = = ID_SHOOT_SWITCH1 )
ExplodeItemNode ( item , Objects [ item - > ObjectNumber ] . nmeshes - 1 , 0 , 64 ) ;
2022-02-13 23:23:36 +11:00
2022-02-09 16:55:46 +11:00
if ( item - > TriggerFlags = = 444 & & item - > ObjectNumber = = ID_SHOOT_SWITCH2 )
2021-09-15 17:20:42 +03:00
{
// TR5 ID_SWITCH_TYPE_8/ID_SHOOT_SWITCH2
ProcessExplodingSwitchType8 ( item ) ;
}
else
{
/*if (item->objectNumber == ID_SHOOT_SWITCH3)
{
// TR4 ID_SWITCH_TYPE7
ExplodeItemNode ( item , Objects [ item - > objectNumber ] . nmeshes - 1 , 0 , 64 ) ;
} */
2022-02-13 23:23:36 +11:00
if ( item - > Flags & IFLAG_ACTIVATION_MASK & &
( item - > Flags & IFLAG_ACTIVATION_MASK ) ! = IFLAG_ACTIVATION_MASK )
2021-09-15 17:20:42 +03:00
{
2022-02-09 16:55:46 +11:00
TestTriggers ( item - > Position . xPos , item - > Position . yPos - 256 , item - > Position . zPos , item - > RoomNumber , true , item - > Flags & IFLAG_ACTIVATION_MASK ) ;
2021-09-15 17:20:42 +03:00
}
else
{
2022-02-13 23:23:36 +11:00
short triggerItems [ 8 ] ;
for ( int count = GetSwitchTrigger ( item , triggerItems , 1 ) ; count > 0 ; - - count )
2021-09-15 17:20:42 +03:00
{
AddActiveItem ( triggerItems [ count - 1 ] ) ;
2022-02-09 16:55:46 +11:00
g_Level . Items [ triggerItems [ count - 1 ] ] . Status = ITEM_ACTIVE ;
g_Level . Items [ triggerItems [ count - 1 ] ] . Flags | = IFLAG_ACTIVATION_MASK ;
2021-09-15 17:20:42 +03:00
}
}
}
}
2022-02-13 23:23:36 +11:00
2022-02-09 16:55:46 +11:00
if ( item - > Status ! = ITEM_DEACTIVATED )
2021-09-15 17:20:42 +03:00
{
AddActiveItem ( itemNumber ) ;
2022-02-09 16:55:46 +11:00
item - > Status = ITEM_ACTIVE ;
item - > Flags | = IFLAG_ACTIVATION_MASK | 0x40 ;
2021-09-15 17:20:42 +03:00
}
}
2022-02-13 23:23:36 +11:00
2022-02-09 16:55:46 +11:00
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 3 , 0 ) ;
2021-09-15 17:20:42 +03:00
}
}
}
else
{
if ( LaserSight & & firing )
2022-02-15 17:34:17 +11:00
FireCrossBowFromLaserSight ( LaraItem , src , & target ) ;
2021-09-15 17:20:42 +03:00
}
}
2022-02-13 23:23:36 +11:00
hit = true ;
2021-09-15 17:20:42 +03:00
}
else
{
2022-03-09 20:37:26 +11:00
if ( Lara . Control . Weapon . GunType = = LaraWeaponType : : Crossbow )
2021-09-15 17:20:42 +03:00
{
if ( firing & & LaserSight )
2022-02-15 17:34:17 +11:00
FireCrossBowFromLaserSight ( LaraItem , src , & target ) ;
2021-09-15 17:20:42 +03:00
}
else
{
target . x - = target . x - src - > x > > 5 ;
target . y - = target . y - src - > y > > 5 ;
target . z - = target . z - src - > z > > 5 ;
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( firing & & ! result )
2022-02-09 16:55:46 +11:00
TriggerRicochetSpark ( & target , LaraItem - > Position . yRot , 8 , 0 ) ;
2021-09-15 17:20:42 +03:00
}
}
2022-02-13 23:23:36 +11:00
if ( drawTarget & & ( hit | | ! result ) )
2021-09-15 17:20:42 +03:00
{
TriggerDynamicLight ( target . x , target . y , target . z , 64 , 255 , 0 , 0 ) ;
LaserSightActive = 1 ;
LaserSightX = target . x ;
LaserSightY = target . y ;
LaserSightZ = target . z ;
}
return hit ;
}
2021-11-04 20:23:26 +03:00
int ObjectOnLOS2 ( GAME_VECTOR * start , GAME_VECTOR * end , PHD_VECTOR * vec , MESH_INFO * * mesh , GAME_OBJECT_ID priorityObject )
2021-09-15 17:20:42 +03:00
{
ClosestItem = NO_LOS_ITEM ;
ClosestDist = SQUARE ( end - > x - start - > x ) + SQUARE ( end - > y - start - > y ) + SQUARE ( end - > z - start - > z ) ;
2021-11-04 20:23:26 +03:00
for ( int r = 0 ; r < NumberLosRooms ; + + r )
2021-09-15 17:20:42 +03:00
{
2021-11-04 20:23:26 +03:00
PHD_3DPOS pos ;
2022-02-14 17:05:52 +11:00
auto * room = & g_Level . Rooms [ LosRooms [ r ] ] ;
2021-09-15 17:20:42 +03:00
2021-11-04 20:23:26 +03:00
for ( int m = 0 ; m < room - > mesh . size ( ) ; m + + )
2021-09-15 17:20:42 +03:00
{
2022-02-14 17:05:52 +11:00
auto * meshp = & room - > mesh [ m ] ;
2021-09-15 17:20:42 +03:00
if ( meshp - > flags & StaticMeshFlags : : SM_VISIBLE )
{
pos . xPos = meshp - > pos . xPos ;
pos . yPos = meshp - > pos . yPos ;
pos . zPos = meshp - > pos . zPos ;
pos . yRot = meshp - > pos . yRot ;
if ( DoRayBox ( start , end , & StaticObjects [ meshp - > staticNumber ] . collisionBox , & pos , vec , - 1 - meshp - > staticNumber ) )
{
* mesh = meshp ;
end - > roomNumber = LosRooms [ r ] ;
}
}
}
2022-02-09 16:55:46 +11:00
for ( short linknum = room - > itemNumber ; linknum ! = NO_ITEM ; linknum = g_Level . Items [ linknum ] . NextItem )
2021-09-15 17:20:42 +03:00
{
2022-02-14 17:05:52 +11:00
auto * item = & g_Level . Items [ linknum ] ;
2021-09-15 17:20:42 +03:00
2022-02-09 16:55:46 +11:00
if ( ( item - > Status = = ITEM_DEACTIVATED ) | | ( item - > Status = = ITEM_INVISIBLE ) )
2021-11-04 20:23:26 +03:00
continue ;
2021-09-15 17:20:42 +03:00
2022-02-09 16:55:46 +11:00
if ( ( priorityObject ! = GAME_OBJECT_ID : : ID_NO_OBJECT ) & & ( item - > ObjectNumber ! = priorityObject ) )
2021-11-04 20:23:26 +03:00
continue ;
2021-09-15 17:20:42 +03:00
2022-02-09 16:55:46 +11:00
if ( ( item - > ObjectNumber ! = ID_LARA ) & & ( Objects [ item - > ObjectNumber ] . collision = = NULL ) )
2021-11-04 20:23:26 +03:00
continue ;
2022-02-09 16:55:46 +11:00
if ( ( item - > ObjectNumber = = ID_LARA ) & & ( priorityObject ! = ID_LARA ) )
2021-11-04 20:23:26 +03:00
continue ;
2022-02-14 17:05:52 +11:00
auto * box = GetBoundsAccurate ( item ) ;
2021-11-04 20:23:26 +03:00
2022-02-09 16:55:46 +11:00
pos . xPos = item - > Position . xPos ;
pos . yPos = item - > Position . yPos ;
pos . zPos = item - > Position . zPos ;
pos . yRot = item - > Position . yRot ;
2021-11-04 20:23:26 +03:00
if ( DoRayBox ( start , end , box , & pos , vec , linknum ) )
end - > roomNumber = LosRooms [ r ] ;
2021-09-15 17:20:42 +03:00
}
}
vec - > x = ClosestCoord . x ;
vec - > y = ClosestCoord . y ;
vec - > z = ClosestCoord . z ;
return ClosestItem ;
}
2022-02-13 23:23:36 +11:00
bool DoRayBox ( GAME_VECTOR * start , GAME_VECTOR * end , BOUNDING_BOX * box , PHD_3DPOS * itemOrStaticPos , PHD_VECTOR * hitPos , short closesItemNumber )
2021-09-15 17:20:42 +03:00
{
// Ray
2021-09-25 16:03:28 -05:00
FXMVECTOR rayStart = { ( float ) start - > x , ( float ) start - > y , ( float ) start - > z } ;
FXMVECTOR rayEnd = { ( float ) end - > x , ( float ) end - > y , ( float ) end - > z } ;
FXMVECTOR rayDir = { ( float ) ( end - > x - start - > x ) , ( float ) ( end - > y - start - > y ) , ( float ) ( end - > z - start - > z ) } ;
2021-09-15 17:20:42 +03:00
XMVECTOR rayDirNormalized = XMVector3Normalize ( rayDir ) ;
// Create the bounding box for raw collision detection
auto obox = TO_DX_BBOX ( * itemOrStaticPos , box ) ;
// Get the collision with the bounding box
float distance ;
bool collided = obox . Intersects ( rayStart , rayDirNormalized , distance ) ;
// If no collision happened, then don't test spheres
if ( ! collided )
2022-02-13 23:23:36 +11:00
return false ;
2021-09-15 17:20:42 +03:00
// Get the raw collision point
Vector3 collidedPoint = rayStart + distance * rayDirNormalized ;
hitPos - > x = collidedPoint . x - itemOrStaticPos - > xPos ;
hitPos - > y = collidedPoint . y - itemOrStaticPos - > yPos ;
hitPos - > z = collidedPoint . z - itemOrStaticPos - > zPos ;
// Now in the case of items we need to test single spheres
2021-12-14 17:20:13 +01:00
int meshIndex = 0 ;
2021-09-15 17:20:42 +03:00
int bit = 0 ;
int sp = - 2 ;
float minDistance = std : : numeric_limits < float > : : max ( ) ;
int action = TrInput & IN_ACTION ;
if ( closesItemNumber < 0 )
{
// Static meshes don't require further tests
sp = - 1 ;
minDistance = distance ;
}
else
{
// For items instead we need to test spheres
ITEM_INFO * item = & g_Level . Items [ closesItemNumber ] ;
2022-02-09 16:55:46 +11:00
OBJECT_INFO * obj = & Objects [ item - > ObjectNumber ] ;
2021-09-15 17:20:42 +03:00
2022-02-13 23:23:36 +11:00
// Get the transformed sphere of meshes
2021-09-15 17:20:42 +03:00
GetSpheres ( item , CreatureSpheres , SPHERES_SPACE_WORLD , Matrix : : Identity ) ;
SPHERE spheres [ 34 ] ;
memcpy ( spheres , CreatureSpheres , sizeof ( SPHERE ) * 34 ) ;
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( obj - > nmeshes < = 0 )
2022-02-13 23:23:36 +11:00
return false ;
2021-09-15 17:20:42 +03:00
2021-12-14 17:20:13 +01:00
meshIndex = obj - > meshIndex ;
2021-09-15 17:20:42 +03:00
for ( int i = 0 ; i < obj - > nmeshes ; i + + )
{
2022-02-13 23:23:36 +11:00
// If mesh is visible...
2022-02-09 16:55:46 +11:00
if ( item - > MeshBits & ( 1 < < i ) )
2021-09-15 17:20:42 +03:00
{
SPHERE * sphere = & CreatureSpheres [ i ] ;
2022-02-13 23:23:36 +11:00
// TODO: this approach is the correct one but, again, Core's math is a mystery and this test was meant
// to fail deliberately in some way. I've so added again Core's legacy test for allowing the current game logic
2021-09-15 17:20:42 +03:00
// but after more testing we should trash it in the future and restore the new way.
#if 0
// Create the bounding sphere and test it against the ray
BoundingSphere sph = BoundingSphere ( Vector3 ( sphere - > x , sphere - > y , sphere - > z ) , sphere - > r ) ;
float newDist ;
if ( sph . Intersects ( rayStart , rayDirNormalized , newDist ) )
{
// HACK: Core seems to take in account for distance not the real hit point but the centre of the sphere.
// This can work well for example for GUARDIAN because the head sphere is so big that would always be hit
// and eyes would not be destroyed.
newDist = sqrt ( SQUARE ( sphere - > x - start - > x ) + SQUARE ( sphere - > y - start - > y ) + SQUARE ( sphere - > z - start - > z ) ) ;
// Test for min distance
if ( newDist < minDistance )
{
minDistance = newDist ;
meshPtr = & g_Level . Meshes [ obj - > meshIndex + i ] ;
bit = 1 < < i ;
sp = i ;
}
}
# endif
PHD_VECTOR p [ 4 ] ;
p [ 1 ] . x = start - > x ;
p [ 1 ] . y = start - > y ;
p [ 1 ] . z = start - > z ;
p [ 2 ] . x = end - > x ;
p [ 2 ] . y = end - > y ;
p [ 2 ] . z = end - > z ;
p [ 3 ] . x = sphere - > x ;
p [ 3 ] . y = sphere - > y ;
p [ 3 ] . z = sphere - > z ;
int r0 = ( p [ 3 ] . x - p [ 1 ] . x ) * ( p [ 2 ] . x - p [ 1 ] . x ) +
( p [ 3 ] . y - p [ 1 ] . y ) * ( p [ 2 ] . y - p [ 1 ] . y ) +
( p [ 3 ] . z - p [ 1 ] . z ) * ( p [ 2 ] . z - p [ 1 ] . z ) ;
int r1 = SQUARE ( p [ 2 ] . x - p [ 1 ] . x ) +
SQUARE ( p [ 2 ] . y - p [ 1 ] . y ) +
SQUARE ( p [ 2 ] . z - p [ 1 ] . z ) ;
2022-02-13 23:23:36 +11:00
if ( ( ( r0 < 0 & & r1 < 0 ) | |
( r1 > 0 & & r0 > 0 ) ) & &
( abs ( r0 ) < = abs ( r1 ) ) )
2021-09-15 17:20:42 +03:00
{
r1 > > = 16 ;
if ( r1 )
r0 / = r1 ;
else
r0 = 0 ;
p [ 0 ] . x = p [ 1 ] . x + ( ( r0 * ( p [ 2 ] . x - p [ 1 ] . x ) ) > > 16 ) ;
p [ 0 ] . y = p [ 1 ] . y + ( ( r0 * ( p [ 2 ] . y - p [ 1 ] . y ) ) > > 16 ) ;
p [ 0 ] . z = p [ 1 ] . z + ( ( r0 * ( p [ 2 ] . z - p [ 1 ] . z ) ) > > 16 ) ;
int dx = p [ 0 ] . x - p [ 3 ] . x ;
int dy = p [ 0 ] . y - p [ 3 ] . y ;
int dz = p [ 0 ] . z - p [ 3 ] . z ;
int distance = dx + dy + dz ;
if ( distance < SQUARE ( sphere - > r ) )
{
dx = SQUARE ( sphere - > x - start - > x ) ;
dy = SQUARE ( sphere - > y - start - > y ) ;
dz = SQUARE ( sphere - > z - start - > z ) ;
distance = dx + dy + dz ;
if ( distance < minDistance )
{
minDistance = distance ;
2021-12-14 17:20:13 +01:00
meshIndex = obj - > meshIndex + i ;
2021-09-15 17:20:42 +03:00
bit = 1 < < i ;
sp = i ;
}
}
}
}
}
if ( sp < - 1 )
2022-02-13 23:23:36 +11:00
return false ;
2021-09-15 17:20:42 +03:00
}
if ( distance > = ClosestDist )
2022-02-13 23:23:36 +11:00
return false ;
2021-09-15 17:20:42 +03:00
// Setup test result
ClosestCoord . x = hitPos - > x + itemOrStaticPos - > xPos ;
ClosestCoord . y = hitPos - > y + itemOrStaticPos - > yPos ;
ClosestCoord . z = hitPos - > z + itemOrStaticPos - > zPos ;
ClosestDist = distance ;
ClosestItem = closesItemNumber ;
// If collided object is an item, then setup the shatter item data struct
if ( sp > = 0 )
{
ITEM_INFO * item = & g_Level . Items [ closesItemNumber ] ;
GetSpheres ( item , CreatureSpheres , SPHERES_SPACE_WORLD | SPHERES_SPACE_BONE_ORIGIN , Matrix : : Identity ) ;
2022-02-09 16:55:46 +11:00
ShatterItem . yRot = item - > Position . yRot ;
2021-12-14 17:20:13 +01:00
ShatterItem . meshIndex = meshIndex ;
2021-09-15 17:20:42 +03:00
ShatterItem . sphere . x = CreatureSpheres [ sp ] . x ;
ShatterItem . sphere . y = CreatureSpheres [ sp ] . y ;
ShatterItem . sphere . z = CreatureSpheres [ sp ] . z ;
ShatterItem . bit = bit ;
ShatterItem . flags = 0 ;
}
2022-02-13 23:23:36 +11:00
return true ;
2021-09-15 17:20:42 +03:00
}
2021-12-01 18:12:04 +03:00
bool LOS ( GAME_VECTOR * start , GAME_VECTOR * end )
2021-09-15 17:20:42 +03:00
{
int result1 , result2 ;
end - > roomNumber = start - > roomNumber ;
if ( abs ( end - > z - start - > z ) > abs ( end - > x - start - > x ) )
{
result1 = xLOS ( start , end ) ;
result2 = zLOS ( start , end ) ;
}
else
{
result1 = zLOS ( start , end ) ;
result2 = xLOS ( start , end ) ;
}
2021-12-01 18:12:04 +03:00
2021-09-15 17:20:42 +03:00
if ( result2 )
{
GetFloor ( end - > x , end - > y , end - > z , & end - > roomNumber ) ;
if ( ClipTarget ( start , end ) & & result1 = = 1 & & result2 = = 1 )
2021-12-01 18:12:04 +03:00
return true ;
2021-09-15 17:20:42 +03:00
}
2021-12-01 18:12:04 +03:00
return false ;
2021-09-15 17:20:42 +03:00
}
int xLOS ( GAME_VECTOR * start , GAME_VECTOR * end )
{
2022-02-13 23:23:36 +11:00
int x , y , z ;
2021-09-15 17:20:42 +03:00
FLOOR_INFO * floor ;
2022-02-13 23:23:36 +11:00
int dx = end - > x - start - > x ;
2021-09-15 17:20:42 +03:00
if ( ! dx )
return 1 ;
2022-02-13 23:23:36 +11:00
int dy = ( end - > y - start - > y < < 10 ) / dx ;
int dz = ( end - > z - start - > z < < 10 ) / dx ;
2021-09-15 17:20:42 +03:00
NumberLosRooms = 1 ;
LosRooms [ 0 ] = start - > roomNumber ;
2022-02-13 23:23:36 +11:00
short room = start - > roomNumber ;
short room2 = start - > roomNumber ;
int flag = 1 ;
2021-09-15 17:20:42 +03:00
if ( dx < 0 )
{
x = start - > x & 0xFFFFFC00 ;
y = ( ( x - start - > x ) * dy > > 10 ) + start - > y ;
z = ( ( x - start - > x ) * dz > > 10 ) + start - > z ;
while ( x > end - > x )
{
floor = GetFloor ( x , y , z , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x , y , z ) | | y < GetCeiling ( floor , x , y , z ) )
{
flag = - 1 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
floor = GetFloor ( x - 1 , y , z , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x - 1 , y , z ) | | y < GetCeiling ( floor , x - 1 , y , z ) )
{
flag = 0 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
x - = 1024 ;
y - = dy ;
z - = dz ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( flag ! = 1 )
{
end - > x = x ;
end - > y = y ;
end - > z = z ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
end - > roomNumber = flag ? room : room2 ;
}
else
{
x = start - > x | 0x3FF ;
y = ( ( x - start - > x ) * dy > > 10 ) + start - > y ;
z = ( ( x - start - > x ) * dz > > 10 ) + start - > z ;
while ( x < end - > x )
{
floor = GetFloor ( x , y , z , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x , y , z ) | | y < GetCeiling ( floor , x , y , z ) )
{
flag = - 1 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
floor = GetFloor ( x + 1 , y , z , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x + 1 , y , z ) | | y < GetCeiling ( floor , x + 1 , y , z ) )
{
flag = 0 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
x + = 1024 ;
y + = dy ;
z + = dz ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( flag ! = 1 )
{
end - > x = x ;
end - > y = y ;
end - > z = z ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
end - > roomNumber = flag ? room : room2 ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
return flag ;
}
int zLOS ( GAME_VECTOR * start , GAME_VECTOR * end )
{
2022-02-13 23:23:36 +11:00
int x , y , z ;
2021-09-15 17:20:42 +03:00
FLOOR_INFO * floor ;
2022-02-13 23:23:36 +11:00
int dz = end - > z - start - > z ;
2021-09-15 17:20:42 +03:00
if ( ! dz )
return 1 ;
2022-02-13 23:23:36 +11:00
int dx = ( end - > x - start - > x < < 10 ) / dz ;
int dy = ( end - > y - start - > y < < 10 ) / dz ;
2021-09-15 17:20:42 +03:00
NumberLosRooms = 1 ;
LosRooms [ 0 ] = start - > roomNumber ;
2022-02-13 23:23:36 +11:00
short room = start - > roomNumber ;
short room2 = start - > roomNumber ;
int flag = 1 ;
2021-09-15 17:20:42 +03:00
if ( dz < 0 )
{
z = start - > z & 0xFFFFFC00 ;
x = ( ( z - start - > z ) * dx > > 10 ) + start - > x ;
y = ( ( z - start - > z ) * dy > > 10 ) + start - > y ;
while ( z > end - > z )
{
floor = GetFloor ( x , y , z , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x , y , z ) | | y < GetCeiling ( floor , x , y , z ) )
{
flag = - 1 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
floor = GetFloor ( x , y , z - 1 , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x , y , z - 1 ) | | y < GetCeiling ( floor , x , y , z - 1 ) )
{
flag = 0 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
z - = 1024 ;
x - = dx ;
y - = dy ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( flag ! = 1 )
{
end - > x = x ;
end - > y = y ;
end - > z = z ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
end - > roomNumber = flag ? room : room2 ;
}
else
{
z = start - > z | 0x3FF ;
x = ( ( z - start - > z ) * dx > > 10 ) + start - > x ;
y = ( ( z - start - > z ) * dy > > 10 ) + start - > y ;
while ( z < end - > z )
{
floor = GetFloor ( x , y , z , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x , y , z ) | | y < GetCeiling ( floor , x , y , z ) )
{
flag = - 1 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
floor = GetFloor ( x , y , z + 1 , & room ) ;
if ( room ! = room2 )
{
room2 = room ;
LosRooms [ NumberLosRooms ] = room ;
+ + NumberLosRooms ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( y > GetFloorHeight ( floor , x , y , z + 1 ) | | y < GetCeiling ( floor , x , y , z + 1 ) )
{
flag = 0 ;
break ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
z + = 1024 ;
x + = dx ;
y + = dy ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
if ( flag ! = 1 )
{
end - > x = x ;
end - > y = y ;
end - > z = z ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
end - > roomNumber = flag ? room : room2 ;
}
2022-02-13 23:23:36 +11:00
2021-09-15 17:20:42 +03:00
return flag ;
}
2021-12-01 18:12:04 +03:00
bool LOSAndReturnTarget ( GAME_VECTOR * start , GAME_VECTOR * target , int push )
{
int floorHeight , ceilingHeight ;
FLOOR_INFO * floor ;
2022-02-14 17:05:52 +11:00
int x = start - > x ;
int y = start - > y ;
int z = start - > z ;
short roomNum = start - > roomNumber ;
short roomNum2 = roomNum ;
int dx = target - > x - x > > 3 ;
int dy = target - > y - y > > 3 ;
int dz = target - > z - z > > 3 ;
bool flag = false ;
bool result = false ;
2021-12-01 18:12:04 +03:00
int i ;
for ( i = 0 ; i < 8 ; + + i )
{
roomNum2 = roomNum ;
floor = GetFloor ( x , y , z , & roomNum ) ;
if ( g_Level . Rooms [ roomNum2 ] . flags & ENV_FLAG_SWAMP )
{
flag = true ;
break ;
}
floorHeight = GetFloorHeight ( floor , x , y , z ) ;
ceilingHeight = GetCeiling ( floor , x , y , z ) ;
if ( floorHeight ! = NO_HEIGHT & & ceilingHeight ! = NO_HEIGHT & & ceilingHeight < floorHeight )
{
if ( y > floorHeight )
{
if ( y - floorHeight > = push )
{
flag = true ;
break ;
}
y = floorHeight ;
}
if ( y < ceilingHeight )
{
if ( ceilingHeight - y > = push )
{
flag = true ;
break ;
}
y = ceilingHeight ;
}
result = true ;
}
else if ( result )
{
flag = true ;
break ;
}
x + = dx ;
y + = dy ;
z + = dz ;
}
if ( i )
{
x - = dx ;
y - = dy ;
z - = dz ;
}
GetFloor ( x , y , z , & roomNum2 ) ;
target - > x = x ;
target - > y = y ;
target - > z = z ;
target - > roomNumber = roomNum2 ;
return ! flag ;
2022-02-13 23:23:36 +11:00
}