2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
2018-11-25 12:35:38 +00:00
// Copyright (C) 1999-2018 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_map.c
/// \brief Movement, collision handling
///
/// Shooting and aiming
# include "doomdef.h"
# include "g_game.h"
# include "m_bbox.h"
# include "m_random.h"
# include "p_local.h"
# include "p_setup.h" // NiGHTS stuff
# include "r_state.h"
# include "r_main.h"
# include "r_sky.h"
# include "s_sound.h"
# include "w_wad.h"
# include "r_splats.h"
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
2014-11-19 00:45:57 +00:00
# include "p_slopes.h"
# endif
2014-03-15 16:59:03 +00:00
# include "z_zone.h"
# include "lua_hook.h"
fixed_t tmbbox [ 4 ] ;
mobj_t * tmthing ;
static INT32 tmflags ;
2015-04-29 05:29:51 +00:00
fixed_t tmx ;
fixed_t tmy ;
2014-03-15 16:59:03 +00:00
static precipmobj_t * tmprecipthing ;
static fixed_t preciptmbbox [ 4 ] ;
// If "floatok" true, move would be ok
// if within "tmfloorz - tmceilingz".
boolean floatok ;
fixed_t tmfloorz , tmceilingz ;
2014-08-04 03:49:33 +00:00
static fixed_t tmdropoffz , tmdrpoffceilz ; // drop-off floor/ceiling heights
2014-03-15 16:59:03 +00:00
mobj_t * tmfloorthing ; // the thing corresponding to tmfloorz or NULL if tmfloorz is from a sector
2015-05-31 12:57:27 +00:00
mobj_t * tmhitthing ; // the solid thing you bumped into (for collisions)
2018-09-10 03:12:37 +00:00
ffloor_t * tmfloorrover , * tmceilingrover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
pslope_t * tmfloorslope , * tmceilingslope ;
# endif
2014-03-15 16:59:03 +00:00
// keep track of the line that lowers the ceiling,
// so missiles don't explode against sky hack walls
line_t * ceilingline ;
// set by PIT_CheckLine() for any line that stopped the PIT_CheckLine()
// that is, for any line which is 'solid'
line_t * blockingline ;
msecnode_t * sector_list = NULL ;
mprecipsecnode_t * precipsector_list = NULL ;
camera_t * mapcampointer ;
//
// TELEPORT MOVE
//
//
// P_TeleportMove
//
boolean P_TeleportMove ( mobj_t * thing , fixed_t x , fixed_t y , fixed_t z )
{
// the move is ok,
// so link the thing into its new position
P_UnsetThingPosition ( thing ) ;
// Remove touching_sectorlist from mobj.
if ( sector_list )
{
P_DelSeclist ( sector_list ) ;
sector_list = NULL ;
}
thing - > x = x ;
thing - > y = y ;
thing - > z = z ;
P_SetThingPosition ( thing ) ;
P_CheckPosition ( thing , thing - > x , thing - > y ) ;
if ( P_MobjWasRemoved ( thing ) )
return true ;
thing - > floorz = tmfloorz ;
thing - > ceilingz = tmceilingz ;
2018-09-10 04:35:40 +00:00
thing - > floorrover = tmfloorrover ;
thing - > ceilingrover = tmceilingrover ;
2014-03-15 16:59:03 +00:00
return true ;
}
// =========================================================================
// MOVEMENT ITERATOR FUNCTIONS
// =========================================================================
2018-05-15 15:10:42 +00:00
// P_DoSpring
//
// MF_SPRING does some weird, mildly hacky stuff sometimes.
// mass = vertical speed
// damage = horizontal speed
// raisestate = state to change spring to on collision
2018-05-19 23:04:39 +00:00
// reactiontime = number of times it can give 10 points (0 is standard)
2018-05-15 15:10:42 +00:00
// painchance = spring mode:
// 0 = standard vanilla spring behaviour
// Positive spring modes are minor variants of vanilla spring behaviour.
// 1 = launch players in jump
// 2 = don't modify player at all, just add momentum
// Negative spring modes are mildly-related gimmicks with customisation.
// -1 = pinball bumper
// Any other spring mode defaults to standard vanilla spring behaviour,
2018-05-19 23:04:39 +00:00
// ****** but forward compatibility is not guaranteed for these. ******
2018-05-15 15:10:42 +00:00
//
2015-07-28 18:28:51 +00:00
boolean P_DoSpring ( mobj_t * spring , mobj_t * object )
2014-03-15 16:59:03 +00:00
{
fixed_t vertispeed = spring - > info - > mass ;
fixed_t horizspeed = spring - > info - > damage ;
2018-11-21 01:23:48 +00:00
boolean final = false ;
2019-06-26 22:26:05 +00:00
UINT8 strong = 0 ;
2014-03-15 16:59:03 +00:00
2018-05-02 19:03:18 +00:00
// Object was already sprung this tic
if ( object - > eflags & MFE_SPRUNG )
2015-07-28 18:28:51 +00:00
return false ;
2015-02-11 20:54:11 +00:00
2014-03-15 16:59:03 +00:00
// Spectators don't trigger springs.
if ( object - > player & & object - > player - > spectator )
2015-07-28 18:28:51 +00:00
return false ;
2014-03-15 16:59:03 +00:00
2018-05-15 15:10:42 +00:00
// "Even in Death" is a song from Volume 8, not a command.
if ( ! spring - > health | | ! object - > health )
return false ;
2019-06-26 22:26:05 +00:00
if ( object - > player )
{
if ( object - > player - > charability = = CA_TWINSPIN & & object - > player - > panim = = PA_ABILITY )
strong = 1 ;
else if ( object - > player - > charability2 = = CA2_MELEE & & object - > player - > panim = = PA_ABILITY2 )
strong = 2 ;
}
2018-05-15 15:10:42 +00:00
if ( spring - > info - > painchance = = - 1 ) // Pinball bumper mode.
{
// The first of the entirely different spring modes!
// Some of the attributes mean different things here.
// mass = default strength (can be controlled by mapthing's spawnangle)
// damage = unused
angle_t horizangle , vertiangle ;
2018-05-19 23:04:39 +00:00
if ( ! vertispeed )
return false ;
if ( object - > player & & object - > player - > homing ) // Sonic Heroes and Shadow the Hedgehog are the only games to contain homing-attackable bumpers!
2018-05-15 15:10:42 +00:00
{
horizangle = 0 ;
vertiangle = ( ( object - > eflags & MFE_VERTICALFLIP ) ? ANGLE_270 : ANGLE_90 ) > > ANGLETOFINESHIFT ;
object - > player - > pflags & = ~ PF_THOKKED ;
if ( spring - > eflags & MFE_VERTICALFLIP )
object - > z = spring - > z - object - > height - 1 ;
else
object - > z = spring - > z + spring - > height + 1 ;
}
else
{
horizangle = R_PointToAngle2 ( spring - > x , spring - > y , object - > x , object - > y ) ;
vertiangle = ( R_PointToAngle2 (
0 ,
spring - > z + spring - > height / 2 ,
FixedHypot ( object - > x - spring - > x , object - > y - spring - > y ) ,
object - > z + object - > height / 2 )
> > ANGLETOFINESHIFT ) & FINEMASK ;
}
if ( spring - > spawnpoint & & spring - > spawnpoint - > angle > 0 )
vertispeed = ( spring - > spawnpoint - > angle < < ( FRACBITS - 1 ) ) / 5 ;
vertispeed = FixedMul ( vertispeed , FixedMul ( object - > scale , spring - > scale ) ) ;
if ( object - > player )
{
fixed_t playervelocity ;
2019-06-26 22:26:05 +00:00
if ( strong )
vertispeed < < = 1 ;
2018-05-15 15:10:42 +00:00
if ( ! ( object - > player - > pflags & PF_THOKKED ) & & ! ( object - > player - > homing )
& & ( ( playervelocity = FixedDiv ( 9 * FixedHypot ( object - > player - > speed , object - > momz ) , 10 < < FRACBITS ) ) > vertispeed ) )
vertispeed = playervelocity ;
if ( object - > player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) // THIS has NiGHTS support, at least...
{
2018-05-19 23:04:39 +00:00
angle_t nightsangle = 0 ;
2018-05-15 15:10:42 +00:00
if ( object - > player - > bumpertime > = TICRATE / 4 )
return false ;
2018-05-19 23:04:39 +00:00
if ( ( object - > player - > pflags & PF_TRANSFERTOCLOSEST ) & & object - > player - > axis1 & & object - > player - > axis2 )
{
nightsangle = R_PointToAngle2 ( object - > player - > axis1 - > x , object - > player - > axis1 - > y , object - > player - > axis2 - > x , object - > player - > axis2 - > y ) ;
nightsangle + = ANGLE_90 ;
}
else if ( object - > target )
{
if ( object - > target - > flags2 & MF2_AMBUSH )
nightsangle = R_PointToAngle2 ( object - > target - > x , object - > target - > y , object - > x , object - > y ) ;
else
nightsangle = R_PointToAngle2 ( object - > x , object - > y , object - > target - > x , object - > target - > y ) ;
}
2018-05-15 15:10:42 +00:00
object - > player - > flyangle = AngleFixed ( R_PointToAngle2 (
0 ,
spring - > z + spring - > height / 2 ,
FixedMul (
2018-05-19 23:04:39 +00:00
FINESINE ( ( ( nightsangle - horizangle ) > > ANGLETOFINESHIFT ) & FINEMASK ) ,
2018-05-15 15:10:42 +00:00
FixedHypot ( object - > x - spring - > x , object - > y - spring - > y ) ) ,
object - > z + object - > height / 2 ) ) > > FRACBITS ;
2018-05-19 23:04:39 +00:00
2018-05-15 15:10:42 +00:00
object - > player - > bumpertime = TICRATE / 2 ;
}
else
{
INT32 pflags = object - > player - > pflags & ( PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING | PF_THOKKED | PF_BOUNCING ) ; // Not identical to below...
UINT8 secondjump = object - > player - > secondjump ;
if ( object - > player - > pflags & PF_GLIDING )
P_SetPlayerMobjState ( object , S_PLAY_FALL ) ;
P_ResetPlayer ( object - > player ) ;
object - > player - > pflags | = pflags ;
object - > player - > secondjump = secondjump ;
}
}
2018-05-19 23:04:39 +00:00
if ( ! P_IsObjectOnGround ( object ) ) // prevents uncurling when spinning due to "landing"
object - > momz = FixedMul ( vertispeed , FINESINE ( vertiangle ) ) ;
2018-05-15 15:10:42 +00:00
P_InstaThrust ( object , horizangle , FixedMul ( vertispeed , FINECOSINE ( vertiangle ) ) ) ;
2018-05-19 23:04:39 +00:00
object - > eflags | = MFE_SPRUNG ; // apply this flag asap!
goto springstate ;
2018-05-15 15:10:42 +00:00
}
2018-05-19 23:04:39 +00:00
// Does nothing?
if ( ! vertispeed & & ! horizspeed )
2015-07-28 18:28:51 +00:00
return false ;
2015-05-27 09:59:42 +00:00
2018-05-02 19:03:18 +00:00
# ifdef ESLOPE
object - > standingslope = NULL ; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you.
# endif
2018-05-15 15:10:42 +00:00
if ( spring - > eflags & MFE_VERTICALFLIP )
vertispeed * = - 1 ;
2017-03-14 18:11:17 +00:00
if ( object - > player & & ( object - > player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) )
2014-03-15 16:59:03 +00:00
{
/*Someone want to make these work like bumpers?*/
2015-07-28 18:28:51 +00:00
return false ;
2014-03-15 16:59:03 +00:00
}
2015-05-27 09:59:42 +00:00
2019-06-26 22:26:05 +00:00
if ( strong )
2017-03-20 19:04:33 +00:00
{
2018-05-02 19:03:18 +00:00
if ( horizspeed )
horizspeed = FixedMul ( horizspeed , ( 4 * FRACUNIT ) / 3 ) ;
if ( vertispeed )
vertispeed = FixedMul ( vertispeed , ( 6 * FRACUNIT ) / 5 ) ; // aprox square root of above
2017-03-20 19:04:33 +00:00
}
2016-06-30 22:23:50 +00:00
2015-02-11 20:54:11 +00:00
object - > eflags | = MFE_SPRUNG ; // apply this flag asap!
2018-05-02 19:03:18 +00:00
spring - > flags & = ~ ( MF_SPRING | MF_SPECIAL ) ; // De-solidify
2014-03-15 16:59:03 +00:00
2018-05-15 15:10:42 +00:00
if ( spring - > info - > painchance ! = 2 )
2014-03-15 16:59:03 +00:00
{
2018-05-15 15:10:42 +00:00
if ( ( horizspeed & & vertispeed ) | | ( object - > player & & object - > player - > homing ) ) // Mimic SA
{
object - > momx = object - > momy = 0 ;
P_TryMove ( object , spring - > x , spring - > y , true ) ;
}
2014-03-15 16:59:03 +00:00
2018-05-15 15:10:42 +00:00
if ( vertispeed > 0 )
object - > z = spring - > z + spring - > height + 1 ;
else if ( vertispeed < 0 )
object - > z = spring - > z - object - > height - 1 ;
else
{
fixed_t offx , offy ;
// Horizontal springs teleport you in FRONT of them.
object - > momx = object - > momy = 0 ;
// Overestimate the distance to position you at
offx = P_ReturnThrustX ( spring , spring - > angle , ( spring - > radius + object - > radius + 1 ) * 2 ) ;
offy = P_ReturnThrustY ( spring , spring - > angle , ( spring - > radius + object - > radius + 1 ) * 2 ) ;
// Make it square by clipping
if ( offx > ( spring - > radius + object - > radius + 1 ) )
offx = spring - > radius + object - > radius + 1 ;
else if ( offx < - ( spring - > radius + object - > radius + 1 ) )
offx = - ( spring - > radius + object - > radius + 1 ) ;
if ( offy > ( spring - > radius + object - > radius + 1 ) )
offy = spring - > radius + object - > radius + 1 ;
else if ( offy < - ( spring - > radius + object - > radius + 1 ) )
offy = - ( spring - > radius + object - > radius + 1 ) ;
// Set position!
P_TryMove ( object , spring - > x + offx , spring - > y + offy , true ) ;
}
2014-03-15 16:59:03 +00:00
}
if ( vertispeed )
object - > momz = FixedMul ( vertispeed , FixedSqrt ( FixedMul ( object - > scale , spring - > scale ) ) ) ;
if ( horizspeed )
P_InstaThrustEvenIn2D ( object , spring - > angle , FixedMul ( horizspeed , FixedSqrt ( FixedMul ( object - > scale , spring - > scale ) ) ) ) ;
// Re-solidify
2018-05-02 19:03:18 +00:00
spring - > flags | = ( spring - > info - > flags & ( MF_SPRING | MF_SPECIAL ) ) ;
2014-03-15 16:59:03 +00:00
if ( object - > player )
{
2018-05-15 15:10:42 +00:00
INT32 pflags ;
UINT8 secondjump ;
boolean washoming ;
2014-03-15 16:59:03 +00:00
if ( spring - > flags & MF_ENEMY ) // Spring shells
P_SetTarget ( & spring - > target , object ) ;
2017-02-06 17:31:48 +00:00
if ( horizspeed )
2014-03-15 16:59:03 +00:00
{
2017-02-06 17:31:48 +00:00
object - > player - > drawangle = spring - > angle ;
if ( object - > player - > cmd . forwardmove = = 0 & & object - > player - > cmd . sidemove = = 0 )
2016-04-05 19:56:48 +00:00
{
2017-02-06 17:31:48 +00:00
object - > angle = spring - > angle ;
if ( ! demoplayback | | P_AnalogMove ( object - > player ) )
{
if ( object - > player = = & players [ consoleplayer ] )
localangle = spring - > angle ;
else if ( object - > player = = & players [ secondarydisplayplayer ] )
localangle2 = spring - > angle ;
}
2016-04-05 19:56:48 +00:00
}
2014-03-15 16:59:03 +00:00
}
2018-05-15 15:10:42 +00:00
pflags = object - > player - > pflags & ( PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING | PF_THOKKED | PF_BOUNCING ) ; // I still need these.
2016-09-28 15:26:29 +00:00
secondjump = object - > player - > secondjump ;
2018-05-15 15:10:42 +00:00
washoming = object - > player - > homing ;
if ( object - > player - > pflags & PF_GLIDING )
P_SetPlayerMobjState ( object , S_PLAY_FALL ) ;
2014-03-15 16:59:03 +00:00
P_ResetPlayer ( object - > player ) ;
2018-05-15 15:10:42 +00:00
if ( spring - > info - > painchance = = 1 ) // For all those ancient, SOC'd abilities.
2016-09-28 15:26:29 +00:00
{
2017-04-03 17:28:02 +00:00
object - > player - > pflags | = P_GetJumpFlags ( object - > player ) ;
2016-09-28 15:26:29 +00:00
P_SetPlayerMobjState ( object , S_PLAY_JUMP ) ;
}
2018-05-15 15:10:42 +00:00
else if ( ( spring - > info - > painchance = = 2 ) | | ( pflags & PF_BOUNCING ) ) // Adding momentum only.
2014-03-15 16:59:03 +00:00
{
2018-05-15 15:10:42 +00:00
object - > player - > pflags | = ( pflags & ~ PF_STARTJUMP ) ;
object - > player - > secondjump = secondjump ;
if ( washoming )
object - > player - > pflags & = ~ PF_THOKKED ;
}
else if ( ! vertispeed )
2014-03-15 16:59:03 +00:00
{
2018-05-15 15:10:42 +00:00
if ( pflags & ( PF_JUMPED | PF_SPINNING ) )
2016-09-28 15:26:29 +00:00
{
object - > player - > pflags | = pflags ;
object - > player - > secondjump = secondjump ;
}
2014-03-15 16:59:03 +00:00
else
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( object , S_PLAY_WALK ) ;
2014-03-15 16:59:03 +00:00
}
2017-02-09 23:24:47 +00:00
else if ( P_MobjFlip ( object ) * vertispeed > 0 )
P_SetPlayerMobjState ( object , S_PLAY_SPRING ) ;
else
P_SetPlayerMobjState ( object , S_PLAY_FALL ) ;
2014-03-15 16:59:03 +00:00
}
2017-03-27 13:37:40 +00:00
# ifdef ESLOPE
2018-05-02 19:03:18 +00:00
object - > standingslope = NULL ; // And again.
2017-03-27 13:37:40 +00:00
# endif
2018-05-19 23:04:39 +00:00
final = true ;
springstate :
if ( ( statenum_t ) ( spring - > state - states ) < spring - > info - > raisestate )
{
P_SetMobjState ( spring , spring - > info - > raisestate ) ;
if ( object - > player & & spring - > reactiontime & & ! ( spring - > info - > flags & MF_ENEMY ) )
{
2018-06-09 18:22:28 +00:00
if ( object - > player - > powers [ pw_carry ] ! = CR_NIGHTSMODE ) // don't make graphic in NiGHTS
P_SetMobjState ( P_SpawnMobj ( spring - > x , spring - > y , spring - > z + ( spring - > height / 2 ) , MT_SCORE ) , mobjinfo [ MT_SCORE ] . spawnstate + 11 ) ;
2018-05-19 23:04:39 +00:00
P_AddPlayerScore ( object - > player , 10 ) ;
spring - > reactiontime - - ;
}
2019-06-26 22:26:05 +00:00
if ( strong )
{
P_TwinSpinRejuvenate ( object - > player , ( strong = = 1 ? object - > player - > thokitem : object - > player - > revitem ) ) ;
S_StartSound ( object , sfx_sprong ) ; // strong spring. sprong.
}
2018-05-19 23:04:39 +00:00
}
return final ;
2014-03-15 16:59:03 +00:00
}
2014-11-12 00:55:07 +00:00
static void P_DoFanAndGasJet ( mobj_t * spring , mobj_t * object )
{
player_t * p = object - > player ; // will be NULL if not a player
fixed_t zdist ; // distance between bottoms
fixed_t speed = spring - > info - > mass ; // conveniently, both fans and gas jets use this for the vertical thrust
SINT8 flipval = P_MobjFlip ( spring ) ; // virtually everything here centers around the thruster's gravity, not the object's!
if ( p & & object - > state = = & states [ object - > info - > painstate ] ) // can't use fans and gas jets when player is in pain!
return ;
2016-06-30 22:23:50 +00:00
// is object's top below thruster's position? if not, calculate distance between their bottoms
2014-11-12 00:55:07 +00:00
if ( spring - > eflags & MFE_VERTICALFLIP )
{
2016-06-30 22:23:50 +00:00
if ( object - > z > spring - > z + spring - > height )
2014-11-12 00:55:07 +00:00
return ;
zdist = ( spring - > z + spring - > height ) - ( object - > z + object - > height ) ;
}
else
{
2016-06-30 22:23:50 +00:00
if ( object - > z + object - > height < spring - > z )
2014-11-12 00:55:07 +00:00
return ;
zdist = object - > z - spring - > z ;
}
2016-06-30 22:23:50 +00:00
# ifdef ESLOPE
object - > standingslope = NULL ; // No launching off at silly angles for you.
# endif
2014-11-12 00:55:07 +00:00
switch ( spring - > type )
{
case MT_FAN : // fan
if ( zdist > ( spring - > health < < FRACBITS ) ) // max z distance determined by health (set by map thing angle)
break ;
if ( flipval * object - > momz > = FixedMul ( speed , spring - > scale ) ) // if object's already moving faster than your best, don't bother
break ;
if ( p & & ( p - > climbing | | p - > pflags & PF_GLIDING ) ) // doesn't affect Knux when he's using his abilities!
break ;
object - > momz + = flipval * FixedMul ( speed / 4 , spring - > scale ) ;
// limit the speed if too high
if ( flipval * object - > momz > FixedMul ( speed , spring - > scale ) )
object - > momz = flipval * FixedMul ( speed , spring - > scale ) ;
if ( p & & ! p - > powers [ pw_tailsfly ] ) // doesn't reset anim for Tails' flight
{
P_ResetPlayer ( p ) ;
if ( p - > panim ! = PA_FALL )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( object , S_PLAY_FALL ) ;
2014-11-12 00:55:07 +00:00
}
break ;
case MT_STEAM : // Steam
if ( zdist > FixedMul ( 16 * FRACUNIT , spring - > scale ) )
break ;
if ( spring - > state ! = & states [ S_STEAM1 ] ) // Only when it bursts
break ;
object - > momz = flipval * FixedMul ( speed , FixedSqrt ( FixedMul ( spring - > scale , object - > scale ) ) ) ; // scale the speed with both objects' scales, just like with springs!
if ( p )
{
P_ResetPlayer ( p ) ;
if ( p - > panim ! = PA_FALL )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( object , S_PLAY_FALL ) ;
2014-11-12 00:55:07 +00:00
}
break ;
default :
break ;
}
}
static void P_DoTailsCarry ( player_t * sonic , player_t * tails )
{
INT32 p ;
fixed_t zdist ; // z distance between the two players' bottoms
2016-09-24 12:18:08 +00:00
if ( tails - > powers [ pw_carry ] )
2014-11-12 00:55:07 +00:00
return ;
2016-09-24 11:38:37 +00:00
if ( sonic - > powers [ pw_carry ] )
2014-11-12 00:55:07 +00:00
return ;
2016-09-24 12:18:08 +00:00
if ( tails - > spectator )
return ;
if ( sonic - > spectator )
2016-09-08 13:38:57 +00:00
return ;
2016-09-24 12:18:08 +00:00
if ( ! ( tails - > pflags & PF_CANCARRY ) )
2014-11-12 00:55:07 +00:00
return ;
if ( tails - > bot = = 1 )
return ;
if ( ( sonic - > mo - > eflags & MFE_VERTICALFLIP ) ! = ( tails - > mo - > eflags & MFE_VERTICALFLIP ) )
return ; // Both should be in same gravity
if ( tails - > mo - > eflags & MFE_VERTICALFLIP )
{
if ( tails - > mo - > ceilingz - ( tails - > mo - > z + tails - > mo - > height ) < sonic - > mo - > height - FixedMul ( 2 * FRACUNIT , sonic - > mo - > scale ) )
return ;
}
else if ( tails - > mo - > z - tails - > mo - > floorz < sonic - > mo - > height - FixedMul ( 2 * FRACUNIT , sonic - > mo - > scale ) )
return ; // No room to pick up this guy!
// Search in case another player is already being carried by this fox.
for ( p = 0 ; p < MAXPLAYERS ; p + + )
if ( playeringame [ p ] & & players [ p ] . mo
2016-09-23 22:48:48 +00:00
& & players [ p ] . powers [ pw_carry ] = = CR_PLAYER & & players [ p ] . mo - > tracer = = tails - > mo )
2014-11-12 00:55:07 +00:00
return ;
2016-09-24 12:18:08 +00:00
// Why block opposing teams from tailsflying each other?
// Sneaking into the hands of a flying tails player in Race might be a viable strategy, who knows.
/*
if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION
| | ( netgame & & ( tails - > spectator | | sonic - > spectator ) )
| | ( G_TagGametype ( ) & & ( ! ( tails - > pflags & PF_TAGIT ) ! = ! ( sonic - > pflags & PF_TAGIT ) ) )
| | ( gametype = = GT_MATCH )
| | ( G_GametypeHasTeams ( ) & & tails - > ctfteam ! = sonic - > ctfteam ) )
return ; */
2014-11-12 00:55:07 +00:00
if ( tails - > mo - > eflags & MFE_VERTICALFLIP )
zdist = ( sonic - > mo - > z + sonic - > mo - > height ) - ( tails - > mo - > z + tails - > mo - > height ) ;
else
zdist = tails - > mo - > z - sonic - > mo - > z ;
2016-09-24 12:18:08 +00:00
if ( zdist < = sonic - > mo - > height + sonic - > mo - > scale // FixedMul(FRACUNIT, sonic->mo->scale), but scale == FRACUNIT by default
2014-11-12 00:55:07 +00:00
& & zdist > sonic - > mo - > height * 2 / 3
& & P_MobjFlip ( tails - > mo ) * sonic - > mo - > momz < = 0 )
{
2016-09-24 12:18:08 +00:00
if ( sonic - players = = consoleplayer & & botingame )
CV_SetValue ( & cv_analog2 , false ) ;
P_ResetPlayer ( sonic ) ;
P_SetTarget ( & sonic - > mo - > tracer , tails - > mo ) ;
sonic - > powers [ pw_carry ] = CR_PLAYER ;
S_StartSound ( sonic - > mo , sfx_s3k4a ) ;
P_UnsetThingPosition ( sonic - > mo ) ;
sonic - > mo - > x = tails - > mo - > x ;
sonic - > mo - > y = tails - > mo - > y ;
P_SetThingPosition ( sonic - > mo ) ;
2014-11-12 00:55:07 +00:00
}
else {
if ( sonic - players = = consoleplayer & & botingame )
CV_SetValue ( & cv_analog2 , true ) ;
2017-03-14 18:11:17 +00:00
P_SetTarget ( & sonic - > mo - > tracer , NULL ) ;
2016-09-23 22:48:48 +00:00
sonic - > powers [ pw_carry ] = CR_NONE ;
2014-11-12 00:55:07 +00:00
}
}
2019-05-05 16:36:55 +00:00
// Boss 5 post-defeat comedy
static void P_SlapStick ( mobj_t * fang , mobj_t * pole )
{
fixed_t momx1 , momx2 , momy1 , momy2 ;
# define dist 3
momx1 = pole - > momx / dist ;
momy1 = pole - > momy / dist ;
momx2 = fang - > momx / dist ;
momy2 = fang - > momy / dist ;
pole - > tracer - > momx = momx1 + ( dist - 1 ) * momx2 ;
pole - > tracer - > momy = momy1 + ( dist - 1 ) * momy2 ;
fang - > momx = ( dist - 1 ) * momx1 + momx2 ;
fang - > momy = ( dist - 1 ) * momy1 + momy2 ;
# undef dist
P_SetMobjState ( pole , pole - > info - > deathstate ) ;
P_SetObjectMomZ ( pole - > tracer , 6 * FRACUNIT , false ) ;
pole - > tracer - > flags & = ~ ( MF_NOGRAVITY | MF_NOCLIP ) ;
pole - > tracer - > movedir = ANGLE_67h ;
if ( ( R_PointToAngle ( fang - > x - pole - > tracer - > x , fang - > y - pole - > tracer - > y ) - pole - > angle ) > ANGLE_180 )
pole - > tracer - > movedir = InvAngle ( pole - > tracer - > movedir ) ;
P_SetObjectMomZ ( fang , 14 * FRACUNIT , false ) ;
fang - > flags | = MF_NOGRAVITY | MF_NOCLIP ;
P_SetMobjState ( fang , fang - > info - > xdeathstate ) ;
pole - > tracer - > tics = pole - > tics = fang - > tics ;
var1 = var2 = 0 ;
A_Scream ( pole - > tracer ) ;
S_StartSound ( fang , sfx_altdi1 ) ;
P_SetTarget ( & pole - > tracer , NULL ) ;
}
2014-03-15 16:59:03 +00:00
//
// PIT_CheckThing
//
static boolean PIT_CheckThing ( mobj_t * thing )
{
2014-11-12 00:55:07 +00:00
fixed_t blockdist ;
2014-03-15 16:59:03 +00:00
// don't clip against self
2015-02-11 20:54:11 +00:00
if ( thing = = tmthing )
return true ;
2014-03-15 16:59:03 +00:00
// Ignore... things.
2015-02-11 20:54:11 +00:00
if ( ! tmthing | | ! thing | | P_MobjWasRemoved ( thing ) )
2014-03-15 16:59:03 +00:00
return true ;
I_Assert ( ! P_MobjWasRemoved ( tmthing ) ) ;
I_Assert ( ! P_MobjWasRemoved ( thing ) ) ;
// Ignore spectators
if ( ( tmthing - > player & & tmthing - > player - > spectator )
| | ( thing - > player & & thing - > player - > spectator ) )
return true ;
# ifdef SEENAMES
// Do name checks all the way up here
// So that NOTHING ELSE can see MT_NAMECHECK because it is client-side.
if ( tmthing - > type = = MT_NAMECHECK )
{
// Ignore things that aren't players, ignore spectators, ignore yourself.
// (also don't bother to check that tmthing->target->player is non-NULL because we're not actually using it here.)
if ( ! thing - > player | | thing - > player - > spectator | | ( tmthing - > target & & thing - > player = = tmthing - > target - > player ) )
return true ;
// Now check that you actually hit them.
blockdist = thing - > radius + tmthing - > radius ;
if ( abs ( thing - > x - tmx ) > = blockdist | | abs ( thing - > y - tmy ) > = blockdist )
return true ; // didn't hit it
// see if it went over / under
if ( tmthing - > z > thing - > z + thing - > height )
return true ; // overhead
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ; // underneath
seenplayer = thing - > player ;
return false ;
}
# endif
// Metal Sonic destroys tiny baby objects.
if ( tmthing - > type = = MT_METALSONIC_RACE
2017-07-18 13:17:10 +00:00
& & ( thing - > flags & ( MF_MISSILE | MF_ENEMY | MF_BOSS )
| | ( thing - > type = = MT_SPIKE
| | thing - > type = = MT_WALLSPIKE ) ) )
2014-03-15 16:59:03 +00:00
{
2016-11-12 15:39:42 +00:00
if ( ( thing - > flags & ( MF_ENEMY | MF_BOSS ) ) & & ( thing - > health < = 0 | | ! ( thing - > flags & MF_SHOOTABLE ) ) )
2014-03-15 16:59:03 +00:00
return true ;
blockdist = thing - > radius + tmthing - > radius ;
if ( abs ( thing - > x - tmx ) > = blockdist | | abs ( thing - > y - tmy ) > = blockdist )
return true ; // didn't hit it
// see if it went over / under
if ( tmthing - > z > thing - > z + thing - > height )
return true ; // overhead
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ; // underneath
2017-07-18 13:17:10 +00:00
if ( thing - > type = = MT_SPIKE
| | thing - > type = = MT_WALLSPIKE )
2014-03-15 16:59:03 +00:00
{
2017-07-18 13:17:10 +00:00
mobjtype_t type = thing - > type ;
2016-08-06 22:54:38 +00:00
if ( thing - > flags & MF_SOLID )
S_StartSound ( tmthing , thing - > info - > deathsound ) ;
2014-03-15 16:59:03 +00:00
for ( thing = thing - > subsector - > sector - > thinglist ; thing ; thing = thing - > snext )
2017-07-18 13:17:10 +00:00
if ( thing - > type = = type & & thing - > health > 0 & & thing - > flags & MF_SOLID & & P_AproxDistance ( P_AproxDistance ( thing - > x - tmthing - > x , thing - > y - tmthing - > y ) , thing - > z - tmthing - > z ) < 56 * thing - > scale ) //FixedMul(56*FRACUNIT, thing->scale))
2015-02-13 16:15:58 +00:00
P_KillMobj ( thing , tmthing , tmthing , 0 ) ;
2014-03-15 16:59:03 +00:00
}
else
{
thing - > health = 0 ;
2015-02-13 16:15:58 +00:00
P_KillMobj ( thing , tmthing , tmthing , 0 ) ;
2014-03-15 16:59:03 +00:00
}
return true ;
}
2016-12-24 00:11:54 +00:00
// SF_DASHMODE users destroy spikes and monitors, CA_TWINSPIN users and CA2_MELEE users destroy spikes.
2016-07-16 17:54:22 +00:00
if ( ( tmthing - > player )
2016-12-24 00:11:54 +00:00
& & ( ( ( tmthing - > player - > charflags & SF_DASHMODE ) & & ( tmthing - > player - > dashmode > = 3 * TICRATE )
2017-07-18 13:17:10 +00:00
& & ( thing - > flags & ( MF_MONITOR )
| | ( thing - > type = = MT_SPIKE
| | thing - > type = = MT_WALLSPIKE ) ) )
2016-07-17 20:31:15 +00:00
| | ( ( ( ( tmthing - > player - > charability = = CA_TWINSPIN ) & & ( tmthing - > player - > panim = = PA_ABILITY ) )
| | ( tmthing - > player - > charability2 = = CA2_MELEE & & tmthing - > player - > panim = = PA_ABILITY2 ) )
2017-07-18 13:17:10 +00:00
& & ( thing - > type = = MT_SPIKE
| | thing - > type = = MT_WALLSPIKE ) ) ) )
2016-07-09 15:53:41 +00:00
{
2016-11-12 15:39:42 +00:00
if ( ( thing - > flags & ( MF_MONITOR ) ) & & ( thing - > health < = 0 | | ! ( thing - > flags & MF_SHOOTABLE ) ) )
2016-07-09 15:53:41 +00:00
return true ;
blockdist = thing - > radius + tmthing - > radius ;
if ( abs ( thing - > x - tmx ) > = blockdist | | abs ( thing - > y - tmy ) > = blockdist )
return true ; // didn't hit it
// see if it went over / under
if ( tmthing - > z > thing - > z + thing - > height )
return true ; // overhead
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ; // underneath
2017-07-18 13:17:10 +00:00
if ( thing - > type = = MT_SPIKE
| | thing - > type = = MT_WALLSPIKE )
2014-03-15 16:59:03 +00:00
{
2017-07-18 13:17:10 +00:00
mobjtype_t type = thing - > type ;
2016-08-06 22:54:38 +00:00
if ( thing - > flags & MF_SOLID )
S_StartSound ( tmthing , thing - > info - > deathsound ) ;
2014-03-15 16:59:03 +00:00
for ( thing = thing - > subsector - > sector - > thinglist ; thing ; thing = thing - > snext )
2017-07-18 13:17:10 +00:00
if ( thing - > type = = type & & thing - > health > 0 & & thing - > flags & MF_SOLID & & P_AproxDistance ( P_AproxDistance ( thing - > x - tmthing - > x , thing - > y - tmthing - > y ) , thing - > z - tmthing - > z ) < 56 * thing - > scale ) //FixedMul(56*FRACUNIT, thing->scale))
2015-02-13 16:15:58 +00:00
P_KillMobj ( thing , tmthing , tmthing , 0 ) ;
2014-03-15 16:59:03 +00:00
}
else
{
thing - > health = 0 ;
2015-02-13 16:15:58 +00:00
P_KillMobj ( thing , tmthing , tmthing , 0 ) ;
2014-03-15 16:59:03 +00:00
}
return true ;
}
2019-07-02 23:58:02 +00:00
// vectorise metal - done in a special case as at this point neither has the right flags for touching
if ( thing - > type = = MT_METALSONIC_BATTLE
& & ( tmthing - > flags & MF_MISSILE )
& & tmthing - > target ! = thing
& & thing - > state = = & states [ thing - > info - > spawnstate ] )
{
blockdist = thing - > radius + tmthing - > radius ;
if ( abs ( thing - > x - tmx ) > = blockdist | | abs ( thing - > y - tmy ) > = blockdist )
return true ; // didn't hit it
if ( tmthing - > z > thing - > z + thing - > height )
return true ; // overhead
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ; // underneath
thing - > flags2 | = MF2_CLASSICPUSH ;
return true ;
}
2018-05-02 19:03:18 +00:00
if ( ! ( thing - > flags & ( MF_SOLID | MF_SPECIAL | MF_PAIN | MF_SHOOTABLE | MF_SPRING ) ) )
2014-03-15 16:59:03 +00:00
return true ;
// Don't collide with your buddies while NiGHTS-flying.
if ( tmthing - > player & & thing - > player & & ( maptol & TOL_NIGHTS )
2017-03-14 18:11:17 +00:00
& & ( ( tmthing - > player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) | | ( thing - > player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) ) )
2014-03-15 16:59:03 +00:00
return true ;
blockdist = thing - > radius + tmthing - > radius ;
if ( abs ( thing - > x - tmx ) > = blockdist | | abs ( thing - > y - tmy ) > = blockdist )
return true ; // didn't hit it
2016-08-20 14:15:48 +00:00
if ( thing - > flags & MF_PAPERCOLLISION ) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing.
2016-08-18 19:09:35 +00:00
{
fixed_t cosradius , sinradius ;
vertex_t v1 , v2 ; // fake vertexes
line_t junk ; // fake linedef
cosradius = FixedMul ( thing - > radius , FINECOSINE ( thing - > angle > > ANGLETOFINESHIFT ) ) ;
sinradius = FixedMul ( thing - > radius , FINESINE ( thing - > angle > > ANGLETOFINESHIFT ) ) ;
v1 . x = thing - > x - cosradius ;
v1 . y = thing - > y - sinradius ;
v2 . x = thing - > x + cosradius ;
v2 . y = thing - > y + sinradius ;
junk . v1 = & v1 ;
junk . v2 = & v2 ;
2016-11-06 16:46:27 +00:00
junk . dx = 2 * cosradius ; // v2.x - v1.x;
junk . dy = 2 * sinradius ; // v2.y - v1.y;
2016-08-18 19:09:35 +00:00
2016-08-20 14:15:48 +00:00
if ( tmthing - > flags & MF_PAPERCOLLISION ) // more strenuous checking to prevent clipping issues
2016-08-18 19:09:35 +00:00
{
2016-08-18 19:55:24 +00:00
INT32 check1 , check2 , check3 , check4 ;
2016-11-06 16:46:27 +00:00
fixed_t tmcosradius = FixedMul ( tmthing - > radius , FINECOSINE ( tmthing - > angle > > ANGLETOFINESHIFT ) ) ;
fixed_t tmsinradius = FixedMul ( tmthing - > radius , FINESINE ( tmthing - > angle > > ANGLETOFINESHIFT ) ) ;
if ( abs ( thing - > x - tmx ) > = ( abs ( tmcosradius ) + abs ( cosradius ) ) | | abs ( thing - > y - tmy ) > = ( abs ( tmsinradius ) + abs ( sinradius ) ) )
return true ; // didn't hit it
check1 = P_PointOnLineSide ( tmx - tmcosradius , tmy - tmsinradius , & junk ) ;
check2 = P_PointOnLineSide ( tmx + tmcosradius , tmy + tmsinradius , & junk ) ;
check3 = P_PointOnLineSide ( tmx + tmthing - > momx - tmcosradius , tmy + tmthing - > momy - tmsinradius , & junk ) ;
check4 = P_PointOnLineSide ( tmx + tmthing - > momx + tmcosradius , tmy + tmthing - > momy + tmsinradius , & junk ) ;
2016-08-18 19:55:24 +00:00
if ( ( check1 = = check2 ) & & ( check2 = = check3 ) & & ( check3 = = check4 ) )
2016-08-18 19:09:35 +00:00
return true ; // the line doesn't cross between collider's start or end
}
else
{
2016-11-06 16:46:27 +00:00
if ( abs ( thing - > x - tmx ) > = ( tmthing - > radius + abs ( cosradius ) ) | | abs ( thing - > y - tmy ) > = ( tmthing - > radius + abs ( sinradius ) ) )
return true ; // didn't hit it
2016-08-18 19:09:35 +00:00
if ( ( P_PointOnLineSide ( tmx - tmthing - > radius , tmy - tmthing - > radius , & junk )
= = P_PointOnLineSide ( tmx + tmthing - > radius , tmy + tmthing - > radius , & junk ) )
& & ( P_PointOnLineSide ( tmx + tmthing - > radius , tmy - tmthing - > radius , & junk )
= = P_PointOnLineSide ( tmx - tmthing - > radius , tmy + tmthing - > radius , & junk ) ) )
return true ; // the line doesn't cross between either pair of opposite corners
}
}
2016-08-20 14:15:48 +00:00
else if ( tmthing - > flags & MF_PAPERCOLLISION )
2016-08-18 19:09:35 +00:00
{
2016-11-06 16:46:27 +00:00
fixed_t tmcosradius , tmsinradius ;
2016-08-18 19:09:35 +00:00
vertex_t v1 , v2 ; // fake vertexes
line_t junk ; // fake linedef
2016-11-06 16:46:27 +00:00
tmcosradius = FixedMul ( tmthing - > radius , FINECOSINE ( tmthing - > angle > > ANGLETOFINESHIFT ) ) ;
tmsinradius = FixedMul ( tmthing - > radius , FINESINE ( tmthing - > angle > > ANGLETOFINESHIFT ) ) ;
if ( abs ( thing - > x - tmx ) > = ( thing - > radius + abs ( tmcosradius ) ) | | abs ( thing - > y - tmy ) > = ( thing - > radius + abs ( tmsinradius ) ) )
return true ; // didn't hit it
2016-08-18 19:09:35 +00:00
2016-11-06 16:46:27 +00:00
v1 . x = tmx - tmcosradius ;
v1 . y = tmy - tmsinradius ;
v2 . x = tmx + tmcosradius ;
v2 . y = tmy + tmsinradius ;
2016-08-18 19:09:35 +00:00
junk . v1 = & v1 ;
junk . v2 = & v2 ;
2016-11-06 16:46:27 +00:00
junk . dx = 2 * tmcosradius ; // v2.x - v1.x;
junk . dy = 2 * tmsinradius ; // v2.y - v1.y;
2016-08-18 19:09:35 +00:00
2016-11-06 16:46:27 +00:00
// no need to check whether other thing has MF_PAPERCOLLISION, since would fall under other condition
2016-08-18 19:09:35 +00:00
if ( ( P_PointOnLineSide ( thing - > x - thing - > radius , thing - > y - thing - > radius , & junk )
= = P_PointOnLineSide ( thing - > x + thing - > radius , thing - > y + thing - > radius , & junk ) )
& & ( P_PointOnLineSide ( thing - > x + thing - > radius , thing - > y - thing - > radius , & junk )
= = P_PointOnLineSide ( thing - > x - thing - > radius , thing - > y + thing - > radius , & junk ) ) )
return true ; // the line doesn't cross between either pair of opposite corners
}
2014-03-15 16:59:03 +00:00
# ifdef HAVE_BLUA
{
UINT8 shouldCollide = LUAh_MobjCollide ( thing , tmthing ) ; // checks hook for thing's type
if ( P_MobjWasRemoved ( tmthing ) | | P_MobjWasRemoved ( thing ) )
return true ; // one of them was removed???
if ( shouldCollide = = 1 )
return false ; // force collide
else if ( shouldCollide = = 2 )
return true ; // force no collide
}
{
UINT8 shouldCollide = LUAh_MobjMoveCollide ( tmthing , thing ) ; // checks hook for tmthing's type
if ( P_MobjWasRemoved ( tmthing ) | | P_MobjWasRemoved ( thing ) )
return true ; // one of them was removed???
if ( shouldCollide = = 1 )
return false ; // force collide
else if ( shouldCollide = = 2 )
return true ; // force no collide
}
# endif
2019-06-13 19:45:30 +00:00
if ( tmthing - > type = = MT_MINECART )
{
//height check
if ( tmthing - > z > thing - > z + thing - > height | | thing - > z > tmthing - > z + tmthing - > height | | ! ( thing - > health ) )
return true ;
if ( thing - > type = = MT_TNTBARREL )
P_KillMobj ( thing , tmthing , tmthing - > target , 0 ) ;
else if ( ( thing - > flags & MF_MONITOR ) | | ( thing - > flags & MF_ENEMY ) )
{
P_KillMobj ( thing , tmthing , tmthing - > target , 0 ) ;
if ( tmthing - > momz * P_MobjFlip ( tmthing ) < 0 )
tmthing - > momz = abs ( tmthing - > momz ) * P_MobjFlip ( tmthing ) ;
}
}
2019-06-12 19:20:14 +00:00
if ( thing - > type = = MT_SALOONDOOR & & tmthing - > player )
{
2019-06-15 18:21:18 +00:00
if ( tmthing - > player - > powers [ pw_carry ] = = CR_MINECART & & tmthing - > tracer & & ! P_MobjWasRemoved ( tmthing - > tracer ) & & tmthing - > tracer - > health )
2019-06-12 19:20:14 +00:00
{
2019-06-15 18:21:18 +00:00
fixed_t dx = tmthing - > tracer - > momx ;
fixed_t dy = tmthing - > tracer - > momy ;
2019-06-12 19:20:14 +00:00
fixed_t dm = min ( FixedHypot ( dx , dy ) , 16 * FRACUNIT ) ;
angle_t ang = R_PointToAngle2 ( 0 , 0 , dx , dy ) - thing - > angle ;
fixed_t s = FINESINE ( ( ang > > ANGLETOFINESHIFT ) & FINEMASK ) ;
S_StartSound ( tmthing , thing - > info - > activesound ) ;
2019-06-16 15:57:03 +00:00
thing - > extravalue2 + = 2 * FixedMul ( s , dm ) / 3 ;
2019-06-12 19:20:14 +00:00
return true ;
}
}
2019-06-09 08:51:33 +00:00
if ( thing - > type = = MT_TNTBARREL & & tmthing - > player )
{
if ( tmthing - > momz < 0 )
{
if ( tmthing - > z + tmthing - > momz > thing - > z + thing - > height )
return true ;
}
else
{
if ( tmthing - > z > thing - > z + thing - > height )
return true ;
}
if ( tmthing - > momz > 0 )
{
if ( tmthing - > z + tmthing - > height + tmthing - > momz < thing - > z )
return true ;
}
else
{
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ;
}
if ( ( tmthing - > player - > pflags & ( PF_SPINNING | PF_GLIDING ) )
| | ( ( tmthing - > player - > pflags & PF_JUMPED )
& & ( ! ( tmthing - > player - > pflags & PF_NOJUMPDAMAGE )
| | ( tmthing - > player - > charability = = CA_TWINSPIN & & tmthing - > player - > panim = = PA_ABILITY ) ) )
| | ( tmthing - > player - > charability2 = = CA2_MELEE & & tmthing - > player - > panim = = PA_ABILITY2 )
| | ( ( tmthing - > player - > charflags & SF_STOMPDAMAGE | | tmthing - > player - > pflags & PF_BOUNCING )
& & ( P_MobjFlip ( tmthing ) * ( tmthing - > z - ( thing - > z + thing - > height / 2 ) ) > 0 ) & & ( P_MobjFlip ( tmthing ) * tmthing - > momz < 0 ) )
| | ( ( ( tmthing - > player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL | | ( tmthing - > player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_BUBBLEWRAP ) & & ( tmthing - > player - > pflags & PF_SHIELDABILITY ) ) )
P_DamageMobj ( thing , tmthing , tmthing , 1 , 0 ) ;
}
2019-06-10 14:09:15 +00:00
if ( thing - > type = = MT_VULTURE & & tmthing - > type = = MT_VULTURE )
{
fixed_t dx = thing - > x - tmthing - > x ;
fixed_t dy = thing - > y - tmthing - > y ;
fixed_t dz = thing - > z - tmthing - > z ;
fixed_t dm = FixedHypot ( dz , FixedHypot ( dx , dy ) ) ;
thing - > momx + = FixedDiv ( dx , dm ) ;
thing - > momy + = FixedDiv ( dy , dm ) ;
thing - > momz + = FixedDiv ( dz , dm ) ;
}
2019-05-05 16:36:55 +00:00
if ( tmthing - > type = = MT_FANG & & thing - > type = = MT_FSGNB )
{
if ( thing - > z > tmthing - > z + tmthing - > height )
return true ; // overhead
if ( thing - > z + thing - > height < tmthing - > z )
return true ; // underneath
if ( ! thing - > tracer )
return true ;
P_SlapStick ( tmthing , thing ) ;
// no return value was used in the original prototype script at this point,
// so I'm assuming we fall back on the solid code to determine how it all ends?
// -- Monster Iestyn
}
2018-04-26 19:18:51 +00:00
// Billiards mines!
2018-05-14 00:19:24 +00:00
if ( thing - > type = = MT_BIGMINE )
2018-04-26 19:18:51 +00:00
{
2018-05-14 00:19:24 +00:00
if ( tmthing - > type = = MT_BIGMINE )
{
if ( ! tmthing - > momx & & ! tmthing - > momy )
return true ;
if ( ( statenum_t ) ( thing - > state - states ) > = thing - > info - > meleestate )
return true ;
if ( thing - > z > tmthing - > z + tmthing - > height )
return true ; // overhead
if ( thing - > z + thing - > height < tmthing - > z )
return true ; // underneath
thing - > momx = tmthing - > momx / 3 ;
thing - > momy = tmthing - > momy / 3 ;
thing - > momz = tmthing - > momz / 3 ;
tmthing - > momx / = - 8 ;
tmthing - > momy / = - 8 ;
tmthing - > momz / = - 8 ;
if ( thing - > info - > activesound )
S_StartSound ( thing , thing - > info - > activesound ) ;
P_SetMobjState ( thing , thing - > info - > meleestate ) ;
P_SetTarget ( & thing - > tracer , tmthing - > tracer ) ;
2018-04-26 19:18:51 +00:00
return true ;
2018-05-14 00:19:24 +00:00
}
else if ( tmthing - > type = = MT_CRUSHCLAW )
{
if ( tmthing - > extravalue1 < = 0 )
return true ;
if ( ( statenum_t ) ( thing - > state - states ) > = thing - > info - > meleestate )
return true ;
if ( thing - > z > tmthing - > z + tmthing - > height )
return true ; // overhead
if ( thing - > z + thing - > height < tmthing - > z )
return true ; // underneath
thing - > momx = P_ReturnThrustX ( tmthing , tmthing - > angle , 2 * tmthing - > extravalue1 * tmthing - > scale / 3 ) ;
thing - > momy = P_ReturnThrustY ( tmthing , tmthing - > angle , 2 * tmthing - > extravalue1 * tmthing - > scale / 3 ) ;
if ( thing - > info - > activesound )
S_StartSound ( thing , thing - > info - > activesound ) ;
P_SetMobjState ( thing , thing - > info - > meleestate ) ;
if ( tmthing - > tracer )
P_SetTarget ( & thing - > tracer , tmthing - > tracer - > target ) ;
return false ;
}
2018-04-26 19:18:51 +00:00
}
2014-03-15 16:59:03 +00:00
// When solid spikes move, assume they just popped up and teleport things on top of them to hurt.
if ( tmthing - > type = = MT_SPIKE & & tmthing - > flags & MF_SOLID )
{
if ( thing - > z > tmthing - > z + tmthing - > height )
return true ; // overhead
if ( thing - > z + thing - > height < tmthing - > z )
return true ; // underneath
if ( tmthing - > eflags & MFE_VERTICALFLIP )
thing - > z = tmthing - > z - thing - > height - FixedMul ( FRACUNIT , tmthing - > scale ) ;
else
thing - > z = tmthing - > z + tmthing - > height + FixedMul ( FRACUNIT , tmthing - > scale ) ;
if ( thing - > flags & MF_SHOOTABLE )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( thing , tmthing , tmthing , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
return true ;
}
2018-05-08 22:26:36 +00:00
if ( thing - > flags & MF_PAIN & & tmthing - > player )
2014-03-15 16:59:03 +00:00
{ // Player touches painful thing sitting on the floor
// see if it went over / under
if ( thing - > z > tmthing - > z + tmthing - > height )
return true ; // overhead
if ( thing - > z + thing - > height < tmthing - > z )
return true ; // underneath
2018-05-08 22:26:36 +00:00
if ( tmthing - > flags & MF_SHOOTABLE & & thing - > health > 0 )
2015-02-13 16:15:58 +00:00
{
2018-05-13 13:09:20 +00:00
UINT8 damagetype = ( thing - > info - > mass & 0xFF ) ;
2018-04-28 14:13:44 +00:00
if ( ! damagetype & & thing - > flags & MF_FIRE ) // BURN!
2015-02-13 16:15:58 +00:00
damagetype = DMG_FIRE ;
2018-05-13 13:09:20 +00:00
if ( P_DamageMobj ( tmthing , thing , thing , 1 , damagetype ) & & ( damagetype = ( thing - > info - > mass > > 8 ) ) )
S_StartSound ( thing , damagetype ) ;
2015-02-13 16:15:58 +00:00
}
2014-03-15 16:59:03 +00:00
return true ;
}
2018-05-08 22:26:36 +00:00
else if ( tmthing - > flags & MF_PAIN & & thing - > player )
2014-03-15 16:59:03 +00:00
{ // Painful thing splats player in the face
// see if it went over / under
if ( tmthing - > z > thing - > z + thing - > height )
return true ; // overhead
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ; // underneath
2018-05-08 22:26:36 +00:00
if ( thing - > flags & MF_SHOOTABLE & & tmthing - > health > 0 )
2015-02-13 16:15:58 +00:00
{
2018-05-13 13:09:20 +00:00
UINT8 damagetype = ( tmthing - > info - > mass & 0xFF ) ;
2018-04-28 14:13:44 +00:00
if ( ! damagetype & & tmthing - > flags & MF_FIRE ) // BURN!
2015-02-13 16:15:58 +00:00
damagetype = DMG_FIRE ;
2018-05-13 13:09:20 +00:00
if ( P_DamageMobj ( thing , tmthing , tmthing , 1 , damagetype ) & & ( damagetype = ( tmthing - > info - > mass > > 8 ) ) )
S_StartSound ( tmthing , damagetype ) ;
2015-02-13 16:15:58 +00:00
}
2014-03-15 16:59:03 +00:00
return true ;
}
if ( thing - > type = = MT_HOOPCOLLIDE & & thing - > flags & MF_SPECIAL & & tmthing - > player )
{
P_TouchSpecialThing ( thing , tmthing , true ) ;
return true ;
}
// check for skulls slamming into things
if ( tmthing - > flags2 & MF2_SKULLFLY )
{
if ( tmthing - > type = = MT_EGGMOBILE ) // Don't make Eggman stop!
return true ; // Let him RUN YOU RIGHT OVER. >:3
else
{
// see if it went over / under
if ( tmthing - > z > thing - > z + thing - > height )
return true ; // overhead
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ; // underneath
tmthing - > flags2 & = ~ MF2_SKULLFLY ;
tmthing - > momx = tmthing - > momy = tmthing - > momz = 0 ;
return false ; // stop moving
}
}
if ( ( thing - > type = = MT_SPRINGSHELL | | thing - > type = = MT_YELLOWSHELL ) & & thing - > health > 0
& & ( tmthing - > player | | ( tmthing - > flags & MF_PUSHABLE ) ) & & tmthing - > health > 0 )
{
// Multiplying by -1 inherently flips "less than" and "greater than"
fixed_t tmz = ( ( thing - > eflags & MFE_VERTICALFLIP ) ? - ( tmthing - > z + tmthing - > height ) : tmthing - > z ) ;
fixed_t tmznext = ( ( thing - > eflags & MFE_VERTICALFLIP ) ? - tmthing - > momz : tmthing - > momz ) + tmz ;
fixed_t thzh = ( ( thing - > eflags & MFE_VERTICALFLIP ) ? - thing - > z : thing - > z + thing - > height ) ;
fixed_t sprarea = FixedMul ( 8 * FRACUNIT , thing - > scale ) * P_MobjFlip ( thing ) ;
if ( ( tmznext < = thzh & & tmz > thzh ) | | ( tmznext > thzh - sprarea & & tmznext < thzh ) )
{
P_DoSpring ( thing , tmthing ) ;
return true ;
}
else if ( tmz > thzh - sprarea & & tmz < thzh ) // Don't damage people springing up / down
return true ;
}
2018-05-08 22:26:36 +00:00
2014-03-15 16:59:03 +00:00
// missiles can hit other things
if ( tmthing - > flags & MF_MISSILE | | tmthing - > type = = MT_SHELL )
{
// see if it went over / under
if ( tmthing - > z > thing - > z + thing - > height )
return true ; // overhead
if ( tmthing - > z + tmthing - > height < thing - > z )
return true ; // underneath
if ( tmthing - > type ! = MT_SHELL & & tmthing - > target & & tmthing - > target - > type = = thing - > type )
{
// Don't hit same species as originator.
if ( thing = = tmthing - > target )
return true ;
if ( thing - > type ! = MT_PLAYER )
{
// Explode, but do no damage.
// Let players missile other players.
return false ;
}
}
// Special case for bounce rings so they don't get caught behind solid objects.
if ( ( tmthing - > type = = MT_THROWNBOUNCE & & tmthing - > fuse > 8 * TICRATE ) & & thing - > flags & MF_SOLID )
return true ;
// Missiles ignore Brak's helper.
if ( thing - > type = = MT_BLACKEGGMAN_HELPER )
return true ;
// Hurting Brak
if ( tmthing - > type = = MT_BLACKEGGMAN_MISSILE
& & thing - > type = = MT_BLACKEGGMAN & & tmthing - > target ! = thing )
{
// Not if Brak's already in pain
if ( ! ( thing - > state > = & states [ S_BLACKEGG_PAIN1 ] & & thing - > state < = & states [ S_BLACKEGG_PAIN35 ] ) )
P_SetMobjState ( thing , thing - > info - > painstate ) ;
return false ;
}
if ( ! ( thing - > flags & MF_SHOOTABLE ) & & ! ( thing - > type = = MT_EGGSHIELD ) )
{
// didn't do any damage
return ! ( thing - > flags & MF_SOLID ) ;
}
if ( tmthing - > flags & MF_MISSILE & & thing - > player & & tmthing - > target & & tmthing - > target - > player
& & thing - > player - > ctfteam = = tmthing - > target - > player - > ctfteam
2016-09-23 22:48:48 +00:00
& & thing - > player - > powers [ pw_carry ] = = CR_PLAYER & & thing - > tracer = = tmthing - > target )
2014-03-15 16:59:03 +00:00
return true ; // Don't give rings to your carry player by accident.
if ( thing - > type = = MT_EGGSHIELD )
{
2018-05-08 22:26:36 +00:00
angle_t angle = ( R_PointToAngle2 ( thing - > x , thing - > y , tmthing - > x - tmthing - > momx , tmthing - > y - tmthing - > momy ) - thing - > angle ) - ANGLE_90 ;
2014-03-15 16:59:03 +00:00
2018-05-08 22:26:36 +00:00
if ( angle < ANGLE_180 ) // hit shield from behind, shield is destroyed!
2015-02-13 16:15:58 +00:00
P_KillMobj ( thing , tmthing , tmthing , 0 ) ;
2018-05-08 22:26:36 +00:00
return false ;
2014-03-15 16:59:03 +00:00
}
// damage / explode
if ( tmthing - > flags & MF_ENEMY ) // An actual ENEMY! (Like the deton, for example)
2015-02-13 16:15:58 +00:00
P_DamageMobj ( thing , tmthing , tmthing , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
else if ( tmthing - > type = = MT_BLACKEGGMAN_MISSILE & & thing - > player
& & ( thing - > player - > pflags & PF_JUMPED )
& & ! thing - > player - > powers [ pw_flashing ]
& & thing - > tracer ! = tmthing
& & tmthing - > target ! = thing )
{
// Hop on the missile for a ride!
2016-09-23 22:48:48 +00:00
thing - > player - > powers [ pw_carry ] = CR_GENERIC ;
2017-03-18 21:06:06 +00:00
thing - > player - > pflags & = ~ ( PF_JUMPED | PF_NOJUMPDAMAGE ) ;
2014-03-15 16:59:03 +00:00
P_SetTarget ( & thing - > tracer , tmthing ) ;
P_SetTarget ( & tmthing - > target , thing ) ; // Set owner to the player
P_SetTarget ( & tmthing - > tracer , NULL ) ; // Disable homing-ness
tmthing - > momz = 0 ;
thing - > angle = tmthing - > angle ;
2016-04-05 19:56:48 +00:00
if ( ! demoplayback | | P_AnalogMove ( thing - > player ) )
{
if ( thing - > player = = & players [ consoleplayer ] )
localangle = thing - > angle ;
else if ( thing - > player = = & players [ secondarydisplayplayer ] )
localangle2 = thing - > angle ;
}
2014-03-15 16:59:03 +00:00
return true ;
}
2016-09-23 22:48:48 +00:00
else if ( tmthing - > type = = MT_BLACKEGGMAN_MISSILE & & thing - > player & & ( ( thing - > player - > powers [ pw_carry ] = = CR_GENERIC ) | | ( thing - > player - > pflags & PF_JUMPED ) ) )
2014-03-15 16:59:03 +00:00
{
// Ignore
}
else if ( tmthing - > type = = MT_BLACKEGGMAN_GOOPFIRE )
{
P_UnsetThingPosition ( tmthing ) ;
tmthing - > x = thing - > x ;
tmthing - > y = thing - > y ;
P_SetThingPosition ( tmthing ) ;
}
2019-06-19 22:20:24 +00:00
else if ( ! ( tmthing - > type = = MT_SHELL & & thing - > player ) ) // player collision handled in touchspecial for shell
2018-04-28 14:13:44 +00:00
{
UINT8 damagetype = tmthing - > info - > mass ;
if ( ! damagetype & & tmthing - > flags & MF_FIRE ) // BURN!
damagetype = DMG_FIRE ;
P_DamageMobj ( thing , tmthing , tmthing - > target , 1 , damagetype ) ;
}
2014-03-15 16:59:03 +00:00
// don't traverse any more
if ( tmthing - > type = = MT_SHELL )
return true ;
else
return false ;
}
2014-08-04 03:49:33 +00:00
if ( thing - > flags & MF_PUSHABLE & & ( tmthing - > player | | tmthing - > flags & MF_PUSHABLE )
2014-03-15 16:59:03 +00:00
& & tmthing - > z + tmthing - > height > thing - > z & & tmthing - > z < thing - > z + thing - > height
& & ! ( netgame & & tmthing - > player & & tmthing - > player - > spectator ) ) // Push thing!
{
if ( thing - > flags2 & MF2_SLIDEPUSH ) // Make it slide
{
if ( tmthing - > momy > 0 & & tmthing - > momy > FixedMul ( 4 * FRACUNIT , thing - > scale ) & & tmthing - > momy > thing - > momy )
{
thing - > momy + = FixedMul ( PUSHACCEL , thing - > scale ) ;
tmthing - > momy - = FixedMul ( PUSHACCEL , thing - > scale ) ;
}
else if ( tmthing - > momy < 0 & & tmthing - > momy < FixedMul ( - 4 * FRACUNIT , thing - > scale )
& & tmthing - > momy < thing - > momy )
{
thing - > momy - = FixedMul ( PUSHACCEL , thing - > scale ) ;
tmthing - > momy + = FixedMul ( PUSHACCEL , thing - > scale ) ;
}
if ( tmthing - > momx > 0 & & tmthing - > momx > FixedMul ( 4 * FRACUNIT , thing - > scale )
& & tmthing - > momx > thing - > momx )
{
thing - > momx + = FixedMul ( PUSHACCEL , thing - > scale ) ;
tmthing - > momx - = FixedMul ( PUSHACCEL , thing - > scale ) ;
}
else if ( tmthing - > momx < 0 & & tmthing - > momx < FixedMul ( - 4 * FRACUNIT , thing - > scale )
& & tmthing - > momx < thing - > momx )
{
thing - > momx - = FixedMul ( PUSHACCEL , thing - > scale ) ;
tmthing - > momx + = FixedMul ( PUSHACCEL , thing - > scale ) ;
}
if ( thing - > momx > FixedMul ( thing - > info - > speed , thing - > scale ) )
thing - > momx = FixedMul ( thing - > info - > speed , thing - > scale ) ;
else if ( thing - > momx < - FixedMul ( thing - > info - > speed , thing - > scale ) )
thing - > momx = - FixedMul ( thing - > info - > speed , thing - > scale ) ;
if ( thing - > momy > FixedMul ( thing - > info - > speed , thing - > scale ) )
thing - > momy = FixedMul ( thing - > info - > speed , thing - > scale ) ;
else if ( thing - > momy < - FixedMul ( thing - > info - > speed , thing - > scale ) )
thing - > momy = - FixedMul ( thing - > info - > speed , thing - > scale ) ;
}
else
{
if ( tmthing - > momx > FixedMul ( 4 * FRACUNIT , thing - > scale ) )
tmthing - > momx = FixedMul ( 4 * FRACUNIT , thing - > scale ) ;
else if ( tmthing - > momx < FixedMul ( - 4 * FRACUNIT , thing - > scale ) )
tmthing - > momx = FixedMul ( - 4 * FRACUNIT , thing - > scale ) ;
if ( tmthing - > momy > FixedMul ( 4 * FRACUNIT , thing - > scale ) )
tmthing - > momy = FixedMul ( 4 * FRACUNIT , thing - > scale ) ;
else if ( tmthing - > momy < FixedMul ( - 4 * FRACUNIT , thing - > scale ) )
tmthing - > momy = FixedMul ( - 4 * FRACUNIT , thing - > scale ) ;
thing - > momx = tmthing - > momx ;
thing - > momy = tmthing - > momy ;
}
if ( thing - > type ! = MT_GARGOYLE | | P_IsObjectOnGround ( thing ) )
S_StartSound ( thing , thing - > info - > activesound ) ;
P_SetTarget ( & thing - > target , tmthing ) ;
}
2018-03-30 18:22:59 +00:00
// NiGHTS lap logic
2014-03-15 16:59:03 +00:00
if ( ( tmthing - > type = = MT_NIGHTSDRONE | | thing - > type = = MT_NIGHTSDRONE )
& & ( tmthing - > player | | thing - > player ) )
{
mobj_t * droneobj = ( tmthing - > type = = MT_NIGHTSDRONE ) ? tmthing : thing ;
player_t * pl = ( droneobj = = thing ) ? tmthing - > player : thing - > player ;
2018-03-30 18:36:49 +00:00
// Must be NiGHTS, must wait about a second
2014-03-15 16:59:03 +00:00
// must be flying in the SAME DIRECTION as the last time you came through.
// not (your direction) xor (stored direction)
// In other words, you can't u-turn and respawn rings near the drone.
2018-03-30 18:36:49 +00:00
if ( ( pl - > powers [ pw_carry ] = = CR_NIGHTSMODE ) & & ( INT32 ) leveltime > droneobj - > extravalue2 & & (
2018-03-26 05:04:02 +00:00
! ( pl - > flyangle > 90 & & pl - > flyangle < 270 )
^ ( droneobj - > extravalue1 > 90 & & droneobj - > extravalue1 < 270 )
2014-03-15 16:59:03 +00:00
) )
{
2018-03-30 18:36:49 +00:00
pl - > marelap + + ;
2018-08-12 23:57:33 +00:00
pl - > totalmarelap + + ;
2018-08-10 21:12:26 +00:00
pl - > lapbegunat = leveltime ;
pl - > lapstartedtime = pl - > nightstime ;
2018-03-30 18:36:49 +00:00
2018-08-12 23:57:33 +00:00
if ( pl - > bonustime )
2018-03-30 18:36:49 +00:00
{
pl - > marebonuslap + + ;
2018-08-12 23:57:33 +00:00
pl - > totalmarebonuslap + + ;
2018-03-30 18:36:49 +00:00
// Respawn rings and items
P_ReloadRings ( ) ;
}
2018-03-30 18:22:59 +00:00
P_RunNightsLapExecutors ( pl - > mo ) ;
2014-03-15 16:59:03 +00:00
}
2018-03-26 04:33:17 +00:00
droneobj - > extravalue1 = pl - > flyangle ;
2014-03-15 16:59:03 +00:00
droneobj - > extravalue2 = ( INT32 ) leveltime + TICRATE ;
}
// check for special pickup
if ( thing - > flags & MF_SPECIAL & & tmthing - > player )
{
P_TouchSpecialThing ( thing , tmthing , true ) ; // can remove thing
return true ;
}
// check again for special pickup
if ( tmthing - > flags & MF_SPECIAL & & thing - > player )
{
P_TouchSpecialThing ( tmthing , thing , true ) ; // can remove thing
return true ;
}
// Sprite Spikes!
// Do not return because solidity code comes below.
2014-08-04 03:49:33 +00:00
if ( tmthing - > type = = MT_SPIKE & & tmthing - > flags & MF_SOLID & & thing - > player ) // moving spike rams into player?!
2014-03-15 16:59:03 +00:00
{
if ( tmthing - > eflags & MFE_VERTICALFLIP )
{
if ( thing - > z + thing - > height < = tmthing - > z + FixedMul ( FRACUNIT , tmthing - > scale )
2017-03-21 00:54:47 +00:00
& & thing - > z + thing - > height + thing - > momz > = tmthing - > z + FixedMul ( FRACUNIT , tmthing - > scale ) + tmthing - > momz
& & ! ( thing - > player - > charability = = CA_BOUNCE & & thing - > player - > panim = = PA_ABILITY & & thing - > eflags & MFE_VERTICALFLIP ) )
2017-07-18 13:17:10 +00:00
P_DamageMobj ( thing , tmthing , tmthing , 1 , DMG_SPIKE ) ;
2014-03-15 16:59:03 +00:00
}
else if ( thing - > z > = tmthing - > z + tmthing - > height - FixedMul ( FRACUNIT , tmthing - > scale )
2017-03-21 00:54:47 +00:00
& & thing - > z + thing - > momz < = tmthing - > z + tmthing - > height - FixedMul ( FRACUNIT , tmthing - > scale ) + tmthing - > momz
& & ! ( thing - > player - > charability = = CA_BOUNCE & & thing - > player - > panim = = PA_ABILITY & & ! ( thing - > eflags & MFE_VERTICALFLIP ) ) )
2017-07-18 13:17:10 +00:00
P_DamageMobj ( thing , tmthing , tmthing , 1 , DMG_SPIKE ) ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
else if ( thing - > type = = MT_SPIKE & & thing - > flags & MF_SOLID & & tmthing - > player ) // unfortunate player falls into spike?!
2014-03-15 16:59:03 +00:00
{
if ( thing - > eflags & MFE_VERTICALFLIP )
{
if ( tmthing - > z + tmthing - > height < = thing - > z - FixedMul ( FRACUNIT , thing - > scale )
2017-03-21 00:54:47 +00:00
& & tmthing - > z + tmthing - > height + tmthing - > momz > = thing - > z - FixedMul ( FRACUNIT , thing - > scale )
& & ! ( tmthing - > player - > charability = = CA_BOUNCE & & tmthing - > player - > panim = = PA_ABILITY & & tmthing - > eflags & MFE_VERTICALFLIP ) )
2017-07-18 13:17:10 +00:00
P_DamageMobj ( tmthing , thing , thing , 1 , DMG_SPIKE ) ;
2014-03-15 16:59:03 +00:00
}
else if ( tmthing - > z > = thing - > z + thing - > height + FixedMul ( FRACUNIT , thing - > scale )
2017-03-21 00:54:47 +00:00
& & tmthing - > z + tmthing - > momz < = thing - > z + thing - > height + FixedMul ( FRACUNIT , thing - > scale )
& & ! ( tmthing - > player - > charability = = CA_BOUNCE & & tmthing - > player - > panim = = PA_ABILITY & & ! ( tmthing - > eflags & MFE_VERTICALFLIP ) ) )
2017-07-18 13:17:10 +00:00
P_DamageMobj ( tmthing , thing , thing , 1 , DMG_SPIKE ) ;
2014-03-15 16:59:03 +00:00
}
2017-07-13 22:00:45 +00:00
if ( tmthing - > type = = MT_WALLSPIKE & & tmthing - > flags & MF_SOLID & & thing - > player ) // wall spike impales player
{
fixed_t bottomz , topz ;
bottomz = tmthing - > z ;
topz = tmthing - > z + tmthing - > height ;
if ( tmthing - > eflags & MFE_VERTICALFLIP )
bottomz - = FixedMul ( FRACUNIT , tmthing - > scale ) ;
else
topz + = FixedMul ( FRACUNIT , tmthing - > scale ) ;
2017-07-14 16:01:13 +00:00
if ( thing - > z + thing - > height > bottomz // above bottom
2017-07-13 22:00:45 +00:00
& & thing - > z < topz ) // below top
2017-07-18 13:17:10 +00:00
// don't check angle, the player was clearly in the way in this case
2017-07-13 22:00:45 +00:00
P_DamageMobj ( thing , tmthing , tmthing , 1 , DMG_SPIKE ) ;
}
else if ( thing - > type = = MT_WALLSPIKE & & thing - > flags & MF_SOLID & & tmthing - > player )
{
fixed_t bottomz , topz ;
2017-07-30 15:52:39 +00:00
angle_t touchangle = R_PointToAngle2 ( thing - > tracer - > x , thing - > tracer - > y , tmthing - > x , tmthing - > y ) ;
2017-07-30 16:45:27 +00:00
if ( P_PlayerInPain ( tmthing - > player ) & & ( tmthing - > momx | | tmthing - > momy ) )
{
angle_t playerangle = R_PointToAngle2 ( 0 , 0 , tmthing - > momx , tmthing - > momy ) - touchangle ;
if ( playerangle > ANGLE_180 )
playerangle = InvAngle ( playerangle ) ;
if ( playerangle < ANGLE_90 )
return true ; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them.
}
2017-07-30 15:52:39 +00:00
2017-07-13 22:00:45 +00:00
bottomz = thing - > z ;
topz = thing - > z + thing - > height ;
2017-07-18 13:17:10 +00:00
2017-07-13 22:00:45 +00:00
if ( thing - > eflags & MFE_VERTICALFLIP )
bottomz - = FixedMul ( FRACUNIT , thing - > scale ) ;
else
topz + = FixedMul ( FRACUNIT , thing - > scale ) ;
2017-07-14 16:01:13 +00:00
if ( tmthing - > z + tmthing - > height > bottomz // above bottom
2017-07-13 22:00:45 +00:00
& & tmthing - > z < topz // below top
& & ! P_MobjWasRemoved ( thing - > tracer ) ) // this probably wouldn't work if we didn't have a tracer
{ // use base as a reference point to determine what angle you touched the spike at
2017-07-18 13:17:10 +00:00
touchangle = thing - > angle - touchangle ;
if ( touchangle > ANGLE_180 )
touchangle = InvAngle ( touchangle ) ;
if ( touchangle < = ANGLE_22h ) // if you touched it at this close an angle, you get poked!
2017-07-13 22:00:45 +00:00
P_DamageMobj ( tmthing , thing , thing , 1 , DMG_SPIKE ) ;
}
2014-03-15 16:59:03 +00:00
}
if ( thing - > flags & MF_PUSHABLE )
{
2014-11-12 00:55:07 +00:00
if ( tmthing - > type = = MT_FAN | | tmthing - > type = = MT_STEAM )
P_DoFanAndGasJet ( tmthing , thing ) ;
2014-03-15 16:59:03 +00:00
}
if ( tmthing - > flags & MF_PUSHABLE )
{
2014-11-12 00:55:07 +00:00
if ( thing - > type = = MT_FAN | | thing - > type = = MT_STEAM )
2018-05-02 19:03:18 +00:00
{
2014-11-12 00:55:07 +00:00
P_DoFanAndGasJet ( thing , tmthing ) ;
2018-05-02 19:03:18 +00:00
return true ;
}
2015-02-11 20:54:11 +00:00
else if ( thing - > flags & MF_SPRING )
2014-03-15 16:59:03 +00:00
{
2015-02-11 20:54:11 +00:00
if ( thing - > z < = tmthing - > z + tmthing - > height
& & tmthing - > z < = thing - > z + thing - > height )
2018-05-02 19:03:18 +00:00
if ( P_DoSpring ( thing , tmthing ) )
return false ;
return true ;
2014-03-15 16:59:03 +00:00
}
}
2018-05-08 22:26:36 +00:00
// thanks to sal for solidenemies dot lua
if ( thing - > flags & ( MF_ENEMY | MF_BOSS ) & & tmthing - > flags & ( MF_ENEMY | MF_BOSS ) )
{
if ( ( thing - > z + thing - > height > = tmthing - > z )
& & ( tmthing - > z + tmthing - > height > = thing - > z ) )
return false ;
}
2014-03-15 16:59:03 +00:00
// Damage other players when invincible
if ( tmthing - > player & & thing - > player
// Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person.
& & ! ( thing - > z + thing - > height < tmthing - > z | | thing - > z > tmthing - > z + tmthing - > height ) )
{
if ( G_RingSlingerGametype ( ) & & ( ! G_GametypeHasTeams ( ) | | tmthing - > player - > ctfteam ! = thing - > player - > ctfteam ) )
{
2016-07-08 20:55:17 +00:00
if ( ( tmthing - > player - > powers [ pw_invulnerability ] | | tmthing - > player - > powers [ pw_super ] | | ( ( ( tmthing - > player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL ) & & ( tmthing - > player - > pflags & PF_SHIELDABILITY ) ) )
2014-03-15 16:59:03 +00:00
& & ! thing - > player - > powers [ pw_super ] )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( thing , tmthing , tmthing , 1 , 0 ) ;
2016-07-08 20:55:17 +00:00
else if ( ( thing - > player - > powers [ pw_invulnerability ] | | thing - > player - > powers [ pw_super ] | | ( ( ( thing - > player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL ) & & ( thing - > player - > pflags & PF_SHIELDABILITY ) ) )
2014-03-15 16:59:03 +00:00
& & ! tmthing - > player - > powers [ pw_super ] )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( tmthing , thing , thing , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
}
// If players are using touch tag, seekers damage hiders.
if ( G_TagGametype ( ) & & cv_touchtag . value & &
( ( thing - > player - > pflags & PF_TAGIT ) ! = ( tmthing - > player - > pflags & PF_TAGIT ) ) )
{
if ( ( tmthing - > player - > pflags & PF_TAGIT ) & & ! ( thing - > player - > pflags & PF_TAGIT ) )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( thing , tmthing , tmthing , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
else if ( ( thing - > player - > pflags & PF_TAGIT ) & & ! ( tmthing - > player - > pflags & PF_TAGIT ) )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( tmthing , thing , tmthing , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
}
}
// Force solid players in hide and seek to avoid corner stacking.
if ( cv_tailspickup . value & & gametype ! = GT_HIDEANDSEEK )
{
if ( tmthing - > player & & thing - > player )
{
2014-11-12 00:55:07 +00:00
P_DoTailsCarry ( thing - > player , tmthing - > player ) ;
2014-03-15 16:59:03 +00:00
return true ;
}
}
else if ( thing - > player ) {
if ( thing - > player - players = = consoleplayer & & botingame )
CV_SetValue ( & cv_analog2 , true ) ;
2016-09-23 22:48:48 +00:00
if ( thing - > player - > powers [ pw_carry ] = = CR_PLAYER )
2017-03-14 18:11:17 +00:00
{
P_SetTarget ( & thing - > tracer , NULL ) ;
2016-09-23 22:48:48 +00:00
thing - > player - > powers [ pw_carry ] = CR_NONE ;
2017-03-14 18:11:17 +00:00
}
2014-03-15 16:59:03 +00:00
}
if ( thing - > player )
{
2014-11-12 00:55:07 +00:00
// Doesn't matter what gravity player's following! Just do your stuff in YOUR direction only
if ( tmthing - > eflags & MFE_VERTICALFLIP
2015-01-20 19:42:10 +00:00
& & ( tmthing - > z + tmthing - > height + tmthing - > momz < thing - > z
2014-11-12 00:55:07 +00:00
| | tmthing - > z + tmthing - > height + tmthing - > momz > = thing - > z + thing - > height ) )
;
else if ( ! ( tmthing - > eflags & MFE_VERTICALFLIP )
& & ( tmthing - > z + tmthing - > momz > thing - > z + thing - > height
| | tmthing - > z + tmthing - > momz < = thing - > z ) )
;
else if ( P_IsObjectOnGround ( thing )
& & ! P_IsObjectOnGround ( tmthing ) // Don't crush if the monitor is on the ground...
& & ( tmthing - > flags & MF_SOLID ) )
2014-03-15 16:59:03 +00:00
{
2014-11-12 00:55:07 +00:00
if ( tmthing - > flags & ( MF_MONITOR | MF_PUSHABLE ) )
2014-03-15 16:59:03 +00:00
{
2014-11-12 00:55:07 +00:00
// Objects kill you if it falls from above.
if ( thing ! = tmthing - > target )
2018-05-08 22:26:36 +00:00
P_DamageMobj ( thing , tmthing , tmthing - > target , 1 , DMG_CRUSHED ) ;
2014-03-15 16:59:03 +00:00
2014-11-12 00:55:07 +00:00
tmthing - > momz = - tmthing - > momz / 2 ; // Bounce, just for fun!
// The tmthing->target allows the pusher of the object
// to get the point if he topples it on an opponent.
2014-03-15 16:59:03 +00:00
}
}
2014-11-12 00:55:07 +00:00
if ( tmthing - > type = = MT_FAN | | tmthing - > type = = MT_STEAM )
P_DoFanAndGasJet ( tmthing , thing ) ;
2014-03-15 16:59:03 +00:00
}
if ( tmthing - > player ) // Is the moving/interacting object the player?
{
if ( ! tmthing - > health )
return true ;
2014-11-12 00:55:07 +00:00
if ( thing - > type = = MT_FAN | | thing - > type = = MT_STEAM )
P_DoFanAndGasJet ( thing , tmthing ) ;
2019-06-13 19:45:30 +00:00
else if ( thing - > flags & MF_SPRING & & tmthing - > player - > powers [ pw_carry ] ! = CR_MINECART )
2015-02-11 20:54:11 +00:00
{
if ( thing - > z < = tmthing - > z + tmthing - > height
& & tmthing - > z < = thing - > z + thing - > height )
2018-05-02 19:03:18 +00:00
if ( P_DoSpring ( thing , tmthing ) )
return false ;
return true ;
2015-02-11 20:54:11 +00:00
}
2018-05-02 19:55:07 +00:00
// Monitor?
else if ( thing - > flags & MF_MONITOR
2019-06-19 11:09:02 +00:00
& & ! ( ( thing - > type = = MT_RING_REDBOX & & tmthing - > player - > ctfteam ! = 1 ) | | ( thing - > type = = MT_RING_BLUEBOX & & tmthing - > player - > ctfteam ! = 2 ) )
& & ( ! ( thing - > flags & MF_SOLID ) | | P_PlayerCanDamage ( tmthing - > player , thing ) ) )
2014-03-15 16:59:03 +00:00
{
2019-06-19 11:09:02 +00:00
if ( thing - > z - thing - > scale < = tmthing - > z + tmthing - > height
& & thing - > z + thing - > height + thing - > scale > = tmthing - > z )
2014-03-15 16:59:03 +00:00
{
2019-06-19 11:09:02 +00:00
player_t * player = tmthing - > player ;
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
UINT8 elementalpierce = ( ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL | | ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_BUBBLEWRAP ) & & ( player - > pflags & PF_SHIELDABILITY )
? ( ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL ) ? 1 : 2 )
: 0 ) ;
SINT8 flipval = P_MobjFlip ( thing ) ; // Save this value in case monitor gets removed.
fixed_t * momz = & tmthing - > momz ; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
fixed_t * z = & tmthing - > z ; // aau.
// Going down? Then bounce back up.
if ( P_DamageMobj ( thing , tmthing , tmthing , 1 , 0 ) // break the monitor
& & ( flipval * ( * momz ) < 0 ) // monitor is on the floor and you're going down, or on the ceiling and you're going up
& & ( elementalpierce ! = 1 ) ) // you're not piercing through the monitor...
2016-10-24 12:33:10 +00:00
{
2019-06-19 11:09:02 +00:00
if ( elementalpierce = = 2 )
P_DoBubbleBounce ( player ) ;
else if ( ! ( player - > charability2 = = CA2_MELEE & & player - > panim = = PA_ABILITY2 ) )
2019-06-26 22:26:05 +00:00
{
2019-06-19 11:09:02 +00:00
* momz = - * momz ; // Therefore, you should be thrust in the opposite direction, vertically.
2019-06-26 22:26:05 +00:00
if ( player - > charability = = CA_TWINSPIN & & player - > panim = = PA_ABILITY )
P_TwinSpinRejuvenate ( player , player - > thokitem ) ;
}
2016-12-24 00:11:54 +00:00
}
2019-06-19 11:09:02 +00:00
if ( ! ( elementalpierce = = 1 & & thing - > flags & MF_GRENADEBOUNCE ) ) // prevent gold monitor clipthrough.
{
if ( player - > pflags & PF_BOUNCING )
P_DoAbilityBounce ( player , false ) ;
return false ;
}
else
* z - = * momz ; // to ensure proper collision.
2014-03-15 16:59:03 +00:00
}
2019-06-19 11:09:02 +00:00
return true ;
2014-03-15 16:59:03 +00:00
}
}
2018-05-02 19:03:18 +00:00
if ( ( ! tmthing - > player ) & & ( thing - > player ) )
2017-07-18 13:17:10 +00:00
; // no solid thing should ever be able to step up onto a player
2014-03-15 16:59:03 +00:00
// z checking at last
// Treat noclip things as non-solid!
2014-08-04 03:49:33 +00:00
else if ( ( thing - > flags & ( MF_SOLID | MF_NOCLIP ) ) = = MF_SOLID
& & ( tmthing - > flags & ( MF_SOLID | MF_NOCLIP ) ) = = MF_SOLID )
2014-03-15 16:59:03 +00:00
{
2014-11-12 00:55:07 +00:00
fixed_t topz , tmtopz ;
2014-03-15 16:59:03 +00:00
if ( tmthing - > eflags & MFE_VERTICALFLIP )
{
// pass under
tmtopz = tmthing - > z ;
if ( tmtopz > thing - > z + thing - > height )
{
if ( thing - > z + thing - > height > tmfloorz )
{
tmfloorz = thing - > z + thing - > height ;
2018-09-10 03:12:37 +00:00
tmfloorrover = NULL ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmfloorslope = NULL ;
# endif
2014-03-15 16:59:03 +00:00
}
return true ;
}
2016-09-22 20:15:12 +00:00
topz = thing - > z - thing - > scale ; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
2014-03-15 16:59:03 +00:00
// block only when jumping not high enough,
// (dont climb max. 24units while already in air)
2016-09-22 10:15:08 +00:00
// since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high
2018-05-02 19:03:18 +00:00
if ( tmthing - > player & & tmthing - > z + tmthing - > height > topz
2014-03-15 16:59:03 +00:00
& & tmthing - > z + tmthing - > height < tmthing - > ceilingz )
2016-09-22 10:15:08 +00:00
{
2018-05-02 19:35:20 +00:00
if ( thing - > flags & MF_GRENADEBOUNCE & & ( thing - > flags & MF_MONITOR | | thing - > info - > flags & MF_MONITOR ) ) // Gold monitor hack...
2016-10-30 14:09:51 +00:00
return false ;
2017-01-16 17:52:06 +00:00
tmfloorz = tmceilingz = topz ; // block while in air
2018-09-10 03:12:37 +00:00
tmceilingrover = NULL ;
2016-09-22 10:15:08 +00:00
# ifdef ESLOPE
tmceilingslope = NULL ;
# endif
tmfloorthing = thing ; // needed for side collision
}
2016-09-21 23:13:34 +00:00
else if ( topz < tmceilingz & & tmthing - > z < = thing - > z + thing - > height )
2014-03-15 16:59:03 +00:00
{
tmceilingz = topz ;
2018-09-10 03:12:37 +00:00
tmceilingrover = NULL ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmceilingslope = NULL ;
# endif
2014-03-15 16:59:03 +00:00
tmfloorthing = thing ; // thing we may stand on
}
}
else
{
// pass under
tmtopz = tmthing - > z + tmthing - > height ;
if ( tmtopz < thing - > z )
{
if ( thing - > z < tmceilingz )
{
tmceilingz = thing - > z ;
2018-09-10 03:12:37 +00:00
tmceilingrover = NULL ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmceilingslope = NULL ;
# endif
2014-03-15 16:59:03 +00:00
}
return true ;
}
2016-09-22 20:15:12 +00:00
topz = thing - > z + thing - > height + thing - > scale ; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
2014-03-15 16:59:03 +00:00
// block only when jumping not high enough,
// (dont climb max. 24units while already in air)
2016-09-22 10:15:08 +00:00
// since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high
2018-05-02 19:03:18 +00:00
if ( tmthing - > player & & tmthing - > z < topz
2016-09-22 10:15:08 +00:00
& & tmthing - > z > tmthing - > floorz )
{
2018-05-02 19:35:20 +00:00
if ( thing - > flags & MF_GRENADEBOUNCE & & ( thing - > flags & MF_MONITOR | | thing - > info - > flags & MF_MONITOR ) ) // Gold monitor hack...
2016-10-30 14:09:51 +00:00
return false ;
2017-01-16 17:52:06 +00:00
tmfloorz = tmceilingz = topz ; // block while in air
2018-09-10 03:12:37 +00:00
tmfloorrover = NULL ;
2016-09-22 10:15:08 +00:00
# ifdef ESLOPE
tmfloorslope = NULL ;
# endif
tmfloorthing = thing ; // needed for side collision
}
2016-09-21 23:13:34 +00:00
else if ( topz > tmfloorz & & tmthing - > z + tmthing - > height > = thing - > z )
2014-03-15 16:59:03 +00:00
{
tmfloorz = topz ;
2018-09-10 03:12:37 +00:00
tmfloorrover = NULL ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmfloorslope = NULL ;
# endif
2014-03-15 16:59:03 +00:00
tmfloorthing = thing ; // thing we may stand on
}
}
}
// not solid not blocked
return true ;
}
// PIT_CheckCameraLine
// Adjusts tmfloorz and tmceilingz as lines are contacted - FOR CAMERA ONLY
static boolean PIT_CheckCameraLine ( line_t * ld )
{
if ( ld - > polyobj & & ! ( ld - > polyobj - > flags & POF_SOLID ) )
return true ;
if ( tmbbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | | tmbbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ]
| | tmbbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | | tmbbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
{
return true ;
}
if ( P_BoxOnLineSide ( tmbbox , ld ) ! = - 1 )
return true ;
// A line has been hit
// The moving thing's destination position will cross
// the given line.
// If this should not be allowed, return false.
// If the line is special, keep track of it
// to process later if the move is proven ok.
// NOTE: specials are NOT sorted by order,
// so two special lines that are only 8 pixels apart
// could be crossed in either order.
// this line is out of the if so upper and lower textures can be hit by a splat
blockingline = ld ;
if ( ! ld - > backsector ) // one sided line
{
if ( P_PointOnLineSide ( mapcampointer - > x , mapcampointer - > y , ld ) )
return true ; // don't hit the back side
return false ;
}
// set openrange, opentop, openbottom
P_CameraLineOpening ( ld ) ;
// adjust floor / ceiling heights
if ( opentop < tmceilingz )
{
tmceilingz = opentop ;
ceilingline = ld ;
}
if ( openbottom > tmfloorz )
{
tmfloorz = openbottom ;
}
2014-08-04 03:49:33 +00:00
if ( highceiling > tmdrpoffceilz )
tmdrpoffceilz = highceiling ;
2014-03-15 16:59:03 +00:00
if ( lowfloor < tmdropoffz )
tmdropoffz = lowfloor ;
return true ;
}
//
// PIT_CheckLine
// Adjusts tmfloorz and tmceilingz as lines are contacted
//
static boolean PIT_CheckLine ( line_t * ld )
{
if ( ld - > polyobj & & ! ( ld - > polyobj - > flags & POF_SOLID ) )
return true ;
if ( tmbbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | | tmbbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ]
| | tmbbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | | tmbbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
return true ;
if ( P_BoxOnLineSide ( tmbbox , ld ) ! = - 1 )
return true ;
2016-08-20 14:15:48 +00:00
if ( tmthing - > flags & MF_PAPERCOLLISION ) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag.
2016-08-18 19:55:24 +00:00
{
2016-08-18 21:20:42 +00:00
fixed_t cosradius , sinradius ;
cosradius = FixedMul ( tmthing - > radius , FINECOSINE ( tmthing - > angle > > ANGLETOFINESHIFT ) ) ;
sinradius = FixedMul ( tmthing - > radius , FINESINE ( tmthing - > angle > > ANGLETOFINESHIFT ) ) ;
2016-08-18 19:55:24 +00:00
if ( P_PointOnLineSide ( tmx - cosradius , tmy - sinradius , ld )
= = P_PointOnLineSide ( tmx + cosradius , tmy + sinradius , ld ) )
return true ; // the line doesn't cross between collider's start or end
2016-08-18 21:20:42 +00:00
# ifdef PAPER_COLLISIONCORRECTION
{
fixed_t dist ;
vertex_t result ;
angle_t langle ;
P_ClosestPointOnLine ( tmx , tmy , ld , & result ) ;
langle = R_PointToAngle2 ( ld - > v1 - > x , ld - > v1 - > y , ld - > v2 - > x , ld - > v2 - > y ) ;
langle + = ANGLE_90 * ( P_PointOnLineSide ( tmx , tmy , ld ) ? - 1 : 1 ) ;
dist = abs ( FixedMul ( tmthing - > radius , FINECOSINE ( ( tmthing - > angle - langle ) > > ANGLETOFINESHIFT ) ) ) ;
cosradius = FixedMul ( dist , FINECOSINE ( langle > > ANGLETOFINESHIFT ) ) ;
sinradius = FixedMul ( dist , FINESINE ( langle > > ANGLETOFINESHIFT ) ) ;
tmthing - > flags | = MF_NOCLIP ;
P_TeleportMove ( tmthing , result . x + cosradius - tmthing - > momx , result . y + sinradius - tmthing - > momy , tmthing - > z ) ;
tmthing - > flags & = ~ MF_NOCLIP ;
}
# endif
2016-08-18 19:55:24 +00:00
}
2014-03-15 16:59:03 +00:00
// A line has been hit
// The moving thing's destination position will cross
// the given line.
// If this should not be allowed, return false.
// If the line is special, keep track of it
// to process later if the move is proven ok.
// NOTE: specials are NOT sorted by order,
// so two special lines that are only 8 pixels apart
// could be crossed in either order.
// this line is out of the if so upper and lower textures can be hit by a splat
blockingline = ld ;
if ( ! ld - > backsector ) // one sided line
{
if ( P_PointOnLineSide ( tmthing - > x , tmthing - > y , ld ) )
return true ; // don't hit the back side
return false ;
}
// missiles can cross uncrossable lines
if ( ! ( tmthing - > flags & MF_MISSILE ) )
{
if ( ld - > flags & ML_IMPASSIBLE ) // block objects from moving through this linedef.
return false ;
2014-08-04 03:49:33 +00:00
if ( ( tmthing - > flags & ( MF_ENEMY | MF_BOSS ) ) & & ld - > flags & ML_BLOCKMONSTERS )
2014-03-15 16:59:03 +00:00
return false ; // block monsters only
}
// set openrange, opentop, openbottom
2016-08-13 20:41:18 +00:00
P_LineOpening ( ld , tmthing ) ;
2014-03-15 16:59:03 +00:00
// adjust floor / ceiling heights
if ( opentop < tmceilingz )
{
tmceilingz = opentop ;
ceilingline = ld ;
2019-08-01 19:17:15 +00:00
tmceilingrover = openceilingrover ;
2016-04-06 21:19:39 +00:00
# ifdef ESLOPE
2015-04-29 05:33:04 +00:00
tmceilingslope = opentopslope ;
2016-04-06 21:19:39 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
if ( openbottom > tmfloorz )
{
tmfloorz = openbottom ;
2019-08-01 19:17:15 +00:00
tmfloorrover = openfloorrover ;
2016-04-06 21:19:39 +00:00
# ifdef ESLOPE
2015-04-29 05:33:04 +00:00
tmfloorslope = openbottomslope ;
2016-04-06 21:19:39 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
if ( highceiling > tmdrpoffceilz )
tmdrpoffceilz = highceiling ;
2014-03-15 16:59:03 +00:00
if ( lowfloor < tmdropoffz )
tmdropoffz = lowfloor ;
return true ;
}
// =========================================================================
// MOVEMENT CLIPPING
// =========================================================================
//
// P_CheckPosition
// This is purely informative, nothing is modified
// (except things picked up).
//
// in:
// a mobj_t (can be valid or invalid)
// a position to be checked
// (doesn't need to be related to the mobj_t->x,y)
//
// during:
// special things are touched if MF_PICKUP
// early out on solid lines?
//
// out:
// newsubsec
// tmfloorz
// tmceilingz
// tmdropoffz
2014-08-04 03:49:33 +00:00
// tmdrpoffceilz
2014-03-15 16:59:03 +00:00
// the lowest point contacted
// (monsters won't move to a dropoff)
// speciallines[]
// numspeciallines
//
// tmfloorz
// the nearest floor or thing's top under tmthing
// tmceilingz
// the nearest ceiling or thing's bottom over tmthing
//
boolean P_CheckPosition ( mobj_t * thing , fixed_t x , fixed_t y )
{
INT32 xl , xh , yl , yh , bx , by ;
subsector_t * newsubsec ;
boolean blockval = true ;
I_Assert ( thing ! = NULL ) ;
# ifdef PARANOIA
if ( P_MobjWasRemoved ( thing ) )
I_Error ( " Previously-removed Thing of type %u crashes P_CheckPosition! " , thing - > type ) ;
# endif
P_SetTarget ( & tmthing , thing ) ;
tmflags = thing - > flags ;
tmx = x ;
tmy = y ;
tmbbox [ BOXTOP ] = y + tmthing - > radius ;
tmbbox [ BOXBOTTOM ] = y - tmthing - > radius ;
tmbbox [ BOXRIGHT ] = x + tmthing - > radius ;
tmbbox [ BOXLEFT ] = x - tmthing - > radius ;
newsubsec = R_PointInSubsector ( x , y ) ;
ceilingline = blockingline = NULL ;
// The base floor / ceiling is from the subsector
// that contains the point.
// Any contacted lines the step closer together
// will adjust them.
2015-04-29 05:29:51 +00:00
tmfloorz = tmdropoffz = P_GetFloorZ ( thing , newsubsec - > sector , x , y , NULL ) ; //newsubsec->sector->floorheight;
tmceilingz = P_GetCeilingZ ( thing , newsubsec - > sector , x , y , NULL ) ; //newsubsec->sector->ceilingheight;
2018-09-10 03:12:37 +00:00
tmfloorrover = NULL ;
tmceilingrover = NULL ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmfloorslope = newsubsec - > sector - > f_slope ;
tmceilingslope = newsubsec - > sector - > c_slope ;
# endif
2014-03-15 16:59:03 +00:00
// Check list of fake floors and see if tmfloorz/tmceilingz need to be altered.
if ( newsubsec - > sector - > ffloors )
{
ffloor_t * rover ;
fixed_t delta1 , delta2 ;
INT32 thingtop = thing - > z + thing - > height ;
for ( rover = newsubsec - > sector - > ffloors ; rover ; rover = rover - > next )
{
2015-10-10 16:57:35 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
2015-10-10 16:57:35 +00:00
topheight = P_GetFOFTopZ ( thing , newsubsec - > sector , rover , x , y , NULL ) ;
bottomheight = P_GetFOFBottomZ ( thing , newsubsec - > sector , rover , x , y , NULL ) ;
2014-11-19 00:45:57 +00:00
2016-09-02 21:53:55 +00:00
if ( ( rover - > flags & ( FF_SWIMMABLE | FF_GOOWATER ) ) = = ( FF_SWIMMABLE | FF_GOOWATER ) & & ! ( thing - > flags & MF_NOGRAVITY ) )
2014-03-15 16:59:03 +00:00
{
// If you're inside goowater and slowing down
fixed_t sinklevel = FixedMul ( thing - > info - > height / 6 , thing - > scale ) ;
2015-04-04 22:38:20 +00:00
fixed_t minspeed = FixedMul ( thing - > info - > height / 9 , thing - > scale ) ;
2014-11-19 00:45:57 +00:00
if ( thing - > z < topheight & & bottomheight < thingtop
2014-03-15 16:59:03 +00:00
& & abs ( thing - > momz ) < minspeed )
{
// Oh no! The object is stick in between the surface of the goo and sinklevel! help them out!
2014-11-19 00:45:57 +00:00
if ( ! ( thing - > eflags & MFE_VERTICALFLIP ) & & thing - > z > topheight - sinklevel
2014-03-15 16:59:03 +00:00
& & thing - > momz > = 0 & & thing - > momz < ( minspeed > > 2 ) )
thing - > momz + = minspeed > > 2 ;
2014-11-19 00:45:57 +00:00
else if ( thing - > eflags & MFE_VERTICALFLIP & & thingtop < bottomheight + sinklevel
2014-03-15 16:59:03 +00:00
& & thing - > momz < = 0 & & thing - > momz > - ( minspeed > > 2 ) )
thing - > momz - = minspeed > > 2 ;
// Land on the top or the bottom, depending on gravity flip.
2014-11-19 00:45:57 +00:00
if ( ! ( thing - > eflags & MFE_VERTICALFLIP ) & & thing - > z > = topheight - sinklevel & & thing - > momz < = 0 )
2014-03-15 16:59:03 +00:00
{
2015-04-29 05:33:04 +00:00
if ( tmfloorz < topheight - sinklevel ) {
2014-11-19 00:45:57 +00:00
tmfloorz = topheight - sinklevel ;
2018-09-10 03:12:37 +00:00
tmfloorrover = rover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
2015-05-17 16:53:28 +00:00
tmfloorslope = * rover - > t_slope ;
2015-04-29 05:33:04 +00:00
# endif
}
2014-03-15 16:59:03 +00:00
}
2014-11-19 00:45:57 +00:00
else if ( thing - > eflags & MFE_VERTICALFLIP & & thingtop < = bottomheight + sinklevel & & thing - > momz > = 0 )
2014-03-15 16:59:03 +00:00
{
2015-04-29 05:33:04 +00:00
if ( tmceilingz > bottomheight + sinklevel ) {
2014-11-19 00:45:57 +00:00
tmceilingz = bottomheight + sinklevel ;
2018-09-10 03:12:37 +00:00
tmceilingrover = rover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
2015-05-17 16:53:28 +00:00
tmceilingslope = * rover - > b_slope ;
2015-04-29 05:33:04 +00:00
# endif
}
2014-03-15 16:59:03 +00:00
}
}
continue ;
}
if ( thing - > player & & ( P_CheckSolidLava ( thing , rover ) | | P_CanRunOnWater ( thing - > player , rover ) ) )
;
else if ( thing - > type = = MT_SKIM & & ( rover - > flags & FF_SWIMMABLE ) )
;
2014-11-12 00:55:07 +00:00
else if ( ! ( ( rover - > flags & FF_BLOCKPLAYER & & thing - > player )
2016-12-23 23:58:12 +00:00
| | ( rover - > flags & FF_BLOCKOTHERS & & ! thing - > player )
2014-03-15 16:59:03 +00:00
| | rover - > flags & FF_QUICKSAND ) )
continue ;
if ( rover - > flags & FF_QUICKSAND )
{
2014-11-19 00:45:57 +00:00
if ( thing - > z < topheight & & bottomheight < thingtop )
2014-03-15 16:59:03 +00:00
{
2015-04-29 05:33:04 +00:00
if ( tmfloorz < thing - > z ) {
2014-03-15 16:59:03 +00:00
tmfloorz = thing - > z ;
2018-09-10 03:12:37 +00:00
tmfloorrover = rover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmfloorslope = NULL ;
# endif
}
2014-03-15 16:59:03 +00:00
}
// Quicksand blocks never change heights otherwise.
continue ;
}
2014-11-19 00:45:57 +00:00
delta1 = thing - > z - ( bottomheight
+ ( ( topheight - bottomheight ) / 2 ) ) ;
delta2 = thingtop - ( bottomheight
+ ( ( topheight - bottomheight ) / 2 ) ) ;
2014-03-15 16:59:03 +00:00
2014-11-19 00:45:57 +00:00
if ( topheight > tmfloorz & & abs ( delta1 ) < abs ( delta2 )
2014-08-04 03:49:33 +00:00
& & ! ( rover - > flags & FF_REVERSEPLATFORM ) )
2014-03-15 16:59:03 +00:00
{
2014-11-19 00:45:57 +00:00
tmfloorz = tmdropoffz = topheight ;
2018-09-10 03:12:37 +00:00
tmfloorrover = rover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
2015-05-17 16:53:28 +00:00
tmfloorslope = * rover - > t_slope ;
2015-04-29 05:33:04 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
2014-11-19 00:45:57 +00:00
if ( bottomheight < tmceilingz & & abs ( delta1 ) > = abs ( delta2 )
2014-08-04 03:49:33 +00:00
& & ! ( rover - > flags & FF_PLATFORM )
2014-03-15 16:59:03 +00:00
& & ! ( thing - > type = = MT_SKIM & & ( rover - > flags & FF_SWIMMABLE ) ) )
{
2014-11-19 00:45:57 +00:00
tmceilingz = tmdrpoffceilz = bottomheight ;
2018-09-10 03:12:37 +00:00
tmceilingrover = rover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
2015-05-17 16:53:28 +00:00
tmceilingslope = * rover - > b_slope ;
2015-04-29 05:33:04 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
}
}
2014-11-12 00:55:07 +00:00
// The bounding box is extended by MAXRADIUS
// because mobj_ts are grouped into mapblocks
// based on their origin point, and can overlap
// into adjacent blocks by up to MAXRADIUS units.
2015-04-09 01:50:49 +00:00
xl = ( unsigned ) ( tmbbox [ BOXLEFT ] - bmaporgx - MAXRADIUS ) > > MAPBLOCKSHIFT ;
xh = ( unsigned ) ( tmbbox [ BOXRIGHT ] - bmaporgx + MAXRADIUS ) > > MAPBLOCKSHIFT ;
yl = ( unsigned ) ( tmbbox [ BOXBOTTOM ] - bmaporgy - MAXRADIUS ) > > MAPBLOCKSHIFT ;
yh = ( unsigned ) ( tmbbox [ BOXTOP ] - bmaporgy + MAXRADIUS ) > > MAPBLOCKSHIFT ;
2014-11-12 00:55:07 +00:00
2015-04-09 02:32:07 +00:00
BMBOUNDFIX ( xl , xh , yl , yh ) ;
2014-03-15 16:59:03 +00:00
# ifdef POLYOBJECTS
// Check polyobjects and see if tmfloorz/tmceilingz need to be altered
{
validcount + + ;
for ( by = yl ; by < = yh ; by + + )
for ( bx = xl ; bx < = xh ; bx + + )
{
INT32 offset ;
polymaplink_t * plink ; // haleyjd 02/22/06
if ( bx < 0 | | by < 0 | | bx > = bmapwidth | | by > = bmapheight )
continue ;
offset = by * bmapwidth + bx ;
// haleyjd 02/22/06: consider polyobject lines
plink = polyblocklinks [ offset ] ;
while ( plink )
{
polyobj_t * po = plink - > po ;
if ( po - > validcount ! = validcount ) // if polyobj hasn't been checked
{
sector_t * polysec ;
fixed_t delta1 , delta2 , thingtop ;
fixed_t polytop , polybottom ;
po - > validcount = validcount ;
if ( ! P_BBoxInsidePolyobj ( po , tmbbox )
| | ! ( po - > flags & POF_SOLID ) )
{
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
continue ;
}
// We're inside it! Yess...
polysec = po - > lines [ 0 ] - > backsector ;
if ( po - > flags & POF_CLIPPLANES )
{
polytop = polysec - > ceilingheight ;
polybottom = polysec - > floorheight ;
}
else
{
polytop = INT32_MAX ;
polybottom = INT32_MIN ;
}
thingtop = thing - > z + thing - > height ;
delta1 = thing - > z - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
delta2 = thingtop - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
2015-04-29 05:33:04 +00:00
if ( polytop > tmfloorz & & abs ( delta1 ) < abs ( delta2 ) ) {
2014-03-15 16:59:03 +00:00
tmfloorz = tmdropoffz = polytop ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmfloorslope = NULL ;
# endif
}
2014-03-15 16:59:03 +00:00
2015-04-29 05:33:04 +00:00
if ( polybottom < tmceilingz & & abs ( delta1 ) > = abs ( delta2 ) ) {
2014-08-04 03:49:33 +00:00
tmceilingz = tmdrpoffceilz = polybottom ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmceilingslope = NULL ;
# endif
}
2014-03-15 16:59:03 +00:00
}
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
}
}
}
# endif
// tmfloorthing is set when tmfloorz comes from a thing's top
tmfloorthing = NULL ;
tmhitthing = NULL ;
validcount + + ;
if ( tmflags & MF_NOCLIP )
return true ;
// Check things first, possibly picking things up.
// MF_NOCLIPTHING: used by camera to not be blocked by things
if ( ! ( thing - > flags & MF_NOCLIPTHING ) )
{
for ( bx = xl ; bx < = xh ; bx + + )
for ( by = yl ; by < = yh ; by + + )
{
if ( ! P_BlockThingsIterator ( bx , by , PIT_CheckThing ) )
blockval = false ;
if ( P_MobjWasRemoved ( tmthing ) )
return false ;
}
}
validcount + + ;
// check lines
for ( bx = xl ; bx < = xh ; bx + + )
for ( by = yl ; by < = yh ; by + + )
if ( ! P_BlockLinesIterator ( bx , by , PIT_CheckLine ) )
blockval = false ;
return blockval ;
}
static const fixed_t hoopblockdist = 16 * FRACUNIT + 8 * FRACUNIT ;
static const fixed_t hoophalfheight = ( 56 * FRACUNIT ) / 2 ;
// P_CheckPosition optimized for the MT_HOOPCOLLIDE object. This needs to be as fast as possible!
void P_CheckHoopPosition ( mobj_t * hoopthing , fixed_t x , fixed_t y , fixed_t z , fixed_t radius )
{
INT32 i ;
( void ) radius ; //unused
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | ! players [ i ] . mo | | players [ i ] . spectator )
continue ;
if ( abs ( players [ i ] . mo - > x - x ) > = hoopblockdist | |
abs ( players [ i ] . mo - > y - y ) > = hoopblockdist | |
abs ( ( players [ i ] . mo - > z + hoophalfheight ) - z ) > = hoopblockdist )
continue ; // didn't hit it
// can remove thing
P_TouchSpecialThing ( hoopthing , players [ i ] . mo , false ) ;
break ;
}
return ;
}
//
// P_CheckCameraPosition
//
boolean P_CheckCameraPosition ( fixed_t x , fixed_t y , camera_t * thiscam )
{
INT32 xl , xh , yl , yh , bx , by ;
subsector_t * newsubsec ;
tmx = x ;
tmy = y ;
tmbbox [ BOXTOP ] = y + thiscam - > radius ;
tmbbox [ BOXBOTTOM ] = y - thiscam - > radius ;
tmbbox [ BOXRIGHT ] = x + thiscam - > radius ;
tmbbox [ BOXLEFT ] = x - thiscam - > radius ;
newsubsec = R_PointInSubsector ( x , y ) ;
ceilingline = blockingline = NULL ;
mapcampointer = thiscam ;
if ( GETSECSPECIAL ( newsubsec - > sector - > special , 4 ) = = 12 )
{ // Camera noclip on entire sector.
tmfloorz = tmdropoffz = thiscam - > z ;
2014-08-04 03:49:33 +00:00
tmceilingz = tmdrpoffceilz = thiscam - > z + thiscam - > height ;
2014-03-15 16:59:03 +00:00
return true ;
}
// The base floor / ceiling is from the subsector
// that contains the point.
// Any contacted lines the step closer together
// will adjust them.
2015-05-21 14:36:20 +00:00
tmfloorz = tmdropoffz = P_CameraGetFloorZ ( thiscam , newsubsec - > sector , x , y , NULL ) ;
2014-11-19 00:45:57 +00:00
2015-05-21 14:36:20 +00:00
tmceilingz = P_CameraGetCeilingZ ( thiscam , newsubsec - > sector , x , y , NULL ) ;
2014-03-15 16:59:03 +00:00
// Cameras use the heightsec's heights rather then the actual sector heights.
// If you can see through it, why not move the camera through it too?
if ( newsubsec - > sector - > heightsec > = 0 )
{
tmfloorz = tmdropoffz = sectors [ newsubsec - > sector - > heightsec ] . floorheight ;
2014-08-04 03:49:33 +00:00
tmceilingz = tmdrpoffceilz = sectors [ newsubsec - > sector - > heightsec ] . ceilingheight ;
}
// Use preset camera clipping heights if set with Sector Special Parameters whose control sector has Camera Intangible special -Red
if ( newsubsec - > sector - > camsec > = 0 )
{
tmfloorz = tmdropoffz = sectors [ newsubsec - > sector - > camsec ] . floorheight ;
tmceilingz = tmdrpoffceilz = sectors [ newsubsec - > sector - > camsec ] . ceilingheight ;
2014-03-15 16:59:03 +00:00
}
// Check list of fake floors and see if tmfloorz/tmceilingz need to be altered.
if ( newsubsec - > sector - > ffloors )
{
ffloor_t * rover ;
fixed_t delta1 , delta2 ;
INT32 thingtop = thiscam - > z + thiscam - > height ;
for ( rover = newsubsec - > sector - > ffloors ; rover ; rover = rover - > next )
{
2015-10-10 16:57:35 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( ! ( rover - > flags & FF_BLOCKOTHERS ) | | ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_RENDERALL ) | | GETSECSPECIAL ( rover - > master - > frontsector - > special , 4 ) = = 12 )
continue ;
2015-10-10 16:57:35 +00:00
topheight = P_CameraGetFOFTopZ ( thiscam , newsubsec - > sector , rover , x , y , NULL ) ;
bottomheight = P_CameraGetFOFBottomZ ( thiscam , newsubsec - > sector , rover , x , y , NULL ) ;
2014-11-19 00:45:57 +00:00
delta1 = thiscam - > z - ( bottomheight
+ ( ( topheight - bottomheight ) / 2 ) ) ;
delta2 = thingtop - ( bottomheight
+ ( ( topheight - bottomheight ) / 2 ) ) ;
if ( topheight > tmfloorz & & abs ( delta1 ) < abs ( delta2 ) )
2014-03-15 16:59:03 +00:00
{
2014-11-19 00:45:57 +00:00
tmfloorz = tmdropoffz = topheight ;
2014-03-15 16:59:03 +00:00
}
2014-11-19 00:45:57 +00:00
if ( bottomheight < tmceilingz & & abs ( delta1 ) > = abs ( delta2 ) )
2014-03-15 16:59:03 +00:00
{
2014-11-19 00:45:57 +00:00
tmceilingz = tmdrpoffceilz = bottomheight ;
2014-03-15 16:59:03 +00:00
}
}
}
2014-11-12 00:55:07 +00:00
// The bounding box is extended by MAXRADIUS
// because mobj_ts are grouped into mapblocks
// based on their origin point, and can overlap
// into adjacent blocks by up to MAXRADIUS units.
2015-04-09 01:50:49 +00:00
xl = ( unsigned ) ( tmbbox [ BOXLEFT ] - bmaporgx ) > > MAPBLOCKSHIFT ;
xh = ( unsigned ) ( tmbbox [ BOXRIGHT ] - bmaporgx ) > > MAPBLOCKSHIFT ;
yl = ( unsigned ) ( tmbbox [ BOXBOTTOM ] - bmaporgy ) > > MAPBLOCKSHIFT ;
yh = ( unsigned ) ( tmbbox [ BOXTOP ] - bmaporgy ) > > MAPBLOCKSHIFT ;
2014-11-12 00:55:07 +00:00
2015-04-09 02:32:07 +00:00
BMBOUNDFIX ( xl , xh , yl , yh ) ;
2014-03-15 16:59:03 +00:00
# ifdef POLYOBJECTS
// Check polyobjects and see if tmfloorz/tmceilingz need to be altered
{
validcount + + ;
for ( by = yl ; by < = yh ; by + + )
for ( bx = xl ; bx < = xh ; bx + + )
{
INT32 offset ;
polymaplink_t * plink ; // haleyjd 02/22/06
if ( bx < 0 | | by < 0 | | bx > = bmapwidth | | by > = bmapheight )
continue ;
offset = by * bmapwidth + bx ;
// haleyjd 02/22/06: consider polyobject lines
plink = polyblocklinks [ offset ] ;
while ( plink )
{
polyobj_t * po = plink - > po ;
if ( po - > validcount ! = validcount ) // if polyobj hasn't been checked
{
sector_t * polysec ;
fixed_t delta1 , delta2 , thingtop ;
fixed_t polytop , polybottom ;
po - > validcount = validcount ;
2016-03-10 20:50:54 +00:00
if ( ! P_PointInsidePolyobj ( po , x , y ) | | ! ( po - > flags & POF_SOLID ) )
2014-03-15 16:59:03 +00:00
{
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
continue ;
}
// We're inside it! Yess...
polysec = po - > lines [ 0 ] - > backsector ;
if ( GETSECSPECIAL ( polysec - > special , 4 ) = = 12 )
{ // Camera noclip polyobj.
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
continue ;
}
if ( po - > flags & POF_CLIPPLANES )
{
polytop = polysec - > ceilingheight ;
polybottom = polysec - > floorheight ;
}
else
{
polytop = INT32_MAX ;
polybottom = INT32_MIN ;
}
thingtop = thiscam - > z + thiscam - > height ;
delta1 = thiscam - > z - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
delta2 = thingtop - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
if ( polytop > tmfloorz & & abs ( delta1 ) < abs ( delta2 ) )
tmfloorz = tmdropoffz = polytop ;
if ( polybottom < tmceilingz & & abs ( delta1 ) > = abs ( delta2 ) )
2014-08-04 03:49:33 +00:00
tmceilingz = tmdrpoffceilz = polybottom ;
2014-03-15 16:59:03 +00:00
}
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
}
}
}
# endif
// check lines
for ( bx = xl ; bx < = xh ; bx + + )
for ( by = yl ; by < = yh ; by + + )
if ( ! P_BlockLinesIterator ( bx , by , PIT_CheckCameraLine ) )
return false ;
return true ;
}
// The highest the camera will "step up" onto another floor.
# define MAXCAMERASTEPMOVE MAXSTEPMOVE
//
// P_TryCameraMove
//
// Attempt to move the camera to a new position
//
// Return true if the move succeeded and no sliding should be done.
//
boolean P_TryCameraMove ( fixed_t x , fixed_t y , camera_t * thiscam )
{
subsector_t * s = R_PointInSubsector ( x , y ) ;
boolean retval = true ;
boolean itsatwodlevel = false ;
floatok = false ;
if ( twodlevel
| | ( thiscam = = & camera & & players [ displayplayer ] . mo & & ( players [ displayplayer ] . mo - > flags2 & MF2_TWOD ) )
| | ( thiscam = = & camera2 & & players [ secondarydisplayplayer ] . mo & & ( players [ secondarydisplayplayer ] . mo - > flags2 & MF2_TWOD ) ) )
itsatwodlevel = true ;
if ( ! itsatwodlevel & & players [ displayplayer ] . mo )
{
fixed_t tryx = thiscam - > x ;
fixed_t tryy = thiscam - > y ;
if ( ( thiscam = = & camera & & ( players [ displayplayer ] . pflags & PF_NOCLIP ) )
| | ( thiscam = = & camera2 & & ( players [ secondarydisplayplayer ] . pflags & PF_NOCLIP ) ) )
{ // Noclipping player camera noclips too!!
floatok = true ;
thiscam - > floorz = thiscam - > z ;
thiscam - > ceilingz = thiscam - > z + thiscam - > height ;
thiscam - > x = x ;
thiscam - > y = y ;
thiscam - > subsector = s ;
return true ;
}
do {
if ( x - tryx > MAXRADIUS )
tryx + = MAXRADIUS ;
else if ( x - tryx < - MAXRADIUS )
tryx - = MAXRADIUS ;
else
tryx = x ;
if ( y - tryy > MAXRADIUS )
tryy + = MAXRADIUS ;
else if ( y - tryy < - MAXRADIUS )
tryy - = MAXRADIUS ;
else
tryy = y ;
if ( ! P_CheckCameraPosition ( tryx , tryy , thiscam ) )
return false ; // solid wall or thing
if ( tmceilingz - tmfloorz < thiscam - > height )
return false ; // doesn't fit
floatok = true ;
if ( tmceilingz - thiscam - > z < thiscam - > height )
{
if ( s = = thiscam - > subsector & & tmceilingz > = thiscam - > z )
{
floatok = true ;
thiscam - > floorz = tmfloorz ;
thiscam - > ceilingz = tmfloorz + thiscam - > height ;
thiscam - > x = x ;
thiscam - > y = y ;
thiscam - > subsector = s ;
return true ;
}
else
return false ; // mobj must lower itself to fit
}
if ( ( tmfloorz - thiscam - > z > MAXCAMERASTEPMOVE ) )
return false ; // too big a step up
} while ( tryx ! = x | | tryy ! = y ) ;
}
else
{
2015-05-23 01:57:58 +00:00
tmfloorz = P_CameraGetFloorZ ( thiscam , thiscam - > subsector - > sector , x , y , NULL ) ;
tmceilingz = P_CameraGetCeilingZ ( thiscam , thiscam - > subsector - > sector , x , y , NULL ) ;
2014-03-15 16:59:03 +00:00
}
// the move is ok,
// so link the thing into its new position
thiscam - > floorz = tmfloorz ;
thiscam - > ceilingz = tmceilingz ;
thiscam - > x = x ;
thiscam - > y = y ;
thiscam - > subsector = s ;
return retval ;
}
//
// PIT_PushableMoved
//
// Move things standing on top
// of pushable things being pushed.
//
static mobj_t * stand ;
static fixed_t standx , standy ;
boolean PIT_PushableMoved ( mobj_t * thing )
{
fixed_t blockdist ;
if ( ! ( thing - > flags & MF_SOLID )
| | ( thing - > flags & MF_NOGRAVITY ) )
return true ; // Don't move something non-solid!
// Only pushables are supported... in 2.0. Now players can be moved too!
if ( ! ( thing - > flags & MF_PUSHABLE | | thing - > player ) )
return true ;
if ( thing = = stand )
return true ;
blockdist = stand - > radius + thing - > radius ;
if ( abs ( thing - > x - stand - > x ) > = blockdist | | abs ( thing - > y - stand - > y ) > = blockdist )
return true ; // didn't hit it
if ( ( ! ( stand - > eflags & MFE_VERTICALFLIP ) & & thing - > z ! = stand - > z + stand - > height + FixedMul ( FRACUNIT , stand - > scale ) )
| | ( ( stand - > eflags & MFE_VERTICALFLIP ) & & thing - > z + thing - > height ! = stand - > z - FixedMul ( FRACUNIT , stand - > scale ) ) )
return true ; // Not standing on top
if ( ! stand - > momx & & ! stand - > momy )
return true ;
// Move this guy!
if ( thing - > player )
{
// Monster Iestyn - 29/11/13
// Ridiculous amount of newly declared stuff so players can't get stuck in walls AND so gargoyles don't break themselves at the same time either
// These are all non-static map variables that are changed for each and every single mobj
// See, changing player's momx/y would possibly trigger stuff as if the player were running somehow, so this must be done to keep the player standing
// All this so players can ride gargoyles!
boolean oldfltok = floatok ;
fixed_t oldflrz = tmfloorz ;
fixed_t oldceilz = tmceilingz ;
mobj_t * oldflrthing = tmfloorthing ;
mobj_t * oldthing = tmthing ;
line_t * oldceilline = ceilingline ;
line_t * oldblockline = blockingline ;
2018-09-10 03:12:37 +00:00
ffloor_t * oldflrrover = tmfloorrover ;
ffloor_t * oldceilrover = tmceilingrover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
pslope_t * oldfslope = tmfloorslope ;
pslope_t * oldcslope = tmceilingslope ;
# endif
2014-03-15 16:59:03 +00:00
// Move the player
P_TryMove ( thing , thing - > x + stand - > momx , thing - > y + stand - > momy , true ) ;
// Now restore EVERYTHING so the gargoyle doesn't keep the player's tmstuff and break
floatok = oldfltok ;
tmfloorz = oldflrz ;
tmceilingz = oldceilz ;
tmfloorthing = oldflrthing ;
P_SetTarget ( & tmthing , oldthing ) ;
ceilingline = oldceilline ;
blockingline = oldblockline ;
2018-09-10 03:12:37 +00:00
tmfloorrover = oldflrrover ;
tmceilingrover = oldceilrover ;
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
tmfloorslope = oldfslope ;
tmceilingslope = oldcslope ;
# endif
2014-08-04 03:49:33 +00:00
thing - > momz = stand - > momz ;
2014-03-15 16:59:03 +00:00
}
else
{
thing - > momx = stand - > momx ;
thing - > momy = stand - > momy ;
2014-08-04 03:49:33 +00:00
thing - > momz = stand - > momz ;
2014-03-15 16:59:03 +00:00
}
return true ;
}
//
// P_TryMove
// Attempt to move to a new position.
//
boolean P_TryMove ( mobj_t * thing , fixed_t x , fixed_t y , boolean allowdropoff )
{
fixed_t tryx = thing - > x ;
fixed_t tryy = thing - > y ;
fixed_t radius = thing - > radius ;
2014-08-04 03:49:33 +00:00
fixed_t thingtop = thing - > z + thing - > height ;
2015-05-13 21:15:32 +00:00
# ifdef ESLOPE
fixed_t startingonground = P_IsObjectOnGround ( thing ) ;
# endif
2014-03-15 16:59:03 +00:00
floatok = false ;
if ( radius < MAXRADIUS / 2 )
radius = MAXRADIUS / 2 ;
do {
if ( thing - > flags & MF_NOCLIP ) {
tryx = x ;
tryy = y ;
} else {
if ( x - tryx > radius )
tryx + = radius ;
else if ( x - tryx < - radius )
tryx - = radius ;
else
tryx = x ;
if ( y - tryy > radius )
tryy + = radius ;
else if ( y - tryy < - radius )
tryy - = radius ;
else
tryy = y ;
}
if ( ! P_CheckPosition ( thing , tryx , tryy ) )
return false ; // solid wall or thing
if ( ! ( thing - > flags & MF_NOCLIP ) )
{
//All things are affected by their scale.
fixed_t maxstep = FixedMul ( MAXSTEPMOVE , thing - > scale ) ;
if ( thing - > player )
{
2014-08-04 03:49:33 +00:00
// If using type Section1:13, double the maxstep.
if ( P_PlayerTouchingSectorSpecial ( thing - > player , 1 , 13 )
| | GETSECSPECIAL ( R_PointInSubsector ( x , y ) - > sector - > special , 1 ) = = 13 )
maxstep < < = 1 ;
2014-03-15 16:59:03 +00:00
// Don't 'step up' while springing,
// Only step up "if needed".
2016-01-14 14:35:10 +00:00
if ( thing - > player - > panim = = PA_SPRING
2014-03-15 16:59:03 +00:00
& & P_MobjFlip ( thing ) * thing - > momz > FixedMul ( FRACUNIT , thing - > scale ) )
maxstep = 0 ;
}
if ( thing - > type = = MT_SKIM )
maxstep = 0 ;
if ( tmceilingz - tmfloorz < thing - > height )
{
if ( tmfloorthing )
tmhitthing = tmfloorthing ;
return false ; // doesn't fit
}
floatok = true ;
if ( thing - > eflags & MFE_VERTICALFLIP )
{
if ( thing - > z < tmfloorz )
return false ; // mobj must raise itself to fit
}
2014-08-04 03:49:33 +00:00
else if ( tmceilingz < thingtop )
2014-03-15 16:59:03 +00:00
return false ; // mobj must lower itself to fit
// Ramp test
2016-08-13 22:43:22 +00:00
if ( maxstep > 0 & & ! (
thing - > player & & (
P_PlayerTouchingSectorSpecial ( thing - > player , 1 , 14 )
| | GETSECSPECIAL ( R_PointInSubsector ( x , y ) - > sector - > special , 1 ) = = 14 )
)
)
2014-03-15 16:59:03 +00:00
{
// If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS
// step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more.
if ( thing - > eflags & MFE_VERTICALFLIP )
{
2014-08-04 03:49:33 +00:00
if ( thingtop = = thing - > ceilingz & & tmceilingz > thingtop & & tmceilingz - thingtop < = maxstep )
2014-03-15 16:59:03 +00:00
{
2015-04-29 05:29:51 +00:00
thing - > z = ( thing - > ceilingz = thingtop = tmceilingz ) - thing - > height ;
2018-09-10 04:35:40 +00:00
thing - > ceilingrover = tmceilingrover ;
2015-04-29 05:29:51 +00:00
thing - > eflags | = MFE_JUSTSTEPPEDDOWN ;
}
2016-05-02 16:04:28 +00:00
# ifdef ESLOPE
// HACK TO FIX DSZ2: apply only if slopes are involved
else if ( tmceilingslope & & tmceilingz < thingtop & & thingtop - tmceilingz < = maxstep )
2015-04-29 05:29:51 +00:00
{
thing - > z = ( thing - > ceilingz = thingtop = tmceilingz ) - thing - > height ;
2018-09-10 04:35:40 +00:00
thing - > ceilingrover = tmceilingrover ;
2014-03-15 16:59:03 +00:00
thing - > eflags | = MFE_JUSTSTEPPEDDOWN ;
}
2016-05-02 16:04:28 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
else if ( thing - > z = = thing - > floorz & & tmfloorz < thing - > z & & thing - > z - tmfloorz < = maxstep )
{
2015-04-29 05:29:51 +00:00
thing - > z = thing - > floorz = tmfloorz ;
2018-09-10 04:35:40 +00:00
thing - > floorrover = tmfloorrover ;
2014-03-15 16:59:03 +00:00
thing - > eflags | = MFE_JUSTSTEPPEDDOWN ;
}
2016-05-02 16:04:28 +00:00
# ifdef ESLOPE
// HACK TO FIX DSZ2: apply only if slopes are involved
else if ( tmfloorslope & & tmfloorz > thing - > z & & tmfloorz - thing - > z < = maxstep )
2015-04-29 05:29:51 +00:00
{
thing - > z = thing - > floorz = tmfloorz ;
2018-09-10 04:35:40 +00:00
thing - > floorrover = tmfloorrover ;
2014-03-15 16:59:03 +00:00
thing - > eflags | = MFE_JUSTSTEPPEDDOWN ;
}
2016-05-02 16:04:28 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
if ( thing - > eflags & MFE_VERTICALFLIP )
{
2014-08-04 03:49:33 +00:00
if ( thingtop - tmceilingz > maxstep )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( tmfloorthing )
tmhitthing = tmfloorthing ;
2014-03-15 16:59:03 +00:00
return false ; // too big a step up
}
}
else if ( tmfloorz - thing - > z > maxstep )
{
if ( tmfloorthing )
tmhitthing = tmfloorthing ;
return false ; // too big a step up
}
2014-08-04 03:49:33 +00:00
if ( ! allowdropoff & & ! ( thing - > flags & MF_FLOAT ) & & thing - > type ! = MT_SKIM & & ! tmfloorthing )
{
if ( thing - > eflags & MFE_VERTICALFLIP )
{
if ( tmdrpoffceilz - tmceilingz > maxstep )
return false ;
}
else if ( tmfloorz - tmdropoffz > maxstep )
2014-03-15 16:59:03 +00:00
return false ; // don't stand over a dropoff
2014-08-04 03:49:33 +00:00
}
2014-03-15 16:59:03 +00:00
}
} while ( tryx ! = x | | tryy ! = y ) ;
// The move is ok!
// If it's a pushable object, check if anything is
// standing on top and move it, too.
if ( thing - > flags & MF_PUSHABLE )
{
INT32 bx , by , xl , xh , yl , yh ;
2015-04-09 01:50:49 +00:00
yh = ( unsigned ) ( thing - > y + MAXRADIUS - bmaporgy ) > > MAPBLOCKSHIFT ;
yl = ( unsigned ) ( thing - > y - MAXRADIUS - bmaporgy ) > > MAPBLOCKSHIFT ;
xh = ( unsigned ) ( thing - > x + MAXRADIUS - bmaporgx ) > > MAPBLOCKSHIFT ;
xl = ( unsigned ) ( thing - > x - MAXRADIUS - bmaporgx ) > > MAPBLOCKSHIFT ;
2014-03-15 16:59:03 +00:00
2015-04-09 02:32:07 +00:00
BMBOUNDFIX ( xl , xh , yl , yh ) ;
2014-03-15 16:59:03 +00:00
stand = thing ;
standx = x ;
standy = y ;
for ( by = yl ; by < = yh ; by + + )
for ( bx = xl ; bx < = xh ; bx + + )
P_BlockThingsIterator ( bx , by , PIT_PushableMoved ) ;
}
// Link the thing into its new position
P_UnsetThingPosition ( thing ) ;
thing - > floorz = tmfloorz ;
thing - > ceilingz = tmceilingz ;
2018-09-10 04:35:40 +00:00
thing - > floorrover = tmfloorrover ;
thing - > ceilingrover = tmceilingrover ;
2015-04-27 18:20:50 +00:00
2015-04-29 05:33:04 +00:00
# ifdef ESLOPE
2016-02-23 22:53:24 +00:00
if ( ! ( thing - > flags & MF_NOCLIPHEIGHT ) )
{
// Assign thing's standingslope if needed
if ( thing - > z < = tmfloorz & & ! ( thing - > eflags & MFE_VERTICALFLIP ) ) {
if ( ! startingonground & & tmfloorslope )
P_HandleSlopeLanding ( thing , tmfloorslope ) ;
2015-05-13 21:15:32 +00:00
2016-02-23 22:53:24 +00:00
if ( thing - > momz < = 0 )
thing - > standingslope = tmfloorslope ;
}
else if ( thing - > z + thing - > height > = tmceilingz & & ( thing - > eflags & MFE_VERTICALFLIP ) ) {
if ( ! startingonground & & tmceilingslope )
P_HandleSlopeLanding ( thing , tmceilingslope ) ;
2015-05-13 21:15:32 +00:00
2016-02-23 22:53:24 +00:00
if ( thing - > momz > = 0 )
thing - > standingslope = tmceilingslope ;
}
2015-05-13 21:15:32 +00:00
}
2016-02-23 22:53:24 +00:00
else // don't set standingslope if you're not going to clip against it
thing - > standingslope = NULL ;
2015-04-29 05:33:04 +00:00
# endif
2014-03-15 16:59:03 +00:00
thing - > x = x ;
thing - > y = y ;
if ( tmfloorthing )
thing - > eflags & = ~ MFE_ONGROUND ; // not on real floor
else
thing - > eflags | = MFE_ONGROUND ;
P_SetThingPosition ( thing ) ;
return true ;
}
boolean P_SceneryTryMove ( mobj_t * thing , fixed_t x , fixed_t y )
{
fixed_t tryx , tryy ;
2014-11-19 00:45:57 +00:00
2014-03-15 16:59:03 +00:00
tryx = thing - > x ;
tryy = thing - > y ;
do {
if ( x - tryx > MAXRADIUS )
tryx + = MAXRADIUS ;
else if ( x - tryx < - MAXRADIUS )
tryx - = MAXRADIUS ;
else
tryx = x ;
if ( y - tryy > MAXRADIUS )
tryy + = MAXRADIUS ;
else if ( y - tryy < - MAXRADIUS )
tryy - = MAXRADIUS ;
else
tryy = y ;
if ( ! P_CheckPosition ( thing , tryx , tryy ) )
return false ; // solid wall or thing
if ( ! ( thing - > flags & MF_NOCLIP ) )
{
const fixed_t maxstep = MAXSTEPMOVE ;
if ( tmceilingz - tmfloorz < thing - > height )
return false ; // doesn't fit
if ( tmceilingz - thing - > z < thing - > height )
return false ; // mobj must lower itself to fit
if ( tmfloorz - thing - > z > maxstep )
return false ; // too big a step up
}
} while ( tryx ! = x | | tryy ! = y ) ;
// the move is ok,
// so link the thing into its new position
P_UnsetThingPosition ( thing ) ;
thing - > floorz = tmfloorz ;
thing - > ceilingz = tmceilingz ;
2018-09-10 04:35:40 +00:00
thing - > floorrover = tmfloorrover ;
thing - > ceilingrover = tmceilingrover ;
2014-03-15 16:59:03 +00:00
thing - > x = x ;
thing - > y = y ;
if ( tmfloorthing )
thing - > eflags & = ~ MFE_ONGROUND ; // not on real floor
else
thing - > eflags | = MFE_ONGROUND ;
P_SetThingPosition ( thing ) ;
return true ;
}
//
// P_ThingHeightClip
// Takes a valid thing and adjusts the thing->floorz,
// thing->ceilingz, and possibly thing->z.
// This is called for all nearby monsters
// whenever a sector changes height.
// If the thing doesn't fit,
// the z will be set to the lowest value
// and false will be returned.
//
static boolean P_ThingHeightClip ( mobj_t * thing )
{
2015-05-29 08:34:53 +00:00
boolean floormoved ;
2014-03-15 16:59:03 +00:00
fixed_t oldfloorz = thing - > floorz ;
2018-09-10 03:12:37 +00:00
ffloor_t * oldfloorrover = thing - > floorrover ;
ffloor_t * oldceilingrover = thing - > ceilingrover ;
2014-03-15 16:59:03 +00:00
boolean onfloor = P_IsObjectOnGround ( thing ) ; //(thing->z <= thing->floorz);
2018-09-08 04:34:56 +00:00
ffloor_t * rover = NULL ;
2014-03-15 16:59:03 +00:00
if ( thing - > flags & MF_NOCLIPHEIGHT )
return true ;
P_CheckPosition ( thing , thing - > x , thing - > y ) ;
if ( P_MobjWasRemoved ( thing ) )
return true ;
2015-05-29 08:34:53 +00:00
floormoved = ( thing - > eflags & MFE_VERTICALFLIP & & tmceilingz ! = thing - > ceilingz )
| | ( ! ( thing - > eflags & MFE_VERTICALFLIP ) & & tmfloorz ! = thing - > floorz ) ;
2014-03-15 16:59:03 +00:00
thing - > floorz = tmfloorz ;
thing - > ceilingz = tmceilingz ;
2018-09-10 03:12:37 +00:00
thing - > floorrover = tmfloorrover ;
thing - > ceilingrover = tmceilingrover ;
2014-03-15 16:59:03 +00:00
// Ugly hack?!?! As long as just ceilingz is the lowest,
// you'll still get crushed, right?
if ( tmfloorz > oldfloorz + thing - > height )
return true ;
2015-05-29 08:34:53 +00:00
if ( onfloor & & ! ( thing - > flags & MF_NOGRAVITY ) & & floormoved )
2014-03-15 16:59:03 +00:00
{
2018-09-10 03:12:37 +00:00
rover = ( thing - > eflags & MFE_VERTICALFLIP ) ? oldceilingrover : oldfloorrover ;
2014-03-15 16:59:03 +00:00
2018-09-08 04:34:56 +00:00
// Match the Thing's old floorz to an FOF and check for FF_EXISTS
// If ~FF_EXISTS, don't set mobj Z.
2018-09-08 05:02:17 +00:00
if ( ! rover | | ( ( rover - > flags & FF_EXISTS ) & & ( rover - > flags & FF_SOLID ) ) )
2018-09-08 04:34:56 +00:00
{
if ( thing - > eflags & MFE_VERTICALFLIP )
thing - > pmomz = thing - > ceilingz - ( thing - > z + thing - > height ) ;
else
thing - > pmomz = thing - > floorz - thing - > z ;
thing - > eflags | = MFE_APPLYPMOMZ ;
if ( thing - > eflags & MFE_VERTICALFLIP )
thing - > z = thing - > ceilingz - thing - > height ;
else
thing - > z = thing - > floorz ;
}
2014-03-15 16:59:03 +00:00
}
else if ( ! tmfloorthing )
{
// don't adjust a floating monster unless forced to
if ( thing - > eflags & MFE_VERTICALFLIP )
{
if ( ! onfloor & & thing - > z < tmfloorz )
thing - > z = thing - > floorz ;
}
else if ( ! onfloor & & thing - > z + thing - > height > tmceilingz )
thing - > z = thing - > ceilingz - thing - > height ;
}
// debug: be sure it falls to the floor
thing - > eflags & = ~ MFE_ONGROUND ;
if ( thing - > ceilingz - thing - > floorz < thing - > height & & thing - > z > = thing - > floorz )
// BP: i know that this code cause many trouble but this also fixes
// a lot of problems, mainly this is implementation of the stepping
// for mobj (walk on solid corpse without jumping or fake 3d bridge)
// problem is imp into imp at map01 and monster going at top of others
return false ;
return true ;
}
//
// SLIDE MOVE
// Allows the player to slide along any angled walls.
//
static fixed_t bestslidefrac , secondslidefrac ;
static line_t * bestslideline ;
static line_t * secondslideline ;
static mobj_t * slidemo ;
static fixed_t tmxmove , tmymove ;
//
// P_HitCameraSlideLine
//
static void P_HitCameraSlideLine ( line_t * ld , camera_t * thiscam )
{
INT32 side ;
angle_t lineangle , moveangle , deltaangle ;
fixed_t movelen , newlen ;
if ( ld - > slopetype = = ST_HORIZONTAL )
{
tmymove = 0 ;
return ;
}
if ( ld - > slopetype = = ST_VERTICAL )
{
tmxmove = 0 ;
return ;
}
side = P_PointOnLineSide ( thiscam - > x , thiscam - > y , ld ) ;
lineangle = R_PointToAngle2 ( 0 , 0 , ld - > dx , ld - > dy ) ;
if ( side = = 1 )
lineangle + = ANGLE_180 ;
moveangle = R_PointToAngle2 ( 0 , 0 , tmxmove , tmymove ) ;
deltaangle = moveangle - lineangle ;
if ( deltaangle > ANGLE_180 )
deltaangle + = ANGLE_180 ;
lineangle > > = ANGLETOFINESHIFT ;
deltaangle > > = ANGLETOFINESHIFT ;
movelen = P_AproxDistance ( tmxmove , tmymove ) ;
newlen = FixedMul ( movelen , FINECOSINE ( deltaangle ) ) ;
tmxmove = FixedMul ( newlen , FINECOSINE ( lineangle ) ) ;
tmymove = FixedMul ( newlen , FINESINE ( lineangle ) ) ;
}
//
// P_HitSlideLine
// Adjusts the xmove / ymove
// so that the next move will slide along the wall.
//
static void P_HitSlideLine ( line_t * ld )
{
INT32 side ;
angle_t lineangle , moveangle , deltaangle ;
fixed_t movelen , newlen ;
if ( ld - > slopetype = = ST_HORIZONTAL )
{
tmymove = 0 ;
return ;
}
if ( ld - > slopetype = = ST_VERTICAL )
{
tmxmove = 0 ;
return ;
}
side = P_PointOnLineSide ( slidemo - > x , slidemo - > y , ld ) ;
lineangle = R_PointToAngle2 ( 0 , 0 , ld - > dx , ld - > dy ) ;
if ( side = = 1 )
lineangle + = ANGLE_180 ;
moveangle = R_PointToAngle2 ( 0 , 0 , tmxmove , tmymove ) ;
deltaangle = moveangle - lineangle ;
if ( deltaangle > ANGLE_180 )
deltaangle + = ANGLE_180 ;
lineangle > > = ANGLETOFINESHIFT ;
deltaangle > > = ANGLETOFINESHIFT ;
movelen = P_AproxDistance ( tmxmove , tmymove ) ;
newlen = FixedMul ( movelen , FINECOSINE ( deltaangle ) ) ;
tmxmove = FixedMul ( newlen , FINECOSINE ( lineangle ) ) ;
tmymove = FixedMul ( newlen , FINESINE ( lineangle ) ) ;
}
//
// P_HitBounceLine
//
// Adjusts the xmove / ymove so that the next move will bounce off the wall.
//
static void P_HitBounceLine ( line_t * ld )
{
angle_t lineangle , moveangle , deltaangle ;
fixed_t movelen ;
if ( ld - > slopetype = = ST_HORIZONTAL )
{
tmymove = - tmymove ;
return ;
}
if ( ld - > slopetype = = ST_VERTICAL )
{
tmxmove = - tmxmove ;
return ;
}
lineangle = R_PointToAngle2 ( 0 , 0 , ld - > dx , ld - > dy ) ;
if ( lineangle > = ANGLE_180 )
lineangle - = ANGLE_180 ;
moveangle = R_PointToAngle2 ( 0 , 0 , tmxmove , tmymove ) ;
deltaangle = moveangle + 2 * ( lineangle - moveangle ) ;
lineangle > > = ANGLETOFINESHIFT ;
deltaangle > > = ANGLETOFINESHIFT ;
movelen = P_AproxDistance ( tmxmove , tmymove ) ;
tmxmove = FixedMul ( movelen , FINECOSINE ( deltaangle ) ) ;
tmymove = FixedMul ( movelen , FINESINE ( deltaangle ) ) ;
deltaangle = R_PointToAngle2 ( 0 , 0 , tmxmove , tmymove ) ;
}
//
// PTR_SlideCameraTraverse
//
static boolean PTR_SlideCameraTraverse ( intercept_t * in )
{
line_t * li ;
I_Assert ( in - > isaline ) ;
li = in - > d . line ;
// one-sided linedef
if ( ! li - > backsector )
{
if ( P_PointOnLineSide ( mapcampointer - > x , mapcampointer - > y , li ) )
return true ; // don't hit the back side
goto isblocking ;
}
// set openrange, opentop, openbottom
P_CameraLineOpening ( li ) ;
if ( openrange < mapcampointer - > height )
goto isblocking ; // doesn't fit
if ( opentop - mapcampointer - > z < mapcampointer - > height )
goto isblocking ; // mobj is too high
if ( openbottom - mapcampointer - > z > 0 ) // We don't want to make the camera step up.
goto isblocking ; // too big a step up
// this line doesn't block movement
return true ;
// the line does block movement,
// see if it is closer than best so far
isblocking :
{
if ( in - > frac < bestslidefrac )
{
secondslidefrac = bestslidefrac ;
secondslideline = bestslideline ;
bestslidefrac = in - > frac ;
bestslideline = li ;
}
}
return false ; // stop
}
//
// P_IsClimbingValid
//
2016-06-20 00:50:47 +00:00
// Unlike P_DoClimbing, don't use when up against a one-sided linedef.
//
2014-03-15 16:59:03 +00:00
static boolean P_IsClimbingValid ( player_t * player , angle_t angle )
{
fixed_t platx , platy ;
subsector_t * glidesector ;
2014-11-19 00:45:57 +00:00
fixed_t floorz , ceilingz ;
2014-03-15 16:59:03 +00:00
platx = P_ReturnThrustX ( player - > mo , angle , player - > mo - > radius + FixedMul ( 8 * FRACUNIT , player - > mo - > scale ) ) ;
platy = P_ReturnThrustY ( player - > mo , angle , player - > mo - > radius + FixedMul ( 8 * FRACUNIT , player - > mo - > scale ) ) ;
glidesector = R_PointInSubsector ( player - > mo - > x + platx , player - > mo - > y + platy ) ;
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
floorz = glidesector - > sector - > f_slope ? P_GetZAt ( glidesector - > sector - > f_slope , player - > mo - > x , player - > mo - > y ) : glidesector - > sector - > floorheight ;
ceilingz = glidesector - > sector - > c_slope ? P_GetZAt ( glidesector - > sector - > c_slope , player - > mo - > x , player - > mo - > y ) : glidesector - > sector - > ceilingheight ;
# else
floorz = glidesector - > sector - > floorheight ;
ceilingz = glidesector - > sector - > ceilingheight ;
# endif
2014-11-19 00:45:57 +00:00
2014-03-15 16:59:03 +00:00
if ( glidesector - > sector ! = player - > mo - > subsector - > sector )
{
boolean floorclimb = false ;
2015-05-23 01:57:58 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( glidesector - > sector - > ffloors )
{
ffloor_t * rover ;
for ( rover = glidesector - > sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_BLOCKPLAYER ) )
continue ;
2015-05-23 01:57:58 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
2015-04-27 18:20:50 +00:00
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
if ( * rover - > t_slope )
topheight = P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) ;
if ( * rover - > b_slope )
bottomheight = P_GetZAt ( * rover - > b_slope , player - > mo - > x , player - > mo - > y ) ;
# endif
2014-11-19 00:45:57 +00:00
2014-03-15 16:59:03 +00:00
floorclimb = true ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
2014-11-19 00:45:57 +00:00
if ( ( topheight < player - > mo - > z + player - > mo - > height ) & & ( ( player - > mo - > z + player - > mo - > height + player - > mo - > momz ) < topheight ) )
2014-03-15 16:59:03 +00:00
{
floorclimb = true ;
}
2014-11-19 00:45:57 +00:00
if ( topheight < player - > mo - > z ) // Waaaay below the ledge.
2014-03-15 16:59:03 +00:00
{
floorclimb = false ;
}
2014-11-19 00:45:57 +00:00
if ( bottomheight > player - > mo - > z + player - > mo - > height - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
2014-03-15 16:59:03 +00:00
{
floorclimb = false ;
}
}
else
{
2014-11-19 00:45:57 +00:00
if ( ( bottomheight > player - > mo - > z ) & & ( ( player - > mo - > z - player - > mo - > momz ) > bottomheight ) )
2014-03-15 16:59:03 +00:00
{
floorclimb = true ;
}
2014-11-19 00:45:57 +00:00
if ( bottomheight > player - > mo - > z + player - > mo - > height ) // Waaaay below the ledge.
2014-03-15 16:59:03 +00:00
{
floorclimb = false ;
}
2014-11-19 00:45:57 +00:00
if ( topheight < player - > mo - > z + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
2014-03-15 16:59:03 +00:00
{
floorclimb = false ;
}
}
if ( floorclimb )
break ;
}
}
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
2014-11-19 00:45:57 +00:00
if ( ( floorz < = player - > mo - > z + player - > mo - > height )
& & ( ( player - > mo - > z + player - > mo - > height - player - > mo - > momz ) < = floorz ) )
2014-03-15 16:59:03 +00:00
floorclimb = true ;
2014-11-19 00:45:57 +00:00
if ( ( floorz > player - > mo - > z )
2014-03-15 16:59:03 +00:00
& & glidesector - > sector - > floorpic = = skyflatnum )
return false ;
2014-11-19 00:45:57 +00:00
if ( ( player - > mo - > z + player - > mo - > height - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) > ceilingz )
| | ( player - > mo - > z + player - > mo - > height < = floorz ) )
2014-03-15 16:59:03 +00:00
floorclimb = true ;
}
else
{
2014-11-19 00:45:57 +00:00
if ( ( ceilingz > = player - > mo - > z )
& & ( ( player - > mo - > z - player - > mo - > momz ) > = ceilingz ) )
2014-03-15 16:59:03 +00:00
floorclimb = true ;
2014-11-19 00:45:57 +00:00
if ( ( ceilingz < player - > mo - > z + player - > mo - > height )
2014-03-15 16:59:03 +00:00
& & glidesector - > sector - > ceilingpic = = skyflatnum )
return false ;
2014-11-19 00:45:57 +00:00
if ( ( player - > mo - > z + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) < ceilingz )
| | ( player - > mo - > z > = ceilingz ) )
2014-03-15 16:59:03 +00:00
floorclimb = true ;
}
if ( ! floorclimb )
return false ;
return true ;
}
return false ;
}
//
// PTR_SlideTraverse
//
static boolean PTR_SlideTraverse ( intercept_t * in )
{
line_t * li ;
I_Assert ( in - > isaline ) ;
li = in - > d . line ;
// one-sided linedefs are always solid to sliding movement.
// one-sided linedef
if ( ! li - > backsector )
{
2014-03-21 18:42:55 +00:00
if ( P_PointOnLineSide ( slidemo - > x , slidemo - > y , li ) )
2014-03-15 16:59:03 +00:00
return true ; // don't hit the back side
goto isblocking ;
}
if ( ! ( slidemo - > flags & MF_MISSILE ) )
{
if ( li - > flags & ML_IMPASSIBLE )
goto isblocking ;
2014-08-04 03:49:33 +00:00
if ( ( slidemo - > flags & ( MF_ENEMY | MF_BOSS ) ) & & li - > flags & ML_BLOCKMONSTERS )
2014-03-15 16:59:03 +00:00
goto isblocking ;
}
// set openrange, opentop, openbottom
2016-08-13 20:41:18 +00:00
P_LineOpening ( li , slidemo ) ;
2014-03-15 16:59:03 +00:00
if ( openrange < slidemo - > height )
goto isblocking ; // doesn't fit
if ( opentop - slidemo - > z < slidemo - > height )
goto isblocking ; // mobj is too high
if ( openbottom - slidemo - > z > FixedMul ( MAXSTEPMOVE , slidemo - > scale ) )
goto isblocking ; // too big a step up
// this line doesn't block movement
return true ;
// the line does block movement,
// see if it is closer than best so far
isblocking :
if ( li - > polyobj & & slidemo - > player )
{
if ( ( li - > polyobj - > lines [ 0 ] - > backsector - > flags & SF_TRIGGERSPECIAL_TOUCH ) & & ! ( li - > polyobj - > flags & POF_NOSPECIALS ) )
P_ProcessSpecialSector ( slidemo - > player , slidemo - > subsector - > sector , li - > polyobj - > lines [ 0 ] - > backsector ) ;
}
if ( slidemo - > player & & ( slidemo - > player - > pflags & PF_GLIDING | | slidemo - > player - > climbing )
& & slidemo - > player - > charability = = CA_GLIDEANDCLIMB )
{
line_t * checkline = li ;
sector_t * checksector ;
ffloor_t * rover ;
2015-05-23 01:57:58 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
boolean fofline = false ;
INT32 side = P_PointOnLineSide ( slidemo - > x , slidemo - > y , li ) ;
if ( ! side & & li - > backsector )
checksector = li - > backsector ;
else
checksector = li - > frontsector ;
if ( checksector - > ffloors )
{
for ( rover = checksector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_BLOCKPLAYER ) | | ( rover - > flags & FF_BUSTUP ) )
continue ;
2015-05-23 01:57:58 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
2014-11-19 00:45:57 +00:00
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
if ( * rover - > t_slope )
topheight = P_GetZAt ( * rover - > t_slope , slidemo - > x , slidemo - > y ) ;
if ( * rover - > b_slope )
bottomheight = P_GetZAt ( * rover - > b_slope , slidemo - > x , slidemo - > y ) ;
# endif
2014-11-19 00:45:57 +00:00
if ( topheight < slidemo - > z )
2014-03-15 16:59:03 +00:00
continue ;
2014-11-19 00:45:57 +00:00
if ( bottomheight > slidemo - > z + slidemo - > height )
2014-03-15 16:59:03 +00:00
continue ;
2014-11-19 00:45:57 +00:00
// Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this?
2014-03-15 16:59:03 +00:00
if ( rover - > master - > flags & ML_TFERLINE )
{
size_t linenum = li - checksector - > lines [ 0 ] ;
checkline = rover - > master - > frontsector - > lines [ 0 ] + linenum ;
fofline = true ;
}
break ;
}
}
// see about climbing on the wall
if ( ! ( checkline - > flags & ML_NOCLIMB ) )
{
2016-08-13 13:16:06 +00:00
boolean canclimb ;
2014-03-15 16:59:03 +00:00
angle_t climbangle , climbline ;
INT32 whichside = P_PointOnLineSide ( slidemo - > x , slidemo - > y , li ) ;
climbangle = climbline = R_PointToAngle2 ( li - > v1 - > x , li - > v1 - > y , li - > v2 - > x , li - > v2 - > y ) ;
if ( whichside ) // on second side?
climbline + = ANGLE_180 ;
climbangle + = ( ANGLE_90 * ( whichside ? - 1 : 1 ) ) ;
2016-06-20 01:08:07 +00:00
canclimb = ( li - > backsector ? P_IsClimbingValid ( slidemo - > player , climbangle ) : true ) ;
2016-06-20 00:50:47 +00:00
2016-03-30 15:47:27 +00:00
if ( ( ( ! slidemo - > player - > climbing & & abs ( ( signed ) ( slidemo - > angle - ANGLE_90 - climbline ) ) < ANGLE_45 )
| | ( slidemo - > player - > climbing = = 1 & & abs ( ( signed ) ( slidemo - > angle - climbline ) ) < ANGLE_135 ) )
2016-06-20 00:50:47 +00:00
& & canclimb )
2014-03-15 16:59:03 +00:00
{
slidemo - > angle = climbangle ;
2016-04-05 19:56:48 +00:00
if ( ! demoplayback | | P_AnalogMove ( slidemo - > player ) )
{
if ( slidemo - > player = = & players [ consoleplayer ] )
localangle = slidemo - > angle ;
else if ( slidemo - > player = = & players [ secondarydisplayplayer ] )
localangle2 = slidemo - > angle ;
}
2014-03-15 16:59:03 +00:00
if ( ! slidemo - > player - > climbing )
{
S_StartSound ( slidemo - > player - > mo , sfx_s3k4a ) ;
slidemo - > player - > climbing = 5 ;
}
2017-03-18 21:06:06 +00:00
slidemo - > player - > pflags & = ~ ( PF_GLIDING | PF_SPINNING | PF_JUMPED | PF_NOJUMPDAMAGE | PF_THOKKED ) ;
2014-03-15 16:59:03 +00:00
slidemo - > player - > glidetime = 0 ;
slidemo - > player - > secondjump = 0 ;
if ( slidemo - > player - > climbing > 1 )
slidemo - > momz = slidemo - > momx = slidemo - > momy = 0 ;
if ( fofline )
whichside = 0 ;
if ( ! whichside )
{
slidemo - > player - > lastsidehit = checkline - > sidenum [ whichside ] ;
slidemo - > player - > lastlinehit = ( INT16 ) ( checkline - lines ) ;
}
P_Thrust ( slidemo , slidemo - > angle , FixedMul ( 5 * FRACUNIT , slidemo - > scale ) ) ;
}
}
}
if ( in - > frac < bestslidefrac & & ( ! slidemo - > player | | ! slidemo - > player - > climbing ) )
{
secondslidefrac = bestslidefrac ;
secondslideline = bestslideline ;
bestslidefrac = in - > frac ;
bestslideline = li ;
}
return false ; // stop
}
//
// P_SlideCameraMove
//
// Tries to slide the camera along a wall.
//
void P_SlideCameraMove ( camera_t * thiscam )
{
fixed_t leadx , leady , trailx , traily , newx , newy ;
INT32 hitcount = 0 ;
INT32 retval = 0 ;
bestslideline = NULL ;
retry :
if ( + + hitcount = = 3 )
goto stairstep ; // don't loop forever
// trace along the three leading corners
if ( thiscam - > momx > 0 )
{
leadx = thiscam - > x + thiscam - > radius ;
trailx = thiscam - > x - thiscam - > radius ;
}
else
{
leadx = thiscam - > x - thiscam - > radius ;
trailx = thiscam - > x + thiscam - > radius ;
}
if ( thiscam - > momy > 0 )
{
leady = thiscam - > y + thiscam - > radius ;
traily = thiscam - > y - thiscam - > radius ;
}
else
{
leady = thiscam - > y - thiscam - > radius ;
traily = thiscam - > y + thiscam - > radius ;
}
bestslidefrac = FRACUNIT + 1 ;
mapcampointer = thiscam ;
P_PathTraverse ( leadx , leady , leadx + thiscam - > momx , leady + thiscam - > momy ,
PT_ADDLINES , PTR_SlideCameraTraverse ) ;
P_PathTraverse ( trailx , leady , trailx + thiscam - > momx , leady + thiscam - > momy ,
PT_ADDLINES , PTR_SlideCameraTraverse ) ;
P_PathTraverse ( leadx , traily , leadx + thiscam - > momx , traily + thiscam - > momy ,
PT_ADDLINES , PTR_SlideCameraTraverse ) ;
// move up to the wall
if ( bestslidefrac = = FRACUNIT + 1 )
{
retval = P_TryCameraMove ( thiscam - > x , thiscam - > y + thiscam - > momy , thiscam ) ;
// the move must have hit the middle, so stairstep
stairstep :
if ( ! retval ) // Allow things to drop off.
P_TryCameraMove ( thiscam - > x + thiscam - > momx , thiscam - > y , thiscam ) ;
return ;
}
// fudge a bit to make sure it doesn't hit
bestslidefrac - = 0x800 ;
if ( bestslidefrac > 0 )
{
newx = FixedMul ( thiscam - > momx , bestslidefrac ) ;
newy = FixedMul ( thiscam - > momy , bestslidefrac ) ;
retval = P_TryCameraMove ( thiscam - > x + newx , thiscam - > y + newy , thiscam ) ;
if ( ! retval )
goto stairstep ;
}
// Now continue along the wall.
// First calculate remainder.
bestslidefrac = FRACUNIT - ( bestslidefrac + 0x800 ) ;
if ( bestslidefrac > FRACUNIT )
bestslidefrac = FRACUNIT ;
if ( bestslidefrac < = 0 )
return ;
tmxmove = FixedMul ( thiscam - > momx , bestslidefrac ) ;
tmymove = FixedMul ( thiscam - > momy , bestslidefrac ) ;
P_HitCameraSlideLine ( bestslideline , thiscam ) ; // clip the moves
thiscam - > momx = tmxmove ;
thiscam - > momy = tmymove ;
retval = P_TryCameraMove ( thiscam - > x + tmxmove , thiscam - > y + tmymove , thiscam ) ;
if ( ! retval )
goto retry ;
}
//
// P_SlideMove
// The momx / momy move is bad, so try to slide
// along a wall.
// Find the first line hit, move flush to it,
// and slide along it
//
// This is a kludgy mess.
//
void P_SlideMove ( mobj_t * mo )
{
fixed_t leadx , leady , trailx , traily , newx , newy ;
INT16 hitcount = 0 ;
boolean success = false ;
2017-07-18 13:17:10 +00:00
boolean papercol = false ;
2017-07-18 13:17:10 +00:00
vertex_t v1 , v2 ; // fake vertexes
line_t junk ; // fake linedef
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( tmhitthing & & mo - > z + mo - > height > tmhitthing - > z & & mo - > z < tmhitthing - > z + tmhitthing - > height )
2014-03-15 16:59:03 +00:00
{
// Don't mess with your momentum if it's a pushable object. Pushables do their own crazy things already.
if ( tmhitthing - > flags & MF_PUSHABLE )
return ;
2017-07-18 13:17:10 +00:00
if ( tmhitthing - > flags & MF_PAPERCOLLISION )
{
2017-07-18 13:17:10 +00:00
fixed_t cosradius , sinradius , num , den ;
2017-07-18 13:17:10 +00:00
// trace along the three leading corners
if ( mo - > momx > 0 )
{
leadx = mo - > x + mo - > radius ;
trailx = mo - > x - mo - > radius ;
}
else
{
leadx = mo - > x - mo - > radius ;
trailx = mo - > x + mo - > radius ;
}
if ( mo - > momy > 0 )
{
leady = mo - > y + mo - > radius ;
traily = mo - > y - mo - > radius ;
}
else
{
leady = mo - > y - mo - > radius ;
traily = mo - > y + mo - > radius ;
}
papercol = true ;
slidemo = mo ;
bestslideline = & junk ;
cosradius = FixedMul ( tmhitthing - > radius , FINECOSINE ( tmhitthing - > angle > > ANGLETOFINESHIFT ) ) ;
sinradius = FixedMul ( tmhitthing - > radius , FINESINE ( tmhitthing - > angle > > ANGLETOFINESHIFT ) ) ;
v1 . x = tmhitthing - > x - cosradius ;
v1 . y = tmhitthing - > y - sinradius ;
v2 . x = tmhitthing - > x + cosradius ;
v2 . y = tmhitthing - > y + sinradius ;
junk . v1 = & v1 ;
junk . v2 = & v2 ;
junk . dx = 2 * cosradius ; // v2.x - v1.x;
junk . dy = 2 * sinradius ; // v2.y - v1.y;
junk . slopetype = ! cosradius ? ST_VERTICAL : ! sinradius ? ST_HORIZONTAL :
( ( sinradius > 0 ) = = ( cosradius > 0 ) ) ? ST_POSITIVE : ST_NEGATIVE ;
bestslidefrac = FRACUNIT + 1 ;
den = FixedMul ( junk . dy > > 8 , mo - > momx ) - FixedMul ( junk . dx > > 8 , mo - > momy ) ;
if ( ! den )
bestslidefrac = 0 ;
else
{
fixed_t frac ;
# define P_PaperTraverse(startx, starty) \
num = FixedMul ( ( v1 . x - leadx ) > > 8 , junk . dy ) + FixedMul ( ( leady - v1 . y ) > > 8 , junk . dx ) ; \
frac = FixedDiv ( num , den ) ; \
if ( frac < bestslidefrac ) \
bestslidefrac = frac
P_PaperTraverse ( leadx , leady ) ;
P_PaperTraverse ( trailx , leady ) ;
P_PaperTraverse ( leadx , traily ) ;
# undef dowork
}
goto papercollision ;
}
2014-03-15 16:59:03 +00:00
// Thankfully box collisions are a lot simpler than arbitrary lines. There's only four possible cases.
if ( mo - > y + mo - > radius < = tmhitthing - > y - tmhitthing - > radius )
{
mo - > momy = 0 ;
P_TryMove ( mo , mo - > x + mo - > momx , tmhitthing - > y - tmhitthing - > radius - mo - > radius , true ) ;
}
else if ( mo - > y - mo - > radius > = tmhitthing - > y + tmhitthing - > radius )
{
mo - > momy = 0 ;
P_TryMove ( mo , mo - > x + mo - > momx , tmhitthing - > y + tmhitthing - > radius + mo - > radius , true ) ;
}
else if ( mo - > x + mo - > radius < = tmhitthing - > x - tmhitthing - > radius )
{
mo - > momx = 0 ;
P_TryMove ( mo , tmhitthing - > x - tmhitthing - > radius - mo - > radius , mo - > y + mo - > momy , true ) ;
}
else if ( mo - > x - mo - > radius > = tmhitthing - > x + tmhitthing - > radius )
{
mo - > momx = 0 ;
P_TryMove ( mo , tmhitthing - > x + tmhitthing - > radius + mo - > radius , mo - > y + mo - > momy , true ) ;
}
else
mo - > momx = mo - > momy = 0 ;
return ;
}
slidemo = mo ;
bestslideline = NULL ;
retry :
2017-07-18 13:17:10 +00:00
if ( ( + + hitcount = = 3 ) | | papercol )
2014-03-15 16:59:03 +00:00
goto stairstep ; // don't loop forever
// trace along the three leading corners
if ( mo - > momx > 0 )
{
leadx = mo - > x + mo - > radius ;
trailx = mo - > x - mo - > radius ;
}
else
{
leadx = mo - > x - mo - > radius ;
trailx = mo - > x + mo - > radius ;
}
if ( mo - > momy > 0 )
{
leady = mo - > y + mo - > radius ;
traily = mo - > y - mo - > radius ;
}
else
{
leady = mo - > y - mo - > radius ;
traily = mo - > y + mo - > radius ;
}
bestslidefrac = FRACUNIT + 1 ;
P_PathTraverse ( leadx , leady , leadx + mo - > momx , leady + mo - > momy ,
PT_ADDLINES , PTR_SlideTraverse ) ;
P_PathTraverse ( trailx , leady , trailx + mo - > momx , leady + mo - > momy ,
PT_ADDLINES , PTR_SlideTraverse ) ;
P_PathTraverse ( leadx , traily , leadx + mo - > momx , traily + mo - > momy ,
PT_ADDLINES , PTR_SlideTraverse ) ;
// Some walls are bouncy even if you're not
if ( bestslideline & & bestslideline - > flags & ML_BOUNCY )
{
P_BounceMove ( mo ) ;
return ;
}
2017-07-18 13:17:10 +00:00
papercollision :
2014-03-15 16:59:03 +00:00
// move up to the wall
if ( bestslidefrac = = FRACUNIT + 1 )
{
// the move must have hit the middle, so stairstep
stairstep :
if ( ! P_TryMove ( mo , mo - > x , mo - > y + mo - > momy , true ) ) //Allow things to drop off.
P_TryMove ( mo , mo - > x + mo - > momx , mo - > y , true ) ;
return ;
}
// fudge a bit to make sure it doesn't hit
bestslidefrac - = 0x800 ;
if ( bestslidefrac > 0 )
{
newx = FixedMul ( mo - > momx , bestslidefrac ) ;
newy = FixedMul ( mo - > momy , bestslidefrac ) ;
if ( ! P_TryMove ( mo , mo - > x + newx , mo - > y + newy , true ) )
goto stairstep ;
}
// Now continue along the wall.
// First calculate remainder.
bestslidefrac = FRACUNIT - ( bestslidefrac + 0x800 ) ;
if ( bestslidefrac > FRACUNIT )
bestslidefrac = FRACUNIT ;
if ( bestslidefrac < = 0 )
return ;
tmxmove = FixedMul ( mo - > momx , bestslidefrac ) ;
tmymove = FixedMul ( mo - > momy , bestslidefrac ) ;
P_HitSlideLine ( bestslideline ) ; // clip the moves
if ( ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) & & mo - > player )
{
mo - > momx = tmxmove ;
tmymove = 0 ;
}
else
{
mo - > momx = tmxmove ;
mo - > momy = tmymove ;
}
do {
if ( tmxmove > mo - > radius ) {
newx = mo - > x + mo - > radius ;
tmxmove - = mo - > radius ;
} else if ( tmxmove < - mo - > radius ) {
newx = mo - > x - mo - > radius ;
tmxmove + = mo - > radius ;
} else {
newx = mo - > x + tmxmove ;
tmxmove = 0 ;
}
if ( tmymove > mo - > radius ) {
newy = mo - > y + mo - > radius ;
tmymove - = mo - > radius ;
} else if ( tmymove < - mo - > radius ) {
newy = mo - > y - mo - > radius ;
tmymove + = mo - > radius ;
} else {
newy = mo - > y + tmymove ;
tmymove = 0 ;
}
if ( ! P_TryMove ( mo , newx , newy , true ) ) {
if ( success )
return ; // Good enough!!
else
goto retry ;
}
success = true ;
} while ( tmxmove | | tmymove ) ;
}
//
// P_BounceMove
//
// The momx / momy move is bad, so try to bounce off a wall.
//
void P_BounceMove ( mobj_t * mo )
{
fixed_t leadx , leady ;
fixed_t trailx , traily ;
fixed_t newx , newy ;
INT32 hitcount ;
fixed_t mmomx = 0 , mmomy = 0 ;
slidemo = mo ;
hitcount = 0 ;
retry :
if ( + + hitcount = = 3 )
goto bounceback ; // don't loop forever
if ( mo - > player )
{
mmomx = mo - > player - > rmomx ;
mmomy = mo - > player - > rmomy ;
}
else
{
mmomx = mo - > momx ;
mmomy = mo - > momy ;
}
// trace along the three leading corners
if ( mo - > momx > 0 )
{
leadx = mo - > x + mo - > radius ;
trailx = mo - > x - mo - > radius ;
}
else
{
leadx = mo - > x - mo - > radius ;
trailx = mo - > x + mo - > radius ;
}
if ( mo - > momy > 0 )
{
leady = mo - > y + mo - > radius ;
traily = mo - > y - mo - > radius ;
}
else
{
leady = mo - > y - mo - > radius ;
traily = mo - > y + mo - > radius ;
}
bestslidefrac = FRACUNIT + 1 ;
P_PathTraverse ( leadx , leady , leadx + mmomx , leady + mmomy , PT_ADDLINES , PTR_SlideTraverse ) ;
P_PathTraverse ( trailx , leady , trailx + mmomx , leady + mmomy , PT_ADDLINES , PTR_SlideTraverse ) ;
P_PathTraverse ( leadx , traily , leadx + mmomx , traily + mmomy , PT_ADDLINES , PTR_SlideTraverse ) ;
// move up to the wall
if ( bestslidefrac = = FRACUNIT + 1 )
{
// the move must have hit the middle, so bounce straight back
bounceback :
if ( P_TryMove ( mo , mo - > x - mmomx , mo - > y - mmomy , true ) )
{
mo - > momx * = - 1 ;
mo - > momy * = - 1 ;
mo - > momx = FixedMul ( mo - > momx , ( FRACUNIT - ( FRACUNIT > > 2 ) - ( FRACUNIT > > 3 ) ) ) ;
mo - > momy = FixedMul ( mo - > momy , ( FRACUNIT - ( FRACUNIT > > 2 ) - ( FRACUNIT > > 3 ) ) ) ;
if ( mo - > player )
{
mo - > player - > cmomx * = - 1 ;
mo - > player - > cmomy * = - 1 ;
mo - > player - > cmomx = FixedMul ( mo - > player - > cmomx ,
( FRACUNIT - ( FRACUNIT > > 2 ) - ( FRACUNIT > > 3 ) ) ) ;
mo - > player - > cmomy = FixedMul ( mo - > player - > cmomy ,
( FRACUNIT - ( FRACUNIT > > 2 ) - ( FRACUNIT > > 3 ) ) ) ;
}
}
return ;
}
// fudge a bit to make sure it doesn't hit
bestslidefrac - = 0x800 ;
if ( bestslidefrac > 0 )
{
newx = FixedMul ( mmomx , bestslidefrac ) ;
newy = FixedMul ( mmomy , bestslidefrac ) ;
if ( ! P_TryMove ( mo , mo - > x + newx , mo - > y + newy , true ) )
goto bounceback ;
}
// Now continue along the wall.
// First calculate remainder.
bestslidefrac = FRACUNIT - bestslidefrac ;
if ( bestslidefrac > FRACUNIT )
bestslidefrac = FRACUNIT ;
if ( bestslidefrac < = 0 )
return ;
if ( mo - > type = = MT_SHELL )
{
tmxmove = mmomx ;
tmymove = mmomy ;
}
else if ( mo - > type = = MT_THROWNBOUNCE )
{
tmxmove = FixedMul ( mmomx , ( FRACUNIT - ( FRACUNIT > > 6 ) - ( FRACUNIT > > 5 ) ) ) ;
tmymove = FixedMul ( mmomy , ( FRACUNIT - ( FRACUNIT > > 6 ) - ( FRACUNIT > > 5 ) ) ) ;
}
else if ( mo - > type = = MT_THROWNGRENADE | | mo - > type = = MT_CYBRAKDEMON_NAPALM_BOMB_LARGE )
{
// Quickly decay speed as it bounces
tmxmove = FixedDiv ( mmomx , 2 * FRACUNIT ) ;
tmymove = FixedDiv ( mmomy , 2 * FRACUNIT ) ;
}
else
{
tmxmove = FixedMul ( mmomx , ( FRACUNIT - ( FRACUNIT > > 2 ) - ( FRACUNIT > > 3 ) ) ) ;
tmymove = FixedMul ( mmomy , ( FRACUNIT - ( FRACUNIT > > 2 ) - ( FRACUNIT > > 3 ) ) ) ;
}
P_HitBounceLine ( bestslideline ) ; // clip the moves
mo - > momx = tmxmove ;
mo - > momy = tmymove ;
if ( mo - > player )
{
mo - > player - > cmomx = tmxmove ;
mo - > player - > cmomy = tmymove ;
}
if ( ! P_TryMove ( mo , mo - > x + tmxmove , mo - > y + tmymove , true ) )
goto retry ;
}
//
// RADIUS ATTACK
//
static fixed_t bombdamage ;
static mobj_t * bombsource ;
static mobj_t * bombspot ;
2018-05-08 22:26:36 +00:00
static UINT8 bombdamagetype ;
2014-03-15 16:59:03 +00:00
//
// PIT_RadiusAttack
// "bombsource" is the creature
// that caused the explosion at "bombspot".
//
static boolean PIT_RadiusAttack ( mobj_t * thing )
{
fixed_t dx , dy , dz , dist ;
2018-05-08 22:26:36 +00:00
if ( thing = = bombspot ) // ignore the bomb itself (Deton fix)
2014-03-15 16:59:03 +00:00
return true ;
2018-05-08 22:26:36 +00:00
if ( ( thing - > flags & ( MF_MONITOR | MF_SHOOTABLE ) ) ! = MF_SHOOTABLE )
2014-03-15 16:59:03 +00:00
return true ;
2018-05-08 22:26:36 +00:00
if ( bombsource & & thing - > type = = bombsource - > type & & ! ( bombdamagetype & DMG_CANHURTSELF ) ) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.)
2016-11-12 15:39:47 +00:00
return true ;
2014-03-15 16:59:03 +00:00
dx = abs ( thing - > x - bombspot - > x ) ;
dy = abs ( thing - > y - bombspot - > y ) ;
dz = abs ( thing - > z + ( thing - > height > > 1 ) - bombspot - > z ) ;
dist = P_AproxDistance ( P_AproxDistance ( dx , dy ) , dz ) ;
dist - = thing - > radius ;
if ( dist < 0 )
dist = 0 ;
if ( dist > = bombdamage )
return true ; // out of range
if ( thing - > floorz > bombspot - > z & & bombspot - > ceilingz < thing - > z )
return true ;
if ( thing - > ceilingz < bombspot - > z & & bombspot - > floorz > thing - > z )
return true ;
if ( P_CheckSight ( thing , bombspot ) )
{ // must be in direct path
2018-05-08 22:26:36 +00:00
P_DamageMobj ( thing , bombspot , bombsource , 1 , bombdamagetype ) ; // Tails 01-11-2001
2014-03-15 16:59:03 +00:00
}
return true ;
}
//
// P_RadiusAttack
// Source is the creature that caused the explosion at spot.
//
2018-05-08 22:26:36 +00:00
void P_RadiusAttack ( mobj_t * spot , mobj_t * source , fixed_t damagedist , UINT8 damagetype )
2014-03-15 16:59:03 +00:00
{
INT32 x , y ;
INT32 xl , xh , yl , yh ;
fixed_t dist ;
dist = FixedMul ( damagedist , spot - > scale ) + MAXRADIUS ;
2015-04-09 01:50:49 +00:00
yh = ( unsigned ) ( spot - > y + dist - bmaporgy ) > > MAPBLOCKSHIFT ;
yl = ( unsigned ) ( spot - > y - dist - bmaporgy ) > > MAPBLOCKSHIFT ;
xh = ( unsigned ) ( spot - > x + dist - bmaporgx ) > > MAPBLOCKSHIFT ;
xl = ( unsigned ) ( spot - > x - dist - bmaporgx ) > > MAPBLOCKSHIFT ;
2014-03-15 16:59:03 +00:00
2015-04-09 02:32:07 +00:00
BMBOUNDFIX ( xl , xh , yl , yh ) ;
2014-03-15 16:59:03 +00:00
bombspot = spot ;
bombsource = source ;
bombdamage = FixedMul ( damagedist , spot - > scale ) ;
2018-05-08 22:26:36 +00:00
bombdamagetype = damagetype ;
2014-03-15 16:59:03 +00:00
for ( y = yl ; y < = yh ; y + + )
for ( x = xl ; x < = xh ; x + + )
P_BlockThingsIterator ( x , y , PIT_RadiusAttack ) ;
}
//
// SECTOR HEIGHT CHANGING
// After modifying a sectors floor or ceiling height,
// call this routine to adjust the positions
// of all things that touch the sector.
//
// If anything doesn't fit anymore, true will be returned.
// If crunch is true, they will take damage
// as they are being crushed.
// If Crunch is false, you should set the sector height back
// the way it was and call P_CheckSector (? was P_ChangeSector - Graue) again
// to undo the changes.
//
static boolean crushchange ;
static boolean nofit ;
//
// PIT_ChangeSector
//
static boolean PIT_ChangeSector ( mobj_t * thing , boolean realcrush )
{
2014-08-04 03:49:33 +00:00
mobj_t * killer = NULL ;
2019-06-10 12:10:37 +00:00
//If a thing is both pushable and vulnerable, it doesn't block the crusher because it gets killed.
boolean immunepushable = ( ( thing - > flags & ( MF_PUSHABLE | MF_SHOOTABLE ) ) = = MF_PUSHABLE ) ;
2014-08-04 03:49:33 +00:00
2014-03-15 16:59:03 +00:00
if ( P_ThingHeightClip ( thing ) )
{
2014-08-04 03:49:33 +00:00
//thing fits, check next thing
2014-03-15 16:59:03 +00:00
return true ;
}
if ( ! ( thing - > flags & ( MF_SHOOTABLE | MF_PUSHABLE ) )
| | thing - > flags & MF_NOCLIPHEIGHT )
{
2014-08-04 03:49:33 +00:00
//doesn't interact with the crusher, just ignore it
2014-03-15 16:59:03 +00:00
return true ;
}
2014-08-04 03:49:33 +00:00
// Thing doesn't fit. If thing is vulnerable, that means it's being crushed. If thing is pushable, it might
// just be blocked by another object - check if it's really a ceiling!
2014-03-15 16:59:03 +00:00
if ( thing - > z + thing - > height > thing - > ceilingz & & thing - > z < = thing - > ceilingz )
{
2019-06-10 12:10:37 +00:00
if ( immunepushable & & thing - > z + thing - > height > thing - > subsector - > sector - > ceilingheight )
2014-08-04 03:49:33 +00:00
{
//Thing is a pushable and blocks the moving ceiling
nofit = true ;
return false ;
}
//Check FOFs in the sector
2019-06-10 12:10:37 +00:00
if ( thing - > subsector - > sector - > ffloors & & ( realcrush | | immunepushable ) )
2014-03-15 16:59:03 +00:00
{
ffloor_t * rover ;
2015-05-23 01:57:58 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
fixed_t delta1 , delta2 ;
INT32 thingtop = thing - > z + thing - > height ;
for ( rover = thing - > subsector - > sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( ( ( rover - > flags & FF_BLOCKPLAYER ) & & thing - > player )
| | ( ( rover - > flags & FF_BLOCKOTHERS ) & & ! thing - > player ) ) | | ! ( rover - > flags & FF_EXISTS ) )
continue ;
2015-05-23 01:57:58 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
2014-11-19 00:45:57 +00:00
/*#ifdef ESLOPE
if ( rover - > t_slope )
topheight = P_GetZAt ( rover - > t_slope , thing - > x , thing - > y ) ;
if ( rover - > b_slope )
bottomheight = P_GetZAt ( rover - > b_slope , thing - > x , thing - > y ) ;
# endif* /
delta1 = thing - > z - ( bottomheight + topheight ) / 2 ;
delta2 = thingtop - ( bottomheight + topheight ) / 2 ;
if ( bottomheight < = thing - > ceilingz & & abs ( delta1 ) > = abs ( delta2 ) )
2014-03-15 16:59:03 +00:00
{
2019-06-10 12:10:37 +00:00
if ( immunepushable )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
//FOF is blocked by pushable
nofit = true ;
return false ;
}
else
{
//If the thing was crushed by a crumbling FOF, reward the player who made it crumble!
thinker_t * think ;
elevator_t * crumbler ;
2014-03-15 16:59:03 +00:00
2019-04-20 20:37:19 +00:00
for ( think = thlist [ THINK_MAIN ] . next ; think ! = & thlist [ THINK_MAIN ] ; think = think - > next )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( think - > function . acp1 ! = ( actionf_p1 ) T_StartCrumble )
continue ;
crumbler = ( elevator_t * ) think ;
if ( crumbler - > player & & crumbler - > player - > mo
& & crumbler - > player - > mo ! = thing
& & crumbler - > actionsector = = thing - > subsector - > sector
& & crumbler - > sector = = rover - > master - > frontsector
& & ( crumbler - > type = = elevateBounce
| | crumbler - > type = = elevateContinuous ) )
{
killer = crumbler - > player - > mo ;
}
2014-03-15 16:59:03 +00:00
}
}
}
}
}
if ( realcrush )
{
2014-08-04 03:49:33 +00:00
// Crush the object
2014-03-15 16:59:03 +00:00
if ( netgame & & thing - > player & & thing - > player - > spectator )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( thing , NULL , NULL , 1 , DMG_SPECTATOR ) ; // Respawn crushed spectators
2014-03-15 16:59:03 +00:00
else
2015-02-13 16:15:58 +00:00
P_DamageMobj ( thing , killer , killer , 1 , DMG_CRUSHED ) ;
return true ;
2014-03-15 16:59:03 +00:00
}
}
if ( realcrush & & crushchange )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( thing , NULL , NULL , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
// keep checking (crush other things)
return true ;
}
//
// P_CheckSector
//
boolean P_CheckSector ( sector_t * sector , boolean crunch )
{
msecnode_t * n ;
nofit = false ;
crushchange = crunch ;
// killough 4/4/98: scan list front-to-back until empty or exhausted,
// restarting from beginning after each thing is processed. Avoids
// crashes, and is sure to examine all things in the sector, and only
// the things which are in the sector, until a steady-state is reached.
// Things can arbitrarily be inserted and removed and it won't mess up.
//
// killough 4/7/98: simplified to avoid using complicated counter
// First, let's see if anything will keep it from crushing.
if ( sector - > numattached )
{
size_t i ;
sector_t * sec ;
for ( i = 0 ; i < sector - > numattached ; i + + )
{
sec = & sectors [ sector - > attached [ i ] ] ;
2016-06-09 13:16:02 +00:00
for ( n = sec - > touching_thinglist ; n ; n = n - > m_thinglist_next )
2014-03-15 16:59:03 +00:00
n - > visited = false ;
sec - > moved = true ;
P_RecalcPrecipInSector ( sec ) ;
if ( ! sector - > attachedsolid [ i ] )
continue ;
do
{
2016-06-09 13:16:02 +00:00
for ( n = sec - > touching_thinglist ; n ; n = n - > m_thinglist_next )
2014-03-15 16:59:03 +00:00
if ( ! n - > visited )
{
n - > visited = true ;
if ( ! ( n - > m_thing - > flags & MF_NOBLOCKMAP ) )
{
if ( ! PIT_ChangeSector ( n - > m_thing , false ) )
{
nofit = true ;
return nofit ;
}
}
break ;
}
} while ( n ) ;
}
}
// Mark all things invalid
sector - > moved = true ;
2016-06-09 13:16:02 +00:00
for ( n = sector - > touching_thinglist ; n ; n = n - > m_thinglist_next )
2014-03-15 16:59:03 +00:00
n - > visited = false ;
do
{
2016-06-09 13:16:02 +00:00
for ( n = sector - > touching_thinglist ; n ; n = n - > m_thinglist_next ) // go through list
2014-03-15 16:59:03 +00:00
if ( ! n - > visited ) // unprocessed thing found
{
n - > visited = true ; // mark thing as processed
if ( ! ( n - > m_thing - > flags & MF_NOBLOCKMAP ) ) //jff 4/7/98 don't do these
{
if ( ! PIT_ChangeSector ( n - > m_thing , false ) ) // process it
{
nofit = true ;
return nofit ;
}
}
break ; // exit and start over
}
} while ( n ) ; // repeat from scratch until all things left are marked valid
// Nothing blocked us, so lets crush for real!
if ( sector - > numattached )
{
size_t i ;
sector_t * sec ;
for ( i = 0 ; i < sector - > numattached ; i + + )
{
sec = & sectors [ sector - > attached [ i ] ] ;
2016-06-09 13:16:02 +00:00
for ( n = sec - > touching_thinglist ; n ; n = n - > m_thinglist_next )
2014-03-15 16:59:03 +00:00
n - > visited = false ;
sec - > moved = true ;
P_RecalcPrecipInSector ( sec ) ;
if ( ! sector - > attachedsolid [ i ] )
continue ;
do
{
2016-06-09 13:16:02 +00:00
for ( n = sec - > touching_thinglist ; n ; n = n - > m_thinglist_next )
2014-03-15 16:59:03 +00:00
if ( ! n - > visited )
{
n - > visited = true ;
if ( ! ( n - > m_thing - > flags & MF_NOBLOCKMAP ) )
{
PIT_ChangeSector ( n - > m_thing , true ) ;
return nofit ;
}
break ;
}
} while ( n ) ;
}
}
// Mark all things invalid
sector - > moved = true ;
2016-06-09 13:16:02 +00:00
for ( n = sector - > touching_thinglist ; n ; n = n - > m_thinglist_next )
2014-03-15 16:59:03 +00:00
n - > visited = false ;
do
{
2016-06-09 13:16:02 +00:00
for ( n = sector - > touching_thinglist ; n ; n = n - > m_thinglist_next ) // go through list
2014-03-15 16:59:03 +00:00
if ( ! n - > visited ) // unprocessed thing found
{
n - > visited = true ; // mark thing as processed
if ( ! ( n - > m_thing - > flags & MF_NOBLOCKMAP ) ) //jff 4/7/98 don't do these
{
PIT_ChangeSector ( n - > m_thing , true ) ; // process it
return nofit ;
}
break ; // exit and start over
}
} while ( n ) ; // repeat from scratch until all things left are marked valid
return nofit ;
}
/*
SoM : 3 / 15 / 2000
Lots of new Boom functions that work faster and add functionality .
*/
static msecnode_t * headsecnode = NULL ;
static mprecipsecnode_t * headprecipsecnode = NULL ;
void P_Initsecnode ( void )
{
headsecnode = NULL ;
headprecipsecnode = NULL ;
}
// P_GetSecnode() retrieves a node from the freelist. The calling routine
// should make sure it sets all fields properly.
static msecnode_t * P_GetSecnode ( void )
{
msecnode_t * node ;
if ( headsecnode )
{
node = headsecnode ;
2016-06-09 13:16:02 +00:00
headsecnode = headsecnode - > m_thinglist_next ;
2014-03-15 16:59:03 +00:00
}
else
node = Z_Calloc ( sizeof ( * node ) , PU_LEVEL , NULL ) ;
return node ;
}
static mprecipsecnode_t * P_GetPrecipSecnode ( void )
{
mprecipsecnode_t * node ;
if ( headprecipsecnode )
{
node = headprecipsecnode ;
2016-06-09 13:16:02 +00:00
headprecipsecnode = headprecipsecnode - > m_thinglist_next ;
2014-03-15 16:59:03 +00:00
}
else
node = Z_Calloc ( sizeof ( * node ) , PU_LEVEL , NULL ) ;
return node ;
}
// P_PutSecnode() returns a node to the freelist.
static inline void P_PutSecnode ( msecnode_t * node )
{
2016-06-09 13:16:02 +00:00
node - > m_thinglist_next = headsecnode ;
2014-03-15 16:59:03 +00:00
headsecnode = node ;
}
// Tails 08-25-2002
static inline void P_PutPrecipSecnode ( mprecipsecnode_t * node )
{
2016-06-09 13:16:02 +00:00
node - > m_thinglist_next = headprecipsecnode ;
2014-03-15 16:59:03 +00:00
headprecipsecnode = node ;
}
// P_AddSecnode() searches the current list to see if this sector is
// already there. If not, it adds a sector node at the head of the list of
// sectors this object appears in. This is called when creating a list of
// nodes that will get linked in later. Returns a pointer to the new node.
static msecnode_t * P_AddSecnode ( sector_t * s , mobj_t * thing , msecnode_t * nextnode )
{
msecnode_t * node ;
node = nextnode ;
while ( node )
{
if ( node - > m_sector = = s ) // Already have a node for this sector?
{
node - > m_thing = thing ; // Yes. Setting m_thing says 'keep it'.
return nextnode ;
}
2016-06-09 13:16:02 +00:00
node = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
}
// Couldn't find an existing node for this sector. Add one at the head
// of the list.
node = P_GetSecnode ( ) ;
// mark new nodes unvisited.
node - > visited = 0 ;
node - > m_sector = s ; // sector
node - > m_thing = thing ; // mobj
2016-06-09 13:16:02 +00:00
node - > m_sectorlist_prev = NULL ; // prev node on Thing thread
node - > m_sectorlist_next = nextnode ; // next node on Thing thread
2014-03-15 16:59:03 +00:00
if ( nextnode )
2016-06-09 13:16:02 +00:00
nextnode - > m_sectorlist_prev = node ; // set back link on Thing
2014-03-15 16:59:03 +00:00
// Add new node at head of sector thread starting at s->touching_thinglist
2016-06-09 13:16:02 +00:00
node - > m_thinglist_prev = NULL ; // prev node on sector thread
node - > m_thinglist_next = s - > touching_thinglist ; // next node on sector thread
2014-03-15 16:59:03 +00:00
if ( s - > touching_thinglist )
2016-06-09 13:16:02 +00:00
node - > m_thinglist_next - > m_thinglist_prev = node ;
2014-03-15 16:59:03 +00:00
s - > touching_thinglist = node ;
return node ;
}
// More crazy crap Tails 08-25-2002
static mprecipsecnode_t * P_AddPrecipSecnode ( sector_t * s , precipmobj_t * thing , mprecipsecnode_t * nextnode )
{
mprecipsecnode_t * node ;
node = nextnode ;
while ( node )
{
if ( node - > m_sector = = s ) // Already have a node for this sector?
{
node - > m_thing = thing ; // Yes. Setting m_thing says 'keep it'.
return nextnode ;
}
2016-06-09 13:16:02 +00:00
node = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
}
// Couldn't find an existing node for this sector. Add one at the head
// of the list.
node = P_GetPrecipSecnode ( ) ;
// mark new nodes unvisited.
node - > visited = 0 ;
node - > m_sector = s ; // sector
node - > m_thing = thing ; // mobj
2016-06-09 13:16:02 +00:00
node - > m_sectorlist_prev = NULL ; // prev node on Thing thread
node - > m_sectorlist_next = nextnode ; // next node on Thing thread
2014-03-15 16:59:03 +00:00
if ( nextnode )
2016-06-09 13:16:02 +00:00
nextnode - > m_sectorlist_prev = node ; // set back link on Thing
2014-03-15 16:59:03 +00:00
// Add new node at head of sector thread starting at s->touching_thinglist
2016-06-09 13:16:02 +00:00
node - > m_thinglist_prev = NULL ; // prev node on sector thread
node - > m_thinglist_next = s - > touching_preciplist ; // next node on sector thread
2014-03-15 16:59:03 +00:00
if ( s - > touching_preciplist )
2016-06-09 13:16:02 +00:00
node - > m_thinglist_next - > m_thinglist_prev = node ;
2014-03-15 16:59:03 +00:00
s - > touching_preciplist = node ;
return node ;
}
// P_DelSecnode() deletes a sector node from the list of
// sectors this object appears in. Returns a pointer to the next node
// on the linked list, or NULL.
static msecnode_t * P_DelSecnode ( msecnode_t * node )
{
msecnode_t * tp ; // prev node on thing thread
msecnode_t * tn ; // next node on thing thread
msecnode_t * sp ; // prev node on sector thread
msecnode_t * sn ; // next node on sector thread
if ( ! node )
return NULL ;
// Unlink from the Thing thread. The Thing thread begins at
// sector_list and not from mobj_t->touching_sectorlist.
2016-06-09 13:16:02 +00:00
tp = node - > m_sectorlist_prev ;
tn = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
if ( tp )
2016-06-09 13:16:02 +00:00
tp - > m_sectorlist_next = tn ;
2014-03-15 16:59:03 +00:00
if ( tn )
2016-06-09 13:16:02 +00:00
tn - > m_sectorlist_prev = tp ;
2014-03-15 16:59:03 +00:00
// Unlink from the sector thread. This thread begins at
// sector_t->touching_thinglist.
2016-06-09 13:16:02 +00:00
sp = node - > m_thinglist_prev ;
sn = node - > m_thinglist_next ;
2014-03-15 16:59:03 +00:00
if ( sp )
2016-06-09 13:16:02 +00:00
sp - > m_thinglist_next = sn ;
2014-03-15 16:59:03 +00:00
else
node - > m_sector - > touching_thinglist = sn ;
if ( sn )
2016-06-09 13:16:02 +00:00
sn - > m_thinglist_prev = sp ;
2014-03-15 16:59:03 +00:00
// Return this node to the freelist
P_PutSecnode ( node ) ;
return tn ;
}
// Tails 08-25-2002
static mprecipsecnode_t * P_DelPrecipSecnode ( mprecipsecnode_t * node )
{
mprecipsecnode_t * tp ; // prev node on thing thread
mprecipsecnode_t * tn ; // next node on thing thread
mprecipsecnode_t * sp ; // prev node on sector thread
mprecipsecnode_t * sn ; // next node on sector thread
if ( ! node )
return NULL ;
// Unlink from the Thing thread. The Thing thread begins at
// sector_list and not from mobj_t->touching_sectorlist.
2016-06-09 13:16:02 +00:00
tp = node - > m_sectorlist_prev ;
tn = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
if ( tp )
2016-06-09 13:16:02 +00:00
tp - > m_sectorlist_next = tn ;
2014-03-15 16:59:03 +00:00
if ( tn )
2016-06-09 13:16:02 +00:00
tn - > m_sectorlist_prev = tp ;
2014-03-15 16:59:03 +00:00
// Unlink from the sector thread. This thread begins at
// sector_t->touching_thinglist.
2016-06-09 13:16:02 +00:00
sp = node - > m_thinglist_prev ;
sn = node - > m_thinglist_next ;
2014-03-15 16:59:03 +00:00
if ( sp )
2016-06-09 13:16:02 +00:00
sp - > m_thinglist_next = sn ;
2014-03-15 16:59:03 +00:00
else
node - > m_sector - > touching_preciplist = sn ;
if ( sn )
2016-06-09 13:16:02 +00:00
sn - > m_thinglist_prev = sp ;
2014-03-15 16:59:03 +00:00
// Return this node to the freelist
P_PutPrecipSecnode ( node ) ;
return tn ;
}
// Delete an entire sector list
void P_DelSeclist ( msecnode_t * node )
{
while ( node )
node = P_DelSecnode ( node ) ;
}
// Tails 08-25-2002
void P_DelPrecipSeclist ( mprecipsecnode_t * node )
{
while ( node )
node = P_DelPrecipSecnode ( node ) ;
}
// PIT_GetSectors
// Locates all the sectors the object is in by looking at the lines that
// cross through it. You have already decided that the object is allowed
// at this location, so don't bother with checking impassable or
// blocking lines.
static inline boolean PIT_GetSectors ( line_t * ld )
{
if ( tmbbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | |
tmbbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ] | |
tmbbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | |
tmbbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
return true ;
if ( P_BoxOnLineSide ( tmbbox , ld ) ! = - 1 )
return true ;
2016-02-28 18:30:29 +00:00
if ( ld - > polyobj ) // line belongs to a polyobject, don't add it
return true ;
2014-03-15 16:59:03 +00:00
// This line crosses through the object.
// Collect the sector(s) from the line and add to the
// sector_list you're examining. If the Thing ends up being
// allowed to move to this position, then the sector_list
// will be attached to the Thing's mobj_t at touching_sectorlist.
sector_list = P_AddSecnode ( ld - > frontsector , tmthing , sector_list ) ;
// Don't assume all lines are 2-sided, since some Things
// like MT_TFOG are allowed regardless of whether their radius takes
// them beyond an impassable linedef.
// Use sidedefs instead of 2s flag to determine two-sidedness.
if ( ld - > backsector )
sector_list = P_AddSecnode ( ld - > backsector , tmthing , sector_list ) ;
return true ;
}
// Tails 08-25-2002
static inline boolean PIT_GetPrecipSectors ( line_t * ld )
{
if ( preciptmbbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | |
preciptmbbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ] | |
preciptmbbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | |
preciptmbbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
return true ;
if ( P_BoxOnLineSide ( preciptmbbox , ld ) ! = - 1 )
return true ;
2016-02-28 18:30:29 +00:00
if ( ld - > polyobj ) // line belongs to a polyobject, don't add it
return true ;
2014-03-15 16:59:03 +00:00
// This line crosses through the object.
// Collect the sector(s) from the line and add to the
// sector_list you're examining. If the Thing ends up being
// allowed to move to this position, then the sector_list
// will be attached to the Thing's mobj_t at touching_sectorlist.
precipsector_list = P_AddPrecipSecnode ( ld - > frontsector , tmprecipthing , precipsector_list ) ;
// Don't assume all lines are 2-sided, since some Things
// like MT_TFOG are allowed regardless of whether their radius takes
// them beyond an impassable linedef.
// Use sidedefs instead of 2s flag to determine two-sidedness.
if ( ld - > backsector )
precipsector_list = P_AddPrecipSecnode ( ld - > backsector , tmprecipthing , precipsector_list ) ;
return true ;
}
// P_CreateSecNodeList alters/creates the sector_list that shows what sectors
// the object resides in.
void P_CreateSecNodeList ( mobj_t * thing , fixed_t x , fixed_t y )
{
INT32 xl , xh , yl , yh , bx , by ;
msecnode_t * node = sector_list ;
mobj_t * saved_tmthing = tmthing ; /* cph - see comment at func end */
fixed_t saved_tmx = tmx , saved_tmy = tmy ; /* ditto */
// First, clear out the existing m_thing fields. As each node is
// added or verified as needed, m_thing will be set properly. When
// finished, delete all nodes where m_thing is still NULL. These
// represent the sectors the Thing has vacated.
while ( node )
{
node - > m_thing = NULL ;
2016-06-09 13:16:02 +00:00
node = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
}
P_SetTarget ( & tmthing , thing ) ;
tmflags = thing - > flags ;
tmx = x ;
tmy = y ;
tmbbox [ BOXTOP ] = y + tmthing - > radius ;
tmbbox [ BOXBOTTOM ] = y - tmthing - > radius ;
tmbbox [ BOXRIGHT ] = x + tmthing - > radius ;
tmbbox [ BOXLEFT ] = x - tmthing - > radius ;
validcount + + ; // used to make sure we only process a line once
2015-04-09 01:50:49 +00:00
xl = ( unsigned ) ( tmbbox [ BOXLEFT ] - bmaporgx ) > > MAPBLOCKSHIFT ;
xh = ( unsigned ) ( tmbbox [ BOXRIGHT ] - bmaporgx ) > > MAPBLOCKSHIFT ;
yl = ( unsigned ) ( tmbbox [ BOXBOTTOM ] - bmaporgy ) > > MAPBLOCKSHIFT ;
yh = ( unsigned ) ( tmbbox [ BOXTOP ] - bmaporgy ) > > MAPBLOCKSHIFT ;
2014-03-15 16:59:03 +00:00
2015-04-09 02:32:07 +00:00
BMBOUNDFIX ( xl , xh , yl , yh ) ;
2014-03-15 16:59:03 +00:00
for ( bx = xl ; bx < = xh ; bx + + )
for ( by = yl ; by < = yh ; by + + )
P_BlockLinesIterator ( bx , by , PIT_GetSectors ) ;
// Add the sector of the (x, y) point to sector_list.
sector_list = P_AddSecnode ( thing - > subsector - > sector , thing , sector_list ) ;
// Now delete any nodes that won't be used. These are the ones where
// m_thing is still NULL.
node = sector_list ;
while ( node )
{
if ( ! node - > m_thing )
{
if ( node = = sector_list )
2016-06-09 13:16:02 +00:00
sector_list = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
node = P_DelSecnode ( node ) ;
}
else
2016-06-09 13:16:02 +00:00
node = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
}
/* cph -
* This is the strife we get into for using global variables . tmthing
* is being used by several different functions calling
* P_BlockThingIterator , including functions that can be called * from *
* P_BlockThingIterator . Using a global tmthing is not reentrant .
* OTOH for Boom / MBF demos we have to preserve the buggy behavior .
* Fun . We restore its previous value unless we ' re in a Boom / MBF demo .
*/
P_SetTarget ( & tmthing , saved_tmthing ) ;
/* And, duh, the same for tmx/y - cph 2002/09/22
* And for tmbbox - cph 2003 / 08 / 10 */
tmx = saved_tmx , tmy = saved_tmy ;
if ( tmthing )
{
tmbbox [ BOXTOP ] = tmy + tmthing - > radius ;
tmbbox [ BOXBOTTOM ] = tmy - tmthing - > radius ;
tmbbox [ BOXRIGHT ] = tmx + tmthing - > radius ;
tmbbox [ BOXLEFT ] = tmx - tmthing - > radius ;
}
}
// More crazy crap Tails 08-25-2002
void P_CreatePrecipSecNodeList ( precipmobj_t * thing , fixed_t x , fixed_t y )
{
INT32 xl , xh , yl , yh , bx , by ;
mprecipsecnode_t * node = precipsector_list ;
precipmobj_t * saved_tmthing = tmprecipthing ; /* cph - see comment at func end */
// First, clear out the existing m_thing fields. As each node is
// added or verified as needed, m_thing will be set properly. When
// finished, delete all nodes where m_thing is still NULL. These
// represent the sectors the Thing has vacated.
while ( node )
{
node - > m_thing = NULL ;
2016-06-09 13:16:02 +00:00
node = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
}
tmprecipthing = thing ;
preciptmbbox [ BOXTOP ] = y + 2 * FRACUNIT ;
preciptmbbox [ BOXBOTTOM ] = y - 2 * FRACUNIT ;
preciptmbbox [ BOXRIGHT ] = x + 2 * FRACUNIT ;
preciptmbbox [ BOXLEFT ] = x - 2 * FRACUNIT ;
validcount + + ; // used to make sure we only process a line once
2015-04-09 01:50:49 +00:00
xl = ( unsigned ) ( preciptmbbox [ BOXLEFT ] - bmaporgx ) > > MAPBLOCKSHIFT ;
xh = ( unsigned ) ( preciptmbbox [ BOXRIGHT ] - bmaporgx ) > > MAPBLOCKSHIFT ;
yl = ( unsigned ) ( preciptmbbox [ BOXBOTTOM ] - bmaporgy ) > > MAPBLOCKSHIFT ;
yh = ( unsigned ) ( preciptmbbox [ BOXTOP ] - bmaporgy ) > > MAPBLOCKSHIFT ;
2014-03-15 16:59:03 +00:00
2015-04-09 02:32:07 +00:00
BMBOUNDFIX ( xl , xh , yl , yh ) ;
2014-03-15 16:59:03 +00:00
for ( bx = xl ; bx < = xh ; bx + + )
for ( by = yl ; by < = yh ; by + + )
P_BlockLinesIterator ( bx , by , PIT_GetPrecipSectors ) ;
// Add the sector of the (x, y) point to sector_list.
precipsector_list = P_AddPrecipSecnode ( thing - > subsector - > sector , thing , precipsector_list ) ;
// Now delete any nodes that won't be used. These are the ones where
// m_thing is still NULL.
node = precipsector_list ;
while ( node )
{
if ( ! node - > m_thing )
{
if ( node = = precipsector_list )
2016-06-09 13:16:02 +00:00
precipsector_list = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
node = P_DelPrecipSecnode ( node ) ;
}
else
2016-06-09 13:16:02 +00:00
node = node - > m_sectorlist_next ;
2014-03-15 16:59:03 +00:00
}
/* cph -
* This is the strife we get into for using global variables . tmthing
* is being used by several different functions calling
* P_BlockThingIterator , including functions that can be called * from *
* P_BlockThingIterator . Using a global tmthing is not reentrant .
* OTOH for Boom / MBF demos we have to preserve the buggy behavior .
* Fun . We restore its previous value unless we ' re in a Boom / MBF demo .
*/
tmprecipthing = saved_tmthing ;
}
/* cphipps 2004/08/30 -
* Must clear tmthing at tic end , as it might contain a pointer to a removed thinker , or the level might have ended / been ended and we clear the objects it was pointing too . Hopefully we don ' t need to carry this between tics for sync . */
void P_MapStart ( void )
{
if ( tmthing )
I_Error ( " P_MapStart: tmthing set! " ) ;
}
void P_MapEnd ( void )
{
P_SetTarget ( & tmthing , NULL ) ;
}
// P_FloorzAtPos
2014-11-19 00:45:57 +00:00
// Returns the floorz of the XYZ position // TODO: Need ceilingpos function too
2014-03-15 16:59:03 +00:00
// Tails 05-26-2003
fixed_t P_FloorzAtPos ( fixed_t x , fixed_t y , fixed_t z , fixed_t height )
{
sector_t * sec = R_PointInSubsector ( x , y ) - > sector ;
fixed_t floorz = sec - > floorheight ;
2017-08-30 18:21:23 +00:00
# ifdef ESLOPE
if ( sec - > f_slope )
floorz = P_GetZAt ( sec - > f_slope , x , y ) ;
# endif
2014-03-15 16:59:03 +00:00
// Intercept the stupid 'fall through 3dfloors' bug Tails 03-17-2002
if ( sec - > ffloors )
{
ffloor_t * rover ;
fixed_t delta1 , delta2 , thingtop = z + height ;
for ( rover = sec - > ffloors ; rover ; rover = rover - > next )
{
2015-10-10 16:57:35 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
if ( ( ! ( rover - > flags & FF_SOLID | | rover - > flags & FF_QUICKSAND ) | | ( rover - > flags & FF_SWIMMABLE ) ) )
continue ;
2015-10-10 16:57:35 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
2015-04-27 18:20:50 +00:00
2015-05-17 16:53:28 +00:00
# ifdef ESLOPE
if ( * rover - > t_slope )
topheight = P_GetZAt ( * rover - > t_slope , x , y ) ;
if ( * rover - > b_slope )
bottomheight = P_GetZAt ( * rover - > b_slope , x , y ) ;
# endif
2014-11-19 00:45:57 +00:00
2014-03-15 16:59:03 +00:00
if ( rover - > flags & FF_QUICKSAND )
{
2014-11-19 00:45:57 +00:00
if ( z < topheight & & bottomheight < thingtop )
2014-03-15 16:59:03 +00:00
{
if ( floorz < z )
floorz = z ;
}
continue ;
}
2014-11-19 00:45:57 +00:00
delta1 = z - ( bottomheight + ( ( topheight - bottomheight ) / 2 ) ) ;
delta2 = thingtop - ( bottomheight + ( ( topheight - bottomheight ) / 2 ) ) ;
if ( topheight > floorz & & abs ( delta1 ) < abs ( delta2 ) )
floorz = topheight ;
2014-03-15 16:59:03 +00:00
}
}
return floorz ;
}