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.
2019-12-06 18:49:42 +00:00
// Copyright (C) 1999-2019 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_user.c
/// \brief New stuff?
/// Player related stuff.
/// Bobbing POV/weapon, movement.
/// Pending weapon.
# include "doomdef.h"
# include "i_system.h"
# include "d_event.h"
# include "d_net.h"
# include "g_game.h"
# include "p_local.h"
# include "r_main.h"
# include "s_sound.h"
# include "r_things.h"
# include "d_think.h"
# include "r_sky.h"
# include "p_setup.h"
# include "m_random.h"
# include "m_misc.h"
# include "i_video.h"
2015-10-10 16:57:35 +00:00
# include "p_slopes.h"
2014-03-15 16:59:03 +00:00
# include "p_spec.h"
# include "r_splats.h"
# include "z_zone.h"
# include "w_wad.h"
# include "hu_stuff.h"
// We need to affect the NiGHTS hud
# include "st_stuff.h"
# include "lua_script.h"
2014-08-04 03:49:33 +00:00
# include "lua_hook.h"
2014-03-15 16:59:03 +00:00
# include "b_bot.h"
// Objectplace
# include "m_cheat.h"
2019-12-08 21:22:51 +00:00
// Thok camera snap (ctrl-f "chalupa")
# include "g_input.h"
2014-03-15 16:59:03 +00:00
# ifdef HW3SOUND
# include "hardware/hw3sound.h"
# endif
# ifdef HWRENDER
# include "hardware/hw_light.h"
# include "hardware/hw_main.h"
# endif
#if 0
static void P_NukeAllPlayers ( player_t * player ) ;
# endif
2019-08-04 11:03:57 +00:00
//
// Jingle stuff.
//
jingle_t jingleinfo [ NUMJINGLES ] = {
// {musname, looping, reset, nest}
{ " " , false } , // JT_NONE
{ " " , false } , // JT_OTHER
{ " " , false } , // JT_MASTER
{ " _1up " , false } ,
{ " _shoes " , true } ,
{ " _inv " , false } ,
{ " _minv " , false } ,
{ " _drown " , false } ,
{ " _super " , true } ,
{ " _gover " , false } ,
{ " _ntime " , false } , // JT_NIGHTSTIMEOUT
{ " _drown " , false } // JT_SSTIMEOUT
// {"_clear" , false},
// {"_inter" , true},
// {"_conti" , true}
} ;
2014-03-15 16:59:03 +00:00
//
// Movement.
//
// 16 pixels of bob
# define MAXBOB (0x10 << FRACBITS)
static boolean onground ;
//
// P_Thrust
// Moves the given origin along a given angle.
//
void P_Thrust ( mobj_t * mo , angle_t angle , fixed_t move )
{
angle > > = ANGLETOFINESHIFT ;
mo - > momx + = FixedMul ( move , FINECOSINE ( angle ) ) ;
if ( ! ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) )
mo - > momy + = FixedMul ( move , FINESINE ( angle ) ) ;
}
#if 0
static inline void P_ThrustEvenIn2D ( mobj_t * mo , angle_t angle , fixed_t move )
{
angle > > = ANGLETOFINESHIFT ;
mo - > momx + = FixedMul ( move , FINECOSINE ( angle ) ) ;
mo - > momy + = FixedMul ( move , FINESINE ( angle ) ) ;
}
static inline void P_VectorInstaThrust ( fixed_t xa , fixed_t xb , fixed_t xc , fixed_t ya , fixed_t yb , fixed_t yc ,
fixed_t za , fixed_t zb , fixed_t zc , fixed_t momentum , mobj_t * mo )
{
fixed_t a1 , b1 , c1 , a2 , b2 , c2 , i , j , k ;
a1 = xb - xa ;
b1 = yb - ya ;
c1 = zb - za ;
a2 = xb - xc ;
b2 = yb - yc ;
c2 = zb - zc ;
/*
// Convert to unit vectors...
a1 = FixedDiv ( a1 , FixedSqrt ( FixedMul ( a1 , a1 ) + FixedMul ( b1 , b1 ) + FixedMul ( c1 , c1 ) ) ) ;
b1 = FixedDiv ( b1 , FixedSqrt ( FixedMul ( a1 , a1 ) + FixedMul ( b1 , b1 ) + FixedMul ( c1 , c1 ) ) ) ;
c1 = FixedDiv ( c1 , FixedSqrt ( FixedMul ( c1 , c1 ) + FixedMul ( c1 , c1 ) + FixedMul ( c1 , c1 ) ) ) ;
a2 = FixedDiv ( a2 , FixedSqrt ( FixedMul ( a2 , a2 ) + FixedMul ( c2 , c2 ) + FixedMul ( c2 , c2 ) ) ) ;
b2 = FixedDiv ( b2 , FixedSqrt ( FixedMul ( a2 , a2 ) + FixedMul ( c2 , c2 ) + FixedMul ( c2 , c2 ) ) ) ;
c2 = FixedDiv ( c2 , FixedSqrt ( FixedMul ( a2 , a2 ) + FixedMul ( c2 , c2 ) + FixedMul ( c2 , c2 ) ) ) ;
*/
// Calculate the momx, momy, and momz
i = FixedMul ( momentum , FixedMul ( b1 , c2 ) - FixedMul ( c1 , b2 ) ) ;
j = FixedMul ( momentum , FixedMul ( c1 , a2 ) - FixedMul ( a1 , c2 ) ) ;
k = FixedMul ( momentum , FixedMul ( a1 , b2 ) - FixedMul ( a1 , c2 ) ) ;
mo - > momx = i ;
mo - > momy = j ;
mo - > momz = k ;
}
# endif
//
// P_InstaThrust
// Moves the given origin along a given angle instantly.
//
// FIXTHIS: belongs in another file, not here
//
void P_InstaThrust ( mobj_t * mo , angle_t angle , fixed_t move )
{
angle > > = ANGLETOFINESHIFT ;
mo - > momx = FixedMul ( move , FINECOSINE ( angle ) ) ;
if ( ! ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) )
mo - > momy = FixedMul ( move , FINESINE ( angle ) ) ;
}
void P_InstaThrustEvenIn2D ( mobj_t * mo , angle_t angle , fixed_t move )
{
angle > > = ANGLETOFINESHIFT ;
mo - > momx = FixedMul ( move , FINECOSINE ( angle ) ) ;
mo - > momy = FixedMul ( move , FINESINE ( angle ) ) ;
}
// Returns a location (hard to explain - go see how it is used)
fixed_t P_ReturnThrustX ( mobj_t * mo , angle_t angle , fixed_t move )
{
( void ) mo ;
angle > > = ANGLETOFINESHIFT ;
return FixedMul ( move , FINECOSINE ( angle ) ) ;
}
fixed_t P_ReturnThrustY ( mobj_t * mo , angle_t angle , fixed_t move )
{
( void ) mo ;
angle > > = ANGLETOFINESHIFT ;
return FixedMul ( move , FINESINE ( angle ) ) ;
}
2015-01-01 19:50:31 +00:00
//
// P_AutoPause
// Returns true when gameplay should be halted even if the game isn't necessarily paused.
//
boolean P_AutoPause ( void )
2014-03-15 16:59:03 +00:00
{
2015-01-01 19:50:31 +00:00
// Don't pause even on menu-up or focus-lost in netgames or record attack
2017-04-18 21:23:23 +00:00
if ( netgame | | modeattacking | | gamestate = = GS_TITLESCREEN )
2014-03-15 16:59:03 +00:00
return false ;
2019-03-11 21:57:11 +00:00
return ( menuactive | | ( window_notinfocus & & cv_pauseifunfocused . value ) ) ;
2014-03-15 16:59:03 +00:00
}
//
// P_CalcHeight
// Calculate the walking / running height adjustment
//
void P_CalcHeight ( player_t * player )
{
INT32 angle ;
fixed_t bob ;
fixed_t pviewheight ;
mobj_t * mo = player - > mo ;
// Regular movement bobbing.
// Should not be calculated when not on ground (FIXTHIS?)
// OPTIMIZE: tablify angle
// Note: a LUT allows for effects
// like a ramp with low health.
2017-10-14 20:11:08 +00:00
player - > bob = FixedMul ( cv_movebob . value ,
( FixedMul ( player - > rmomx , player - > rmomx )
+ FixedMul ( player - > rmomy , player - > rmomy ) ) > > 2 ) ;
2014-03-15 16:59:03 +00:00
2017-10-14 20:11:08 +00:00
if ( player - > bob > FixedMul ( cv_movebob . value , FixedMul ( MAXBOB , mo - > scale ) ) )
player - > bob = FixedMul ( cv_movebob . value , FixedMul ( MAXBOB , mo - > scale ) ) ;
2014-03-15 16:59:03 +00:00
if ( ! P_IsObjectOnGround ( mo ) )
{
if ( mo - > eflags & MFE_VERTICALFLIP )
{
player - > viewz = mo - > z + mo - > height - player - > viewheight ;
if ( player - > viewz < mo - > floorz + FixedMul ( FRACUNIT , mo - > scale ) )
player - > viewz = mo - > floorz + FixedMul ( FRACUNIT , mo - > scale ) ;
}
else
{
player - > viewz = mo - > z + player - > viewheight ;
if ( player - > viewz > mo - > ceilingz - FixedMul ( FRACUNIT , mo - > scale ) )
player - > viewz = mo - > ceilingz - FixedMul ( FRACUNIT , mo - > scale ) ;
}
return ;
}
angle = ( FINEANGLES / 20 * localgametic ) & FINEMASK ;
bob = FixedMul ( player - > bob / 2 , FINESINE ( angle ) ) ;
// move viewheight
2017-10-14 20:11:08 +00:00
pviewheight = FixedMul ( 41 * player - > height / 48 , mo - > scale ) ; // default eye view height
2014-03-15 16:59:03 +00:00
if ( player - > playerstate = = PST_LIVE )
{
player - > viewheight + = player - > deltaviewheight ;
if ( player - > viewheight > pviewheight )
{
player - > viewheight = pviewheight ;
player - > deltaviewheight = 0 ;
}
if ( player - > viewheight < pviewheight / 2 )
{
player - > viewheight = pviewheight / 2 ;
if ( player - > deltaviewheight < = 0 )
player - > deltaviewheight = 1 ;
}
if ( player - > deltaviewheight )
{
player - > deltaviewheight + = FixedMul ( FRACUNIT / 4 , mo - > scale ) ;
if ( ! player - > deltaviewheight )
player - > deltaviewheight = 1 ;
}
}
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
player - > viewz = mo - > z + mo - > height - player - > viewheight - bob ;
else
player - > viewz = mo - > z + player - > viewheight + bob ;
if ( player - > viewz > mo - > ceilingz - FixedMul ( 4 * FRACUNIT , mo - > scale ) )
player - > viewz = mo - > ceilingz - FixedMul ( 4 * FRACUNIT , mo - > scale ) ;
if ( player - > viewz < mo - > floorz + FixedMul ( 4 * FRACUNIT , mo - > scale ) )
player - > viewz = mo - > floorz + FixedMul ( 4 * FRACUNIT , mo - > scale ) ;
}
/** Decides if a player is moving.
* \ param pnum The player number to test .
* \ return True if the player is considered to be moving .
* \ author Graue < graue @ oceanbase . org >
*/
boolean P_PlayerMoving ( INT32 pnum )
{
player_t * p = & players [ pnum ] ;
2014-03-18 17:56:54 +00:00
if ( ! Playing ( ) )
return false ;
2014-03-15 16:59:03 +00:00
if ( p - > jointime < 5 * TICRATE | | p - > playerstate = = PST_DEAD | | p - > playerstate = = PST_REBORN | | p - > spectator )
return false ;
return gamestate = = GS_LEVEL & & p - > mo & & p - > mo - > health > 0
& & ( abs ( p - > rmomx ) > = FixedMul ( FRACUNIT / 2 , p - > mo - > scale )
| | abs ( p - > rmomy ) > = FixedMul ( FRACUNIT / 2 , p - > mo - > scale )
| | abs ( p - > mo - > momz ) > = FixedMul ( FRACUNIT / 2 , p - > mo - > scale )
| | p - > climbing | | p - > powers [ pw_tailsfly ]
| | ( p - > pflags & PF_JUMPED ) | | ( p - > pflags & PF_SPINNING ) ) ;
}
// P_GetNextEmerald
//
// Gets the number (0 based) of the next emerald to obtain
//
UINT8 P_GetNextEmerald ( void )
{
2018-06-06 15:07:14 +00:00
if ( gamemap > = sstage_start & & gamemap < = sstage_end )
2014-03-15 16:59:03 +00:00
return ( UINT8 ) ( gamemap - sstage_start ) ;
2018-06-06 15:07:14 +00:00
if ( gamemap > = smpstage_start | | gamemap < = smpstage_end )
return ( UINT8 ) ( gamemap - smpstage_start ) ;
return 0 ;
2014-03-15 16:59:03 +00:00
}
//
// P_GiveEmerald
//
// Award an emerald upon completion
// of a special stage.
//
void P_GiveEmerald ( boolean spawnObj )
{
2018-06-03 21:41:54 +00:00
UINT8 em = P_GetNextEmerald ( ) ;
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_cgot ) ; // Got the emerald!
emeralds | = ( 1 < < em ) ;
2019-07-30 15:44:40 +00:00
stagefailed = false ;
2014-03-15 16:59:03 +00:00
2019-07-30 15:44:40 +00:00
if ( spawnObj )
2014-03-15 16:59:03 +00:00
{
2018-06-03 21:41:54 +00:00
// The Chaos Emerald begins to orbit us!
2019-07-30 15:44:40 +00:00
// Only visibly give it to ONE person!
UINT8 i , pnum = ( ( playeringame [ consoleplayer ] ) & & ( ! players [ consoleplayer ] . spectator ) & & ( players [ consoleplayer ] . mo ) ) ? consoleplayer : 255 ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
mobj_t * emmo ;
if ( ! playeringame [ i ] )
continue ;
if ( players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo )
continue ;
emmo = P_SpawnMobjFromMobj ( players [ i ] . mo , 0 , 0 , players [ i ] . mo - > height , MT_GOTEMERALD ) ;
2019-11-25 14:33:15 +00:00
if ( ! emmo )
continue ;
2019-07-30 15:44:40 +00:00
P_SetTarget ( & emmo - > target , players [ i ] . mo ) ;
P_SetMobjState ( emmo , mobjinfo [ MT_GOTEMERALD ] . meleestate + em ) ;
P_SetTarget ( & players [ i ] . mo - > tracer , emmo ) ;
if ( pnum = = 255 )
{
2019-11-25 14:33:15 +00:00
pnum = i ;
2019-07-30 15:44:40 +00:00
continue ;
}
if ( i = = pnum )
continue ;
emmo - > flags2 | = MF2_DONTDRAW ;
}
2014-03-15 16:59:03 +00:00
}
}
2017-03-20 16:57:24 +00:00
#if 0
2014-03-15 16:59:03 +00:00
//
// P_ResetScore
//
2015-01-01 19:50:31 +00:00
// This is called when your chain is reset.
2014-03-15 16:59:03 +00:00
void P_ResetScore ( player_t * player )
{
2015-01-01 19:50:31 +00:00
// Formally a host for Chaos mode behavior
2014-03-15 16:59:03 +00:00
player - > scoreadd = 0 ;
}
2017-03-20 16:57:24 +00:00
# endif
2014-03-15 16:59:03 +00:00
//
// P_FindLowestMare
//
// Returns the lowest open mare available
//
UINT8 P_FindLowestMare ( void )
{
thinker_t * th ;
mobj_t * mo2 ;
UINT8 mare = UINT8_MAX ;
if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION )
return 0 ;
// scan the thinkers
// to find the egg capsule with the lowest mare
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > type ! = MT_EGGCAPSULE )
continue ;
if ( mo2 - > health < = 0 )
continue ;
2014-03-15 16:59:03 +00:00
{
const UINT8 threshold = ( UINT8 ) mo2 - > threshold ;
if ( mare = = 255 )
mare = threshold ;
else if ( threshold < mare )
mare = threshold ;
}
}
CONS_Debug ( DBG_NIGHTS , " Lowest mare found: %d \n " , mare ) ;
return mare ;
}
//
// P_TransferToNextMare
//
// Transfers the player to the next Mare.
// (Finds the lowest mare # for capsules that have not been destroyed).
// Returns true if successful, false if there is no other mare.
//
boolean P_TransferToNextMare ( player_t * player )
{
thinker_t * th ;
mobj_t * mo2 ;
mobj_t * closestaxis = NULL ;
INT32 lowestaxisnum = - 1 ;
UINT8 mare = P_FindLowestMare ( ) ;
fixed_t dist1 , dist2 = 0 ;
if ( mare = = 255 )
return false ;
CONS_Debug ( DBG_NIGHTS , " Mare is %d \n " , mare ) ;
player - > mare = mare ;
2018-03-30 18:36:49 +00:00
player - > marelap = 0 ;
player - > marebonuslap = 0 ;
2014-03-15 16:59:03 +00:00
// scan the thinkers
// to find the closest axis point
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > type ! = MT_AXIS )
continue ;
if ( mo2 - > threshold ! = mare )
continue ;
if ( closestaxis = = NULL )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
closestaxis = mo2 ;
lowestaxisnum = mo2 - > health ;
dist2 = R_PointToDist2 ( player - > mo - > x , player - > mo - > y , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
}
else if ( mo2 - > health < lowestaxisnum )
{
dist1 = R_PointToDist2 ( player - > mo - > x , player - > mo - > y , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
2014-03-15 16:59:03 +00:00
2019-07-12 23:42:03 +00:00
if ( dist1 < dist2 )
{
closestaxis = mo2 ;
lowestaxisnum = mo2 - > health ;
dist2 = dist1 ;
2014-03-15 16:59:03 +00:00
}
}
}
if ( closestaxis = = NULL )
return false ;
P_SetTarget ( & player - > mo - > target , closestaxis ) ;
return true ;
}
//
// P_FindAxis
//
// Given a mare and axis number, returns
// the mobj for that axis point.
static mobj_t * P_FindAxis ( INT32 mare , INT32 axisnum )
{
thinker_t * th ;
mobj_t * mo2 ;
// scan the thinkers
// to find the closest axis point
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
// Axis things are only at beginning of list.
if ( ! ( mo2 - > flags2 & MF2_AXIS ) )
return NULL ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > type ! = MT_AXIS )
continue ;
if ( mo2 - > health ! = axisnum )
continue ;
if ( mo2 - > threshold ! = mare )
continue ;
return mo2 ;
2014-03-15 16:59:03 +00:00
}
return NULL ;
}
//
// P_FindAxisTransfer
//
// Given a mare and axis number, returns
// the mobj for that axis transfer point.
static mobj_t * P_FindAxisTransfer ( INT32 mare , INT32 axisnum , mobjtype_t type )
{
thinker_t * th ;
mobj_t * mo2 ;
// scan the thinkers
// to find the closest axis point
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
// Axis things are only at beginning of list.
if ( ! ( mo2 - > flags2 & MF2_AXIS ) )
return NULL ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > type ! = type )
continue ;
if ( mo2 - > health ! = axisnum )
continue ;
if ( mo2 - > threshold ! = mare )
continue ;
return mo2 ;
2014-03-15 16:59:03 +00:00
}
return NULL ;
}
//
// P_TransferToAxis
//
// Finds the CLOSEST axis with the number specified.
void P_TransferToAxis ( player_t * player , INT32 axisnum )
{
thinker_t * th ;
mobj_t * mo2 ;
mobj_t * closestaxis ;
INT32 mare = player - > mare ;
fixed_t dist1 , dist2 = 0 ;
CONS_Debug ( DBG_NIGHTS , " Transferring to axis %d \n Leveltime: %u... \n " , axisnum , leveltime ) ;
closestaxis = NULL ;
// scan the thinkers
// to find the closest axis point
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > type ! = MT_AXIS )
continue ;
if ( mo2 - > health ! = axisnum )
continue ;
if ( mo2 - > threshold ! = mare )
continue ;
if ( closestaxis = = NULL )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
closestaxis = mo2 ;
dist2 = R_PointToDist2 ( player - > mo - > x , player - > mo - > y , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
}
else
{
dist1 = R_PointToDist2 ( player - > mo - > x , player - > mo - > y , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
2014-03-15 16:59:03 +00:00
2019-07-12 23:42:03 +00:00
if ( dist1 < dist2 )
{
closestaxis = mo2 ;
dist2 = dist1 ;
2014-03-15 16:59:03 +00:00
}
}
}
if ( ! closestaxis )
{
CONS_Debug ( DBG_NIGHTS , " ERROR: Specified axis point to transfer to not found! \n %d \n " , axisnum ) ;
}
else
{
CONS_Debug ( DBG_NIGHTS , " Transferred to axis %d, mare %d \n " , closestaxis - > health , closestaxis - > threshold ) ;
}
P_SetTarget ( & player - > mo - > target , closestaxis ) ;
}
//
// P_DeNightserizePlayer
//
// Whoops! Ran out of NiGHTS time!
//
static void P_DeNightserizePlayer ( player_t * player )
{
thinker_t * th ;
mobj_t * mo2 ;
2017-09-15 19:34:46 +00:00
player - > powers [ pw_carry ] = CR_NIGHTSFALL ;
2014-03-15 16:59:03 +00:00
player - > powers [ pw_underwater ] = 0 ;
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ ( PF_USEDOWN | PF_JUMPDOWN | PF_ATTACKDOWN | PF_STARTDASH | PF_GLIDING | PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_THOKKED | PF_SPINNING | PF_DRILLING | PF_TRANSFERTOCLOSEST ) ;
2014-03-15 16:59:03 +00:00
player - > secondjump = 0 ;
player - > homing = 0 ;
player - > climbing = 0 ;
player - > mo - > fuse = 0 ;
player - > speed = 0 ;
2018-03-30 18:36:49 +00:00
player - > marelap = 0 ;
player - > marebonuslap = 0 ;
2018-03-26 05:54:38 +00:00
player - > flyangle = 0 ;
player - > anotherflyangle = 0 ;
2019-11-15 01:14:40 +00:00
# ifdef ROTSPRITE
player - > mo - > rollangle = 0 ;
# endif
2014-03-15 16:59:03 +00:00
P_SetTarget ( & player - > mo - > target , NULL ) ;
P_SetTarget ( & player - > axis1 , P_SetTarget ( & player - > axis2 , NULL ) ) ;
player - > mo - > flags & = ~ MF_NOGRAVITY ;
2016-08-12 01:57:37 +00:00
player - > mo - > skin = & skins [ player - > skin ] ;
2017-10-02 13:08:58 +00:00
player - > followitem = skins [ player - > skin ] . followitem ;
2016-08-12 01:57:37 +00:00
player - > mo - > color = player - > skincolor ;
2019-07-30 16:24:21 +00:00
G_GhostAddColor ( GHC_RETURNSKIN ) ;
2014-03-15 16:59:03 +00:00
// Restore aiming angle
if ( player = = & players [ consoleplayer ] )
localaiming = 0 ;
else if ( player = = & players [ secondarydisplayplayer ] )
localaiming2 = 0 ;
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2014-03-15 16:59:03 +00:00
// If in a special stage, add some preliminary exit time.
if ( G_IsSpecialStage ( gamemap ) )
{
INT32 i ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2017-03-14 18:11:17 +00:00
if ( playeringame [ i ] & & players [ i ] . powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
players [ i ] . nightstime = 1 ; // force everyone else to fall too.
player - > exiting = 3 * TICRATE ;
2018-08-13 15:12:53 +00:00
// If you screwed up, kiss your score and ring bonus goodbye.
2018-09-07 12:19:22 +00:00
// But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground.
player - > marescore = player - > spheres = \
player - > rings = 0 ;
2014-03-15 16:59:03 +00:00
}
// Check to see if the player should be killed.
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
if ( ! ( mo2 - > type = = MT_NIGHTSDRONE ) )
continue ;
2016-08-18 19:09:35 +00:00
if ( mo2 - > flags2 & MF2_AMBUSH )
2018-09-07 12:19:22 +00:00
{
player - > marescore = player - > spheres = \
player - > rings = 0 ;
2015-02-13 16:15:58 +00:00
P_DamageMobj ( player - > mo , NULL , NULL , 1 , DMG_INSTAKILL ) ;
2019-03-15 03:10:14 +00:00
// Reset music to beginning if MIXNIGHTSCOUNTDOWN
if ( ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_MIXNIGHTSCOUNTDOWN )
# ifdef _WIN32
& & S_MusicType ( ) ! = MU_MID
# endif
)
S_SetMusicPosition ( 0 ) ;
2018-09-07 12:19:22 +00:00
}
2014-03-15 16:59:03 +00:00
break ;
}
2018-08-11 04:51:33 +00:00
if ( player - > mo - > scale ! = player - > oldscale )
player - > mo - > destscale = player - > oldscale ;
player - > oldscale = 0 ;
2014-03-15 16:59:03 +00:00
// Restore from drowning music
2019-03-15 03:10:14 +00:00
if ( ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_MIXNIGHTSCOUNTDOWN )
# ifdef _WIN32
& & S_MusicType ( ) ! = MU_MID
# endif
)
{
S_StopSoundByNum ( sfx_timeup ) ;
S_StopFadingMusic ( ) ;
S_SetInternalMusicVolume ( 100 ) ;
// Reset the music if you did not destroy all the capsules, because you failed.
// Why make the all-capsules exception: because it's your reward for nearly finishing the level!
// (unless the player auto-loses upon denightserizing; for death case, see above.)
if ( P_FindLowestMare ( ) ! = UINT8_MAX | | G_IsSpecialStage ( gamemap ) )
S_SetMusicPosition ( 0 ) ;
}
else
2019-08-04 11:03:57 +00:00
{
music_stack_fadein = 0 ; // HACK: Change fade-in for restore music
2019-03-15 03:10:14 +00:00
P_RestoreMusic ( player ) ;
2019-08-04 11:03:57 +00:00
}
2018-03-30 18:22:59 +00:00
2018-03-31 14:11:27 +00:00
P_RunDeNightserizeExecutors ( player - > mo ) ;
2014-03-15 16:59:03 +00:00
}
2016-08-12 01:57:37 +00:00
2014-03-15 16:59:03 +00:00
//
// P_NightserizePlayer
//
// NiGHTS Time!
void P_NightserizePlayer ( player_t * player , INT32 nighttime )
{
2018-08-10 20:30:49 +00:00
UINT8 oldmare , oldmarelap , oldmarebonuslap ;
2014-03-15 16:59:03 +00:00
2017-03-11 17:14:39 +00:00
// Bots can't be NiGHTSerized, silly!1 :P
2014-03-15 16:59:03 +00:00
if ( player - > bot )
return ;
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] ! = CR_NIGHTSMODE )
2018-08-11 04:51:33 +00:00
{
2016-08-12 13:42:22 +00:00
player - > mo - > height = P_GetPlayerHeight ( player ) ; // Just to make sure jumping into the drone doesn't result in a squashed hitbox.
2018-08-11 04:51:33 +00:00
player - > oldscale = player - > mo - > scale ;
2019-08-04 14:25:13 +00:00
2019-11-14 16:37:03 +00:00
if ( skins [ player - > skin ] . sprites [ SPR2_NFLY ] . numframes = = 0 ) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
2019-08-04 14:25:13 +00:00
{
player - > mo - > skin = & skins [ DEFAULTNIGHTSSKIN ] ;
if ( ! ( cv_debug | | devparm ) & & ! ( netgame | | multiplayer | | demoplayback ) )
player - > mo - > color = skins [ DEFAULTNIGHTSSKIN ] . prefcolor ;
player - > followitem = skins [ DEFAULTNIGHTSSKIN ] . followitem ;
G_GhostAddColor ( GHC_NIGHTSSKIN ) ;
}
2018-08-11 04:51:33 +00:00
}
2014-08-04 03:49:33 +00:00
2017-03-18 21:06:06 +00:00
player - > pflags & = ~ ( PF_USEDOWN | PF_JUMPDOWN | PF_ATTACKDOWN | PF_STARTDASH | PF_GLIDING | PF_JUMPED | PF_NOJUMPDAMAGE | PF_THOKKED | PF_SHIELDABILITY | PF_SPINNING | PF_DRILLING ) ;
2014-03-15 16:59:03 +00:00
player - > homing = 0 ;
player - > mo - > fuse = 0 ;
player - > speed = 0 ;
player - > climbing = 0 ;
player - > secondjump = 0 ;
2018-03-26 05:54:38 +00:00
player - > flyangle = 0 ;
player - > anotherflyangle = 0 ;
2019-11-15 01:14:40 +00:00
# ifdef ROTSPRITE
player - > mo - > rollangle = 0 ;
# endif
2014-03-15 16:59:03 +00:00
player - > powers [ pw_shield ] = SH_NONE ;
2017-03-11 17:14:39 +00:00
player - > powers [ pw_super ] = 0 ;
2014-03-15 16:59:03 +00:00
player - > mo - > flags | = MF_NOGRAVITY ;
2018-08-10 21:12:26 +00:00
player - > nightstime = player - > startedtime = player - > lapstartedtime = nighttime * TICRATE ;
2014-03-15 16:59:03 +00:00
player - > bonustime = false ;
2019-03-15 03:10:14 +00:00
// Restore from drowning music
if ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_MIXNIGHTSCOUNTDOWN )
{
S_StopSoundByNum ( sfx_timeup ) ;
S_StopFadingMusic ( ) ;
S_SetInternalMusicVolume ( 100 ) ;
}
else
2019-08-04 11:03:57 +00:00
{
music_stack_fadein = 0 ; // HACK: Change fade-in for restore music
2019-03-15 03:10:14 +00:00
P_RestoreMusic ( player ) ;
2019-08-04 11:03:57 +00:00
}
2019-03-15 03:10:14 +00:00
2014-03-15 16:59:03 +00:00
if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION )
{
if ( player - > drillmeter < 48 * 20 )
player - > drillmeter = 48 * 20 ;
}
else
{
if ( player - > drillmeter < 40 * 20 )
player - > drillmeter = 40 * 20 ;
}
oldmare = player - > mare ;
2018-08-10 20:30:49 +00:00
oldmarelap = player - > marelap ;
oldmarebonuslap = player - > marebonuslap ;
2014-03-15 16:59:03 +00:00
2018-06-03 21:41:54 +00:00
if ( ! P_TransferToNextMare ( player ) )
2014-03-15 16:59:03 +00:00
{
INT32 i ;
2018-06-03 21:41:54 +00:00
INT32 total_spheres = 0 ;
2014-03-15 16:59:03 +00:00
INT32 total_rings = 0 ;
P_SetTarget ( & player - > mo - > target , NULL ) ;
if ( G_IsSpecialStage ( gamemap ) )
{
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2017-03-14 18:11:17 +00:00
if ( playeringame [ i ] /* && players[i].powers[pw_carry] == CR_NIGHTSMODE*/ )
2018-08-10 08:05:20 +00:00
{
2018-06-03 21:41:54 +00:00
total_spheres + = players [ i ] . spheres ;
2015-08-15 20:07:16 +00:00
total_rings + = players [ i ] . rings ;
2018-08-10 08:05:20 +00:00
}
2014-03-15 16:59:03 +00:00
}
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | ! players [ i ] . mo | | players [ i ] . spectator )
continue ;
players [ i ] . texttimer = ( 3 * TICRATE ) - 10 ;
players [ i ] . textvar = 4 ; // Score and grades
players [ i ] . lastmare = players [ i ] . mare ;
2018-08-10 20:30:49 +00:00
players [ i ] . lastmarelap = players [ i ] . marelap ;
players [ i ] . lastmarebonuslap = players [ i ] . marebonuslap ;
2014-03-15 16:59:03 +00:00
if ( G_IsSpecialStage ( gamemap ) )
{
2018-06-03 21:41:54 +00:00
players [ i ] . finishedspheres = ( INT16 ) total_spheres ;
2014-03-15 16:59:03 +00:00
players [ i ] . finishedrings = ( INT16 ) total_rings ;
2018-06-03 21:41:54 +00:00
P_AddPlayerScore ( player , total_spheres * 50 ) ;
2014-03-15 16:59:03 +00:00
}
else
{
2018-06-03 21:41:54 +00:00
players [ i ] . finishedspheres = ( INT16 ) ( players [ i ] . spheres ) ;
2015-08-15 20:07:16 +00:00
players [ i ] . finishedrings = ( INT16 ) ( players [ i ] . rings ) ;
2018-06-03 21:41:54 +00:00
P_AddPlayerScore ( & players [ i ] , ( players [ i ] . spheres ) * 50 ) ;
2014-03-15 16:59:03 +00:00
}
// Add score to leaderboards now
if ( ! ( netgame | | multiplayer ) & & P_IsLocalPlayer ( & players [ i ] ) )
G_AddTempNightsRecords ( players [ i ] . marescore , leveltime - player - > marebegunat , players [ i ] . mare + 1 ) ;
// transfer scores anyway
2018-08-12 23:59:34 +00:00
players [ i ] . totalmarescore + = players [ i ] . marescore ;
2014-03-15 16:59:03 +00:00
players [ i ] . lastmarescore = players [ i ] . marescore ;
players [ i ] . marescore = 0 ;
2018-08-10 07:05:10 +00:00
players [ i ] . spheres = players [ i ] . rings = 0 ;
2014-03-15 16:59:03 +00:00
P_DoPlayerExit ( & players [ i ] ) ;
}
}
else if ( oldmare ! = player - > mare )
{
/// \todo Handle multi-mare special stages.
2018-06-03 21:41:54 +00:00
// Spheres bonus
P_AddPlayerScore ( player , ( player - > spheres ) * 50 ) ;
2014-03-15 16:59:03 +00:00
2018-08-10 20:30:49 +00:00
player - > lastmare = oldmare ;
player - > lastmarelap = oldmarelap ;
player - > lastmarebonuslap = oldmarebonuslap ;
2014-03-15 16:59:03 +00:00
player - > texttimer = 4 * TICRATE ;
player - > textvar = 4 ; // Score and grades
2018-06-03 21:41:54 +00:00
player - > finishedspheres = ( INT16 ) ( player - > spheres ) ;
2018-08-10 20:17:28 +00:00
player - > finishedrings = ( INT16 ) ( player - > rings ) ;
2014-03-15 16:59:03 +00:00
// Add score to temp leaderboards
if ( ! ( netgame | | multiplayer ) & & P_IsLocalPlayer ( player ) )
G_AddTempNightsRecords ( player - > marescore , leveltime - player - > marebegunat , ( UINT8 ) ( oldmare + 1 ) ) ;
// Starting a new mare, transfer scores
2018-08-12 23:26:18 +00:00
player - > totalmarescore + = player - > marescore ;
2014-03-15 16:59:03 +00:00
player - > lastmarescore = player - > marescore ;
player - > marescore = 0 ;
player - > marebegunat = leveltime ;
2018-08-10 21:12:26 +00:00
player - > lapbegunat = leveltime ;
2014-03-15 16:59:03 +00:00
2018-08-10 07:05:10 +00:00
player - > spheres = player - > rings = 0 ;
2014-03-15 16:59:03 +00:00
}
else
{
player - > textvar = 5 ; // Nothing, just tells it to go to the GET n RINGS/SPHERES text in a bit
player - > texttimer = 40 ;
// Don't show before title card
// Not consistency safe, but this only affects drawing
2018-06-14 19:17:31 +00:00
if ( timeinmap + 40 < ( 110 - 70 ) )
player - > texttimer = ( UINT8 ) ( ( 110 - 70 ) - timeinmap ) ;
2014-03-15 16:59:03 +00:00
}
2018-08-11 04:51:33 +00:00
if ( player - > drone & & player - > drone - > scale ! = player - > mo - > scale )
player - > mo - > destscale = player - > drone - > scale ;
2018-04-02 19:21:19 +00:00
// force NiGHTS to face forward or backward
2018-04-02 14:02:16 +00:00
if ( player - > mo - > target )
2019-08-04 14:25:13 +00:00
{
player - > angle_pos = R_PointToAngle2 ( player - > mo - > target - > x , player - > mo - > target - > y , player - > mo - > x , player - > mo - > y ) ;
2019-10-13 15:15:46 +00:00
player - > drawangle = player - > angle_pos
2018-04-07 10:28:31 +00:00
+ ( ( player - > mo - > target - > flags2 & MF2_AMBUSH ) ? // if axis is invert, take the opposite right angle
2019-08-04 14:25:13 +00:00
- ANGLE_90 : ANGLE_90 ) ; // flyangle is always 0 here, below is kept for posterity
/*(player->flyangle > 90 && player->flyangle < 270 ? ANGLE_90 : -ANGLE_90)
: ( player - > flyangle > 90 & & player - > flyangle < 270 ? - ANGLE_90 : ANGLE_90 ) ) ; */
}
2018-04-02 14:02:16 +00:00
2018-03-31 14:11:27 +00:00
// Do this before setting CR_NIGHTSMODE so we can tell if player was non-NiGHTS
2018-03-30 18:22:59 +00:00
P_RunNightserizeExecutors ( player - > mo ) ;
2018-03-31 14:11:27 +00:00
2017-03-14 18:11:17 +00:00
player - > powers [ pw_carry ] = CR_NIGHTSMODE ;
2019-08-04 14:25:13 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_NIGHTS_TRANS1 ) ;
2014-03-15 16:59:03 +00:00
}
2017-04-03 17:28:02 +00:00
pflags_t P_GetJumpFlags ( player_t * player )
{
if ( player - > charflags & SF_NOJUMPDAMAGE )
return ( PF_JUMPED | PF_NOJUMPDAMAGE ) ;
return PF_JUMPED ;
2014-03-15 16:59:03 +00:00
}
//
// P_PlayerInPain
//
// Is player in pain??
// Checks for painstate and pw_flashing, if both found return true
//
boolean P_PlayerInPain ( player_t * player )
{
// no silly, sliding isn't pain
if ( ! ( player - > pflags & PF_SLIDING ) & & player - > mo - > state = = & states [ player - > mo - > info - > painstate ] & & player - > powers [ pw_flashing ] )
return true ;
2019-07-08 12:26:40 +00:00
if ( player - > mo - > state = = & states [ S_PLAY_STUN ] )
return true ;
2014-03-15 16:59:03 +00:00
return false ;
}
//
// P_DoPlayerPain
//
// Player was hit,
// put them in pain.
//
void P_DoPlayerPain ( player_t * player , mobj_t * source , mobj_t * inflictor )
{
2016-10-12 16:55:07 +00:00
if ( player - > powers [ pw_carry ] = = CR_ROPEHANG )
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2014-03-15 16:59:03 +00:00
2016-10-12 16:55:07 +00:00
{
angle_t ang ;
fixed_t fallbackspeed ;
2014-03-15 16:59:03 +00:00
2016-10-12 16:55:07 +00:00
P_ResetPlayer ( player ) ;
P_SetPlayerMobjState ( player - > mo , player - > mo - > info - > painstate ) ;
2014-03-15 16:59:03 +00:00
2016-10-12 16:55:07 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
player - > mo - > z - - ;
else
player - > mo - > z + + ;
if ( player - > mo - > eflags & MFE_UNDERWATER )
P_SetObjectMomZ ( player - > mo , FixedDiv ( 10511 * FRACUNIT , 2600 * FRACUNIT ) , false ) ;
else
P_SetObjectMomZ ( player - > mo , FixedDiv ( 69 * FRACUNIT , 10 * FRACUNIT ) , false ) ;
2014-03-15 16:59:03 +00:00
2016-10-12 16:55:07 +00:00
if ( inflictor )
2014-03-15 16:59:03 +00:00
{
2017-07-18 13:17:10 +00:00
if ( inflictor - > type = = MT_WALLSPIKE )
ang = inflictor - > angle ;
else
ang = R_PointToAngle2 ( inflictor - > x - inflictor - > momx , inflictor - > y - inflictor - > momy , player - > mo - > x - player - > mo - > momx , player - > mo - > y - player - > mo - > momy ) ;
2014-03-15 16:59:03 +00:00
2016-10-12 16:55:07 +00:00
// explosion and rail rings send you farther back, making it more difficult
// to recover
if ( ( inflictor - > flags2 & MF2_SCATTER ) & & source )
{
fixed_t dist = P_AproxDistance ( P_AproxDistance ( source - > x - player - > mo - > x , source - > y - player - > mo - > y ) , source - > z - player - > mo - > z ) ;
2014-03-15 16:59:03 +00:00
2016-10-12 16:55:07 +00:00
dist = FixedMul ( 128 * FRACUNIT , inflictor - > scale ) - dist / 4 ;
2014-03-15 16:59:03 +00:00
2016-10-12 16:55:07 +00:00
if ( dist < FixedMul ( 4 * FRACUNIT , inflictor - > scale ) )
dist = FixedMul ( 4 * FRACUNIT , inflictor - > scale ) ;
fallbackspeed = dist ;
}
else if ( inflictor - > flags2 & MF2_EXPLOSION )
{
if ( inflictor - > flags2 & MF2_RAILRING )
fallbackspeed = FixedMul ( 38 * FRACUNIT , inflictor - > scale ) ; // 7x
else
fallbackspeed = FixedMul ( 30 * FRACUNIT , inflictor - > scale ) ; // 5x
}
else if ( inflictor - > flags2 & MF2_RAILRING )
fallbackspeed = FixedMul ( 45 * FRACUNIT , inflictor - > scale ) ; // 4x
2014-03-15 16:59:03 +00:00
else
2016-10-12 16:55:07 +00:00
fallbackspeed = FixedMul ( 4 * FRACUNIT , inflictor - > scale ) ; // the usual amount of force
2014-03-15 16:59:03 +00:00
}
else
2016-10-12 16:55:07 +00:00
{
2018-06-03 21:41:54 +00:00
ang = ( ( player - > mo - > momx | | player - > mo - > momy ) ? R_PointToAngle2 ( player - > mo - > momx , player - > mo - > momy , 0 , 0 ) : player - > drawangle ) ;
2016-10-12 16:55:07 +00:00
fallbackspeed = FixedMul ( 4 * FRACUNIT , player - > mo - > scale ) ;
}
2014-03-15 16:59:03 +00:00
2017-02-06 17:31:48 +00:00
player - > drawangle = ang + ANGLE_180 ;
2016-10-12 16:55:07 +00:00
P_InstaThrust ( player - > mo , ang , fallbackspeed ) ;
}
2014-03-15 16:59:03 +00:00
// Point penalty for hitting a hazard during tag.
// Discourages players from intentionally hurting themselves to avoid being tagged.
2017-09-15 19:34:46 +00:00
if ( gametype = = GT_TAG & & ( ! ( player - > pflags & PF_GAMETYPEOVER ) & & ! ( player - > pflags & PF_TAGIT ) ) )
2014-03-15 16:59:03 +00:00
{
if ( player - > score > = 50 )
player - > score - = 50 ;
else
player - > score = 0 ;
}
player - > powers [ pw_flashing ] = flashingtics ;
if ( player - > timeshit ! = UINT8_MAX )
+ + player - > timeshit ;
}
//
// P_ResetPlayer
//
// Useful when you want to kill everything the player is doing.
void P_ResetPlayer ( player_t * player )
{
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ ( PF_SPINNING | PF_STARTDASH | PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_GLIDING | PF_THOKKED | PF_CANCARRY | PF_SHIELDABILITY | PF_BOUNCING ) ;
2017-03-14 18:11:17 +00:00
2019-09-29 19:05:08 +00:00
if ( player - > powers [ pw_carry ] = = CR_ROLLOUT )
{
if ( player - > mo - > tracer & & ! P_MobjWasRemoved ( player - > mo - > tracer ) )
{
player - > mo - > tracer - > flags | = MF_PUSHABLE ;
2019-10-07 06:51:32 +00:00
P_SetTarget ( & player - > mo - > tracer - > tracer , NULL ) ;
2019-09-29 19:05:08 +00:00
}
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
player - > powers [ pw_carry ] = CR_NONE ;
}
2019-06-13 19:45:30 +00:00
if ( ! ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE | | player - > powers [ pw_carry ] = = CR_NIGHTSFALL | | player - > powers [ pw_carry ] = = CR_BRAKGOOP | | player - > powers [ pw_carry ] = = CR_MINECART ) )
2017-03-14 18:11:17 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
player - > secondjump = 0 ;
player - > glidetime = 0 ;
player - > homing = 0 ;
player - > climbing = 0 ;
player - > powers [ pw_tailsfly ] = 0 ;
player - > onconveyor = 0 ;
player - > skidtime = 0 ;
if ( player - players = = consoleplayer & & botingame )
CV_SetValue ( & cv_analog2 , true ) ;
}
2019-06-19 11:09:02 +00:00
// P_PlayerCanDamage
//
// Can player do damage?
//
boolean P_PlayerCanDamage ( player_t * player , mobj_t * thing )
{
2019-08-13 19:11:44 +00:00
fixed_t bottomheight , topheight ;
2019-06-19 11:09:02 +00:00
if ( ! player - > mo | | player - > spectator | | ! thing | | P_MobjWasRemoved ( thing ) )
return false ;
"PlayerCanDamage" hook!
* Takes function(player, mo) input.
* Return TRUE for stating that yes, the player is in a state that can cause contact damage, do with that what you will.
* Return FALSE for stating that no, the player is weak and vulnerable and cannot cause contact damage, do with that what you will.
* Return NIL for allowing the function to continue regular operation.
Fills a different ideological niche than ShouldDamage - that's for determining whether damage dished between two objects should happen, this is for determining which way around damage should be dished when considering a player-object interaction.
Or, in other words, think of it as "ShouldDamage is whether damage that has been requested should be granted, for object-object interaction, while PlayerCanDamage is for whether global player properties should cause damage to enemies and monitors in the first place, like spinning, hammering or stomping."
2019-06-19 11:55:05 +00:00
# ifdef HAVE_BLUA
{
UINT8 shouldCollide = LUAh_PlayerCanDamage ( player , thing ) ;
if ( P_MobjWasRemoved ( thing ) )
return false ; // removed???
if ( shouldCollide = = 1 )
return true ; // force yes
else if ( shouldCollide = = 2 )
return false ; // force no
}
# endif
2019-06-19 12:20:34 +00:00
// Invinc/super. Not for Monitors.
if ( ! ( thing - > flags & MF_MONITOR ) & & ( player - > powers [ pw_invulnerability ] | | player - > powers [ pw_super ] ) )
return true ;
// NiGHTS drill. Wasn't originally for monitors, but that's more an oversight being corrected than anything else.
2019-06-19 11:09:02 +00:00
if ( ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) & & ( player - > pflags & PF_DRILLING ) )
return true ;
2019-06-19 12:20:34 +00:00
// Jumping.
2019-06-19 11:09:02 +00:00
if ( ( player - > pflags & PF_JUMPED )
& & ( ! ( player - > pflags & PF_NOJUMPDAMAGE )
| | ( player - > charability = = CA_TWINSPIN & & player - > panim = = PA_ABILITY ) ) )
return true ;
2019-06-19 12:20:34 +00:00
// Spinning.
if ( player - > pflags & PF_SPINNING )
2019-06-19 11:09:02 +00:00
return true ;
2019-10-28 18:37:26 +00:00
2019-10-23 05:46:30 +00:00
if ( player - > dashmode > = DASHMODE_THRESHOLD & & ( player - > charflags & ( SF_DASHMODE | SF_MACHINE ) ) = = ( SF_DASHMODE | SF_MACHINE ) )
2019-10-23 05:41:32 +00:00
return true ;
2019-06-19 11:09:02 +00:00
2019-06-19 12:20:34 +00:00
// From the front.
if ( ( ( player - > pflags & PF_GLIDING ) | | ( player - > charability2 = = CA2_MELEE & & player - > panim = = PA_ABILITY2 ) )
& & ( player - > drawangle - R_PointToAngle2 ( player - > mo - > x - player - > mo - > momx , player - > mo - > y - player - > mo - > momy , thing - > x , thing - > y ) + + ANGLE_90 ) < ANGLE_180 )
2019-06-19 11:09:02 +00:00
return true ;
2019-06-26 22:26:05 +00:00
// From the top/bottom.
2019-08-13 19:11:44 +00:00
bottomheight = player - > mo - > z ;
topheight = player - > mo - > z + player - > mo - > height ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2019-06-26 22:26:05 +00:00
{
2019-08-13 19:11:44 +00:00
fixed_t swap = bottomheight ;
bottomheight = topheight ;
topheight = swap ;
}
if ( P_MobjFlip ( player - > mo ) * ( bottomheight - ( thing - > z + thing - > height / 2 ) ) > 0 )
2019-06-26 22:26:05 +00:00
{
2019-08-13 19:11:44 +00:00
if ( ( player - > charflags & SF_STOMPDAMAGE | | player - > pflags & PF_BOUNCING ) & & ( P_MobjFlip ( player - > mo ) * ( player - > mo - > momz - thing - > momz ) < 0 ) )
return true ;
}
else if ( P_MobjFlip ( player - > mo ) * ( topheight - ( thing - > z + thing - > height / 2 ) ) < 0 )
{
2019-09-18 12:46:17 +00:00
if ( player - > charability = = CA_FLY & & player - > panim = = PA_ABILITY & & ! ( player - > mo - > eflags & MFE_UNDERWATER ) & & ( P_MobjFlip ( player - > mo ) * ( player - > mo - > momz - thing - > momz ) > 0 ) )
2019-06-26 22:26:05 +00:00
return true ;
}
2019-06-19 11:09:02 +00:00
2019-06-19 12:20:34 +00:00
// Shield stomp.
2019-06-19 11:09:02 +00:00
if ( ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL | | ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_BUBBLEWRAP ) & & ( player - > pflags & PF_SHIELDABILITY ) )
return true ;
return false ;
}
2014-03-15 16:59:03 +00:00
//
// P_GivePlayerRings
//
// Gives rings to the player, and does any special things required.
// Call this function when you want to increment the player's health.
//
2018-04-06 13:42:49 +00:00
2014-03-15 16:59:03 +00:00
void P_GivePlayerRings ( player_t * player , INT32 num_rings )
{
2018-04-06 13:42:49 +00:00
if ( ! player )
return ;
2014-03-15 16:59:03 +00:00
if ( player - > bot )
player = & players [ consoleplayer ] ;
if ( ! player - > mo )
return ;
2015-08-15 20:07:16 +00:00
player - > rings + = num_rings ;
2014-03-15 16:59:03 +00:00
2018-06-03 21:41:54 +00:00
player - > totalring + = num_rings ;
2014-03-15 16:59:03 +00:00
// Can only get up to 9999 rings, sorry!
2015-08-15 20:07:16 +00:00
if ( player - > rings > 9999 )
player - > rings = 9999 ;
else if ( player - > rings < 0 )
player - > rings = 0 ;
2014-03-15 16:59:03 +00:00
// Now extra life bonuses are handled here instead of in P_MovePlayer, since why not?
2018-08-23 19:09:39 +00:00
if ( ! ultimatemode & & ! modeattacking & & ! G_IsSpecialStage ( gamemap ) & & G_GametypeUsesLives ( ) & & player - > lives ! = INFLIVES )
2014-03-15 16:59:03 +00:00
{
INT32 gainlives = 0 ;
2015-08-15 20:07:16 +00:00
while ( player - > xtralife < maxXtraLife & & player - > rings > = 100 * ( player - > xtralife + 1 ) )
2014-03-15 16:59:03 +00:00
{
+ + gainlives ;
+ + player - > xtralife ;
}
if ( gainlives )
{
2018-04-06 13:42:49 +00:00
player - > lives + = gainlives ;
if ( player - > lives > 99 )
player - > lives = 99 ;
else if ( player - > lives < 1 )
player - > lives = 1 ;
2014-03-15 16:59:03 +00:00
P_PlayLivesJingle ( player ) ;
}
}
}
2018-06-03 21:41:54 +00:00
void P_GivePlayerSpheres ( player_t * player , INT32 num_spheres )
{
if ( ! player )
return ;
if ( player - > bot )
player = & players [ consoleplayer ] ;
if ( ! player - > mo )
return ;
player - > spheres + = num_spheres ;
// Can only get up to 9999 spheres, sorry!
if ( player - > spheres > 9999 )
player - > spheres = 9999 ;
else if ( player - > spheres < 0 )
player - > spheres = 0 ;
}
2014-03-15 16:59:03 +00:00
//
// P_GivePlayerLives
//
// Gives the player an extra life.
// Call this function when you want to add lives to the player.
//
void P_GivePlayerLives ( player_t * player , INT32 numlives )
{
2019-11-25 14:59:06 +00:00
UINT8 prevlives = player - > lives ;
2018-04-06 13:42:49 +00:00
if ( ! player )
return ;
if ( player - > bot )
player = & players [ consoleplayer ] ;
if ( gamestate = = GS_LEVEL )
{
2018-08-23 19:09:39 +00:00
if ( player - > lives = = INFLIVES | | ( gametype ! = GT_COOP & & gametype ! = GT_COMPETITION ) )
2018-04-06 13:42:49 +00:00
{
P_GivePlayerRings ( player , 100 * numlives ) ;
return ;
}
if ( ( netgame | | multiplayer ) & & gametype = = GT_COOP & & cv_cooplives . value = = 0 )
{
P_GivePlayerRings ( player , 100 * numlives ) ;
if ( player - > lives - prevlives > = numlives )
2019-11-25 14:59:06 +00:00
goto docooprespawn ;
2018-04-06 13:42:49 +00:00
numlives = ( numlives + prevlives - player - > lives ) ;
}
}
2019-11-07 14:06:27 +00:00
else if ( player - > lives = = INFLIVES )
return ;
2017-08-17 23:58:16 +00:00
2014-03-15 16:59:03 +00:00
player - > lives + = numlives ;
if ( player - > lives > 99 )
player - > lives = 99 ;
else if ( player - > lives < 1 )
player - > lives = 1 ;
2019-11-25 14:59:06 +00:00
docooprespawn :
if ( cv_coopstarposts . value )
return ;
if ( prevlives > 0 )
return ;
if ( ! player - > spectator )
return ;
P_SpectatorJoinGame ( player ) ;
2014-03-15 16:59:03 +00:00
}
2017-05-29 21:19:31 +00:00
void P_GiveCoopLives ( player_t * player , INT32 numlives , boolean sound )
2017-05-29 21:18:02 +00:00
{
2017-06-03 11:26:42 +00:00
if ( ! ( ( netgame | | multiplayer ) & & gametype = = GT_COOP ) )
2017-05-29 21:18:02 +00:00
{
2017-05-29 21:19:31 +00:00
P_GivePlayerLives ( player , numlives ) ;
2017-05-29 21:18:02 +00:00
if ( sound )
P_PlayLivesJingle ( player ) ;
}
else
{
INT32 i ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
2017-05-29 21:19:31 +00:00
P_GivePlayerLives ( & players [ i ] , numlives ) ;
2017-05-29 21:18:02 +00:00
if ( sound )
P_PlayLivesJingle ( & players [ i ] ) ;
}
}
}
2014-03-15 16:59:03 +00:00
//
// P_DoSuperTransformation
//
// Transform into Super Sonic!
void P_DoSuperTransformation ( player_t * player , boolean giverings )
{
player - > powers [ pw_super ] = 1 ;
if ( ! ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_NOSSMUSIC ) & & P_IsLocalPlayer ( player ) )
2019-08-04 11:03:57 +00:00
P_PlayJingle ( player , JT_SUPER ) ;
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_supert ) ; //let all players hear it -mattw_cfi
2018-06-03 21:41:54 +00:00
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = player - > cmomx = player - > cmomy = player - > rmomx = player - > rmomy = 0 ;
2014-03-15 16:59:03 +00:00
// Transformation animation
2017-10-04 16:45:03 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_SUPER_TRANS1 ) ;
2014-03-15 16:59:03 +00:00
if ( giverings )
2015-08-15 20:07:16 +00:00
player - > rings = 50 ;
2014-03-15 16:59:03 +00:00
// Just in case.
if ( ! ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_NOSSMUSIC ) )
{
player - > powers [ pw_extralife ] = 0 ;
player - > powers [ pw_invulnerability ] = 0 ;
2014-08-27 03:56:30 +00:00
player - > powers [ pw_sneakers ] = 0 ;
2014-03-15 16:59:03 +00:00
}
if ( gametype ! = GT_COOP )
{
HU_SetCEchoFlags ( 0 ) ;
HU_SetCEchoDuration ( 5 ) ;
HU_DoCEcho ( va ( " %s \\ is now super. \\ \\ \\ \\ " , player_names [ player - players ] ) ) ;
}
P_PlayerFlagBurst ( player , false ) ;
}
2015-05-27 06:08:18 +00:00
2014-03-15 16:59:03 +00:00
// Adds to the player's score
void P_AddPlayerScore ( player_t * player , UINT32 amount )
{
UINT32 oldscore ;
if ( player - > bot )
player = & players [ consoleplayer ] ;
// NiGHTS does it different!
if ( gamestate = = GS_LEVEL & & mapheaderinfo [ gamemap - 1 ] - > typeoflevel & TOL_NIGHTS )
{
if ( ( netgame | | multiplayer ) & & G_IsSpecialStage ( gamemap ) )
{ // Pseudo-shared score for multiplayer special stages.
INT32 i ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2017-03-14 18:11:17 +00:00
if ( playeringame [ i ] & & players [ i ] . powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
oldscore = players [ i ] . marescore ;
// Don't go above MAXSCORE.
if ( players [ i ] . marescore + amount < MAXSCORE )
players [ i ] . marescore + = amount ;
else
players [ i ] . marescore = MAXSCORE ;
// Continues are worthless in netgames.
// If that stops being the case uncomment this.
/* if (!ultimatemode && players[i].marescore > 50000
& & oldscore < 50000 )
{
players [ i ] . continues + = 1 ;
players [ i ] . gotcontinue = true ;
if ( P_IsLocalPlayer ( player ) )
2017-04-18 14:57:52 +00:00
S_StartSound ( NULL , sfx_s3kac ) ;
2014-03-15 16:59:03 +00:00
} */
}
}
else
{
oldscore = player - > marescore ;
// Don't go above MAXSCORE.
if ( player - > marescore + amount < MAXSCORE )
player - > marescore + = amount ;
else
player - > marescore = MAXSCORE ;
if ( ! ultimatemode & & ! ( netgame | | multiplayer ) & & G_IsSpecialStage ( gamemap )
& & player - > marescore > = 50000 & & oldscore < 50000 )
{
player - > continues + = 1 ;
player - > gotcontinue = true ;
if ( P_IsLocalPlayer ( player ) )
2017-04-18 14:57:52 +00:00
S_StartSound ( NULL , sfx_s3kac ) ;
2014-03-15 16:59:03 +00:00
}
}
if ( gametype = = GT_COOP )
return ;
}
oldscore = player - > score ;
// Don't go above MAXSCORE.
2017-09-25 19:35:04 +00:00
player - > score + = amount ;
if ( player - > score > MAXSCORE )
2014-03-15 16:59:03 +00:00
player - > score = MAXSCORE ;
// check for extra lives every 50000 pts
if ( ! ultimatemode & & ! modeattacking & & player - > score > oldscore & & player - > score % 50000 < amount & & ( gametype = = GT_COMPETITION | | gametype = = GT_COOP ) )
{
P_GivePlayerLives ( player , ( player - > score / 50000 ) - ( oldscore / 50000 ) ) ;
P_PlayLivesJingle ( player ) ;
}
// In team match, all awarded points are incremented to the team's running score.
if ( gametype = = GT_TEAMMATCH )
{
if ( player - > ctfteam = = 1 )
redscore + = amount ;
else if ( player - > ctfteam = = 2 )
bluescore + = amount ;
}
}
2015-05-27 06:08:18 +00:00
// Steals from every enemy's score.
void P_StealPlayerScore ( player_t * player , UINT32 amount )
{
boolean teams = G_GametypeHasTeams ( ) ;
UINT32 stolen = 0 ;
int i ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( & players [ i ] = = player
| | ( teams & & players [ i ] . ctfteam = = player - > ctfteam ) )
continue ;
if ( players [ i ] . score > = amount )
{
stolen + = amount ;
players [ i ] . score - = amount ;
}
else
{
stolen + = players [ i ] . score ;
players [ i ] . score = 0 ;
}
}
if ( stolen > 0 )
{
// In team match, all stolen points are removed from the enemy team's running score.
if ( gametype = = GT_TEAMMATCH )
{
if ( player - > ctfteam = = 1 )
bluescore - = amount ;
else if ( player - > ctfteam = = 2 )
redscore - = amount ;
}
P_AddPlayerScore ( player , stolen ) ;
}
}
2014-03-15 16:59:03 +00:00
//
// P_PlayLivesJingle
//
void P_PlayLivesJingle ( player_t * player )
{
if ( player & & ! P_IsLocalPlayer ( player ) )
return ;
2018-04-06 13:42:49 +00:00
if ( use1upSound )
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_oneup ) ;
else if ( mariomode )
S_StartSound ( NULL , sfx_marioa ) ;
else
{
2019-09-07 10:48:58 +00:00
P_PlayJingle ( player , JT_1UP ) ;
2014-03-15 16:59:03 +00:00
if ( player )
2019-08-04 11:03:57 +00:00
player - > powers [ pw_extralife ] = extralifetics + 1 ;
2017-04-29 15:27:52 +00:00
strlcpy ( S_sfx [ sfx_None ] . caption , " One-up " , 7 ) ;
S_StartCaption ( sfx_None , - 1 , extralifetics + 1 ) ;
2014-03-15 16:59:03 +00:00
}
}
2019-08-04 11:03:57 +00:00
void P_PlayJingle ( player_t * player , jingletype_t jingletype )
{
const char * musname = jingleinfo [ jingletype ] . musname ;
UINT16 musflags = 0 ;
boolean looping = jingleinfo [ jingletype ] . looping ;
char newmusic [ 7 ] ;
strncpy ( newmusic , musname , 7 ) ;
# if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
if ( LUAh_MusicJingle ( jingletype , newmusic , & musflags , & looping ) )
return ;
# endif
newmusic [ 6 ] = 0 ;
P_PlayJingleMusic ( player , newmusic , musflags , looping , jingletype ) ;
}
//
// P_PlayJingleMusic
//
void P_PlayJingleMusic ( player_t * player , const char * musname , UINT16 musflags , boolean looping , UINT16 status )
{
// If gamestate != GS_LEVEL, always play the jingle (1-up intermission)
if ( gamestate = = GS_LEVEL & & ! P_IsLocalPlayer ( player ) )
return ;
S_RetainMusic ( musname , musflags , looping , 0 , status ) ;
S_StopMusic ( ) ;
S_ChangeMusicInternal ( musname , looping ) ;
}
boolean P_EvaluateMusicStatus ( UINT16 status )
{
// \todo lua hook
int i ;
boolean result = false ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! P_IsLocalPlayer ( & players [ i ] ) )
continue ;
switch ( status )
{
case JT_1UP : // Extra life
result = ( players [ i ] . powers [ pw_extralife ] > 1 ) ;
break ;
case JT_SHOES : // Speed shoes
if ( players [ i ] . powers [ pw_sneakers ] > 1 & & ! players [ i ] . powers [ pw_super ] )
{
//strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
//S_StartCaption(sfx_None, -1, players[i].powers[pw_sneakers]);
result = true ;
}
else
result = false ;
break ;
case JT_INV : // Invincibility
case JT_MINV : // Mario Invincibility
if ( players [ i ] . powers [ pw_invulnerability ] > 1 )
{
//strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
//S_StartCaption(sfx_None, -1, players[i].powers[pw_invulnerability]);
result = true ;
}
else
result = false ;
break ;
case JT_DROWN : // Drowning
result = ( players [ i ] . powers [ pw_underwater ] & & players [ i ] . powers [ pw_underwater ] < = 11 * TICRATE + 1 ) ;
break ;
case JT_SUPER : // Super Sonic
result = ( players [ i ] . powers [ pw_super ] & & ! ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_NOSSMUSIC ) ) ;
break ;
case JT_GOVER : // Game Over
result = ( players [ i ] . lives < = 0 ) ;
break ;
case JT_NIGHTSTIMEOUT : // NiGHTS Time Out (10 seconds)
case JT_SSTIMEOUT :
result = ( players [ i ] . nightstime & & players [ i ] . nightstime < = 10 * TICRATE ) ;
break ;
case JT_NONE : // Null state
case JT_OTHER : // Other state
case JT_MASTER : // Main level music
default :
result = true ;
}
if ( result )
break ;
}
return result ;
}
2014-03-15 16:59:03 +00:00
//
// P_RestoreMusic
//
// Restores music after some special music change
//
void P_RestoreMusic ( player_t * player )
{
if ( ! P_IsLocalPlayer ( player ) ) // Only applies to a local player
return ;
2019-08-04 11:03:57 +00:00
S_SpeedMusic ( 1.0f ) ;
// Jingles have a priority in this order, so follow it
// and as a default case, go down the music stack.
// Extra life
2014-03-15 16:59:03 +00:00
if ( player - > powers [ pw_extralife ] > 1 )
return ;
2019-08-04 11:03:57 +00:00
// Super
else if ( player - > powers [ pw_super ] & & ! ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_NOSSMUSIC )
& & ! S_RecallMusic ( JT_SUPER , false ) )
P_PlayJingle ( player , JT_SUPER ) ;
// Invulnerability
2014-03-15 16:59:03 +00:00
else if ( player - > powers [ pw_invulnerability ] > 1 )
2017-04-29 15:27:52 +00:00
{
strlcpy ( S_sfx [ sfx_None ] . caption , " Invincibility " , 14 ) ;
S_StartCaption ( sfx_None , - 1 , player - > powers [ pw_invulnerability ] ) ;
2019-08-04 11:03:57 +00:00
if ( ! S_RecallMusic ( JT_INV , false ) & & ! S_RecallMusic ( JT_MINV , false ) )
P_PlayJingle ( player , ( mariomode ) ? JT_MINV : JT_INV ) ;
2017-04-29 15:27:52 +00:00
}
2019-08-04 11:03:57 +00:00
// Shoes
2014-04-14 05:14:58 +00:00
else if ( player - > powers [ pw_sneakers ] > 1 & & ! player - > powers [ pw_super ] )
{
2017-04-29 15:27:52 +00:00
strlcpy ( S_sfx [ sfx_None ] . caption , " Speed shoes " , 12 ) ;
S_StartCaption ( sfx_None , - 1 , player - > powers [ pw_sneakers ] ) ;
2014-04-14 05:14:58 +00:00
if ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_SPEEDMUSIC )
{
S_SpeedMusic ( 1.4f ) ;
2019-08-04 11:03:57 +00:00
if ( ! S_RecallMusic ( JT_MASTER , true ) )
S_ChangeMusicEx ( mapmusname , mapmusflags , true , mapmusposition , 0 , 0 ) ;
2014-04-14 05:14:58 +00:00
}
2019-08-04 11:03:57 +00:00
else if ( ! S_RecallMusic ( JT_SHOES , false ) )
P_PlayJingle ( player , JT_SHOES ) ;
2014-04-14 05:14:58 +00:00
}
2019-08-04 11:03:57 +00:00
// Default
else if ( ! S_RecallMusic ( JT_NONE , false ) ) // go down the stack
{
CONS_Debug ( DBG_BASIC , " Cannot find any music in resume stack! \n " ) ;
S_ChangeMusicEx ( mapmusname , mapmusflags , true , mapmusposition , 0 , 0 ) ;
}
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
//
// P_IsObjectInGoop
//
// Returns true if the object is inside goop water.
// (Spectators and objects otherwise without gravity cannot have goop gravity!)
//
boolean P_IsObjectInGoop ( mobj_t * mo )
{
if ( mo - > player & & mo - > player - > spectator )
return false ;
if ( mo - > flags & MF_NOGRAVITY )
return false ;
return ( ( mo - > eflags & ( MFE_UNDERWATER | MFE_GOOWATER ) ) = = ( MFE_UNDERWATER | MFE_GOOWATER ) ) ;
}
2014-03-15 16:59:03 +00:00
//
// P_IsObjectOnGround
//
// Returns true if the player is
// on the ground. Takes reverse
// gravity and FOFs into account.
//
boolean P_IsObjectOnGround ( mobj_t * mo )
{
2017-02-09 23:24:47 +00:00
if ( P_IsObjectInGoop ( mo ) & & ! ( mo - > player & & mo - > player - > pflags & PF_BOUNCING ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
/*
2014-03-15 16:59:03 +00:00
// It's a crazy hack that checking if you're on the ground
// would actually CHANGE your position and momentum,
if ( mo - > z < mo - > floorz )
{
mo - > z = mo - > floorz ;
mo - > momz = 0 ;
}
else if ( mo - > z + mo - > height > mo - > ceilingz )
{
mo - > z = mo - > ceilingz - mo - > height ;
mo - > momz = 0 ;
}
2014-08-04 03:49:33 +00:00
*/
2014-03-15 16:59:03 +00:00
// but I don't want you to ever 'stand' while submerged in goo.
// You're in constant vertical momentum, even if you get stuck on something.
// No exceptions.
return false ;
}
if ( mo - > eflags & MFE_VERTICALFLIP )
{
if ( mo - > z + mo - > height > = mo - > ceilingz )
return true ;
}
else
{
if ( mo - > z < = mo - > floorz )
return true ;
}
return false ;
}
//
// P_IsObjectOnGroundIn
//
// Returns true if the player is
// on the ground in a specific sector. Takes reverse
// gravity and FOFs into account.
//
boolean P_IsObjectOnGroundIn ( mobj_t * mo , sector_t * sec )
{
ffloor_t * rover ;
// Is the object in reverse gravity?
if ( mo - > eflags & MFE_VERTICALFLIP )
{
// Detect if the player is on the ceiling.
2015-05-24 17:53:30 +00:00
if ( mo - > z + mo - > height > = P_GetSpecialTopZ ( mo , sec , sec ) )
2014-03-15 16:59:03 +00:00
return true ;
// Otherwise, detect if the player is on the bottom of a FOF.
else
{
for ( rover = sec - > ffloors ; rover ; rover = rover - > next )
{
// If the FOF doesn't exist, continue.
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
2017-07-17 19:47:00 +00:00
// If the FOF is configured to let the object through, continue.
if ( ! ( ( rover - > flags & FF_BLOCKPLAYER & & mo - > player )
| | ( rover - > flags & FF_BLOCKOTHERS & & ! mo - > player ) ) )
2014-03-15 16:59:03 +00:00
continue ;
2017-07-17 19:47:00 +00:00
// If the the platform is intangible from below, continue.
2014-03-15 16:59:03 +00:00
if ( rover - > flags & FF_PLATFORM )
continue ;
// If the FOF is a water block, continue. (Unnecessary check?)
if ( rover - > flags & FF_SWIMMABLE )
continue ;
// Actually check if the player is on the suitable FOF.
2015-05-24 17:53:30 +00:00
if ( mo - > z + mo - > height = = P_GetSpecialBottomZ ( mo , sectors + rover - > secnum , sec ) )
2014-03-15 16:59:03 +00:00
return true ;
}
}
}
// Nope!
else
{
// Detect if the player is on the floor.
2015-05-24 17:53:30 +00:00
if ( mo - > z < = P_GetSpecialBottomZ ( mo , sec , sec ) )
2014-03-15 16:59:03 +00:00
return true ;
// Otherwise, detect if the player is on the top of a FOF.
else
{
for ( rover = sec - > ffloors ; rover ; rover = rover - > next )
{
// If the FOF doesn't exist, continue.
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
2017-07-17 19:47:00 +00:00
// If the FOF is configured to let the object through, continue.
if ( ! ( ( rover - > flags & FF_BLOCKPLAYER & & mo - > player )
| | ( rover - > flags & FF_BLOCKOTHERS & & ! mo - > player ) ) )
2014-03-15 16:59:03 +00:00
continue ;
2017-07-17 19:47:00 +00:00
// If the the platform is intangible from above, continue.
2014-03-15 16:59:03 +00:00
if ( rover - > flags & FF_REVERSEPLATFORM )
continue ;
// If the FOF is a water block, continue. (Unnecessary check?)
if ( rover - > flags & FF_SWIMMABLE )
continue ;
// Actually check if the player is on the suitable FOF.
2015-05-24 17:53:30 +00:00
if ( mo - > z = = P_GetSpecialTopZ ( mo , sectors + rover - > secnum , sec ) )
2014-03-15 16:59:03 +00:00
return true ;
}
}
}
return false ;
}
//
// P_SetObjectMomZ
//
// Sets the player momz appropriately.
// Takes reverse gravity into account.
//
void P_SetObjectMomZ ( mobj_t * mo , fixed_t value , boolean relative )
{
if ( mo - > eflags & MFE_VERTICALFLIP )
value = - value ;
if ( mo - > scale ! = FRACUNIT )
value = FixedMul ( value , mo - > scale ) ;
if ( relative )
mo - > momz + = value ;
else
mo - > momz = value ;
}
//
// P_IsLocalPlayer
//
// Returns true if player is
// on the local machine.
//
boolean P_IsLocalPlayer ( player_t * player )
{
return ( ( splitscreen & & player = = & players [ secondarydisplayplayer ] ) | | player = = & players [ consoleplayer ] ) ;
}
//
// P_SpawnShieldOrb
//
// Spawns the shield orb on the player
// depending on which shield they are
// supposed to have.
//
void P_SpawnShieldOrb ( player_t * player )
{
mobjtype_t orbtype ;
thinker_t * th ;
mobj_t * shieldobj , * ov ;
# ifdef PARANOIA
if ( ! player - > mo )
I_Error ( " P_SpawnShieldOrb: player->mo is NULL! \n " ) ;
# endif
2016-10-20 19:55:15 +00:00
# ifdef HAVE_BLUA
if ( LUAh_ShieldSpawn ( player ) )
return ;
# endif
2014-03-15 16:59:03 +00:00
if ( player - > powers [ pw_shield ] & SH_FORCE )
2016-10-13 14:13:33 +00:00
orbtype = MT_FORCE_ORB ;
2014-03-15 16:59:03 +00:00
else switch ( player - > powers [ pw_shield ] & SH_NOSTACK )
{
2016-10-13 14:13:33 +00:00
case SH_WHIRLWIND :
orbtype = MT_WHIRLWIND_ORB ;
2014-03-15 16:59:03 +00:00
break ;
case SH_ATTRACT :
2016-10-13 14:13:33 +00:00
orbtype = MT_ATTRACT_ORB ;
2014-03-15 16:59:03 +00:00
break ;
case SH_ELEMENTAL :
2016-10-13 14:13:33 +00:00
orbtype = MT_ELEMENTAL_ORB ;
2014-03-15 16:59:03 +00:00
break ;
2016-10-13 14:13:33 +00:00
case SH_ARMAGEDDON :
orbtype = MT_ARMAGEDDON_ORB ;
2014-03-15 16:59:03 +00:00
break ;
case SH_PITY :
2019-06-19 22:20:24 +00:00
case SH_PINK : // PITY IN PINK
2016-10-13 14:13:33 +00:00
orbtype = MT_PITY_ORB ;
break ;
case SH_FLAMEAURA :
orbtype = MT_FLAMEAURA_ORB ;
break ;
case SH_BUBBLEWRAP :
orbtype = MT_BUBBLEWRAP_ORB ;
break ;
case SH_THUNDERCOIN :
orbtype = MT_THUNDERCOIN_ORB ;
2014-03-15 16:59:03 +00:00
break ;
default :
return ;
}
// blaze through the thinkers to see if an orb already exists!
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
shieldobj = ( mobj_t * ) th ;
if ( shieldobj - > type = = orbtype & & shieldobj - > target = = player - > mo )
P_RemoveMobj ( shieldobj ) ; //kill the old one(s)
}
shieldobj = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z , orbtype ) ;
2016-10-23 19:34:43 +00:00
shieldobj - > flags2 | = MF2_SHIELD ;
2014-03-15 16:59:03 +00:00
P_SetTarget ( & shieldobj - > target , player - > mo ) ;
2019-06-19 22:20:24 +00:00
if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_PINK )
{
shieldobj - > color = SKINCOLOR_PINK ;
shieldobj - > colorized = true ;
}
else
shieldobj - > color = ( UINT8 ) shieldobj - > info - > painchance ;
2016-10-23 19:34:43 +00:00
shieldobj - > threshold = ( player - > powers [ pw_shield ] & SH_FORCE ) ? SH_FORCE : ( player - > powers [ pw_shield ] & SH_NOSTACK ) ;
2014-03-15 16:59:03 +00:00
if ( shieldobj - > info - > seestate )
{
ov = P_SpawnMobj ( shieldobj - > x , shieldobj - > y , shieldobj - > z , MT_OVERLAY ) ;
P_SetTarget ( & ov - > target , shieldobj ) ;
P_SetMobjState ( ov , shieldobj - > info - > seestate ) ;
2016-10-17 13:39:32 +00:00
P_SetTarget ( & shieldobj - > tracer , ov ) ;
2014-03-15 16:59:03 +00:00
}
if ( shieldobj - > info - > meleestate )
{
ov = P_SpawnMobj ( shieldobj - > x , shieldobj - > y , shieldobj - > z , MT_OVERLAY ) ;
P_SetTarget ( & ov - > target , shieldobj ) ;
P_SetMobjState ( ov , shieldobj - > info - > meleestate ) ;
}
if ( shieldobj - > info - > missilestate )
{
ov = P_SpawnMobj ( shieldobj - > x , shieldobj - > y , shieldobj - > z , MT_OVERLAY ) ;
P_SetTarget ( & ov - > target , shieldobj ) ;
P_SetMobjState ( ov , shieldobj - > info - > missilestate ) ;
}
2014-05-14 23:27:37 +00:00
if ( player - > powers [ pw_shield ] & SH_FORCE )
{
//Copy and pasted from P_ShieldLook in p_mobj.c
2016-09-30 11:15:22 +00:00
shieldobj - > movecount = ( player - > powers [ pw_shield ] & SH_FORCEHP ) ;
2014-05-14 23:27:37 +00:00
if ( shieldobj - > movecount < 1 )
{
if ( shieldobj - > info - > painstate )
P_SetMobjState ( shieldobj , shieldobj - > info - > painstate ) ;
else
shieldobj - > flags2 | = MF2_SHADOW ;
}
}
2014-03-15 16:59:03 +00:00
}
2016-09-30 13:18:13 +00:00
//
// P_SwitchShield
//
2016-10-13 14:13:33 +00:00
// Handles the possibility of switching between
// the non-stack layer of shields thoroughly,
// then adds the desired one.
//
2016-10-24 11:35:40 +00:00
void P_SwitchShield ( player_t * player , UINT16 shieldtype )
2016-09-30 12:48:33 +00:00
{
2017-08-10 12:57:09 +00:00
boolean donthavealready ;
// If you already have a bomb shield, use it!
if ( ( shieldtype = = SH_ARMAGEDDON ) & & ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ARMAGEDDON )
P_BlackOw ( player ) ;
donthavealready = ( shieldtype & SH_FORCE )
? ( ! ( player - > powers [ pw_shield ] & SH_FORCE ) | | ( player - > powers [ pw_shield ] & SH_FORCEHP ) < ( shieldtype & ~ SH_FORCE ) )
: ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) ! = shieldtype ) ;
2016-10-13 14:13:33 +00:00
if ( donthavealready )
2016-09-30 12:48:33 +00:00
{
2016-10-20 20:15:41 +00:00
boolean stopshieldability = ( shieldtype & SH_FORCE )
? ( ! ( player - > powers [ pw_shield ] & SH_FORCE ) )
: true ;
2016-09-30 12:48:33 +00:00
// Just in case.
2016-10-13 14:13:33 +00:00
if ( stopshieldability & & player - > pflags & PF_SHIELDABILITY )
2016-09-30 12:48:33 +00:00
{
2016-10-13 14:13:33 +00:00
player - > pflags & = ~ ( PF_SPINNING | PF_SHIELDABILITY ) ; // They'll still have PF_THOKKED...
2016-09-30 12:48:33 +00:00
player - > homing = 0 ;
}
2016-10-24 11:35:40 +00:00
player - > powers [ pw_shield ] = shieldtype | ( player - > powers [ pw_shield ] & SH_STACK ) ;
2016-09-30 12:48:33 +00:00
P_SpawnShieldOrb ( player ) ;
2016-10-13 14:13:33 +00:00
if ( shieldtype & SH_PROTECTWATER )
{
if ( player - > powers [ pw_underwater ] & & player - > powers [ pw_underwater ] < = 12 * TICRATE + 1 )
2019-08-04 11:03:57 +00:00
{
player - > powers [ pw_underwater ] = 0 ;
2016-10-13 14:13:33 +00:00
P_RestoreMusic ( player ) ;
2019-08-04 11:03:57 +00:00
}
else
player - > powers [ pw_underwater ] = 0 ;
2016-10-13 14:13:33 +00:00
if ( player - > powers [ pw_spacetime ] > 1 )
{
player - > powers [ pw_spacetime ] = 0 ;
P_RestoreMusic ( player ) ;
}
}
2016-09-30 12:48:33 +00:00
}
}
2014-03-15 16:59:03 +00:00
//
// P_SpawnGhostMobj
//
// Spawns a ghost object on the player
//
mobj_t * P_SpawnGhostMobj ( mobj_t * mobj )
{
2017-10-02 15:01:10 +00:00
mobj_t * ghost = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_GHOST ) ;
2014-03-15 16:59:03 +00:00
P_SetScale ( ghost , mobj - > scale ) ;
ghost - > destscale = mobj - > scale ;
if ( mobj - > eflags & MFE_VERTICALFLIP )
{
ghost - > eflags | = MFE_VERTICALFLIP ;
ghost - > z + = mobj - > height - ghost - > height ;
}
ghost - > color = mobj - > color ;
2019-06-26 22:26:05 +00:00
ghost - > colorized = mobj - > colorized ; // alternatively, "true" for sonic advance style colourisation
2014-03-15 16:59:03 +00:00
2017-02-08 12:29:45 +00:00
ghost - > angle = ( mobj - > player ? mobj - > player - > drawangle : mobj - > angle ) ;
2014-03-15 16:59:03 +00:00
ghost - > sprite = mobj - > sprite ;
2015-01-22 15:23:45 +00:00
ghost - > sprite2 = mobj - > sprite2 ;
2014-03-15 16:59:03 +00:00
ghost - > frame = mobj - > frame ;
ghost - > tics = - 1 ;
ghost - > frame & = ~ FF_TRANSMASK ;
ghost - > frame | = tr_trans50 < < FF_TRANSSHIFT ;
ghost - > fuse = ghost - > info - > damage ;
ghost - > skin = mobj - > skin ;
if ( mobj - > flags2 & MF2_OBJECTFLIP )
ghost - > flags | = MF2_OBJECTFLIP ;
2017-10-02 15:01:10 +00:00
if ( mobj - > player & & mobj - > player - > followmobj )
{
mobj_t * ghost2 = P_SpawnGhostMobj ( mobj - > player - > followmobj ) ;
P_SetTarget ( & ghost2 - > tracer , ghost ) ;
P_SetTarget ( & ghost - > tracer , ghost2 ) ;
2019-10-23 04:35:17 +00:00
ghost2 - > flags2 | = ( mobj - > player - > followmobj - > flags2 & MF2_LINKDRAW ) ;
2017-10-02 15:01:10 +00:00
}
2014-03-15 16:59:03 +00:00
return ghost ;
}
//
// P_SpawnThokMobj
//
// Spawns the appropriate thok object on the player
//
2014-05-23 20:39:04 +00:00
void P_SpawnThokMobj ( player_t * player )
2014-03-15 16:59:03 +00:00
{
mobj_t * mobj ;
mobjtype_t type = player - > thokitem ;
fixed_t zheight ;
if ( player - > skincolor = = 0 )
return ;
if ( player - > spectator )
return ;
2019-06-19 22:20:24 +00:00
if ( ! type )
return ;
2014-03-15 16:59:03 +00:00
if ( type = = MT_GHOST )
mobj = P_SpawnGhostMobj ( player - > mo ) ; // virtually does everything here for us
else
{
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
zheight = player - > mo - > z + player - > mo - > height + FixedDiv ( P_GetPlayerHeight ( player ) - player - > mo - > height , 3 * FRACUNIT ) - FixedMul ( mobjinfo [ type ] . height , player - > mo - > scale ) ;
else
zheight = player - > mo - > z - FixedDiv ( P_GetPlayerHeight ( player ) - player - > mo - > height , 3 * FRACUNIT ) ;
if ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & zheight < player - > mo - > floorz & & ! ( mobjinfo [ type ] . flags & MF_NOCLIPHEIGHT ) )
zheight = player - > mo - > floorz ;
else if ( player - > mo - > eflags & MFE_VERTICALFLIP & & zheight + FixedMul ( mobjinfo [ type ] . height , player - > mo - > scale ) > player - > mo - > ceilingz & & ! ( mobjinfo [ type ] . flags & MF_NOCLIPHEIGHT ) )
zheight = player - > mo - > ceilingz - FixedMul ( mobjinfo [ type ] . height , player - > mo - > scale ) ;
mobj = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , zheight , type ) ;
// set to player's angle, just in case
2017-02-08 12:29:45 +00:00
mobj - > angle = player - > drawangle ;
2014-03-15 16:59:03 +00:00
// color and skin
mobj - > color = player - > mo - > color ;
mobj - > skin = player - > mo - > skin ;
// vertical flip
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
mobj - > flags2 | = MF2_OBJECTFLIP ;
mobj - > eflags | = ( player - > mo - > eflags & MFE_VERTICALFLIP ) ;
// scale
2019-10-29 15:32:22 +00:00
P_SetScale ( mobj , ( mobj - > destscale = player - > mo - > scale ) ) ;
2017-03-21 16:04:49 +00:00
if ( type = = MT_THOK ) // spintrail-specific modification for MT_THOK
{
mobj - > frame = FF_TRANS70 ;
mobj - > fuse = mobj - > tics ;
}
2014-03-15 16:59:03 +00:00
}
P_SetTarget ( & mobj - > target , player - > mo ) ; // the one thing P_SpawnGhostMobj doesn't do
2019-10-29 15:32:22 +00:00
G_GhostAddThok ( ) ;
2014-03-15 16:59:03 +00:00
}
//
// P_SpawnSpinMobj
//
// Spawns the appropriate spin object on the player
//
2014-05-23 21:55:16 +00:00
void P_SpawnSpinMobj ( player_t * player , mobjtype_t type )
2014-03-15 16:59:03 +00:00
{
mobj_t * mobj ;
fixed_t zheight ;
if ( player - > skincolor = = 0 )
return ;
if ( player - > spectator )
return ;
2019-06-19 22:20:24 +00:00
if ( ! type )
return ;
2014-03-15 16:59:03 +00:00
if ( type = = MT_GHOST )
mobj = P_SpawnGhostMobj ( player - > mo ) ; // virtually does everything here for us
else
{
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
zheight = player - > mo - > z + player - > mo - > height + FixedDiv ( P_GetPlayerHeight ( player ) - player - > mo - > height , 3 * FRACUNIT ) - FixedMul ( mobjinfo [ type ] . height , player - > mo - > scale ) ;
else
zheight = player - > mo - > z - FixedDiv ( P_GetPlayerHeight ( player ) - player - > mo - > height , 3 * FRACUNIT ) ;
if ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & zheight < player - > mo - > floorz & & ! ( mobjinfo [ type ] . flags & MF_NOCLIPHEIGHT ) )
zheight = player - > mo - > floorz ;
else if ( player - > mo - > eflags & MFE_VERTICALFLIP & & zheight + FixedMul ( mobjinfo [ type ] . height , player - > mo - > scale ) > player - > mo - > ceilingz & & ! ( mobjinfo [ type ] . flags & MF_NOCLIPHEIGHT ) )
zheight = player - > mo - > ceilingz - FixedMul ( mobjinfo [ type ] . height , player - > mo - > scale ) ;
mobj = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , zheight , type ) ;
// set to player's angle, just in case
2017-02-08 12:29:45 +00:00
mobj - > angle = player - > drawangle ;
2014-03-15 16:59:03 +00:00
// color and skin
mobj - > color = player - > mo - > color ;
mobj - > skin = player - > mo - > skin ;
// vertical flip
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
mobj - > flags2 | = MF2_OBJECTFLIP ;
mobj - > eflags | = ( player - > mo - > eflags & MFE_VERTICALFLIP ) ;
// scale
P_SetScale ( mobj , player - > mo - > scale ) ;
mobj - > destscale = player - > mo - > scale ;
2017-01-21 01:09:39 +00:00
if ( type = = MT_THOK ) // spintrail-specific modification for MT_THOK
{
mobj - > frame = FF_TRANS70 ;
mobj - > fuse = mobj - > tics ;
}
2014-03-15 16:59:03 +00:00
}
P_SetTarget ( & mobj - > target , player - > mo ) ; // the one thing P_SpawnGhostMobj doesn't do
}
2019-11-15 14:35:28 +00:00
/** Called when \p player finishes the level.
*
* Only use for cases where the player should be able to move
* while waiting for others to finish . Otherwise , use P_DoPlayerExit ( ) .
*
* In single player or if : : cv_exitmove is disabled , this will also cause
* P_PlayerThink ( ) to call P_DoPlayerExit ( ) , so you do not need to
* make a special cases for those .
*
* \ param player The player who finished the level .
* \ sa P_DoPlayerExit
*
*/
void P_DoPlayerFinish ( player_t * player )
{
if ( player - > pflags & PF_FINISHED )
return ;
player - > pflags | = PF_FINISHED ;
if ( netgame )
CONS_Printf ( M_GetText ( " %s has completed the level. \n " ) , player_names [ player - players ] ) ;
2019-11-19 21:44:33 +00:00
player - > powers [ pw_underwater ] = 0 ;
player - > powers [ pw_spacetime ] = 0 ;
P_RestoreMusic ( player ) ;
2019-11-15 14:35:28 +00:00
}
2014-03-15 16:59:03 +00:00
//
// P_DoPlayerExit
//
// Player exits the map via sector trigger
void P_DoPlayerExit ( player_t * player )
{
if ( player - > exiting )
return ;
if ( cv_allowexitlevel . value = = 0 & & ! G_PlatformGametype ( ) )
return ;
else if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION ) // If in Race Mode, allow
{
if ( ! countdown ) // a 60-second wait ala Sonic 2.
2018-03-21 18:18:45 +00:00
countdown = ( cv_countdowntime . value - 1 ) * TICRATE + 1 ; // Use cv_countdowntime
2014-03-15 16:59:03 +00:00
player - > exiting = 3 * TICRATE ;
if ( ! countdown2 )
countdown2 = ( 8 + cv_countdowntime . value ) * TICRATE + 1 ; // 8 sec more than countdowntime -- 11 is too much
if ( P_CheckRacers ( ) )
player - > exiting = ( 14 * TICRATE ) / 5 + 1 ;
}
else
player - > exiting = ( 14 * TICRATE ) / 5 + 2 ; // Accidental death safeguard???
2014-08-04 03:49:33 +00:00
//player->pflags &= ~PF_GLIDING;
if ( player - > climbing )
{
player - > climbing = 0 ;
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-01-14 14:35:10 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-08-04 03:49:33 +00:00
}
2019-11-15 15:20:36 +00:00
else if ( player - > pflags & PF_STARTDASH )
{
player - > pflags & = ~ PF_STARTDASH ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
2014-03-15 16:59:03 +00:00
player - > powers [ pw_underwater ] = 0 ;
player - > powers [ pw_spacetime ] = 0 ;
P_RestoreMusic ( player ) ;
}
# define SPACESPECIAL 12
2014-08-04 03:49:33 +00:00
boolean P_InSpaceSector ( mobj_t * mo ) // Returns true if you are in space
2014-03-15 16:59:03 +00:00
{
2016-10-31 22:14:34 +00:00
sector_t * sector = mo - > subsector - > sector ;
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( GETSECSPECIAL ( sector - > special , 1 ) = = SPACESPECIAL )
return true ;
if ( sector - > ffloors )
{
ffloor_t * rover ;
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
2018-05-11 19:35:46 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
2014-03-15 16:59:03 +00:00
if ( GETSECSPECIAL ( rover - > master - > frontsector - > special , 1 ) ! = SPACESPECIAL )
continue ;
2016-10-31 22:14:34 +00:00
# ifdef ESLOPE
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , mo - > x , mo - > y ) : * rover - > topheight ;
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , mo - > x , mo - > y ) : * rover - > bottomheight ;
# else
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# endif
2014-03-15 16:59:03 +00:00
2016-10-31 22:14:34 +00:00
if ( mo - > z + ( mo - > height / 2 ) > topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-10-31 22:14:34 +00:00
if ( mo - > z + ( mo - > height / 2 ) < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
return true ;
}
}
return false ; // No vacuum here, Captain!
}
2017-09-15 19:34:46 +00:00
//
// P_PlayerHitFloor
//
// Handles player hitting floor surface.
// Returns whether to clip momz.
2019-07-17 20:33:18 +00:00
boolean P_PlayerHitFloor ( player_t * player , boolean dorollstuff )
2017-09-15 19:34:46 +00:00
{
boolean clipmomz ;
I_Assert ( player - > mo ! = NULL ) ;
2019-08-04 14:25:13 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
return true ;
2017-09-15 19:34:46 +00:00
if ( ( clipmomz = ! ( P_CheckDeathPitCollide ( player - > mo ) ) ) & & player - > mo - > health & & ! player - > spectator )
{
2019-07-17 20:33:18 +00:00
if ( dorollstuff )
2017-09-15 19:34:46 +00:00
{
2019-11-09 17:49:26 +00:00
if ( ( player - > charability2 = = CA2_SPINDASH ) & & ! ( ( player - > pflags & ( PF_SPINNING | PF_THOKKED ) ) = = PF_THOKKED ) & & ( player - > cmd . buttons & BT_USE ) & & ( FixedHypot ( player - > mo - > momx , player - > mo - > momy ) > ( 5 * player - > mo - > scale ) ) )
player - > pflags = ( player - > pflags | PF_SPINNING ) & ~ PF_THOKKED ;
2019-08-11 13:36:52 +00:00
else if ( ! ( player - > pflags & PF_STARTDASH ) )
2019-07-17 20:33:18 +00:00
player - > pflags & = ~ PF_SPINNING ;
2017-09-15 19:34:46 +00:00
}
2019-09-19 12:20:05 +00:00
if ( player - > pflags & PF_BOUNCING )
2019-08-04 14:25:13 +00:00
{
2019-09-19 12:20:05 +00:00
if ( dorollstuff & & player - > mo - > state - states ! = S_PLAY_BOUNCE_LANDING )
2019-08-04 14:25:13 +00:00
{
2019-09-19 12:20:05 +00:00
P_MobjCheckWater ( player - > mo ) ;
player - > mo - > momz * = - 1 ;
P_DoAbilityBounce ( player , true ) ;
if ( player - > scoreadd )
player - > scoreadd - - ;
2019-08-04 14:25:13 +00:00
}
2019-09-19 12:20:05 +00:00
clipmomz = false ;
2019-08-04 14:25:13 +00:00
}
2019-09-19 12:20:05 +00:00
else
2019-07-17 20:33:18 +00:00
{
2019-09-19 12:20:05 +00:00
if ( player - > pflags & PF_SPINNING )
2017-09-15 19:34:46 +00:00
{
2019-09-19 12:20:05 +00:00
if ( player - > mo - > state - states ! = S_PLAY_ROLL & & ! ( player - > pflags & PF_STARTDASH ) )
{
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
S_StartSound ( player - > mo , sfx_spin ) ;
}
2017-09-15 19:34:46 +00:00
}
2019-09-19 12:20:05 +00:00
else if ( player - > pflags & PF_GLIDING ) // ground gliding
2017-09-15 19:34:46 +00:00
{
2019-09-19 12:20:05 +00:00
if ( dorollstuff )
2019-06-19 22:20:24 +00:00
{
2019-09-19 12:20:05 +00:00
player - > skidtime = TICRATE ;
player - > mo - > tics = - 1 ;
2019-06-19 22:20:24 +00:00
}
2019-09-19 12:20:05 +00:00
else if ( ! player - > skidtime )
player - > pflags & = ~ PF_GLIDING ;
2017-09-21 21:34:53 +00:00
}
2019-11-24 11:30:20 +00:00
else if ( player - > charability = = CA_GLIDEANDCLIMB & & player - > pflags & PF_THOKKED & & ! ( player - > pflags & ( PF_JUMPED | PF_SHIELDABILITY ) ) & & player - > mo - > state - states = = S_PLAY_FALL )
2019-09-23 18:17:20 +00:00
{
if ( player - > mo - > state - states ! = S_PLAY_GLIDE_LANDING )
{
P_ResetPlayer ( player ) ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_GLIDE_LANDING ) ;
S_StartSound ( player - > mo , sfx_s3k4c ) ;
2019-09-23 19:21:01 +00:00
player - > pflags | = PF_STASIS ;
2019-09-30 06:38:58 +00:00
player - > mo - > momx = ( ( player - > mo - > momx - player - > cmomx ) / 3 ) + player - > cmomx ;
player - > mo - > momy = ( ( player - > mo - > momy - player - > cmomy ) / 3 ) + player - > cmomy ;
2019-09-23 18:17:20 +00:00
}
}
2019-10-21 04:49:12 +00:00
else if ( player - > charability2 = = CA2_MELEE
& & ( ( player - > panim = = PA_ABILITY2 ) | | ( player - > charability = = CA_TWINSPIN & & player - > panim = = PA_ABILITY & & player - > cmd . buttons & ( BT_JUMP | BT_USE ) ) ) )
2017-09-21 21:34:53 +00:00
{
2019-09-19 12:20:05 +00:00
if ( player - > mo - > state - states ! = S_PLAY_MELEE_LANDING )
{
mobjtype_t type = player - > revitem ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_MELEE_LANDING ) ;
player - > mo - > tics = ( player - > mo - > movefactor = = FRACUNIT ) ? TICRATE / 2 : ( FixedDiv ( 35 < < ( FRACBITS - 1 ) , FixedSqrt ( player - > mo - > movefactor ) ) ) > > FRACBITS ;
S_StartSound ( player - > mo , sfx_s3k8b ) ;
player - > pflags | = PF_FULLSTASIS ;
// hearticles
if ( type )
{
UINT8 i = 0 ;
angle_t throwang = - ( 2 * ANG30 ) ;
fixed_t xo = P_ReturnThrustX ( player - > mo , player - > drawangle , 16 * player - > mo - > scale ) ;
fixed_t yo = P_ReturnThrustY ( player - > mo , player - > drawangle , 16 * player - > mo - > scale ) ;
fixed_t zo = 6 * player - > mo - > scale ;
fixed_t mu = FixedMul ( player - > maxdash , player - > mo - > scale ) ;
fixed_t mu2 = FixedHypot ( player - > mo - > momx , player - > mo - > momy ) ;
fixed_t ev ;
mobj_t * missile = NULL ;
if ( mu2 < mu )
mu2 = mu ;
ev = ( 50 * FRACUNIT - ( mu / 25 ) ) / 50 ;
while ( i < 5 )
{
missile = P_SpawnMobjFromMobj ( player - > mo , xo , yo , zo , type ) ;
P_SetTarget ( & missile - > target , player - > mo ) ;
missile - > angle = throwang + player - > drawangle ;
P_Thrust ( missile , player - > drawangle + ANGLE_90 ,
P_ReturnThrustY ( missile , throwang , mu ) ) ; // side to side component
P_Thrust ( missile , player - > drawangle , mu2 ) ; // forward component
P_SetObjectMomZ ( missile , ( 4 + ( ( i & 1 ) < < 1 ) ) * FRACUNIT , true ) ;
missile - > momz + = player - > mo - > pmomz ;
missile - > fuse = TICRATE / 2 ;
missile - > extravalue2 = ev ;
i + + ;
throwang + = ANG30 ;
}
if ( mobjinfo [ type ] . seesound & & missile )
S_StartSound ( missile , missile - > info - > seesound ) ;
}
}
2019-07-17 20:33:18 +00:00
}
2019-09-19 12:20:05 +00:00
else if ( player - > charability2 = = CA2_GUNSLINGER & & player - > panim = = PA_ABILITY2 )
;
else if ( player - > panim ! = PA_IDLE & & player - > panim ! = PA_WALK & & player - > panim ! = PA_RUN & & player - > panim ! = PA_DASH )
2019-07-17 20:33:18 +00:00
{
2019-11-22 21:06:25 +00:00
fixed_t runspd = FixedMul ( player - > runspeed , player - > mo - > scale ) ;
// See comments in P_MovePlayer for explanation of changes.
if ( player - > powers [ pw_super ] )
runspd = FixedMul ( runspd , 5 * FRACUNIT / 3 ) ;
runspd = FixedMul ( runspd , player - > mo - > movefactor ) ;
if ( maptol & TOL_2D )
runspd = FixedMul ( runspd , 2 * FRACUNIT / 3 ) ;
2019-09-19 12:20:05 +00:00
if ( player - > cmomx | | player - > cmomy )
{
2019-10-23 04:35:17 +00:00
if ( player - > charflags & SF_DASHMODE & & player - > dashmode > = DASHMODE_THRESHOLD & & player - > panim ! = PA_DASH )
2019-09-19 12:20:05 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_DASH ) ;
2019-11-22 21:06:25 +00:00
else if ( player - > speed > = runspd
2019-09-19 12:20:05 +00:00
& & ( player - > panim ! = PA_RUN | | player - > mo - > state - states = = S_PLAY_FLOAT_RUN ) )
P_SetPlayerMobjState ( player - > mo , S_PLAY_RUN ) ;
else if ( ( player - > rmomx | | player - > rmomy )
& & ( player - > panim ! = PA_WALK | | player - > mo - > state - states = = S_PLAY_FLOAT ) )
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
else if ( ! player - > rmomx & & ! player - > rmomy & & player - > panim ! = PA_IDLE )
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
else
{
2019-10-23 04:35:17 +00:00
if ( player - > charflags & SF_DASHMODE & & player - > dashmode > = DASHMODE_THRESHOLD & & player - > panim ! = PA_DASH )
2019-09-19 12:20:05 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_DASH ) ;
2019-11-22 21:06:25 +00:00
else if ( player - > speed > = runspd
2019-09-19 12:20:05 +00:00
& & ( player - > panim ! = PA_RUN | | player - > mo - > state - states = = S_PLAY_FLOAT_RUN ) )
P_SetPlayerMobjState ( player - > mo , S_PLAY_RUN ) ;
else if ( ( player - > mo - > momx | | player - > mo - > momy )
& & ( player - > panim ! = PA_WALK | | player - > mo - > state - states = = S_PLAY_FLOAT ) )
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
else if ( ! player - > mo - > momx & & ! player - > mo - > momy & & player - > panim ! = PA_IDLE )
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
2017-09-15 19:34:46 +00:00
}
2019-09-19 12:20:05 +00:00
if ( ! ( player - > pflags & PF_GLIDING ) )
player - > pflags & = ~ ( PF_JUMPED | PF_NOJUMPDAMAGE ) ;
player - > pflags & = ~ ( PF_STARTJUMP | PF_THOKKED | PF_CANCARRY /*|PF_GLIDING*/ ) ;
player - > secondjump = 0 ;
player - > glidetime = 0 ;
player - > climbing = 0 ;
player - > powers [ pw_tailsfly ] = 0 ;
2017-09-15 19:34:46 +00:00
2019-09-19 12:20:05 +00:00
if ( player - > pflags & PF_SHIELDABILITY )
2017-09-15 19:34:46 +00:00
{
2019-09-19 12:20:05 +00:00
player - > pflags & = ~ PF_SHIELDABILITY ;
if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL ) // Elemental shield's stomp attack.
2017-09-15 19:34:46 +00:00
{
2019-09-19 12:20:05 +00:00
if ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_TOUCHWATER ) ) // play a blunt sound
S_StartSound ( player - > mo , sfx_s3k4c ) ;
else // create a fire pattern on the ground
{
S_StartSound ( player - > mo , sfx_s3k47 ) ;
P_ElementalFire ( player , true ) ;
}
P_SetObjectMomZ ( player - > mo ,
( player - > mo - > eflags & MFE_UNDERWATER )
? 6 * FRACUNIT / 5
: 5 * FRACUNIT / 2 ,
false ) ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
player - > mo - > momx = player - > mo - > momy = 0 ;
clipmomz = false ;
}
else if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_BUBBLEWRAP ) // Bubble shield's bounce attack.
2017-09-15 19:34:46 +00:00
{
2019-09-19 12:20:05 +00:00
P_DoBubbleBounce ( player ) ;
clipmomz = false ;
2017-09-15 19:34:46 +00:00
}
}
}
}
return clipmomz ;
}
2014-08-04 03:49:33 +00:00
boolean P_InQuicksand ( mobj_t * mo ) // Returns true if you are in quicksand
2014-03-15 16:59:03 +00:00
{
2016-10-31 22:14:34 +00:00
sector_t * sector = mo - > subsector - > sector ;
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
2016-10-31 22:14:34 +00:00
fixed_t flipoffset = ( ( mo - > eflags & MFE_VERTICALFLIP ) ? ( mo - > height / 2 ) : 0 ) ;
2014-03-15 16:59:03 +00:00
if ( sector - > ffloors )
{
ffloor_t * rover ;
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
if ( ! ( rover - > flags & FF_QUICKSAND ) )
continue ;
2016-10-31 22:14:34 +00:00
# ifdef ESLOPE
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , mo - > x , mo - > y ) : * rover - > topheight ;
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , mo - > x , mo - > y ) : * rover - > bottomheight ;
# else
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# endif
if ( mo - > z + flipoffset > topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-10-31 22:14:34 +00:00
if ( mo - > z + ( mo - > height / 2 ) + flipoffset < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
return true ;
}
}
return false ; // No sand here, Captain!
}
static void P_CheckBustableBlocks ( player_t * player )
{
msecnode_t * node ;
fixed_t oldx ;
fixed_t oldy ;
if ( ( netgame | | multiplayer ) & & player - > spectator )
return ;
oldx = player - > mo - > x ;
oldy = player - > mo - > y ;
2016-12-23 23:58:12 +00:00
if ( ! ( player - > pflags & PF_BOUNCING ) ) // Bouncers only get to break downwards, not sideways
{
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x + = player - > mo - > momx ;
player - > mo - > y + = player - > mo - > momy ;
P_SetThingPosition ( player - > mo ) ;
}
2014-03-15 16:59:03 +00:00
2016-06-09 13:16:02 +00:00
for ( node = player - > mo - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
if ( ! node - > m_sector )
break ;
if ( node - > m_sector - > ffloors )
{
ffloor_t * rover ;
2016-09-02 20:41:45 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
for ( rover = node - > m_sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) ) continue ;
if ( ( rover - > flags & FF_BUSTUP ) /* && !rover->master->frontsector->crumblestate*/ )
{
2019-10-19 20:20:48 +00:00
// If it's an FF_SHATTER, you can break it just by touching it.
if ( rover - > flags & FF_SHATTER )
goto bust ;
// If it's an FF_SPINBUST, you can break it if you are in your spinning frames
// (either from jumping or spindashing).
if ( rover - > flags & FF_SPINBUST
& & ( ( ( player - > pflags & PF_SPINNING ) & & ! ( player - > pflags & PF_STARTDASH ) )
| | ( player - > pflags & PF_JUMPED & & ! ( player - > pflags & PF_NOJUMPDAMAGE ) ) ) )
goto bust ;
// You can always break it if you have CA_GLIDEANDCLIMB
// or if you are bouncing on it
// or you are using CA_TWINSPIN/CA2_MELEE.
if ( player - > charability = = CA_GLIDEANDCLIMB
| | ( player - > pflags & PF_BOUNCING )
| | ( ( player - > charability = = CA_TWINSPIN ) & & ( player - > panim = = PA_ABILITY ) )
| | ( player - > charability2 = = CA2_MELEE & & player - > panim = = PA_ABILITY2 ) )
goto bust ;
if ( rover - > flags & FF_STRONGBUST )
2014-03-15 16:59:03 +00:00
continue ;
2019-10-19 20:20:48 +00:00
// If it's not an FF_STRONGBUST, you can break if you are spinning (and not jumping)
// or you are super
// or you are in dashmode with SF_DASHMODE
// or you are drilling in NiGHTS
// or you are recording for Metal Sonic
if ( ! ( ( player - > pflags & PF_SPINNING ) & & ! ( player - > pflags & PF_JUMPED ) )
2016-07-17 15:34:07 +00:00
& & ! ( player - > powers [ pw_super ] )
2019-10-23 05:46:30 +00:00
& & ! ( ( ( player - > charflags & ( SF_DASHMODE | SF_MACHINE ) ) = = ( SF_DASHMODE | SF_MACHINE ) ) & & ( player - > dashmode > = DASHMODE_THRESHOLD ) )
2016-07-17 15:34:07 +00:00
& & ! ( player - > pflags & PF_DRILLING )
& & ! metalrecording )
2014-03-15 16:59:03 +00:00
continue ;
2019-10-19 20:20:48 +00:00
bust :
2016-09-02 20:41:45 +00:00
topheight = P_GetFOFTopZ ( player - > mo , node - > m_sector , rover , player - > mo - > x , player - > mo - > y , NULL ) ;
bottomheight = P_GetFOFBottomZ ( player - > mo , node - > m_sector , rover , player - > mo - > x , player - > mo - > y , NULL ) ;
2017-02-04 18:25:16 +00:00
if ( ( ( player - > charability = = CA_TWINSPIN ) & & ( player - > panim = = PA_ABILITY ) )
| | ( ( P_MobjFlip ( player - > mo ) * player - > mo - > momz < 0 ) & & ( player - > pflags & PF_BOUNCING | | ( ( player - > charability2 = = CA2_MELEE ) & & ( player - > panim = = PA_ABILITY2 ) ) ) ) )
2016-12-23 23:58:12 +00:00
{
2017-02-04 18:25:16 +00:00
topheight - = player - > mo - > momz ;
bottomheight - = player - > mo - > momz ;
2016-12-23 23:58:12 +00:00
}
2014-03-15 16:59:03 +00:00
// Height checks
if ( rover - > flags & FF_SHATTERBOTTOM )
{
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z + player - > mo - > momz + player - > mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z + player - > mo - > height > bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
}
else if ( rover - > flags & FF_SPINBUST )
{
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z + player - > mo - > momz > topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z + player - > mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
}
else if ( rover - > flags & FF_SHATTER )
{
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z + player - > mo - > momz > topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z + player - > mo - > momz + player - > mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
}
else
{
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z > = topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( player - > mo - > z + player - > mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
}
// Impede the player's fall a bit
2016-09-02 20:41:45 +00:00
if ( ( ( rover - > flags & FF_SPINBUST ) | | ( rover - > flags & FF_SHATTER ) ) & & player - > mo - > z > = topheight )
2014-03-15 16:59:03 +00:00
player - > mo - > momz > > = 1 ;
else if ( rover - > flags & FF_SHATTER )
{
player - > mo - > momx > > = 1 ;
player - > mo - > momy > > = 1 ;
}
//if (metalrecording)
// G_RecordBustup(rover);
2017-09-25 19:35:04 +00:00
EV_CrumbleChain ( NULL , rover ) ; // node->m_sector
2014-03-15 16:59:03 +00:00
// Run a linedef executor??
if ( rover - > master - > flags & ML_EFFECT5 )
P_LinedefExecute ( ( INT16 ) ( P_AproxDistance ( rover - > master - > dx , rover - > master - > dy ) > > FRACBITS ) , player - > mo , node - > m_sector ) ;
goto bustupdone ;
}
}
}
}
bustupdone :
2016-12-23 23:58:12 +00:00
if ( ! ( player - > pflags & PF_BOUNCING ) )
{
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x = oldx ;
player - > mo - > y = oldy ;
P_SetThingPosition ( player - > mo ) ;
}
2014-03-15 16:59:03 +00:00
}
static void P_CheckBouncySectors ( player_t * player )
{
msecnode_t * node ;
fixed_t oldx ;
fixed_t oldy ;
fixed_t oldz ;
2015-05-21 20:49:49 +00:00
# ifdef ESLOPE
2015-05-23 03:07:07 +00:00
vector3_t momentum ;
2015-05-21 20:49:49 +00:00
# endif
2014-03-15 16:59:03 +00:00
oldx = player - > mo - > x ;
oldy = player - > mo - > y ;
oldz = player - > mo - > z ;
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x + = player - > mo - > momx ;
player - > mo - > y + = player - > mo - > momy ;
player - > mo - > z + = player - > mo - > momz ;
P_SetThingPosition ( player - > mo ) ;
2016-06-09 13:16:02 +00:00
for ( node = player - > mo - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
if ( ! node - > m_sector )
break ;
if ( node - > m_sector - > ffloors )
{
ffloor_t * rover ;
boolean top = true ;
2015-05-21 20:49:49 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
for ( rover = node - > m_sector - > ffloors ; rover ; rover = rover - > next )
{
2018-05-11 19:35:46 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ; // FOFs should not be bouncy if they don't even "exist"
if ( GETSECSPECIAL ( rover - > master - > frontsector - > special , 1 ) ! = 15 )
continue ; // this sector type is required for FOFs to be bouncy
2015-05-21 20:49:49 +00:00
topheight = P_GetFOFTopZ ( player - > mo , node - > m_sector , rover , player - > mo - > x , player - > mo - > y , NULL ) ;
bottomheight = P_GetFOFBottomZ ( player - > mo , node - > m_sector , rover , player - > mo - > x , player - > mo - > y , NULL ) ;
if ( player - > mo - > z > topheight )
2014-03-15 16:59:03 +00:00
continue ;
2015-05-21 20:49:49 +00:00
if ( player - > mo - > z + player - > mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
2015-05-21 20:49:49 +00:00
if ( oldz < P_GetFOFTopZ ( player - > mo , node - > m_sector , rover , oldx , oldy , NULL )
& & oldz + player - > mo - > height > P_GetFOFBottomZ ( player - > mo , node - > m_sector , rover , oldx , oldy , NULL ) )
2014-03-15 16:59:03 +00:00
top = false ;
{
fixed_t linedist ;
linedist = P_AproxDistance ( rover - > master - > v1 - > x - rover - > master - > v2 - > x , rover - > master - > v1 - > y - rover - > master - > v2 - > y ) ;
linedist = FixedDiv ( linedist , 100 * FRACUNIT ) ;
if ( top )
{
fixed_t newmom ;
2015-05-21 20:49:49 +00:00
# ifdef ESLOPE
pslope_t * slope ;
if ( abs ( oldz - topheight ) < abs ( oldz + player - > mo - > height - bottomheight ) ) { // Hit top
slope = * rover - > t_slope ;
} else { // Hit bottom
slope = * rover - > b_slope ;
}
momentum . x = player - > mo - > momx ;
momentum . y = player - > mo - > momy ;
momentum . z = player - > mo - > momz * 2 ;
2016-06-12 18:27:34 +00:00
if ( slope )
P_ReverseQuantizeMomentumToSlope ( & momentum , slope ) ;
2015-05-21 20:49:49 +00:00
newmom = momentum . z = - FixedMul ( momentum . z , linedist ) / 2 ;
# else
2014-03-15 16:59:03 +00:00
newmom = - FixedMul ( player - > mo - > momz , linedist ) ;
2015-05-21 20:49:49 +00:00
# endif
2014-03-15 16:59:03 +00:00
if ( abs ( newmom ) < ( linedist * 2 ) )
{
goto bouncydone ;
}
if ( ! ( rover - > master - > flags & ML_BOUNCY ) )
{
if ( newmom > 0 )
{
if ( newmom < 8 * FRACUNIT )
newmom = 8 * FRACUNIT ;
}
else if ( newmom > - 8 * FRACUNIT & & newmom ! = 0 )
newmom = - 8 * FRACUNIT ;
}
if ( newmom > P_GetPlayerHeight ( player ) / 2 )
newmom = P_GetPlayerHeight ( player ) / 2 ;
else if ( newmom < - P_GetPlayerHeight ( player ) / 2 )
newmom = - P_GetPlayerHeight ( player ) / 2 ;
2015-05-21 20:49:49 +00:00
# ifdef ESLOPE
momentum . z = newmom * 2 ;
if ( slope )
P_QuantizeMomentumToSlope ( & momentum , slope ) ;
player - > mo - > momx = momentum . x ;
player - > mo - > momy = momentum . y ;
player - > mo - > momz = momentum . z / 2 ;
# else
2014-03-15 16:59:03 +00:00
player - > mo - > momz = newmom ;
2015-05-21 20:49:49 +00:00
# endif
2014-03-15 16:59:03 +00:00
if ( player - > pflags & PF_SPINNING )
{
player - > pflags & = ~ PF_SPINNING ;
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2014-03-15 16:59:03 +00:00
player - > pflags | = PF_THOKKED ;
}
}
else
{
player - > mo - > momx = - FixedMul ( player - > mo - > momx , linedist ) ;
player - > mo - > momy = - FixedMul ( player - > mo - > momy , linedist ) ;
if ( player - > pflags & PF_SPINNING )
{
player - > pflags & = ~ PF_SPINNING ;
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-10-23 14:53:12 +00:00
player - > pflags | = PF_THOKKED ;
2014-03-15 16:59:03 +00:00
}
}
if ( ( player - > pflags & PF_SPINNING ) & & player - > speed < FixedMul ( 1 < < FRACBITS , player - > mo - > scale ) & & player - > mo - > momz )
{
player - > pflags & = ~ PF_SPINNING ;
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2014-03-15 16:59:03 +00:00
}
goto bouncydone ;
}
}
}
}
bouncydone :
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x = oldx ;
player - > mo - > y = oldy ;
player - > mo - > z = oldz ;
P_SetThingPosition ( player - > mo ) ;
}
static void P_CheckQuicksand ( player_t * player )
{
ffloor_t * rover ;
fixed_t sinkspeed , friction ;
2016-10-31 21:34:43 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( ! ( player - > mo - > subsector - > sector - > ffloors & & player - > mo - > momz < = 0 ) )
return ;
for ( rover = player - > mo - > subsector - > sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) ) continue ;
if ( ! ( rover - > flags & FF_QUICKSAND ) )
continue ;
2016-10-31 22:14:34 +00:00
# ifdef ESLOPE
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) : * rover - > topheight ;
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , player - > mo - > x , player - > mo - > y ) : * rover - > bottomheight ;
# else
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# endif
2016-10-31 21:34:43 +00:00
if ( topheight > = player - > mo - > z & & bottomheight < player - > mo - > z + player - > mo - > height )
2014-03-15 16:59:03 +00:00
{
sinkspeed = abs ( rover - > master - > v1 - > x - rover - > master - > v2 - > x ) > > 1 ;
sinkspeed = FixedDiv ( sinkspeed , TICRATE * FRACUNIT ) ;
2016-10-31 21:34:43 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
fixed_t ceilingheight = P_GetCeilingZ ( player - > mo , player - > mo - > subsector - > sector , player - > mo - > x , player - > mo - > y , NULL ) ;
player - > mo - > z + = sinkspeed ;
2014-03-15 16:59:03 +00:00
2016-10-31 21:34:43 +00:00
if ( player - > mo - > z + player - > mo - > height > = ceilingheight )
player - > mo - > z = ceilingheight - player - > mo - > height ;
2017-09-15 19:34:46 +00:00
if ( player - > mo - > momz < = 0 )
2019-07-17 20:33:18 +00:00
P_PlayerHitFloor ( player , false ) ;
2016-10-31 21:34:43 +00:00
}
else
{
fixed_t floorheight = P_GetFloorZ ( player - > mo , player - > mo - > subsector - > sector , player - > mo - > x , player - > mo - > y , NULL ) ;
player - > mo - > z - = sinkspeed ;
2014-03-15 16:59:03 +00:00
2016-10-31 21:34:43 +00:00
if ( player - > mo - > z < = floorheight )
player - > mo - > z = floorheight ;
2017-09-15 19:34:46 +00:00
if ( player - > mo - > momz > = 0 )
2019-07-17 20:33:18 +00:00
P_PlayerHitFloor ( player , false ) ;
2016-10-31 21:34:43 +00:00
}
2014-03-15 16:59:03 +00:00
friction = abs ( rover - > master - > v1 - > y - rover - > master - > v2 - > y ) > > 6 ;
player - > mo - > momx = FixedMul ( player - > mo - > momx , friction ) ;
player - > mo - > momy = FixedMul ( player - > mo - > momy , friction ) ;
}
}
}
//
// P_CheckSneakerAndLivesTimer
//
// Restores music from sneaker and life fanfares
//
static void P_CheckSneakerAndLivesTimer ( player_t * player )
{
if ( player - > powers [ pw_extralife ] = = 1 ) // Extra Life!
P_RestoreMusic ( player ) ;
if ( player - > powers [ pw_sneakers ] = = 1 )
P_RestoreMusic ( player ) ;
}
//
// P_CheckUnderwaterAndSpaceTimer
//
// Restores music from underwater and space warnings, and handles number generation
//
static void P_CheckUnderwaterAndSpaceTimer ( player_t * player )
{
2016-07-16 16:11:34 +00:00
tic_t timeleft = ( player - > powers [ pw_spacetime ] ) ? player - > powers [ pw_spacetime ] : player - > powers [ pw_underwater ] ;
2014-03-15 16:59:03 +00:00
2019-11-19 21:44:33 +00:00
if ( player - > exiting | | ( player - > pflags & PF_FINISHED ) )
2018-03-30 20:49:15 +00:00
player - > powers [ pw_underwater ] = player - > powers [ pw_spacetime ] = 0 ;
timeleft - - ; // The original code was all n*TICRATE + 1, so let's remove 1 tic for simplicity
if ( ( timeleft = = 11 * TICRATE ) // 5
| | ( timeleft = = 9 * TICRATE ) // 4
| | ( timeleft = = 7 * TICRATE ) // 3
| | ( timeleft = = 5 * TICRATE ) // 2
| | ( timeleft = = 3 * TICRATE ) // 1
| | ( timeleft = = 1 * TICRATE ) // 0
2016-07-16 16:11:34 +00:00
) {
fixed_t height = ( player - > mo - > eflags & MFE_VERTICALFLIP )
2016-12-24 00:11:54 +00:00
? player - > mo - > z - FixedMul ( 8 * FRACUNIT + mobjinfo [ MT_DROWNNUMBERS ] . height , FixedMul ( player - > mo - > scale , player - > shieldscale ) )
: player - > mo - > z + player - > mo - > height + FixedMul ( 8 * FRACUNIT , FixedMul ( player - > mo - > scale , player - > shieldscale ) ) ;
2014-03-15 16:59:03 +00:00
2016-07-16 16:11:34 +00:00
mobj_t * numbermobj = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , height , MT_DROWNNUMBERS ) ;
2018-03-30 20:49:15 +00:00
timeleft / = ( 2 * TICRATE ) ; // To be strictly accurate it'd need to be ((timeleft/TICRATE) - 1)/2, but integer division rounds down for us
2016-07-16 16:11:34 +00:00
2016-07-16 21:43:49 +00:00
if ( player - > charflags & SF_MACHINE )
{
S_StartSound ( player - > mo , sfx_buzz1 ) ;
timeleft + = 6 ;
}
else
S_StartSound ( player - > mo , sfx_dwnind ) ;
2016-07-16 16:11:34 +00:00
if ( timeleft ) // Don't waste time setting the state if the time is 0.
P_SetMobjState ( numbermobj , numbermobj - > info - > spawnstate + timeleft ) ;
P_SetTarget ( & numbermobj - > target , player - > mo ) ;
numbermobj - > threshold = 40 ;
numbermobj - > destscale = player - > mo - > scale ;
P_SetScale ( numbermobj , player - > mo - > scale ) ;
2014-03-15 16:59:03 +00:00
}
// Underwater timer runs out
2016-07-16 16:11:34 +00:00
else if ( timeleft = = 1 )
2014-03-15 16:59:03 +00:00
{
if ( ( netgame | | multiplayer ) & & P_IsLocalPlayer ( player ) )
2016-01-08 03:48:20 +00:00
S_ChangeMusic ( mapmusname , mapmusflags , true ) ;
2014-03-15 16:59:03 +00:00
2016-07-16 16:11:34 +00:00
if ( player - > powers [ pw_spacetime ] = = 1 )
P_DamageMobj ( player - > mo , NULL , NULL , 1 , DMG_SPACEDROWN ) ;
else
P_DamageMobj ( player - > mo , NULL , NULL , 1 , DMG_DROWNED ) ;
2014-03-15 16:59:03 +00:00
}
if ( ! ( player - > mo - > eflags & MFE_UNDERWATER ) & & player - > powers [ pw_underwater ] )
{
if ( player - > powers [ pw_underwater ] < = 12 * TICRATE + 1 )
2019-08-04 11:03:57 +00:00
{
player - > powers [ pw_underwater ] = 0 ;
2014-03-15 16:59:03 +00:00
P_RestoreMusic ( player ) ;
2019-08-04 11:03:57 +00:00
}
else
player - > powers [ pw_underwater ] = 0 ;
2014-03-15 16:59:03 +00:00
}
if ( player - > powers [ pw_spacetime ] > 1 & & ! P_InSpaceSector ( player - > mo ) )
player - > powers [ pw_spacetime ] = 0 ;
// Underwater audio cues
if ( P_IsLocalPlayer ( player ) & & ! player - > bot )
{
2016-07-16 21:43:49 +00:00
if ( ( player - > powers [ pw_underwater ] = = 25 * TICRATE + 1 )
| | ( player - > powers [ pw_underwater ] = = 20 * TICRATE + 1 )
| | ( player - > powers [ pw_underwater ] = = 15 * TICRATE + 1 ) )
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_wtrdng ) ;
2016-07-16 16:11:34 +00:00
2014-03-15 16:59:03 +00:00
if ( player - > powers [ pw_underwater ] = = 11 * TICRATE + 1
& & player = = & players [ consoleplayer ] )
{
2019-08-04 11:03:57 +00:00
P_PlayJingle ( player , JT_DROWN ) ;
2014-03-15 16:59:03 +00:00
}
}
}
//
// P_CheckInvincibilityTimer
//
// Restores music from invincibility, and handles invincibility sparkles
//
static void P_CheckInvincibilityTimer ( player_t * player )
{
2014-08-04 03:49:33 +00:00
if ( ! player - > powers [ pw_invulnerability ] )
return ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( mariomode & & ! player - > powers [ pw_super ] )
2017-07-22 22:24:12 +00:00
player - > mo - > color = ( UINT8 ) ( SKINCOLOR_RUBY + ( leveltime % ( MAXSKINCOLORS - SKINCOLOR_RUBY ) ) ) ; // Passes through all saturated colours
2014-08-04 03:49:33 +00:00
else if ( leveltime % ( TICRATE / 7 ) = = 0 )
{
2015-11-23 21:04:33 +00:00
mobj_t * sparkle = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z , MT_IVSP ) ;
2014-08-04 03:49:33 +00:00
sparkle - > destscale = player - > mo - > scale ;
P_SetScale ( sparkle , player - > mo - > scale ) ;
2014-03-15 16:59:03 +00:00
}
// Resume normal music stuff.
if ( player - > powers [ pw_invulnerability ] = = 1 )
{
if ( ! player - > powers [ pw_super ] )
{
if ( mariomode )
{
2016-10-24 11:35:40 +00:00
if ( ( player - > powers [ pw_shield ] & SH_STACK ) = = SH_FIREFLOWER )
2014-03-15 16:59:03 +00:00
{
player - > mo - > color = SKINCOLOR_WHITE ;
G_GhostAddColor ( GHC_FIREFLOWER ) ;
}
else
{
player - > mo - > color = player - > skincolor ;
G_GhostAddColor ( GHC_NORMAL ) ;
}
}
// If you had a shield, restore its visual significance
P_SpawnShieldOrb ( player ) ;
}
if ( ! player - > powers [ pw_super ] | | ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_NOSSMUSIC ) )
P_RestoreMusic ( player ) ;
}
}
//
// P_DoBubbleBreath
//
// Handles bubbles spawned by the player
//
static void P_DoBubbleBreath ( player_t * player )
{
2016-07-16 21:43:49 +00:00
fixed_t x = player - > mo - > x ;
fixed_t y = player - > mo - > y ;
fixed_t z = player - > mo - > z ;
2014-03-15 16:59:03 +00:00
mobj_t * bubble = NULL ;
2017-03-14 18:11:17 +00:00
if ( ! ( player - > mo - > eflags & MFE_UNDERWATER ) | | ( ( player - > powers [ pw_shield ] & SH_PROTECTWATER ) & & ! ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) ) | | player - > spectator )
2014-03-15 16:59:03 +00:00
return ;
2016-07-16 21:43:49 +00:00
if ( player - > charflags & SF_MACHINE )
{
2017-07-07 12:35:48 +00:00
if ( player - > powers [ pw_underwater ] & & P_RandomChance ( ( 128 - ( player - > powers [ pw_underwater ] / 4 ) ) * FRACUNIT / 256 ) )
2016-07-16 21:43:49 +00:00
{
2016-07-16 22:26:52 +00:00
fixed_t r = player - > mo - > radius > > FRACBITS ;
x + = ( P_RandomRange ( r , - r ) < < FRACBITS ) ;
y + = ( P_RandomRange ( r , - r ) < < FRACBITS ) ;
2016-07-16 21:43:49 +00:00
z + = ( P_RandomKey ( player - > mo - > height > > FRACBITS ) < < FRACBITS ) ;
bubble = P_SpawnMobj ( x , y , z , MT_WATERZAP ) ;
S_StartSound ( bubble , sfx_beelec ) ;
}
}
else
{
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
z + = player - > mo - > height - FixedDiv ( player - > mo - > height , 5 * ( FRACUNIT / 4 ) ) ;
else
z + = FixedDiv ( player - > mo - > height , 5 * ( FRACUNIT / 4 ) ) ;
if ( P_RandomChance ( FRACUNIT / 16 ) )
bubble = P_SpawnMobj ( x , y , z , MT_SMALLBUBBLE ) ;
else if ( P_RandomChance ( 3 * FRACUNIT / 256 ) )
bubble = P_SpawnMobj ( x , y , z , MT_MEDIUMBUBBLE ) ;
}
2014-03-15 16:59:03 +00:00
if ( bubble )
{
bubble - > threshold = 42 ;
bubble - > destscale = player - > mo - > scale ;
P_SetScale ( bubble , bubble - > destscale ) ;
}
// Tails stirs up the water while flying in it
if ( player - > powers [ pw_tailsfly ] & & ( leveltime & 1 ) & & player - > charability ! = CA_SWIM )
{
2019-09-18 12:46:17 +00:00
fixed_t radius = player - > mo - > radius ;
2014-03-15 16:59:03 +00:00
angle_t fa = ( ( leveltime % 45 ) * FINEANGLES / 8 ) & FINEMASK ;
fixed_t stirwaterx = FixedMul ( FINECOSINE ( fa ) , radius ) ;
fixed_t stirwatery = FixedMul ( FINESINE ( fa ) , radius ) ;
fixed_t stirwaterz ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2019-09-18 12:46:17 +00:00
stirwaterz = player - > mo - > z + player - > mo - > height - ( 4 < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
else
2019-09-18 12:46:17 +00:00
stirwaterz = player - > mo - > z + ( 4 < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
bubble = P_SpawnMobj (
player - > mo - > x + stirwaterx ,
player - > mo - > y + stirwatery ,
stirwaterz , MT_SMALLBUBBLE ) ;
bubble - > destscale = player - > mo - > scale ;
P_SetScale ( bubble , bubble - > destscale ) ;
bubble = P_SpawnMobj (
player - > mo - > x - stirwaterx ,
player - > mo - > y - stirwatery ,
stirwaterz , MT_SMALLBUBBLE ) ;
bubble - > destscale = player - > mo - > scale ;
P_SetScale ( bubble , bubble - > destscale ) ;
}
}
//
// P_DoPlayerHeadSigns
//
// Spawns "IT" and "GOT FLAG" signs for Tag and CTF respectively
//
static void P_DoPlayerHeadSigns ( player_t * player )
{
if ( G_TagGametype ( ) )
{
// If you're "IT", show a big "IT" over your head for others to see.
if ( player - > pflags & PF_TAGIT )
{
2017-04-29 15:27:52 +00:00
if ( ! P_IsLocalPlayer ( player ) ) // Don't display it on your own view.
2014-03-15 16:59:03 +00:00
{
if ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP ) )
P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + player - > mo - > height , MT_TAG ) ;
else
P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z - mobjinfo [ MT_TAG ] . height , MT_TAG ) - > eflags | = MFE_VERTICALFLIP ;
}
}
}
2017-03-22 18:51:30 +00:00
else if ( gametype = = GT_CTF & & ( player - > gotflag & ( GF_REDFLAG | GF_BLUEFLAG ) ) ) // If you have the flag (duh).
2014-03-15 16:59:03 +00:00
{
2017-03-22 18:51:30 +00:00
// Spawn a got-flag message over the head of the player that
// has it (but not on your own screen if you have the flag).
if ( splitscreen | | player ! = & players [ consoleplayer ] )
2014-03-15 16:59:03 +00:00
{
2017-03-23 19:11:22 +00:00
mobj_t * sign = P_SpawnMobj ( player - > mo - > x + player - > mo - > momx , player - > mo - > y + player - > mo - > momy ,
player - > mo - > z + player - > mo - > momz , MT_GOTFLAG ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
sign - > z + = player - > mo - > height - P_GetPlayerHeight ( player ) - mobjinfo [ MT_GOTFLAG ] . height - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) ;
sign - > eflags | = MFE_VERTICALFLIP ;
}
2017-03-22 18:51:30 +00:00
else
2017-03-23 19:11:22 +00:00
sign - > z + = P_GetPlayerHeight ( player ) + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) ;
2018-03-26 22:53:09 +00:00
if ( player - > gotflag & GF_REDFLAG )
sign - > frame = 1 | FF_FULLBRIGHT ;
else //if (player->gotflag & GF_BLUEFLAG)
sign - > frame = 2 | FF_FULLBRIGHT ;
2014-03-15 16:59:03 +00:00
}
}
}
//
// P_DoClimbing
//
// Handles player climbing
//
static void P_DoClimbing ( player_t * player )
{
ticcmd_t * cmd = & player - > cmd ;
fixed_t platx ;
fixed_t platy ;
subsector_t * glidesector ;
boolean climb = true ;
platx = P_ReturnThrustX ( player - > mo , player - > mo - > angle , player - > mo - > radius + FixedMul ( 8 * FRACUNIT , player - > mo - > scale ) ) ;
platy = P_ReturnThrustY ( player - > mo , player - > mo - > angle , player - > mo - > radius + FixedMul ( 8 * FRACUNIT , player - > mo - > scale ) ) ;
2016-10-27 22:14:22 +00:00
glidesector = R_IsPointInSubsector ( player - > mo - > x + platx , player - > mo - > y + platy ) ;
2014-03-15 16:59:03 +00:00
{
2016-08-13 13:16:06 +00:00
boolean floorclimb = false ;
boolean thrust = false ;
boolean boostup = false ;
boolean skyclimber = false ;
2015-10-10 16:57:35 +00:00
fixed_t floorheight , ceilingheight ; // ESLOPE
2014-03-15 16:59:03 +00:00
2016-10-27 22:14:22 +00:00
if ( ! glidesector )
2016-08-13 13:16:06 +00:00
floorclimb = true ;
else
2016-06-20 00:50:47 +00:00
{
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
2016-06-20 00:50:47 +00:00
floorheight = glidesector - > sector - > f_slope ? P_GetZAt ( glidesector - > sector - > f_slope , player - > mo - > x , player - > mo - > y )
: glidesector - > sector - > floorheight ;
ceilingheight = glidesector - > sector - > c_slope ? P_GetZAt ( glidesector - > sector - > c_slope , player - > mo - > x , player - > mo - > y )
: glidesector - > sector - > ceilingheight ;
2015-05-21 00:08:49 +00:00
# else
2016-06-20 00:50:47 +00:00
floorheight = glidesector - > sector - > floorheight ;
ceilingheight = glidesector - > sector - > ceilingheight ;
2015-05-21 00:08:49 +00:00
# endif
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
if ( glidesector - > sector - > ffloors )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
ffloor_t * rover ;
fixed_t topheight , bottomheight ; // ESLOPE
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
for ( rover = glidesector - > sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_BLOCKPLAYER ) | | ( rover - > flags & FF_BUSTUP ) )
continue ;
floorclimb = true ;
2014-03-15 16:59:03 +00:00
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
2016-06-20 00:50:47 +00:00
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) : * rover - > topheight ;
2016-10-31 22:14:34 +00:00
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , player - > mo - > x , player - > mo - > y ) : * rover - > bottomheight ;
2015-05-21 00:08:49 +00:00
# else
2016-06-20 00:50:47 +00:00
topheight = * rover - > topheight ;
2016-10-31 22:14:34 +00:00
bottomheight = * rover - > bottomheight ;
2015-05-21 00:08:49 +00:00
# endif
2016-06-20 00:50:47 +00:00
// Only supports rovers that are moving like an 'elevator', not just the top or bottom.
if ( rover - > master - > frontsector - > floorspeed & & rover - > master - > frontsector - > ceilspeed = = 42 )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
if ( ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & ( bottomheight < player - > mo - > z + player - > mo - > height )
& & ( topheight > = player - > mo - > z + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) ) )
| | ( ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & ( topheight > player - > mo - > z )
& & ( bottomheight < = player - > mo - > z + player - > mo - > height - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) ) ) )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
if ( cmd - > forwardmove ! = 0 )
player - > mo - > momz + = rover - > master - > frontsector - > floorspeed ;
else
{
player - > mo - > momz = rover - > master - > frontsector - > floorspeed ;
climb = false ;
}
2014-03-15 16:59:03 +00:00
}
}
2016-06-20 00:50:47 +00:00
// Gravity is flipped, so the comments are, too.
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
// Trying to climb down past the bottom of the FOF
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
{
2016-06-20 00:50:47 +00:00
fixed_t bottomheight2 ;
ffloor_t * roverbelow ;
boolean foundfof = false ;
floorclimb = true ;
boostup = false ;
// Is there a FOF directly below this one that we can move onto?
for ( roverbelow = glidesector - > sector - > ffloors ; roverbelow ; roverbelow = roverbelow - > next )
{
if ( ! ( roverbelow - > flags & FF_EXISTS ) | | ! ( roverbelow - > flags & FF_BLOCKPLAYER ) | | ( roverbelow - > flags & FF_BUSTUP ) )
continue ;
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
if ( roverbelow = = rover )
continue ;
2014-03-15 16:59:03 +00:00
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
2016-06-20 00:50:47 +00:00
bottomheight2 = * roverbelow - > b_slope ? P_GetZAt ( * roverbelow - > b_slope , player - > mo - > x , player - > mo - > y ) : * roverbelow - > bottomheight ;
2015-05-21 00:08:49 +00:00
# else
2016-06-20 00:50:47 +00:00
bottomheight2 = * roverbelow - > bottomheight ;
2015-05-21 00:08:49 +00:00
# endif
2016-06-20 00:50:47 +00:00
if ( bottomheight2 < topheight + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
foundfof = true ;
}
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
if ( ! foundfof )
player - > mo - > momz = 0 ;
}
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
// Below the FOF
if ( topheight < = player - > mo - > z )
{
floorclimb = false ;
boostup = false ;
thrust = false ;
}
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
// Above the FOF
if ( bottomheight > player - > mo - > z + player - > mo - > height - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
{
floorclimb = false ;
thrust = true ;
boostup = true ;
}
2014-03-15 16:59:03 +00:00
}
2016-06-20 00:50:47 +00:00
else
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
// Trying to climb down past the bottom of a FOF
if ( ( bottomheight < = player - > mo - > z ) & & ( ( player - > mo - > z + player - > mo - > momz ) < = bottomheight ) )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
fixed_t topheight2 ;
ffloor_t * roverbelow ;
boolean foundfof = false ;
floorclimb = true ;
boostup = false ;
// Is there a FOF directly below this one that we can move onto?
for ( roverbelow = glidesector - > sector - > ffloors ; roverbelow ; roverbelow = roverbelow - > next )
{
if ( ! ( roverbelow - > flags & FF_EXISTS ) | | ! ( roverbelow - > flags & FF_BLOCKPLAYER ) | | ( roverbelow - > flags & FF_BUSTUP ) )
continue ;
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
if ( roverbelow = = rover )
continue ;
2014-03-15 16:59:03 +00:00
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
2016-06-20 00:50:47 +00:00
topheight2 = * roverbelow - > t_slope ? P_GetZAt ( * roverbelow - > t_slope , player - > mo - > x , player - > mo - > y ) : * roverbelow - > topheight ;
2015-05-21 00:08:49 +00:00
# else
2016-06-20 00:50:47 +00:00
topheight2 = * roverbelow - > topheight ;
2015-05-21 00:08:49 +00:00
# endif
2016-06-20 00:50:47 +00:00
if ( topheight2 > bottomheight - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
foundfof = true ;
}
if ( ! foundfof )
player - > mo - > momz = 0 ;
2014-03-15 16:59:03 +00:00
}
2016-06-20 00:50:47 +00:00
// Below the FOF
if ( bottomheight > = player - > mo - > z + player - > mo - > height )
{
floorclimb = false ;
boostup = false ;
thrust = false ;
}
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
// Above the FOF
if ( topheight < player - > mo - > z + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
{
floorclimb = false ;
thrust = true ;
boostup = true ;
}
2014-03-15 16:59:03 +00:00
}
2016-06-20 00:50:47 +00:00
if ( floorclimb )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
if ( rover - > flags & FF_CRUMBLE & & ! ( netgame & & player - > spectator ) )
EV_StartCrumble ( rover - > master - > frontsector , rover , ( rover - > flags & FF_FLOATBOB ) , player , rover - > alpha , ! ( rover - > flags & FF_NORETURN ) ) ;
break ;
2014-03-15 16:59:03 +00:00
}
}
}
2016-06-20 00:50:47 +00:00
// Gravity is flipped, so are comments.
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
// Trying to climb down past the upper texture area
if ( ( floorheight > = player - > mo - > z + player - > mo - > height ) & & ( ( player - > mo - > z + player - > mo - > height + player - > mo - > momz ) > = floorheight ) )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
boolean foundfof = false ;
floorclimb = true ;
// Is there a FOF directly below that we can move onto?
if ( glidesector - > sector - > ffloors )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
fixed_t bottomheight ;
ffloor_t * rover ;
for ( rover = glidesector - > sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_BLOCKPLAYER ) | | ( rover - > flags & FF_BUSTUP ) )
continue ;
2014-03-15 16:59:03 +00:00
2015-05-21 00:08:49 +00:00
# ifdef ESLOPE
2016-06-20 00:50:47 +00:00
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , player - > mo - > x , player - > mo - > y ) : * rover - > bottomheight ;
2015-05-21 00:08:49 +00:00
# else
2016-06-20 00:50:47 +00:00
bottomheight = * rover - > bottomheight ;
2015-05-21 00:08:49 +00:00
# endif
2016-06-20 00:50:47 +00:00
if ( bottomheight < floorheight + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
{
foundfof = true ;
break ;
}
2014-03-15 16:59:03 +00:00
}
}
2016-06-20 00:50:47 +00:00
if ( ! foundfof )
player - > mo - > momz = 0 ;
}
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
// Reached the top of the lower texture area
if ( ! floorclimb & & ceilingheight > player - > mo - > z + player - > mo - > height - FixedMul ( 16 * FRACUNIT , player - > mo - > scale )
& & ( glidesector - > sector - > ceilingpic = = skyflatnum | | floorheight < ( player - > mo - > z - FixedMul ( 8 * FRACUNIT , player - > mo - > scale ) ) ) )
{
thrust = true ;
boostup = true ;
// Play climb-up animation here
}
2014-03-15 16:59:03 +00:00
}
2016-06-20 00:50:47 +00:00
else
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
// Trying to climb down past the upper texture area
if ( ( ceilingheight < = player - > mo - > z ) & & ( ( player - > mo - > z + player - > mo - > momz ) < = ceilingheight ) )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
boolean foundfof = false ;
floorclimb = true ;
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
// Is there a FOF directly below that we can move onto?
if ( glidesector - > sector - > ffloors )
{
2016-10-31 22:14:34 +00:00
fixed_t topheight ;
2016-06-20 00:50:47 +00:00
ffloor_t * rover ;
for ( rover = glidesector - > sector - > ffloors ; rover ; rover = rover - > next )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_BLOCKPLAYER ) | | ( rover - > flags & FF_BUSTUP ) )
continue ;
2016-10-31 22:14:34 +00:00
# ifdef ESLOPE
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) : * rover - > topheight ;
# else
topheight = * rover - > topheight ;
# endif
if ( topheight > ceilingheight - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
2016-06-20 00:50:47 +00:00
{
foundfof = true ;
break ;
}
2014-03-15 16:59:03 +00:00
}
}
2016-06-20 00:50:47 +00:00
if ( ! foundfof )
player - > mo - > momz = 0 ;
2014-03-15 16:59:03 +00:00
}
2016-06-20 00:50:47 +00:00
// Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
if ( player - > mo - > z > ceilingheight - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) )
{
floorclimb = true ;
thrust = false ;
boostup = false ;
}
2014-03-15 16:59:03 +00:00
2016-06-20 00:50:47 +00:00
// Reached the top of the lower texture area
if ( ! floorclimb & & floorheight < player - > mo - > z + FixedMul ( 16 * FRACUNIT , player - > mo - > scale )
& & ( glidesector - > sector - > ceilingpic = = skyflatnum | | ceilingheight > ( player - > mo - > z + player - > mo - > height + FixedMul ( 8 * FRACUNIT , player - > mo - > scale ) ) ) )
{
thrust = true ;
boostup = true ;
// Play climb-up animation here
}
2014-03-15 16:59:03 +00:00
}
2016-06-20 00:50:47 +00:00
// Trying to climb on the sky
if ( ( ceilingheight < player - > mo - > z ) & & glidesector - > sector - > ceilingpic = = skyflatnum )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
skyclimber = true ;
2014-03-15 16:59:03 +00:00
}
2016-06-20 00:50:47 +00:00
// Climbing on the lower texture area?
if ( ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & player - > mo - > z + FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) < floorheight )
| | ( ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & player - > mo - > z + player - > mo - > height < = floorheight ) )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
floorclimb = true ;
if ( glidesector - > sector - > floorspeed )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
if ( cmd - > forwardmove ! = 0 )
player - > mo - > momz + = glidesector - > sector - > floorspeed ;
else
{
player - > mo - > momz = glidesector - > sector - > floorspeed ;
climb = false ;
}
2014-03-15 16:59:03 +00:00
}
}
2016-06-20 00:50:47 +00:00
// Climbing on the upper texture area?
else if ( ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & player - > mo - > z > = ceilingheight )
| | ( ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & player - > mo - > z + player - > mo - > height - FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) > ceilingheight ) )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
floorclimb = true ;
if ( glidesector - > sector - > ceilspeed )
2014-03-15 16:59:03 +00:00
{
2016-06-20 00:50:47 +00:00
if ( cmd - > forwardmove ! = 0 )
player - > mo - > momz + = glidesector - > sector - > ceilspeed ;
else
{
player - > mo - > momz = glidesector - > sector - > ceilspeed ;
climb = false ;
}
2014-03-15 16:59:03 +00:00
}
}
}
if ( player - > lastsidehit ! = - 1 & & player - > lastlinehit ! = - 1 )
{
thinker_t * think ;
scroll_t * scroller ;
angle_t sideangle ;
2015-01-01 19:50:31 +00:00
fixed_t dx , dy ;
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
{
if ( think - > function . acp1 ! = ( actionf_p1 ) T_Scroll )
continue ;
scroller = ( scroll_t * ) think ;
if ( scroller - > type ! = sc_side )
continue ;
if ( scroller - > affectee ! = player - > lastsidehit )
continue ;
2015-01-01 19:50:31 +00:00
if ( scroller - > accel )
{
dx = scroller - > vdx ;
dy = scroller - > vdy ;
}
else
{
dx = scroller - > dx ;
dy = scroller - > dy ;
}
2014-03-15 16:59:03 +00:00
if ( cmd - > forwardmove ! = 0 )
{
2015-01-01 19:50:31 +00:00
player - > mo - > momz + = dy ;
2014-03-15 16:59:03 +00:00
climb = true ;
}
else
{
2015-01-01 19:50:31 +00:00
player - > mo - > momz = dy ;
2014-03-15 16:59:03 +00:00
climb = false ;
}
sideangle = R_PointToAngle2 ( lines [ player - > lastlinehit ] . v2 - > x , lines [ player - > lastlinehit ] . v2 - > y , lines [ player - > lastlinehit ] . v1 - > x , lines [ player - > lastlinehit ] . v1 - > y ) ;
if ( cmd - > sidemove ! = 0 )
{
2015-01-01 19:50:31 +00:00
P_Thrust ( player - > mo , sideangle , dx ) ;
2014-03-15 16:59:03 +00:00
climb = true ;
}
else
{
2015-01-01 19:50:31 +00:00
P_InstaThrust ( player - > mo , sideangle , dx ) ;
2014-03-15 16:59:03 +00:00
climb = false ;
}
}
}
if ( cmd - > sidemove ! = 0 | | cmd - > forwardmove ! = 0 )
climb = true ;
else
climb = false ;
if ( player - > climbing & & climb & & ( player - > mo - > momx | | player - > mo - > momy | | player - > mo - > momz )
2015-01-22 15:23:45 +00:00
& & player - > mo - > state - states ! = S_PLAY_CLIMB )
P_SetPlayerMobjState ( player - > mo , S_PLAY_CLIMB ) ;
else if ( ( ! ( player - > mo - > momx | | player - > mo - > momy | | player - > mo - > momz ) | | ! climb ) & & player - > mo - > state - states ! = S_PLAY_CLING )
P_SetPlayerMobjState ( player - > mo , S_PLAY_CLING ) ;
2014-03-15 16:59:03 +00:00
if ( ! floorclimb )
{
if ( boostup )
2019-09-30 02:55:57 +00:00
{
2014-03-15 16:59:03 +00:00
P_SetObjectMomZ ( player - > mo , 2 * FRACUNIT , true ) ;
2019-09-30 02:55:57 +00:00
if ( cmd - > forwardmove )
2019-11-24 11:30:20 +00:00
player - > mo - > momz = 2 * player - > mo - > momz / 3 ;
2019-09-30 02:55:57 +00:00
}
2014-03-15 16:59:03 +00:00
if ( thrust )
2019-09-30 02:55:57 +00:00
P_Thrust ( player - > mo , player - > mo - > angle , FixedMul ( 4 * FRACUNIT , player - > mo - > scale ) ) ; // Lil' boost up.
2014-03-15 16:59:03 +00:00
player - > climbing = 0 ;
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-01-14 14:35:10 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-03-15 16:59:03 +00:00
}
if ( skyclimber )
{
player - > climbing = 0 ;
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-01-14 14:35:10 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-03-15 16:59:03 +00:00
}
}
if ( cmd - > sidemove ! = 0 | | cmd - > forwardmove ! = 0 )
climb = true ;
else
climb = false ;
if ( player - > climbing & & climb & & ( player - > mo - > momx | | player - > mo - > momy | | player - > mo - > momz )
2015-01-22 15:23:45 +00:00
& & player - > mo - > state - states ! = S_PLAY_CLIMB )
P_SetPlayerMobjState ( player - > mo , S_PLAY_CLIMB ) ;
else if ( ( ! ( player - > mo - > momx | | player - > mo - > momy | | player - > mo - > momz ) | | ! climb ) & & player - > mo - > state - states ! = S_PLAY_CLING )
P_SetPlayerMobjState ( player - > mo , S_PLAY_CLING ) ;
2014-03-15 16:59:03 +00:00
if ( cmd - > buttons & BT_USE & & ! ( player - > pflags & PF_JUMPSTASIS ) )
{
player - > climbing = 0 ;
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-01-14 14:35:10 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-03-15 16:59:03 +00:00
P_SetObjectMomZ ( player - > mo , 4 * FRACUNIT , false ) ;
2019-09-30 02:55:57 +00:00
P_Thrust ( player - > mo , player - > mo - > angle , FixedMul ( - 4 * FRACUNIT , player - > mo - > scale ) ) ;
2014-03-15 16:59:03 +00:00
}
2019-10-14 17:19:58 +00:00
# define CLIMBCONEMAX FixedAngle(90*FRACUNIT)
2016-04-05 19:56:48 +00:00
if ( ! demoplayback | | P_AnalogMove ( player ) )
{
if ( player = = & players [ consoleplayer ] )
2019-10-14 17:19:58 +00:00
{
angle_t angdiff = localangle - player - > mo - > angle ;
if ( angdiff < ANGLE_180 & & angdiff > CLIMBCONEMAX )
localangle = player - > mo - > angle + CLIMBCONEMAX ;
else if ( angdiff > ANGLE_180 & & angdiff < InvAngle ( CLIMBCONEMAX ) )
localangle = player - > mo - > angle - CLIMBCONEMAX ;
}
2016-04-05 19:56:48 +00:00
else if ( player = = & players [ secondarydisplayplayer ] )
2019-10-14 17:19:58 +00:00
{
angle_t angdiff = localangle2 - player - > mo - > angle ;
if ( angdiff < ANGLE_180 & & angdiff > CLIMBCONEMAX )
localangle2 = player - > mo - > angle + CLIMBCONEMAX ;
else if ( angdiff > ANGLE_180 & & angdiff < InvAngle ( CLIMBCONEMAX ) )
localangle2 = player - > mo - > angle - CLIMBCONEMAX ;
}
2016-04-05 19:56:48 +00:00
}
2014-03-15 16:59:03 +00:00
if ( player - > climbing = = 0 )
2016-01-14 14:35:10 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-03-15 16:59:03 +00:00
if ( player - > climbing & & P_IsObjectOnGround ( player - > mo ) )
{
P_ResetPlayer ( player ) ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
}
2015-01-01 19:50:31 +00:00
//
// PIT_CheckSolidsTeeter
// AKA: PIT_HacksToStopPlayersTeeteringOnGargoyles
//
static mobj_t * teeterer ; // the player checking for teetering
static boolean solidteeter ; // saves whether the player can teeter on this or not
static fixed_t highesttop ; // highest floor found so far
// reserved for standing on multiple objects
static boolean couldteeter ;
static fixed_t teeterxl , teeterxh ;
static fixed_t teeteryl , teeteryh ;
static boolean PIT_CheckSolidsTeeter ( mobj_t * thing )
{
fixed_t blockdist ;
fixed_t tiptop = FixedMul ( MAXSTEPMOVE , teeterer - > scale ) ;
fixed_t thingtop = thing - > z + thing - > height ;
fixed_t teeterertop = teeterer - > z + teeterer - > height ;
if ( ! teeterer | | ! thing )
return true ;
if ( ! ( thing - > flags & MF_SOLID ) )
return true ;
if ( thing - > flags & MF_NOCLIP )
return true ;
if ( thing = = teeterer )
return true ;
if ( thing - > player & & cv_tailspickup . value & & gametype ! = GT_HIDEANDSEEK )
return true ;
blockdist = teeterer - > radius + thing - > radius ;
if ( abs ( thing - > x - teeterer - > x ) > = blockdist | | abs ( thing - > y - teeterer - > y ) > = blockdist )
return true ; // didn't hit it
if ( teeterer - > eflags & MFE_VERTICALFLIP )
{
if ( thingtop < teeterer - > z )
return true ;
if ( thing - > z > highesttop )
return true ;
highesttop = thing - > z ;
if ( thing - > z > teeterertop + tiptop )
{
solidteeter = true ;
return true ;
}
}
else
{
if ( thing - > z > teeterertop )
return true ;
if ( thingtop < highesttop )
return true ;
highesttop = thingtop ;
if ( thingtop < teeterer - > z - tiptop )
{
solidteeter = true ;
return true ;
}
}
// are you standing on this?
if ( ( teeterer - > eflags & MFE_VERTICALFLIP & & thing - > z - FixedMul ( FRACUNIT , teeterer - > scale ) = = teeterertop )
| | ( ! ( teeterer - > eflags & MFE_VERTICALFLIP ) & & thingtop + FixedMul ( FRACUNIT , teeterer - > scale ) = = teeterer - > z ) )
{
fixed_t teeterdist = thing - > radius - FixedMul ( 5 * FRACUNIT , teeterer - > scale ) ;
// how far are you from the edge?
if ( abs ( teeterer - > x - thing - > x ) > teeterdist | | abs ( teeterer - > y - thing - > y ) > teeterdist )
{
if ( couldteeter ) // player is standing on another object already, see if we can stand on both and not teeter!
{
if ( thing - > x - teeterdist < teeterxl )
teeterxl = thing - > x - teeterdist ;
if ( thing - > x + teeterdist > teeterxh )
teeterxh = thing - > x + teeterdist ;
if ( thing - > y - teeterdist < teeteryl )
teeteryl = thing - > y - teeterdist ;
if ( thing - > y + teeterdist > teeteryh )
teeteryh = thing - > y + teeterdist ;
if ( teeterer - > x < teeterxl )
return true ;
if ( teeterer - > x > teeterxh )
return true ;
if ( teeterer - > y < teeteryl )
return true ;
if ( teeterer - > y > teeteryh )
return true ;
solidteeter = false ; // you can stop teetering now!
couldteeter = false ; // just in case...
return false ;
}
else
{
// too far! don't change teeter status though
// save teeter x/y limits to bring up later
teeterxl = thing - > x - teeterdist ;
teeterxh = thing - > x + teeterdist ;
teeteryl = thing - > y - teeterdist ;
teeteryh = thing - > y + teeterdist ;
}
couldteeter = true ;
return true ;
}
solidteeter = false ;
couldteeter = false ;
return false ; // you're definitely not teetering, that's the end of the matter
}
solidteeter = false ;
return true ; // you're not teetering but it's not neccessarily over, YET
}
2014-03-15 16:59:03 +00:00
//
// P_DoTeeter
//
// Handles player teetering
//
static void P_DoTeeter ( player_t * player )
{
boolean teeter = false ;
boolean roverfloor ; // solid 3d floors?
2016-06-07 16:37:25 +00:00
fixed_t floorheight , ceilingheight ;
fixed_t topheight , bottomheight ; // for 3d floor usage
2014-03-15 16:59:03 +00:00
const fixed_t tiptop = FixedMul ( MAXSTEPMOVE , player - > mo - > scale ) ; // Distance you have to be above the ground in order to teeter.
2016-06-19 15:59:49 +00:00
if ( player - > mo - > standingslope & & player - > mo - > standingslope - > zdelta > = ( FRACUNIT / 2 ) ) // Always teeter if the slope is too steep.
2016-06-07 16:37:25 +00:00
teeter = true ;
else // Let's do some checks...
2014-03-15 16:59:03 +00:00
{
UINT8 i ;
2016-06-19 15:59:49 +00:00
sector_t * sec ;
2016-06-19 15:38:11 +00:00
fixed_t highestceilingheight = INT32_MIN ;
fixed_t lowestfloorheight = INT32_MAX ;
2014-03-15 16:59:03 +00:00
teeter = false ;
roverfloor = false ;
for ( i = 0 ; i < 4 ; i + + )
{
ffloor_t * rover ;
2016-06-07 16:37:25 +00:00
# define xsign ((i & 1) ? -1 : 1) // 0 -> 1 | 1 -> -1 | 2 -> 1 | 3 -> -1
# define ysign ((i & 2) ? 1 : -1) // 0 -> 1 | 1 -> 1 | 2 -> -1 | 3 -> -1
fixed_t checkx = player - > mo - > x + ( xsign * FixedMul ( 5 * FRACUNIT , player - > mo - > scale ) ) ;
fixed_t checky = player - > mo - > y + ( ysign * FixedMul ( 5 * FRACUNIT , player - > mo - > scale ) ) ;
2016-06-09 14:20:45 +00:00
# undef xsign
# undef ysign
2016-06-07 16:37:25 +00:00
2016-06-07 16:55:03 +00:00
sec = R_PointInSubsector ( checkx , checky ) - > sector ;
2016-06-07 16:37:25 +00:00
2016-06-07 18:44:43 +00:00
ceilingheight = sec - > ceilingheight ;
floorheight = sec - > floorheight ;
2016-06-07 16:37:25 +00:00
# ifdef ESLOPE
2016-06-07 16:55:03 +00:00
if ( sec - > c_slope )
2016-06-07 17:18:47 +00:00
ceilingheight = P_GetZAt ( sec - > c_slope , checkx , checky ) ;
2016-06-07 16:55:03 +00:00
if ( sec - > f_slope )
2016-06-07 17:18:47 +00:00
floorheight = P_GetZAt ( sec - > f_slope , checkx , checky ) ;
2016-06-07 16:37:25 +00:00
# endif
2016-06-07 17:18:47 +00:00
highestceilingheight = ( ceilingheight > highestceilingheight ) ? ceilingheight : highestceilingheight ;
lowestfloorheight = ( floorheight < lowestfloorheight ) ? floorheight : lowestfloorheight ;
2016-06-07 16:37:25 +00:00
2016-06-07 16:55:03 +00:00
if ( ! ( sec - > ffloors ) )
2014-03-15 16:59:03 +00:00
continue ; // move on to the next subsector
2016-06-07 16:55:03 +00:00
for ( rover = sec - > ffloors ; rover ; rover = rover - > next )
2014-03-15 16:59:03 +00:00
{
if ( ! ( rover - > flags & FF_EXISTS ) ) continue ;
2016-10-31 22:14:34 +00:00
# ifdef ESLOPE
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) : * rover - > topheight ;
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , player - > mo - > x , player - > mo - > y ) : * rover - > bottomheight ;
# else
2016-06-07 16:37:25 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# endif
2019-10-01 19:58:18 +00:00
if ( P_CheckSolidLava ( rover ) )
2014-03-15 16:59:03 +00:00
;
else if ( ! ( rover - > flags & FF_BLOCKPLAYER | | rover - > flags & FF_QUICKSAND ) )
continue ; // intangible 3d floor
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
2016-06-07 17:18:47 +00:00
if ( bottomheight > ceilingheight ) // Above the ceiling
2014-03-15 16:59:03 +00:00
continue ;
2016-06-07 16:37:25 +00:00
if ( bottomheight > player - > mo - > z + player - > mo - > height + tiptop
| | ( topheight < player - > mo - > z
2016-06-07 17:18:47 +00:00
& & player - > mo - > z + player - > mo - > height < ceilingheight - tiptop ) )
2014-03-15 16:59:03 +00:00
{
teeter = true ;
roverfloor = true ;
}
else
{
teeter = false ;
roverfloor = true ;
break ;
}
}
else
{
2016-06-07 17:18:47 +00:00
if ( topheight < floorheight ) // Below the floor
2014-03-15 16:59:03 +00:00
continue ;
2016-06-07 16:37:25 +00:00
if ( topheight < player - > mo - > z - tiptop
| | ( bottomheight > player - > mo - > z + player - > mo - > height
2016-06-07 17:18:47 +00:00
& & player - > mo - > z > floorheight + tiptop ) )
2014-03-15 16:59:03 +00:00
{
teeter = true ;
roverfloor = true ;
}
else
{
teeter = false ;
roverfloor = true ;
break ;
}
}
}
break ; // break out of loop now, we're done
}
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
2016-06-07 17:18:47 +00:00
if ( ! teeter & & ! roverfloor & & ( highestceilingheight > player - > mo - > ceilingz + tiptop ) )
2014-03-15 16:59:03 +00:00
teeter = true ;
}
else
{
2016-06-07 17:18:47 +00:00
if ( ! teeter & & ! roverfloor & & ( lowestfloorheight < player - > mo - > floorz - tiptop ) )
2014-03-15 16:59:03 +00:00
teeter = true ;
}
}
{
INT32 bx , by , xl , xh , yl , yh ;
2015-04-09 01:50:49 +00:00
yh = ( unsigned ) ( player - > mo - > y + player - > mo - > radius - bmaporgy ) > > MAPBLOCKSHIFT ;
yl = ( unsigned ) ( player - > mo - > y - player - > mo - > radius - bmaporgy ) > > MAPBLOCKSHIFT ;
xh = ( unsigned ) ( player - > mo - > x + player - > mo - > radius - bmaporgx ) > > MAPBLOCKSHIFT ;
xl = ( unsigned ) ( player - > mo - > x - player - > mo - > radius - bmaporgx ) > > MAPBLOCKSHIFT ;
2014-03-15 16:59:03 +00:00
2015-04-09 02:32:07 +00:00
BMBOUNDFIX ( xl , xh , yl , yh ) ;
2015-01-01 19:50:31 +00:00
// Polyobjects
# ifdef POLYOBJECTS
validcount + + ;
2014-03-15 16:59:03 +00:00
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 polytop , polybottom ;
po - > validcount = validcount ;
if ( ! ( po - > flags & POF_SOLID ) )
{
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
continue ;
}
if ( ! P_MobjInsidePolyobj ( po , player - > mo ) )
{
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 ;
}
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
if ( polybottom > player - > mo - > ceilingz ) // Above the ceiling
{
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
continue ;
}
if ( polybottom > player - > mo - > z + player - > mo - > height + tiptop
2016-02-28 18:30:29 +00:00
| | ( polytop < player - > mo - > z
2015-01-01 19:50:31 +00:00
& & player - > mo - > z + player - > mo - > height < player - > mo - > ceilingz - tiptop ) )
2014-03-15 16:59:03 +00:00
teeter = true ;
else
{
teeter = false ;
break ;
}
}
else
{
if ( polytop < player - > mo - > floorz ) // Below the floor
{
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
continue ;
}
if ( polytop < player - > mo - > z - tiptop
2016-02-28 18:30:29 +00:00
| | ( polybottom > player - > mo - > z + player - > mo - > height
2015-01-01 19:50:31 +00:00
& & player - > mo - > z > player - > mo - > floorz + tiptop ) )
2014-03-15 16:59:03 +00:00
teeter = true ;
else
{
teeter = false ;
break ;
}
}
}
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
}
}
# endif
2015-01-01 19:50:31 +00:00
if ( teeter ) // only bother with objects as a last resort if you were already teetering
{
mobj_t * oldtmthing = tmthing ;
2019-07-13 12:43:22 +00:00
teeterer = player - > mo ;
P_SetTarget ( & tmthing , teeterer ) ;
2015-01-01 19:50:31 +00:00
teeterxl = teeterxh = player - > mo - > x ;
teeteryl = teeteryh = player - > mo - > y ;
couldteeter = false ;
solidteeter = teeter ;
for ( by = yl ; by < = yh ; by + + )
for ( bx = xl ; bx < = xh ; bx + + )
{
highesttop = INT32_MIN ;
if ( ! P_BlockThingsIterator ( bx , by , PIT_CheckSolidsTeeter ) )
goto teeterdone ; // we've found something that stops us teetering at all, how about we stop already
}
teeterdone :
teeter = solidteeter ;
2019-07-13 12:43:22 +00:00
P_SetTarget ( & tmthing , oldtmthing ) ; // restore old tmthing, goodness knows what the game does with this before mobj thinkers
2015-01-01 19:50:31 +00:00
}
}
2014-03-15 16:59:03 +00:00
if ( teeter )
{
2015-06-18 15:36:08 +00:00
if ( player - > panim = = PA_IDLE )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_EDGE ) ;
2014-03-15 16:59:03 +00:00
}
2016-07-11 19:49:34 +00:00
else if ( player - > panim = = PA_EDGE )
2014-03-15 16:59:03 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
//
// P_SetWeaponDelay
//
// Sets weapon delay. Properly accounts for Knux's firing rate bonus.
//
static void P_SetWeaponDelay ( player_t * player , INT32 delay )
{
player - > weapondelay = delay ;
if ( player - > skin = = 2 ) // Knuckles
{
// Multiply before dividing.
// Loss of precision can make a surprisingly large difference.
player - > weapondelay * = 2 ;
player - > weapondelay / = 3 ;
}
}
2019-08-26 23:07:17 +00:00
//
// P_DrainWeaponAmmo
//
// Reduces rings and weapon ammo. Also penalizes the player
// for using weapon rings with no normal rings! >:V
//
static void P_DrainWeaponAmmo ( player_t * player , INT32 power )
{
player - > powers [ power ] - - ;
if ( player - > rings < 1 )
{
player - > ammoremovalweapon = player - > currentweapon ;
player - > ammoremovaltimer = ammoremovaltics ;
if ( player - > powers [ power ] > 0 ) // can't take a ring that doesn't exist
{
player - > powers [ power ] - - ;
player - > ammoremoval = 2 ;
}
else
player - > ammoremoval = 1 ;
}
else
player - > rings - - ;
}
2014-03-15 16:59:03 +00:00
//
// P_DoFiring()
//
// Handles firing ring weapons and Mario fireballs.
//
static void P_DoFiring ( player_t * player , ticcmd_t * cmd )
{
INT32 i ;
2018-06-06 13:42:50 +00:00
mobj_t * mo = NULL ;
2014-03-15 16:59:03 +00:00
I_Assert ( player ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( player - > mo ) ) ;
2018-06-06 13:42:50 +00:00
if ( ! ( cmd - > buttons & ( BT_ATTACK | BT_FIRENORMAL ) ) )
2014-03-15 16:59:03 +00:00
{
2018-06-06 13:42:50 +00:00
// Not holding any firing buttons anymore.
// Release the grenade / whatever.
player - > pflags & = ~ PF_ATTACKDOWN ;
return ;
}
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
if ( player - > pflags & PF_ATTACKDOWN | | player - > climbing | | ( G_TagGametype ( ) & & ! ( player - > pflags & PF_TAGIT ) ) )
return ;
2015-05-27 05:13:26 +00:00
2019-11-18 00:25:17 +00:00
if ( ( ( player - > powers [ pw_shield ] & SH_STACK ) = = SH_FIREFLOWER ) & & ! ( player - > weapondelay ) )
2018-06-06 13:42:50 +00:00
{
player - > pflags | = PF_ATTACKDOWN ;
mo = P_SpawnPlayerMissile ( player - > mo , MT_FIREBALL , 0 ) ;
2019-11-19 11:53:45 +00:00
if ( mo )
P_InstaThrust ( mo , player - > mo - > angle , ( ( mo - > info - > speed > > FRACBITS ) * player - > mo - > scale ) + player - > speed ) ;
2018-06-06 13:42:50 +00:00
S_StartSound ( player - > mo , sfx_mario7 ) ;
2019-11-18 00:25:17 +00:00
P_SetWeaponDelay ( player , TICRATE ) ; // Short delay between fireballs so you can't spam them everywhere
2018-06-06 13:42:50 +00:00
return ;
}
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
if ( ! G_RingSlingerGametype ( ) | | player - > weapondelay )
return ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
player - > pflags | = PF_ATTACKDOWN ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
if ( cmd - > buttons & BT_FIRENORMAL ) // No powers, just a regular ring.
goto firenormal ; //code repetition sucks.
// Bounce ring
else if ( player - > currentweapon = = WEP_BOUNCE & & player - > powers [ pw_bouncering ] )
{
2019-08-26 23:07:17 +00:00
P_DrainWeaponAmmo ( player , pw_bouncering ) ;
2018-06-06 13:42:50 +00:00
P_SetWeaponDelay ( player , TICRATE / 4 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
mo = P_SpawnPlayerMissile ( player - > mo , MT_THROWNBOUNCE , MF2_BOUNCERING ) ;
2014-03-15 16:59:03 +00:00
2019-11-19 11:53:45 +00:00
if ( mo )
mo - > fuse = 3 * TICRATE ; // Bounce Ring time
2018-06-06 13:42:50 +00:00
}
// Rail ring
else if ( player - > currentweapon = = WEP_RAIL & & player - > powers [ pw_railring ] )
{
2019-08-26 23:07:17 +00:00
P_DrainWeaponAmmo ( player , pw_railring ) ;
2018-06-06 13:42:50 +00:00
P_SetWeaponDelay ( player , ( 3 * TICRATE ) / 2 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
mo = P_SpawnPlayerMissile ( player - > mo , MT_REDRING , MF2_RAILRING | MF2_DONTDRAW ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
// Rail has no unique thrown object, therefore its sound plays here.
S_StartSound ( player - > mo , sfx_rail1 ) ;
}
// Automatic
else if ( player - > currentweapon = = WEP_AUTO & & player - > powers [ pw_automaticring ] )
{
2019-08-26 23:07:17 +00:00
P_DrainWeaponAmmo ( player , pw_automaticring ) ;
2018-06-06 13:42:50 +00:00
player - > pflags & = ~ PF_ATTACKDOWN ;
P_SetWeaponDelay ( player , 2 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
mo = P_SpawnPlayerMissile ( player - > mo , MT_THROWNAUTOMATIC , MF2_AUTOMATIC ) ;
}
// Explosion
else if ( player - > currentweapon = = WEP_EXPLODE & & player - > powers [ pw_explosionring ] )
{
2019-08-26 23:07:17 +00:00
P_DrainWeaponAmmo ( player , pw_explosionring ) ;
2018-06-06 13:42:50 +00:00
P_SetWeaponDelay ( player , ( 3 * TICRATE ) / 2 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
mo = P_SpawnPlayerMissile ( player - > mo , MT_THROWNEXPLOSION , MF2_EXPLOSION ) ;
}
// Grenade
else if ( player - > currentweapon = = WEP_GRENADE & & player - > powers [ pw_grenadering ] )
{
2019-08-26 23:07:17 +00:00
P_DrainWeaponAmmo ( player , pw_grenadering ) ;
2018-06-06 13:42:50 +00:00
P_SetWeaponDelay ( player , TICRATE / 3 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
mo = P_SpawnPlayerMissile ( player - > mo , MT_THROWNGRENADE , MF2_EXPLOSION ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
if ( mo )
{
//P_InstaThrust(mo, player->mo->angle, FixedMul(mo->info->speed, player->mo->scale));
mo - > fuse = mo - > info - > reactiontime ;
}
}
// Scatter
// Note: Ignores MF2_RAILRING
else if ( player - > currentweapon = = WEP_SCATTER & & player - > powers [ pw_scatterring ] )
{
fixed_t oldz = player - > mo - > z ;
angle_t shotangle = player - > mo - > angle ;
angle_t oldaiming = player - > aiming ;
2014-03-15 16:59:03 +00:00
2019-08-26 23:07:17 +00:00
P_DrainWeaponAmmo ( player , pw_scatterring ) ;
2018-06-06 13:42:50 +00:00
P_SetWeaponDelay ( player , ( 2 * TICRATE ) / 3 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
// Center
mo = P_SpawnPlayerMissile ( player - > mo , MT_THROWNSCATTER , MF2_SCATTER ) ;
if ( mo )
shotangle = R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , mo - > x , mo - > y ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
// Left
mo = P_SPMAngle ( player - > mo , MT_THROWNSCATTER , shotangle - ANG2 , true , MF2_SCATTER ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
// Right
mo = P_SPMAngle ( player - > mo , MT_THROWNSCATTER , shotangle + ANG2 , true , MF2_SCATTER ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
// Down
player - > mo - > z + = FixedMul ( 12 * FRACUNIT , player - > mo - > scale ) ;
player - > aiming + = ANG1 ;
mo = P_SPMAngle ( player - > mo , MT_THROWNSCATTER , shotangle , true , MF2_SCATTER ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
// Up
player - > mo - > z - = FixedMul ( 24 * FRACUNIT , player - > mo - > scale ) ;
player - > aiming - = ANG2 ;
mo = P_SPMAngle ( player - > mo , MT_THROWNSCATTER , shotangle , true , MF2_SCATTER ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
player - > mo - > z = oldz ;
player - > aiming = oldaiming ;
return ;
}
// No powers, just a regular ring.
else
{
2014-03-15 16:59:03 +00:00
firenormal :
2018-06-06 13:42:50 +00:00
// Infinity ring was selected.
// Mystic wants this ONLY to happen specifically if it's selected,
// and to not be able to get around it EITHER WAY with firenormal.
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
// Infinity Ring
if ( player - > currentweapon = = 0
& & player - > powers [ pw_infinityring ] )
{
P_SetWeaponDelay ( player , TICRATE / 4 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
mo = P_SpawnPlayerMissile ( player - > mo , MT_THROWNINFINITY , 0 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
player - > powers [ pw_infinityring ] - - ;
}
// Red Ring
else
{
if ( player - > rings < = 0 )
return ;
P_SetWeaponDelay ( player , TICRATE / 4 ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
mo = P_SpawnPlayerMissile ( player - > mo , MT_REDRING , 0 ) ;
2014-03-15 16:59:03 +00:00
if ( mo )
2018-06-06 13:42:50 +00:00
P_ColorTeamMissile ( mo , player ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
player - > rings - - ;
}
}
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
if ( mo )
{
if ( mo - > flags & MF_MISSILE & & mo - > flags2 & MF2_RAILRING )
{
const boolean nblockmap = ! ( mo - > flags & MF_NOBLOCKMAP ) ;
for ( i = 0 ; i < 256 ; i + + )
2014-03-15 16:59:03 +00:00
{
2018-06-06 13:42:50 +00:00
if ( nblockmap )
2014-03-15 16:59:03 +00:00
{
2018-06-06 13:42:50 +00:00
P_UnsetThingPosition ( mo ) ;
mo - > flags | = MF_NOBLOCKMAP ;
P_SetThingPosition ( mo ) ;
2014-03-15 16:59:03 +00:00
}
2018-06-06 13:42:50 +00:00
if ( i & 1 )
P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_SPARK ) ;
2014-03-15 16:59:03 +00:00
2018-06-06 13:42:50 +00:00
if ( P_RailThinker ( mo ) )
break ; // mobj was removed (missile hit a wall) or couldn't move
2014-03-15 16:59:03 +00:00
}
2018-06-06 13:42:50 +00:00
// Other rail sound plays at contact point.
S_StartSound ( mo , sfx_rail2 ) ;
2014-03-15 16:59:03 +00:00
}
}
}
//
// P_DoSuperStuff()
//
// Handle related superform functionality.
//
static void P_DoSuperStuff ( player_t * player )
{
2015-02-20 23:25:27 +00:00
mobj_t * spark ;
2014-08-04 03:49:33 +00:00
ticcmd_t * cmd = & player - > cmd ;
2017-10-04 16:45:03 +00:00
if ( player - > mo - > state > = & states [ S_PLAY_SUPER_TRANS1 ]
& & player - > mo - > state < & states [ S_PLAY_SUPER_TRANS6 ] )
2014-08-04 03:49:33 +00:00
return ; // don't do anything right now, we're in the middle of transforming!
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-08-04 03:49:33 +00:00
return ; // NiGHTS Super doesn't mix with normal super
2014-03-15 16:59:03 +00:00
if ( player - > powers [ pw_super ] )
{
// If you're super and not Sonic, de-superize!
2015-05-27 06:08:18 +00:00
if ( ! ( ALL7EMERALDS ( emeralds ) & & player - > charflags & SF_SUPER ) )
2014-03-15 16:59:03 +00:00
{
player - > powers [ pw_super ] = 0 ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
2019-10-24 17:51:12 +00:00
if ( P_IsLocalPlayer ( player ) )
{
music_stack_noposition = true ; // HACK: Do not reposition next music
music_stack_fadeout = MUSICRATE / 2 ; // HACK: Fade out current music
}
2014-03-15 16:59:03 +00:00
P_RestoreMusic ( player ) ;
P_SpawnShieldOrb ( player ) ;
2014-03-23 16:00:29 +00:00
// Restore color
2017-10-11 21:12:41 +00:00
if ( ( player - > powers [ pw_shield ] & SH_STACK ) = = SH_FIREFLOWER )
2014-03-23 16:00:29 +00:00
{
player - > mo - > color = SKINCOLOR_WHITE ;
G_GhostAddColor ( GHC_FIREFLOWER ) ;
}
else
{
player - > mo - > color = player - > skincolor ;
G_GhostAddColor ( GHC_NORMAL ) ;
}
2014-03-15 16:59:03 +00:00
if ( gametype ! = GT_COOP )
{
HU_SetCEchoFlags ( 0 ) ;
HU_SetCEchoDuration ( 5 ) ;
HU_DoCEcho ( va ( " %s \\ is no longer super. \\ \\ \\ \\ " , player_names [ player - players ] ) ) ;
}
2014-03-23 16:00:29 +00:00
return ;
2014-03-15 16:59:03 +00:00
}
2017-10-04 16:45:03 +00:00
player - > mo - > color = ( player - > pflags & PF_GODMODE & & cv_debug = = 0 )
? ( SKINCOLOR_SUPERSILVER1 + 5 * ( ( ( signed ) leveltime > > 1 ) % 7 ) ) // A wholesome easter egg.
: skins [ player - > skin ] . supercolor + abs ( ( ( player - > powers [ pw_super ] > > 1 ) % 9 ) - 4 ) ; // This is where super flashing is handled.
G_GhostAddColor ( GHC_SUPER ) ;
if ( player - > mo - > state = = & states [ S_PLAY_SUPER_TRANS6 ] ) // stop here for now
return ;
2014-03-15 16:59:03 +00:00
// Deplete one ring every second while super
if ( ( leveltime % TICRATE = = 0 ) & & ! ( player - > exiting ) )
2015-08-15 20:07:16 +00:00
player - > rings - - ;
2014-03-15 16:59:03 +00:00
2016-09-23 22:48:48 +00:00
if ( ( cmd - > forwardmove ! = 0 | | cmd - > sidemove ! = 0 | | player - > powers [ pw_carry ] )
2014-08-04 03:49:33 +00:00
& & ! ( leveltime % TICRATE ) & & ( player - > mo - > momx | | player - > mo - > momy ) )
2015-02-20 23:25:27 +00:00
{
spark = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z , MT_SUPERSPARK ) ;
spark - > destscale = player - > mo - > scale ;
P_SetScale ( spark , player - > mo - > scale ) ;
}
2015-03-02 00:30:22 +00:00
2014-03-15 16:59:03 +00:00
// Ran out of rings while super!
2015-08-15 20:07:16 +00:00
if ( player - > rings < = 0 | | player - > exiting )
2014-03-15 16:59:03 +00:00
{
player - > powers [ pw_emeralds ] = 0 ; // lost the power stones
P_SpawnGhostMobj ( player - > mo ) ;
player - > powers [ pw_super ] = 0 ;
// Restore color
2017-10-11 21:12:41 +00:00
if ( ( player - > powers [ pw_shield ] & SH_STACK ) = = SH_FIREFLOWER )
2014-03-15 16:59:03 +00:00
{
player - > mo - > color = SKINCOLOR_WHITE ;
G_GhostAddColor ( GHC_FIREFLOWER ) ;
}
else
{
player - > mo - > color = player - > skincolor ;
G_GhostAddColor ( GHC_NORMAL ) ;
}
if ( gametype ! = GT_COOP )
player - > powers [ pw_flashing ] = flashingtics - 1 ;
2019-10-24 17:51:12 +00:00
if ( player - > mo - > sprite2 & FF_SPR2SUPER )
2017-03-11 02:09:01 +00:00
P_SetPlayerMobjState ( player - > mo , player - > mo - > state - states ) ;
2014-03-15 16:59:03 +00:00
// Inform the netgame that the champion has fallen in the heat of battle.
if ( gametype ! = GT_COOP )
{
S_StartSound ( NULL , sfx_s3k66 ) ; //let all players hear it.
HU_SetCEchoFlags ( 0 ) ;
HU_SetCEchoDuration ( 5 ) ;
HU_DoCEcho ( va ( " %s \\ is no longer super. \\ \\ \\ \\ " , player_names [ player - players ] ) ) ;
}
// Resume normal music if you're the console player
2019-10-24 17:51:12 +00:00
if ( P_IsLocalPlayer ( player ) )
{
music_stack_noposition = true ; // HACK: Do not reposition next music
music_stack_fadeout = MUSICRATE / 2 ; // HACK: Fade out current music
}
2014-03-15 16:59:03 +00:00
P_RestoreMusic ( player ) ;
// If you had a shield, restore its visual significance.
P_SpawnShieldOrb ( player ) ;
}
}
}
//
// P_SuperReady
//
// Returns true if player is ready to turn super, duh
//
boolean P_SuperReady ( player_t * player )
{
2018-06-03 21:41:54 +00:00
if ( ! player - > powers [ pw_super ]
2014-03-15 16:59:03 +00:00
& & ! player - > powers [ pw_invulnerability ]
2018-06-03 21:41:54 +00:00
& & ! player - > powers [ pw_tailsfly ]
& & ( player - > charflags & SF_SUPER )
& & ( player - > pflags & PF_JUMPED )
& & ! ( player - > powers [ pw_shield ] & SH_NOSTACK )
& & ! ( maptol & TOL_NIGHTS )
& & ALL7EMERALDS ( emeralds )
& & ( player - > rings > = 50 ) )
2014-03-15 16:59:03 +00:00
return true ;
return false ;
}
//
// P_DoJump
//
// Jump routine for the player
//
void P_DoJump ( player_t * player , boolean soundandstate )
{
fixed_t factor ;
const fixed_t dist6 = FixedMul ( FixedDiv ( player - > speed , player - > mo - > scale ) , player - > actionspd ) / 20 ;
if ( player - > pflags & PF_JUMPSTASIS )
return ;
if ( ! player - > jumpfactor )
return ;
if ( player - > climbing )
{
// Jump this high.
if ( player - > powers [ pw_super ] )
player - > mo - > momz = 5 * FRACUNIT ;
else if ( player - > mo - > eflags & MFE_UNDERWATER )
player - > mo - > momz = 2 * FRACUNIT ;
else
player - > mo - > momz = 15 * ( FRACUNIT / 4 ) ;
2017-09-15 19:34:46 +00:00
player - > drawangle = player - > mo - > angle = player - > mo - > angle - ANGLE_180 ; // Turn around from the wall you were climbing.
2014-03-15 16:59:03 +00:00
2016-04-05 19:56:48 +00:00
if ( ! demoplayback | | P_AnalogMove ( player ) )
{
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ; // Adjust the local control angle.
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
}
2014-03-15 16:59:03 +00:00
player - > climbing = 0 ; // Stop climbing, duh!
P_InstaThrust ( player - > mo , player - > mo - > angle , FixedMul ( 6 * FRACUNIT , player - > mo - > scale ) ) ; // Jump off the wall.
}
// Quicksand jumping.
else if ( P_InQuicksand ( player - > mo ) )
{
2014-08-04 03:49:33 +00:00
if ( player - > mo - > ceilingz - player - > mo - > floorz < = player - > mo - > height - 1 )
return ;
2014-03-15 16:59:03 +00:00
player - > mo - > momz + = ( 39 * ( FRACUNIT / 4 ) ) > > 1 ;
if ( player - > mo - > momz > = 6 * FRACUNIT )
player - > mo - > momz = 6 * FRACUNIT ; //max momz in quicksand
else if ( player - > mo - > momz < 0 ) // still descending?
player - > mo - > momz = ( 39 * ( FRACUNIT / 4 ) ) > > 1 ; // just default to the jump height.
}
2017-03-18 21:06:06 +00:00
else if ( ! ( player - > pflags & PF_JUMPED ) ) // Jump
2014-03-15 16:59:03 +00:00
{
if ( player - > mo - > ceilingz - player - > mo - > floorz < = player - > mo - > height - 1 )
return ;
2019-09-29 16:42:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_PTERABYTE )
2019-10-07 22:00:41 +00:00
{
S_StartSound ( player - > mo , sfx_s3kd7s ) ;
player - > mo - > tracer - > cusval + = 10 ;
player - > mo - > tracer - > watertop = P_RandomRange ( - player - > mo - > tracer - > cusval , player - > mo - > tracer - > cusval ) < < ( FRACBITS - 1 ) ;
player - > mo - > tracer - > waterbottom = P_RandomRange ( - player - > mo - > tracer - > cusval , player - > mo - > tracer - > cusval ) < < ( FRACBITS - 1 ) ;
player - > mo - > tracer - > cvmem = P_RandomRange ( - player - > mo - > tracer - > cusval , player - > mo - > tracer - > cusval ) < < ( FRACBITS - 1 ) ;
2019-09-29 16:42:17 +00:00
return ;
2019-10-07 22:00:41 +00:00
}
2019-09-29 16:42:17 +00:00
2014-03-15 16:59:03 +00:00
// Jump this high.
2016-09-23 22:48:48 +00:00
if ( player - > powers [ pw_carry ] = = CR_PLAYER )
2014-03-15 16:59:03 +00:00
{
player - > mo - > momz = 9 * FRACUNIT ;
2016-09-23 22:48:48 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
2017-03-14 18:11:17 +00:00
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2014-03-15 16:59:03 +00:00
if ( player - players = = consoleplayer & & botingame )
CV_SetValue ( & cv_analog2 , true ) ;
}
2016-09-23 22:48:48 +00:00
else if ( player - > powers [ pw_carry ] = = CR_GENERIC )
2014-03-15 16:59:03 +00:00
{
player - > mo - > momz = 9 * FRACUNIT ;
2016-09-23 22:48:48 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
2019-09-29 12:18:40 +00:00
P_SetTarget ( & player - > mo - > tracer - > target , NULL ) ;
2017-03-14 18:11:17 +00:00
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2014-03-15 16:59:03 +00:00
}
2016-09-23 22:48:48 +00:00
else if ( player - > powers [ pw_carry ] = = CR_ROPEHANG )
2014-03-15 16:59:03 +00:00
{
player - > mo - > momz = 12 * FRACUNIT ;
2016-09-23 22:48:48 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
}
2019-09-29 12:18:40 +00:00
else if ( player - > powers [ pw_carry ] = = CR_ROLLOUT )
{
2019-11-17 21:30:14 +00:00
player - > mo - > momz = 9 * FRACUNIT ;
2019-11-18 14:36:25 +00:00
if ( P_MobjFlip ( player - > mo - > tracer ) * player - > mo - > tracer - > momz > 0 )
player - > mo - > momz + = player - > mo - > tracer - > momz ;
2019-11-20 15:45:34 +00:00
if ( ! P_IsObjectOnGround ( player - > mo - > tracer ) )
P_SetObjectMomZ ( player - > mo - > tracer , - 9 * FRACUNIT , true ) ;
2019-09-29 12:18:40 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
player - > mo - > tracer - > flags | = MF_PUSHABLE ;
2019-10-07 06:51:32 +00:00
P_SetTarget ( & player - > mo - > tracer - > tracer , NULL ) ;
2019-09-29 12:18:40 +00:00
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
}
2014-03-15 16:59:03 +00:00
else if ( player - > mo - > eflags & MFE_GOOWATER )
{
player - > mo - > momz = 7 * FRACUNIT ;
if ( player - > charability = = CA_JUMPBOOST & & onground )
{
2017-03-27 14:03:21 +00:00
if ( player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
player - > mo - > momz + = FixedMul ( FRACUNIT / 4 , dist6 ) ;
else
player - > mo - > momz + = FixedMul ( FRACUNIT / 8 , dist6 ) ;
}
}
else if ( maptol & TOL_NIGHTS )
2018-08-15 00:42:20 +00:00
player - > mo - > momz = 18 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
else if ( player - > powers [ pw_super ] )
{
2016-12-24 00:11:54 +00:00
player - > mo - > momz = 13 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
// Add a boost for super characters with float/slowfall and multiability.
2016-12-24 00:11:54 +00:00
if ( player - > charability = = CA_JUMPBOOST )
2014-03-15 16:59:03 +00:00
{
2017-03-27 14:03:21 +00:00
if ( player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
player - > mo - > momz + = FixedMul ( FRACUNIT / 4 , dist6 ) ;
else
player - > mo - > momz + = FixedMul ( FRACUNIT / 8 , dist6 ) ;
}
}
else
{
player - > mo - > momz = 39 * ( FRACUNIT / 4 ) ; // Default jump momentum.
if ( player - > charability = = CA_JUMPBOOST & & onground )
{
2017-03-27 14:03:21 +00:00
if ( player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
player - > mo - > momz + = FixedMul ( FRACUNIT / 4 , dist6 ) ;
else
player - > mo - > momz + = FixedMul ( FRACUNIT / 8 , dist6 ) ;
}
}
// Reduce player momz by 58.5% when underwater.
if ( player - > mo - > eflags & MFE_UNDERWATER )
player - > mo - > momz = FixedMul ( player - > mo - > momz , FixedDiv ( 117 * FRACUNIT , 200 * FRACUNIT ) ) ;
2017-03-22 18:51:30 +00:00
player - > pflags | = PF_STARTJUMP ;
2014-03-15 16:59:03 +00:00
}
factor = player - > jumpfactor ;
if ( twodlevel | | ( player - > mo - > flags2 & MF2_TWOD ) )
factor + = player - > jumpfactor / 10 ;
2017-03-27 14:03:21 +00:00
if ( player - > charflags & SF_MULTIABILITY & & player - > charability = = CA_DOUBLEJUMP )
2016-07-17 16:41:44 +00:00
factor - = max ( 0 , player - > secondjump * player - > jumpfactor / ( ( player - > actionspd > > FRACBITS ) + 1 ) ) ; // Reduce the jump height each time
2018-11-22 02:21:36 +00:00
//if (maptol & TOL_NIGHTS)
// factor = player->jumpfactor; // all skins jump the same. if you nerf jumping abilities, you may want this.
2018-08-15 00:42:20 +00:00
2014-03-15 16:59:03 +00:00
P_SetObjectMomZ ( player - > mo , FixedMul ( factor , player - > mo - > momz ) , false ) ; // Custom height
// set just an eensy above the ground
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2015-05-29 08:34:53 +00:00
{
2014-03-15 16:59:03 +00:00
player - > mo - > z - - ;
2015-05-29 08:34:53 +00:00
if ( player - > mo - > pmomz < 0 )
player - > mo - > momz + = player - > mo - > pmomz ; // Add the platform's momentum to your jump.
2015-05-29 17:53:06 +00:00
else
player - > mo - > pmomz = 0 ;
2015-05-29 08:34:53 +00:00
}
2014-03-15 16:59:03 +00:00
else
2015-05-29 08:34:53 +00:00
{
2014-03-15 16:59:03 +00:00
player - > mo - > z + + ;
2015-05-29 08:34:53 +00:00
if ( player - > mo - > pmomz > 0 )
player - > mo - > momz + = player - > mo - > pmomz ; // Add the platform's momentum to your jump.
2015-05-29 17:53:06 +00:00
else
player - > mo - > pmomz = 0 ;
2015-05-29 08:34:53 +00:00
}
2015-05-29 17:53:06 +00:00
player - > mo - > eflags & = ~ MFE_APPLYPMOMZ ;
2014-03-15 16:59:03 +00:00
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ; ;
2014-03-15 16:59:03 +00:00
if ( soundandstate )
{
if ( ! player - > spectator )
S_StartSound ( player - > mo , sfx_jump ) ; // Play jump sound!
A thorough reimplementation of Nojumpspin for the SPR2_ age.
* SF_NOJUMPSPIN - Player's height is full whilst jumping, SPR2_JUMP defaults to SPR2_SPNG instead of SPR2_SPIN, and the player goes into fall frames if they start moving downwards or use their ability.
* PA_JUMP - for jumping (upwards in the case of SF_NOJUMPSPIN.
* SF_NOJUMPDAMAGE - Ala rosy.wad, don't damage enemies, etc when jumping into them.
* SF_STOMPDAMAGE - Just for fun. Ala in Mario, always damage enemies when you land on top of them (your gravity reference, not theirs).
* SF_MARIODAMAGE - SF_NOJUMPDAMAGE|SF_STOMPDAMAGE is reasonably accurate to the Mario games, and might as well be surfaced as such.
Also, a minor change:
* Instead of not spawning the revitem if your SPR2_ is SPR2_DASH, don't spawn it if it's set to 0. This requires the player.dta I uploaded a couple days ago to behave as it was previously.
* Don't get stuck in spindash frames if your maxdash is 0, and don't flash rolling frames if you're on goop.
2016-07-10 17:41:38 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-03-15 16:59:03 +00:00
}
}
2016-11-10 17:51:10 +00:00
static void P_DoSpinDashDust ( player_t * player )
{
UINT32 i ;
mobj_t * particle ;
2016-11-10 21:09:05 +00:00
INT32 prandom [ 3 ] ;
2016-11-10 17:51:10 +00:00
for ( i = 0 ; i < = ( leveltime % 7 ) / 2 ; i + + ) { // 1, 2, 3 or 4 particles
particle = P_SpawnMobjFromMobj ( player - > mo , 0 , 0 , 0 , MT_SPINDUST ) ;
2016-11-13 22:02:29 +00:00
if ( player - > mo - > eflags & ( MFE_TOUCHWATER | MFE_UNDERWATER ) ) // overrides fire version
2016-11-10 21:09:05 +00:00
P_SetMobjState ( particle , S_SPINDUST_BUBBLE1 ) ;
2016-11-13 22:02:29 +00:00
else if ( player - > powers [ pw_shield ] = = SH_ELEMENTAL )
P_SetMobjState ( particle , S_SPINDUST_FIRE1 ) ;
2016-11-10 17:51:10 +00:00
P_SetTarget ( & particle - > target , player - > mo ) ;
particle - > destscale = ( 2 * player - > mo - > scale ) / 3 ;
P_SetScale ( particle , particle - > destscale ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP ) // readjust z position if needed
particle - > z = player - > mo - > z + player - > mo - > height - particle - > height ;
prandom [ 0 ] = P_RandomFixed ( ) < < 2 ; // P_RandomByte()<<10
prandom [ 1 ] = P_RandomRange ( - 30 , 30 ) ; // P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT
prandom [ 2 ] = P_RandomFixed ( ) < < 3 ; // P_RandomByte()<<11
P_SetObjectMomZ ( particle , player - > dashspeed / 50 + prandom [ 0 ] , false ) ;
P_InstaThrust ( particle ,
2017-02-08 12:51:31 +00:00
player - > drawangle + ( prandom [ 1 ] * ANG1 ) ,
2016-11-10 17:51:10 +00:00
- FixedMul ( player - > dashspeed / 12 + FRACUNIT + prandom [ 2 ] , player - > mo - > scale ) ) ;
P_TryMove ( particle , particle - > x + particle - > momx , particle - > y + particle - > momy , true ) ;
}
}
2014-03-15 16:59:03 +00:00
//
2016-07-17 20:31:15 +00:00
// P_DoSpinAbility
2014-03-15 16:59:03 +00:00
//
// Player spindash handling
//
2016-07-17 20:31:15 +00:00
static void P_DoSpinAbility ( player_t * player , ticcmd_t * cmd )
2014-03-15 16:59:03 +00:00
{
2016-11-10 17:51:10 +00:00
boolean canstand = true ; // can we stand on the ground? (mostly relevant for slopes)
2019-09-23 18:17:20 +00:00
if ( player - > pflags & PF_STASIS
& & ( player - > pflags & PF_JUMPSTASIS | | player - > mo - > state - states ! = S_PLAY_GLIDE_LANDING ) )
2014-03-15 16:59:03 +00:00
return ;
2014-08-04 03:49:33 +00:00
# ifdef HAVE_BLUA
if ( cmd - > buttons & BT_USE )
{
if ( LUAh_SpinSpecial ( player ) )
return ;
}
# endif
2015-05-20 18:18:41 +00:00
# ifdef ESLOPE
2016-11-10 17:51:10 +00:00
canstand = ( ! player - > mo - > standingslope | | ( player - > mo - > standingslope - > flags & SL_NOPHYSICS ) | | abs ( player - > mo - > standingslope - > zdelta ) < FRACUNIT / 2 ) ;
2015-05-20 18:18:41 +00:00
# endif
2016-11-10 17:51:10 +00:00
///////////////////////////////
// ability-specific behavior //
///////////////////////////////
if ( ! ( player - > pflags & PF_SLIDING ) & & ! player - > exiting & & ! P_PlayerInPain ( player ) )
{
switch ( player - > charability2 )
2014-03-15 16:59:03 +00:00
{
2016-11-10 17:51:10 +00:00
case CA2_SPINDASH : // Spinning and Spindashing
// Start revving
2019-09-30 06:38:58 +00:00
if ( ( cmd - > buttons & BT_USE ) & & ( player - > speed < FixedMul ( 5 < < FRACBITS , player - > mo - > scale ) | | player - > mo - > state - states = = S_PLAY_GLIDE_LANDING )
2016-11-10 17:51:10 +00:00
& & ! player - > mo - > momz & & onground & & ! ( player - > pflags & ( PF_USEDOWN | PF_SPINNING ) )
& & canstand )
{
player - > mo - > momx = player - > cmomx ;
player - > mo - > momy = player - > cmomy ;
2017-03-21 00:54:47 +00:00
player - > pflags | = ( PF_USEDOWN | PF_STARTDASH | PF_SPINNING ) ;
2016-11-10 17:51:10 +00:00
player - > dashspeed = player - > mindash ;
2017-03-11 02:09:01 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_SPINDASH ) ;
2016-11-10 17:51:10 +00:00
if ( ! player - > spectator )
2019-11-30 11:30:58 +00:00
S_StartSound ( player - > mo , sfx_spndsh ) ; // Make the rev sound!
2016-11-10 17:51:10 +00:00
}
// Revving
else if ( ( cmd - > buttons & BT_USE ) & & ( player - > pflags & PF_STARTDASH ) )
{
2019-11-24 22:55:37 +00:00
if ( player - > speed > 5 * player - > mo - > scale )
{
player - > pflags & = ~ PF_STARTDASH ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
S_StartSound ( player - > mo , sfx_spin ) ;
break ;
}
2016-11-10 17:51:10 +00:00
if ( player - > dashspeed < player - > maxdash )
{
2016-09-02 16:27:39 +00:00
# define chargecalculation (6*(player->dashspeed - player->mindash)) / (player->maxdash - player->mindash)
2016-11-10 17:51:10 +00:00
fixed_t soundcalculation = chargecalculation ;
player - > dashspeed + = FRACUNIT ;
if ( ! player - > spectator & & soundcalculation ! = chargecalculation )
2019-11-30 11:30:58 +00:00
S_StartSound ( player - > mo , sfx_spndsh ) ; // Make the rev sound!
2016-09-02 16:27:39 +00:00
# undef chargecalculation
2016-11-10 17:51:10 +00:00
}
if ( player - > revitem & & ! ( leveltime % 5 ) ) // Now spawn the color thok circle.
{
P_SpawnSpinMobj ( player , player - > revitem ) ;
2019-10-29 15:32:22 +00:00
G_GhostAddRev ( ) ;
2016-11-10 17:51:10 +00:00
}
}
2017-02-04 17:08:14 +00:00
// If not moving up or down, and travelling faster than a speed of five while not holding
2016-11-10 17:51:10 +00:00
// down the spin button and not spinning.
// AKA Just go into a spin on the ground, you idiot. ;)
else if ( ( cmd - > buttons & BT_USE | | ( ( twodlevel | | ( player - > mo - > flags2 & MF2_TWOD ) ) & & cmd - > forwardmove < - 20 ) )
& & ! player - > climbing & & ! player - > mo - > momz & & onground & & ( player - > speed > FixedMul ( 5 < < FRACBITS , player - > mo - > scale )
| | ! canstand ) & & ! ( player - > pflags & ( PF_USEDOWN | PF_SPINNING ) ) )
{
2017-03-21 00:54:47 +00:00
player - > pflags | = ( PF_USEDOWN | PF_SPINNING ) ;
2017-03-11 02:09:01 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
2016-11-10 17:51:10 +00:00
if ( ! player - > spectator )
S_StartSound ( player - > mo , sfx_spin ) ;
2017-03-21 00:54:47 +00:00
}
2017-03-21 02:06:24 +00:00
else
2017-03-21 00:54:47 +00:00
// Catapult the player from a spindash rev!
if ( onground & & ! ( player - > pflags & PF_USEDOWN ) & & ( player - > pflags & PF_STARTDASH ) & & ( player - > pflags & PF_SPINNING ) )
{
player - > pflags & = ~ PF_STARTDASH ;
if ( player - > powers [ pw_carry ] = = CR_BRAKGOOP )
player - > dashspeed = 0 ;
if ( ! ( ( gametype = = GT_RACE | | gametype = = GT_COMPETITION ) & & leveltime < 4 * TICRATE ) )
{
if ( player - > dashspeed )
{
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
2017-03-21 02:06:24 +00:00
P_InstaThrust ( player - > mo , player - > mo - > angle , ( player - > speed = FixedMul ( player - > dashspeed , player - > mo - > scale ) ) ) ; // catapult forward ho!!
2017-03-21 00:54:47 +00:00
}
else
{
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
player - > pflags & = ~ PF_SPINNING ;
}
if ( ! player - > spectator )
S_StartSound ( player - > mo , sfx_zoom ) ;
}
player - > dashspeed = 0 ;
}
break ;
case CA2_GUNSLINGER :
2017-03-22 18:51:30 +00:00
if ( ! player - > mo - > momz & & onground & & ! player - > weapondelay & & canstand )
2017-03-21 00:54:47 +00:00
{
2017-03-22 18:51:30 +00:00
if ( player - > speed > FixedMul ( 10 < < FRACBITS , player - > mo - > scale ) )
{ }
2017-03-21 00:54:47 +00:00
else
{
2017-03-22 18:51:30 +00:00
mobj_t * lockon = P_LookForEnemies ( player , false , true ) ;
if ( lockon )
2017-03-21 00:54:47 +00:00
{
2017-04-29 15:27:52 +00:00
if ( P_IsLocalPlayer ( player ) ) // Only display it on your own view.
2017-03-22 18:51:30 +00:00
{
2017-03-23 19:11:22 +00:00
mobj_t * visual = P_SpawnMobj ( lockon - > x , lockon - > y , lockon - > z , MT_LOCKON ) ; // positioning, flip handled in P_SceneryThinker
2019-07-12 23:42:03 +00:00
P_SetTarget ( & visual - > target , lockon ) ;
2017-03-22 18:51:30 +00:00
}
2017-03-21 00:54:47 +00:00
}
2017-03-22 18:51:30 +00:00
if ( ( cmd - > buttons & BT_USE ) & & ! ( player - > pflags & PF_USEDOWN ) )
{
mobj_t * bullet ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_FIRE ) ;
# define zpos(posmo) (posmo->z + (posmo->height - mobjinfo[player->revitem].height) / 2)
if ( lockon )
{
player - > mo - > angle = R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , lockon - > x , lockon - > y ) ;
bullet = P_SpawnPointMissile ( player - > mo , lockon - > x , lockon - > y , zpos ( lockon ) , player - > revitem , player - > mo - > x , player - > mo - > y , zpos ( player - > mo ) ) ;
if ( ! demoplayback | | P_AnalogMove ( player ) )
{
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
}
}
else
{
bullet = P_SpawnPointMissile ( player - > mo , player - > mo - > x + P_ReturnThrustX ( NULL , player - > mo - > angle , FRACUNIT ) , player - > mo - > y + P_ReturnThrustY ( NULL , player - > mo - > angle , FRACUNIT ) , zpos ( player - > mo ) , player - > revitem , player - > mo - > x , player - > mo - > y , zpos ( player - > mo ) ) ;
if ( bullet )
{
bullet - > flags & = ~ MF_NOGRAVITY ;
bullet - > momx > > = 1 ;
bullet - > momy > > = 1 ;
}
}
2017-04-05 19:18:40 +00:00
player - > drawangle = player - > mo - > angle ;
2017-03-21 16:04:49 +00:00
# undef zpos
2017-03-22 18:51:30 +00:00
player - > mo - > momx > > = 1 ;
player - > mo - > momy > > = 1 ;
player - > pflags | = PF_USEDOWN ;
P_SetWeaponDelay ( player , TICRATE / 2 ) ;
}
}
2016-11-10 17:51:10 +00:00
}
break ;
case CA2_MELEE : // Melee attack
2017-03-21 00:54:47 +00:00
if ( player - > panim ! = PA_ABILITY2 & & ( cmd - > buttons & BT_USE )
2016-11-10 17:51:10 +00:00
& & ! player - > mo - > momz & & onground & & ! ( player - > pflags & PF_USEDOWN )
& & canstand )
{
P_ResetPlayer ( player ) ;
2017-03-21 16:04:49 +00:00
player - > pflags | = PF_THOKKED ;
#if 0
2017-03-19 16:48:35 +00:00
if ( ( player - > charability = = CA_TWINSPIN ) & & ( player - > speed > FixedMul ( player - > runspeed , player - > mo - > scale ) ) )
{
P_DoJump ( player , false ) ;
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ PF_STARTJUMP ;
2017-03-19 22:22:39 +00:00
player - > mo - > momz = FixedMul ( player - > mo - > momz , 3 * FRACUNIT / 2 ) ; // NOT 1.5 times the jump height, but 2.25 times.
2017-03-19 16:48:35 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_TWINSPIN ) ;
S_StartSound ( player - > mo , sfx_s3k8b ) ;
}
else
2017-03-21 16:04:49 +00:00
# endif
2017-03-19 16:48:35 +00:00
{
player - > mo - > z + = P_MobjFlip ( player - > mo ) ;
P_SetObjectMomZ ( player - > mo , player - > mindash , false ) ;
2019-07-17 22:25:49 +00:00
if ( P_MobjFlip ( player - > mo ) * player - > mo - > pmomz > 0 )
player - > mo - > momz + = player - > mo - > pmomz ; // Add the platform's momentum to your jump.
else
player - > mo - > pmomz = 0 ;
2017-03-19 22:22:39 +00:00
if ( player - > mo - > eflags & MFE_UNDERWATER )
player - > mo - > momz > > = 1 ;
2019-06-19 12:20:34 +00:00
#if 0
2017-03-19 16:48:35 +00:00
if ( FixedMul ( player - > speed , FINECOSINE ( ( ( player - > mo - > angle - R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) ) > > ANGLETOFINESHIFT ) & FINEMASK ) ) < FixedMul ( player - > maxdash , player - > mo - > scale ) )
2019-06-19 12:20:34 +00:00
# else
if ( player - > speed < FixedMul ( player - > maxdash , player - > mo - > scale ) )
# endif
2017-04-05 15:01:02 +00:00
{
2019-10-07 14:03:28 +00:00
if ( player - > panim = = PA_IDLE )
player - > drawangle = player - > mo - > angle ;
P_InstaThrust ( player - > mo , player - > drawangle , FixedMul ( player - > maxdash , player - > mo - > scale ) ) ;
2017-04-05 15:01:02 +00:00
}
2017-03-19 16:48:35 +00:00
player - > mo - > momx + = player - > cmomx ;
player - > mo - > momy + = player - > cmomy ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_MELEE ) ;
S_StartSound ( player - > mo , sfx_s3k42 ) ;
}
2016-11-10 17:51:10 +00:00
player - > pflags | = PF_USEDOWN ;
}
break ;
2014-03-15 16:59:03 +00:00
}
}
2016-11-10 17:51:10 +00:00
///////////////////////////////
// general spinning behavior //
///////////////////////////////
2014-03-15 16:59:03 +00:00
// Rolling normally
if ( onground & & player - > pflags & PF_SPINNING & & ! ( player - > pflags & PF_STARTDASH )
2019-11-24 22:55:37 +00:00
& & player - > speed < 5 * player - > mo - > scale & & canstand )
2014-03-15 16:59:03 +00:00
{
if ( GETSECSPECIAL ( player - > mo - > subsector - > sector - > special , 4 ) = = 7 | | ( player - > mo - > ceilingz - player - > mo - > floorz < P_GetPlayerHeight ( player ) ) )
2019-11-24 22:55:37 +00:00
P_InstaThrust ( player - > mo , player - > mo - > angle , 10 * player - > mo - > scale ) ;
2014-03-15 16:59:03 +00:00
else
{
player - > skidtime = 0 ;
player - > pflags & = ~ PF_SPINNING ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
player - > mo - > momx = player - > cmomx ;
player - > mo - > momy = player - > cmomy ;
}
}
2016-08-30 14:00:01 +00:00
if ( onground & & player - > pflags & PF_STARTDASH )
{
2016-11-10 17:51:10 +00:00
// Spawn spin dash dust
2016-11-13 22:33:57 +00:00
if ( ! ( player - > charflags & SF_NOSPINDASHDUST ) & & ! ( player - > mo - > eflags & MFE_GOOWATER ) )
2016-11-10 17:51:10 +00:00
P_DoSpinDashDust ( player ) ;
2016-08-30 14:00:01 +00:00
}
2014-03-15 16:59:03 +00:00
}
//
// P_DoJumpShield
//
// Jump Shield Activation
//
2014-08-04 03:49:33 +00:00
void P_DoJumpShield ( player_t * player )
2014-03-15 16:59:03 +00:00
{
2016-10-13 14:13:33 +00:00
boolean electric = ( ( player - > powers [ pw_shield ] & SH_PROTECTELECTRIC ) = = SH_PROTECTELECTRIC ) ;
2014-03-15 16:59:03 +00:00
if ( player - > pflags & PF_THOKKED )
return ;
player - > pflags & = ~ PF_JUMPED ;
P_DoJump ( player , false ) ;
2016-10-13 14:13:33 +00:00
player - > secondjump = 0 ;
2016-09-29 19:02:58 +00:00
player - > pflags | = PF_THOKKED | PF_SHIELDABILITY ;
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ ( PF_STARTJUMP | PF_SPINNING | PF_BOUNCING ) ;
2016-10-13 14:13:33 +00:00
if ( electric )
{
2016-10-17 22:22:04 +00:00
mobj_t * spark ;
INT32 i ;
# define numangles 6
# define limitangle (360 / numangles)
2017-03-20 16:57:24 +00:00
const angle_t travelangle = player - > mo - > angle + P_RandomRange ( - limitangle , limitangle ) * ANG1 ;
2016-10-17 22:22:04 +00:00
for ( i = 0 ; i < numangles ; i + + )
{
spark = P_SpawnMobjFromMobj ( player - > mo , 0 , 0 , 0 , MT_THUNDERCOIN_SPARK ) ;
P_InstaThrust ( spark , travelangle + i * ( ANGLE_MAX / numangles ) , FixedMul ( 4 * FRACUNIT , spark - > scale ) ) ;
if ( i % 2 )
P_SetObjectMomZ ( spark , - 4 * FRACUNIT , false ) ;
2019-06-29 13:10:32 +00:00
spark - > fuse = 18 ;
2016-10-17 22:22:04 +00:00
}
# undef limitangle
# undef numangles
2016-10-13 14:13:33 +00:00
S_StartSound ( player - > mo , sfx_s3k45 ) ;
}
else
{
2017-03-18 21:06:06 +00:00
player - > pflags & = ~ ( PF_JUMPED | PF_NOJUMPDAMAGE ) ;
2016-10-13 14:13:33 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
S_StartSound ( player - > mo , sfx_wdjump ) ;
}
2014-03-15 16:59:03 +00:00
}
2016-10-24 12:33:10 +00:00
//
// P_DoBubbleBounce
//
// Bubblewrap shield landing handling
//
void P_DoBubbleBounce ( player_t * player )
{
2017-03-18 21:06:06 +00:00
player - > pflags & = ~ ( PF_JUMPED | PF_NOJUMPDAMAGE | PF_SHIELDABILITY ) ;
2016-10-24 12:33:10 +00:00
S_StartSound ( player - > mo , sfx_s3k44 ) ;
2017-03-25 12:42:39 +00:00
P_MobjCheckWater ( player - > mo ) ;
2016-10-24 12:33:10 +00:00
P_DoJump ( player , false ) ;
if ( player - > charflags & SF_NOJUMPSPIN )
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2017-09-09 23:02:11 +00:00
else
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
2016-10-24 12:33:10 +00:00
player - > pflags | = PF_THOKKED ;
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ PF_STARTJUMP ;
2016-10-24 12:33:10 +00:00
player - > secondjump = UINT8_MAX ;
player - > mo - > momz = FixedMul ( player - > mo - > momz , 5 * FRACUNIT / 4 ) ;
}
2016-12-24 00:11:54 +00:00
//
// P_DoAbilityBounce
//
// CA_BOUNCE landing handling
//
void P_DoAbilityBounce ( player_t * player , boolean changemomz )
{
fixed_t prevmomz ;
if ( player - > mo - > state - states = = S_PLAY_BOUNCE_LANDING )
return ;
if ( changemomz )
{
2019-08-06 21:35:20 +00:00
fixed_t minmomz ;
2017-02-09 23:24:47 +00:00
prevmomz = player - > mo - > momz ;
if ( P_MobjFlip ( player - > mo ) * prevmomz < 0 )
2016-12-24 00:11:54 +00:00
prevmomz = 0 ;
else if ( player - > mo - > eflags & MFE_UNDERWATER )
prevmomz / = 2 ;
P_DoJump ( player , false ) ;
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ ( PF_STARTJUMP | PF_JUMPED ) ;
2019-08-06 21:35:20 +00:00
minmomz = FixedMul ( player - > mo - > momz , 3 * FRACUNIT / 2 ) ;
player - > mo - > momz = max ( minmomz , ( minmomz + prevmomz ) / 2 ) ;
2016-12-24 00:11:54 +00:00
}
S_StartSound ( player - > mo , sfx_boingf ) ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_BOUNCE_LANDING ) ;
player - > pflags | = PF_BOUNCING | PF_THOKKED ;
}
2019-06-26 22:26:05 +00:00
//
// P_TwinSpinRejuvenate
//
// CA_TWINSPIN landing handling
//
void P_TwinSpinRejuvenate ( player_t * player , mobjtype_t type )
{
fixed_t actionspd ;
angle_t movang , ang , fa ;
fixed_t v , h ;
UINT8 i ;
if ( ! player - > mo | | ! type )
return ;
actionspd = FixedMul ( player - > actionspd , player - > mo - > scale ) ;
fa = ( R_PointToAngle2 ( 0 , 0 , player - > mo - > momz , FixedHypot ( player - > mo - > momx , player - > mo - > momy ) ) > > ANGLETOFINESHIFT ) & FINEMASK ;
movang = R_PointToAngle2 ( 0 , 0 , player - > mo - > momx , player - > mo - > momy ) ;
ang = 0 ;
v = FixedMul ( actionspd , FINESINE ( fa ) ) ;
h = actionspd - FixedMul ( actionspd , FINECOSINE ( fa ) ) ;
// hearticles
for ( i = 0 ; i < = 7 ; i + + )
{
fixed_t side = actionspd - FixedMul ( h , abs ( FINESINE ( ( ang > > ANGLETOFINESHIFT ) & FINEMASK ) ) ) ;
fixed_t xo = P_ReturnThrustX ( NULL , ang + movang , side ) ;
fixed_t yo = P_ReturnThrustY ( NULL , ang + movang , side ) ;
fixed_t zo = - FixedMul ( FINECOSINE ( ( ( ang > > ANGLETOFINESHIFT ) & FINEMASK ) ) , v ) ;
mobj_t * missile = P_SpawnMobjFromMobj ( player - > mo ,
xo ,
yo ,
player - > mo - > height / 2 + zo ,
type ) ;
P_SetTarget ( & missile - > target , player - > mo ) ;
P_SetScale ( missile , ( missile - > destscale > > = 1 ) ) ;
missile - > angle = ang + movang ;
missile - > fuse = TICRATE / 2 ;
missile - > extravalue2 = ( 99 * FRACUNIT ) / 100 ;
missile - > momx = xo ;
missile - > momy = yo ;
missile - > momz = zo ;
ang + = ANGLE_45 ;
}
player - > pflags & = ~ PF_THOKKED ;
}
2014-03-15 16:59:03 +00:00
//
// P_Telekinesis
//
// Morph's fancy stuff-moving character ability
// +ve thrust pushes away, -ve thrust pulls in
//
2014-05-26 02:41:05 +00:00
void P_Telekinesis ( player_t * player , fixed_t thrust , fixed_t range )
2014-03-15 16:59:03 +00:00
{
thinker_t * th ;
mobj_t * mo2 ;
fixed_t dist = 0 ;
angle_t an ;
if ( player - > powers [ pw_super ] ) // increase range when super
range * = 2 ;
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 = = player - > mo )
continue ;
if ( ! ( ( mo2 - > flags & MF_SHOOTABLE & & mo2 - > flags & MF_ENEMY ) | | mo2 - > type = = MT_EGGGUARD | | mo2 - > player ) )
continue ;
dist = P_AproxDistance ( P_AproxDistance ( player - > mo - > x - mo2 - > x , player - > mo - > y - mo2 - > y ) , player - > mo - > z - mo2 - > z ) ;
if ( range < dist )
continue ;
if ( ! P_CheckSight ( player - > mo , mo2 ) )
continue ; // if your psychic powers can't "see" it don't bother
an = R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , mo2 - > x , mo2 - > y ) ;
if ( mo2 - > health > 0 )
{
P_Thrust ( mo2 , an , thrust ) ;
if ( mo2 - > type = = MT_GOLDBUZZ | | mo2 - > type = = MT_REDBUZZ )
mo2 - > tics + = 8 ;
}
}
P_SpawnThokMobj ( player ) ;
player - > pflags | = PF_THOKKED ;
}
//
// P_DoJumpStuff
//
// Handles player jumping
//
static void P_DoJumpStuff ( player_t * player , ticcmd_t * cmd )
{
2019-09-06 18:01:46 +00:00
mobj_t * lockonthok = NULL , * lockonshield = NULL , * visual = NULL ;
2017-03-23 19:11:22 +00:00
2014-03-15 16:59:03 +00:00
if ( player - > pflags & PF_JUMPSTASIS )
return ;
2019-09-06 18:01:46 +00:00
if ( ( player - > charability = = CA_HOMINGTHOK ) & & ! player - > homing & & ( player - > pflags & PF_JUMPED ) & & ( ! ( player - > pflags & PF_THOKKED ) | | ( player - > charflags & SF_MULTIABILITY ) ) & & ( lockonthok = P_LookForEnemies ( player , true , false ) ) )
2017-03-23 19:11:22 +00:00
{
2017-04-29 15:27:52 +00:00
if ( P_IsLocalPlayer ( player ) ) // Only display it on your own view.
2017-03-23 19:11:22 +00:00
{
2019-09-06 18:01:46 +00:00
visual = P_SpawnMobj ( lockonthok - > x , lockonthok - > y , lockonthok - > z , MT_LOCKON ) ; // positioning, flip handled in P_SceneryThinker
P_SetTarget ( & visual - > target , lockonthok ) ;
2017-03-23 19:11:22 +00:00
}
}
2019-09-06 18:01:46 +00:00
//////////////////
//SHIELD ACTIVES//
//& SUPER FLOAT!//
//////////////////
if ( ( player - > pflags & PF_JUMPED ) & & ! player - > exiting & & ! P_PlayerInPain ( player ) )
2014-03-15 16:59:03 +00:00
{
2019-09-06 18:01:46 +00:00
if ( onground | | player - > climbing | | player - > powers [ pw_carry ] )
;
else if ( gametype = = GT_CTF & & player - > gotflag )
;
else if ( player - > pflags & ( PF_GLIDING | PF_SLIDING | PF_SHIELDABILITY ) ) // If the player has used an ability previously
;
else if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) & & ! player - > powers [ pw_super ] & & ! ( player - > pflags & PF_USEDOWN )
& & ( ( ! ( player - > pflags & PF_THOKKED ) | | ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_BUBBLEWRAP & & player - > secondjump = = UINT8_MAX ) ) ) ) // thokked is optional if you're bubblewrapped
{
if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ATTRACT )
{
if ( ( lockonshield = P_LookForEnemies ( player , false , false ) ) )
{
if ( P_IsLocalPlayer ( player ) ) // Only display it on your own view.
{
boolean dovis = true ;
if ( lockonshield = = lockonthok )
{
if ( leveltime & 2 )
dovis = false ;
else if ( visual )
P_RemoveMobj ( visual ) ;
}
if ( dovis )
{
visual = P_SpawnMobj ( lockonshield - > x , lockonshield - > y , lockonshield - > z , MT_LOCKON ) ; // positioning, flip handled in P_SceneryThinker
P_SetTarget ( & visual - > target , lockonshield ) ;
P_SetMobjStateNF ( visual , visual - > info - > spawnstate + 1 ) ;
}
}
}
}
if ( cmd - > buttons & BT_USE // Spin button effects
# ifdef HAVE_BLUA
& & ! LUAh_ShieldSpecial ( player )
# endif
)
{
// Force stop
if ( ( player - > powers [ pw_shield ] & ~ ( SH_FORCEHP | SH_STACK ) ) = = SH_FORCE )
{
player - > pflags | = PF_THOKKED | PF_SHIELDABILITY ;
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
S_StartSound ( player - > mo , sfx_ngskid ) ;
}
else
{
switch ( player - > powers [ pw_shield ] & SH_NOSTACK )
{
// Whirlwind jump/Thunder jump
case SH_WHIRLWIND :
case SH_THUNDERCOIN :
P_DoJumpShield ( player ) ;
break ;
// Armageddon pow
case SH_ARMAGEDDON :
player - > pflags | = PF_THOKKED | PF_SHIELDABILITY ;
P_BlackOw ( player ) ;
break ;
// Attraction blast
case SH_ATTRACT :
player - > pflags | = PF_THOKKED | PF_SHIELDABILITY ;
player - > homing = 2 ;
P_SetTarget ( & player - > mo - > target , P_SetTarget ( & player - > mo - > tracer , lockonshield ) ) ;
if ( lockonshield )
{
player - > mo - > angle = R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , lockonshield - > x , lockonshield - > y ) ;
player - > pflags & = ~ PF_NOJUMPDAMAGE ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
S_StartSound ( player - > mo , sfx_s3k40 ) ;
player - > homing = 3 * TICRATE ;
}
else
S_StartSound ( player - > mo , sfx_s3ka6 ) ;
break ;
// Elemental stomp/Bubble bounce
case SH_ELEMENTAL :
case SH_BUBBLEWRAP :
{
boolean elem = ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL ) ;
player - > pflags | = PF_THOKKED | PF_SHIELDABILITY ;
if ( elem )
{
player - > pflags | = PF_NOJUMPDAMAGE ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
S_StartSound ( player - > mo , sfx_s3k43 ) ;
}
else
{
player - > pflags & = ~ PF_NOJUMPDAMAGE ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
S_StartSound ( player - > mo , sfx_s3k44 ) ;
}
player - > secondjump = 0 ;
player - > mo - > momx = player - > mo - > momy = 0 ;
P_SetObjectMomZ ( player - > mo , - 24 * FRACUNIT , false ) ;
break ;
}
// Flame burst
case SH_FLAMEAURA :
player - > pflags | = PF_THOKKED | PF_SHIELDABILITY ;
P_Thrust ( player - > mo , player - > mo - > angle , FixedMul ( 30 * FRACUNIT - FixedSqrt ( FixedDiv ( player - > speed , player - > mo - > scale ) ) , player - > mo - > scale ) ) ;
player - > drawangle = player - > mo - > angle ;
S_StartSound ( player - > mo , sfx_s3k43 ) ;
default :
break ;
}
}
}
}
else if ( ( cmd - > buttons & BT_USE ) )
2014-03-15 16:59:03 +00:00
{
2019-09-06 18:01:46 +00:00
if ( ! ( player - > pflags & PF_USEDOWN ) & & P_SuperReady ( player ) )
{
// If you can turn super and aren't already,
// and you don't have a shield, do it!
P_DoSuperTransformation ( player , false ) ;
}
else
2014-08-04 03:49:33 +00:00
# ifdef HAVE_BLUA
if ( ! LUAh_JumpSpinSpecial ( player ) )
# endif
2014-03-15 16:59:03 +00:00
switch ( player - > charability )
{
2019-09-06 18:01:46 +00:00
case CA_THOK :
if ( player - > powers [ pw_super ] ) // Super Sonic float
2014-03-15 16:59:03 +00:00
{
2019-09-06 18:01:46 +00:00
if ( ( player - > speed > 5 * player - > mo - > scale ) // FixedMul(5<<FRACBITS, player->mo->scale), but scale is FRACUNIT-based
& & ( P_MobjFlip ( player - > mo ) * player - > mo - > momz < = 0 ) )
2014-03-15 16:59:03 +00:00
{
2019-09-06 18:01:46 +00:00
if ( player - > panim ! = PA_RUN & & player - > panim ! = PA_WALK )
{
if ( player - > speed > = FixedMul ( player - > runspeed , player - > mo - > scale ) )
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLOAT_RUN ) ;
else
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLOAT ) ;
}
player - > mo - > momz = 0 ;
player - > pflags & = ~ ( PF_STARTJUMP | PF_SPINNING ) ;
2014-03-15 16:59:03 +00:00
}
}
break ;
2019-09-06 18:01:46 +00:00
case CA_TELEKINESIS :
if ( ! ( player - > pflags & ( PF_THOKKED | PF_USEDOWN ) ) | | ( player - > charflags & SF_MULTIABILITY ) )
2014-03-15 16:59:03 +00:00
{
2019-09-06 18:01:46 +00:00
P_Telekinesis ( player ,
- FixedMul ( player - > actionspd , player - > mo - > scale ) , // -ve thrust (pulling towards player)
FixedMul ( 384 * FRACUNIT , player - > mo - > scale ) ) ;
}
break ;
case CA_TWINSPIN :
if ( ( player - > charability2 = = CA2_MELEE ) & & ( ! ( player - > pflags & ( PF_THOKKED | PF_USEDOWN ) ) | | player - > charflags & SF_MULTIABILITY ) )
{
player - > pflags | = PF_THOKKED ;
S_StartSound ( player - > mo , sfx_s3k42 ) ;
player - > mo - > frame = 0 ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_TWINSPIN ) ;
2014-03-15 16:59:03 +00:00
}
break ;
default :
break ;
}
}
}
if ( player - > charability = = CA_AIRDRILL )
{
if ( player - > pflags & PF_JUMPED )
{
2019-09-06 18:01:46 +00:00
if ( cmd - > buttons & BT_USE & & player - > secondjump < 42 ) // speed up falling down
player - > secondjump + + ;
2014-03-15 16:59:03 +00:00
if ( player - > flyangle > 0 & & player - > pflags & PF_THOKKED )
{
player - > flyangle - - ;
P_SetObjectMomZ ( player - > mo , ( ( player - > flyangle - 24 - player - > secondjump * 3 ) * ( ( player - > actionspd > > FRACBITS ) / 12 + 1 ) < < FRACBITS ) / 7 , false ) ;
P_SpawnThokMobj ( player ) ;
if ( ( player - > mo - > eflags & MFE_UNDERWATER ) )
P_InstaThrust ( player - > mo , player - > mo - > angle , FixedMul ( player - > normalspeed , player - > mo - > scale ) * ( 80 - player - > flyangle - ( player - > actionspd > > FRACBITS ) / 2 ) / 80 ) ;
else
P_InstaThrust ( player - > mo , player - > mo - > angle , ( ( FixedMul ( player - > normalspeed - player - > actionspd / 4 , player - > mo - > scale ) ) * 2 ) / 3 ) ;
2017-02-06 20:19:17 +00:00
player - > drawangle = player - > mo - > angle ;
2014-03-15 16:59:03 +00:00
}
}
}
2019-09-06 18:01:46 +00:00
///////////////
// CHARACTER //
// ABILITIES!//
///////////////
2014-08-04 03:49:33 +00:00
if ( cmd - > buttons & BT_JUMP & & ! player - > exiting & & ! P_PlayerInPain ( player ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
# ifdef HAVE_BLUA
if ( LUAh_JumpSpecial ( player ) )
;
else
# endif
if ( player - > pflags & PF_JUMPDOWN ) // all situations below this require jump button not to be pressed already
;
else
2014-03-15 16:59:03 +00:00
// Jump S3&K style while in quicksand.
if ( P_InQuicksand ( player - > mo ) )
{
P_DoJump ( player , true ) ;
player - > secondjump = 0 ;
player - > pflags & = ~ PF_THOKKED ;
}
2016-09-23 22:48:48 +00:00
else if ( player - > powers [ pw_carry ] = = CR_MACESPIN & & player - > mo - > tracer )
{
player - > powers [ pw_carry ] = CR_NONE ;
2017-03-14 18:11:17 +00:00
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2016-09-23 22:48:48 +00:00
player - > powers [ pw_flashing ] = TICRATE / 4 ;
}
2014-03-15 16:59:03 +00:00
else
// can't jump while in air, can't jump while jumping
2016-09-23 22:48:48 +00:00
if ( onground | | player - > climbing | | player - > powers [ pw_carry ] )
2014-03-15 16:59:03 +00:00
{
P_DoJump ( player , true ) ;
player - > secondjump = 0 ;
player - > pflags & = ~ PF_THOKKED ;
}
2014-08-04 03:49:33 +00:00
else if ( player - > pflags & PF_SLIDING | | ( gametype = = GT_CTF & & player - > gotflag ) )
;
2018-06-03 21:41:54 +00:00
/*else if (P_SuperReady(player))
2014-08-04 03:49:33 +00:00
{
// If you can turn super and aren't already,
// and you don't have a shield, do it!
P_DoSuperTransformation ( player , false ) ;
2018-06-03 21:41:54 +00:00
} */
2014-08-04 03:49:33 +00:00
else if ( player - > pflags & PF_JUMPED )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
# ifdef HAVE_BLUA
if ( ! LUAh_AbilitySpecial ( player ) )
# endif
2014-03-15 16:59:03 +00:00
switch ( player - > charability )
{
case CA_THOK :
case CA_HOMINGTHOK :
2014-07-05 07:08:39 +00:00
case CA_JUMPTHOK : // Credit goes to CZ64 and Sryder13 for the original
2014-03-15 16:59:03 +00:00
// Now it's Sonic's abilities turn!
2014-08-04 03:49:33 +00:00
// THOK!
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | ( player - > charflags & SF_MULTIABILITY ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
// Catapult the player
fixed_t actionspd = player - > actionspd ;
2016-07-16 20:03:32 +00:00
2016-12-24 00:11:54 +00:00
if ( player - > charflags & SF_DASHMODE )
2016-01-03 04:34:55 +00:00
actionspd = max ( player - > normalspeed , FixedDiv ( player - > speed , player - > mo - > scale ) ) ;
2016-07-16 20:03:32 +00:00
2014-08-04 03:49:33 +00:00
if ( player - > mo - > eflags & MFE_UNDERWATER )
actionspd > > = 1 ;
2016-07-16 20:03:32 +00:00
2014-08-04 18:38:19 +00:00
if ( ( player - > charability = = CA_JUMPTHOK ) & & ! ( player - > pflags & PF_THOKKED ) )
2014-08-04 03:49:33 +00:00
{
player - > pflags & = ~ PF_JUMPED ;
P_DoJump ( player , false ) ;
}
2016-07-16 20:03:32 +00:00
2014-08-04 03:49:33 +00:00
P_InstaThrust ( player - > mo , player - > mo - > angle , FixedMul ( actionspd , player - > mo - > scale ) ) ;
2014-08-04 18:38:19 +00:00
if ( maptol & TOL_2D )
2014-08-04 03:49:33 +00:00
{
player - > mo - > momx / = 2 ;
player - > mo - > momy / = 2 ;
}
2019-07-02 23:58:02 +00:00
if ( player - > charability = = CA_HOMINGTHOK )
2014-08-04 03:49:33 +00:00
{
2019-07-02 23:58:02 +00:00
player - > mo - > momx / = 2 ;
player - > mo - > momy / = 2 ;
2014-08-04 03:49:33 +00:00
}
2017-03-23 19:11:22 +00:00
if ( player - > charability = = CA_HOMINGTHOK )
2014-03-15 16:59:03 +00:00
{
2019-09-06 18:01:46 +00:00
P_SetTarget ( & player - > mo - > target , P_SetTarget ( & player - > mo - > tracer , lockonthok ) ) ;
if ( lockonthok )
2014-03-15 16:59:03 +00:00
{
2017-09-09 21:12:23 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
2019-09-06 18:01:46 +00:00
player - > mo - > angle = R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , lockonthok - > x , lockonthok - > y ) ;
2017-03-21 16:04:49 +00:00
player - > homing = 3 * TICRATE ;
2014-03-15 16:59:03 +00:00
}
2017-03-21 16:04:49 +00:00
else
2014-03-15 16:59:03 +00:00
{
2017-03-21 16:04:49 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
player - > pflags & = ~ PF_JUMPED ;
2017-06-03 12:47:08 +00:00
player - > mo - > height = P_GetPlayerHeight ( player ) ;
2014-03-15 16:59:03 +00:00
}
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ PF_NOJUMPDAMAGE ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
2019-09-06 18:01:46 +00:00
player - > drawangle = player - > mo - > angle ;
2017-06-03 12:47:08 +00:00
if ( player - > mo - > info - > attacksound & & ! player - > spectator )
S_StartSound ( player - > mo , player - > mo - > info - > attacksound ) ; // Play the THOK sound
P_SpawnThokMobj ( player ) ;
2014-08-04 03:49:33 +00:00
player - > pflags & = ~ ( PF_SPINNING | PF_STARTDASH ) ;
player - > pflags | = PF_THOKKED ;
2019-12-08 20:35:50 +00:00
2019-12-10 13:54:27 +00:00
// Change localangle to match for simple controls? (P.S. chalupa)
// disabled because it seemed to disorient people and Z-targeting exists now
/*if (!demoplayback)
2019-12-08 21:49:10 +00:00
{
if ( player = = & players [ consoleplayer ] & & cv_cam_turnfacingability [ 0 ] . value > 0 & & ! ( PLAYER1INPUTDOWN ( gc_turnleft ) | | PLAYER1INPUTDOWN ( gc_turnright ) ) )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] & & cv_cam_turnfacingability [ 1 ] . value > 0 & & ! ( PLAYER2INPUTDOWN ( gc_turnleft ) | | PLAYER2INPUTDOWN ( gc_turnright ) ) )
localangle2 = player - > mo - > angle ;
2019-12-10 13:54:27 +00:00
} */
2014-03-15 16:59:03 +00:00
}
break ;
case CA_FLY :
2016-07-13 17:18:18 +00:00
case CA_SWIM :
2014-03-15 16:59:03 +00:00
// If currently in the air from a jump, and you pressed the
// button again and have the ability to fly, do so!
2014-08-04 03:49:33 +00:00
if ( player - > charability = = CA_SWIM & & ! ( player - > mo - > eflags & MFE_UNDERWATER ) )
; // Can't do anything if you're a fish out of water!
else if ( ! ( player - > pflags & PF_THOKKED ) & & ! ( player - > powers [ pw_tailsfly ] ) )
2014-03-15 16:59:03 +00:00
{
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLY ) ; // Change to the flying animation
2014-03-15 16:59:03 +00:00
player - > powers [ pw_tailsfly ] = tailsflytics + 1 ; // Set the fly timer
2017-03-18 21:06:06 +00:00
player - > pflags & = ~ ( PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING | PF_STARTDASH ) ;
2019-11-18 05:30:07 +00:00
if ( player - > bot = = 1 )
player - > pflags | = PF_THOKKED ;
else
player - > pflags | = ( PF_THOKKED | PF_CANCARRY ) ;
2014-03-15 16:59:03 +00:00
}
break ;
case CA_GLIDEANDCLIMB :
// Now Knuckles-type abilities are checked.
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
{
2019-10-28 13:30:36 +00:00
fixed_t glidespeed = FixedMul ( player - > actionspd , player - > mo - > scale ) ;
fixed_t playerspeed = player - > speed ;
2019-11-07 22:15:57 +00:00
2019-10-28 13:30:36 +00:00
if ( player - > mo - > eflags & MFE_UNDERWATER )
{
glidespeed > > = 1 ;
playerspeed > > = 1 ;
player - > mo - > momx = ( ( player - > mo - > momx - player - > cmomx ) > > 1 ) + player - > cmomx ;
player - > mo - > momy = ( ( player - > mo - > momy - player - > cmomy ) > > 1 ) + player - > cmomy ;
}
2014-03-15 16:59:03 +00:00
player - > pflags | = PF_GLIDING | PF_THOKKED ;
player - > glidetime = 0 ;
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_GLIDE ) ;
2019-10-28 13:30:36 +00:00
if ( playerspeed < glidespeed )
P_Thrust ( player - > mo , player - > mo - > angle , glidespeed - playerspeed ) ;
2014-03-15 16:59:03 +00:00
player - > pflags & = ~ ( PF_SPINNING | PF_STARTDASH ) ;
}
break ;
case CA_DOUBLEJUMP : // Double-Jump
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | ( ( player - > charflags & SF_MULTIABILITY ) & & ( player - > secondjump < ( player - > actionspd > > FRACBITS ) ) ) )
2014-03-15 16:59:03 +00:00
{
2016-12-24 00:11:54 +00:00
player - > pflags | = PF_THOKKED ;
2016-07-17 16:41:44 +00:00
player - > pflags & = ~ PF_JUMPED ;
P_DoJump ( player , true ) ;
player - > secondjump + + ;
2014-03-15 16:59:03 +00:00
}
break ;
case CA_FLOAT : // Float
case CA_SLOWFALL : // Slow descent hover
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | player - > charflags & SF_MULTIABILITY )
2016-12-24 00:11:54 +00:00
{
2019-10-23 04:35:17 +00:00
if ( player - > charflags & SF_DASHMODE & & player - > dashmode > = DASHMODE_THRESHOLD )
2017-03-11 02:09:01 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_DASH ) ;
2017-02-08 16:46:16 +00:00
else if ( player - > speed > = FixedMul ( player - > runspeed , player - > mo - > scale ) )
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLOAT_RUN ) ;
else
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLOAT ) ;
2016-12-24 00:11:54 +00:00
player - > pflags | = PF_THOKKED ;
2017-03-18 21:06:06 +00:00
player - > pflags & = ~ ( PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING ) ;
2014-03-15 16:59:03 +00:00
player - > secondjump = 1 ;
2016-12-24 00:11:54 +00:00
}
2014-03-15 16:59:03 +00:00
break ;
case CA_TELEKINESIS :
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
P_Telekinesis ( player ,
FixedMul ( player - > actionspd , player - > mo - > scale ) , // +ve thrust (pushing away from player)
FixedMul ( 384 * FRACUNIT , player - > mo - > scale ) ) ;
2014-03-15 16:59:03 +00:00
}
break ;
case CA_FALLSWITCH :
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
player - > mo - > momz = - player - > mo - > momz ;
P_SpawnThokMobj ( player ) ;
player - > pflags | = PF_THOKKED ;
2014-03-15 16:59:03 +00:00
}
break ;
case CA_AIRDRILL :
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
player - > flyangle = 56 + ( 60 - ( player - > actionspd > > FRACBITS ) ) / 3 ;
player - > pflags | = PF_THOKKED ;
S_StartSound ( player - > mo , sfx_spndsh ) ;
2014-03-15 16:59:03 +00:00
}
break ;
2016-12-23 17:31:07 +00:00
case CA_BOUNCE :
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | player - > charflags & SF_MULTIABILITY )
2016-12-23 17:31:07 +00:00
{
P_SetPlayerMobjState ( player - > mo , S_PLAY_BOUNCE ) ;
2017-03-18 21:06:06 +00:00
player - > pflags & = ~ ( PF_JUMPED | PF_NOJUMPDAMAGE ) ;
2016-12-23 23:13:31 +00:00
player - > pflags | = PF_THOKKED | PF_BOUNCING ;
2016-12-23 17:31:07 +00:00
player - > mo - > momx > > = 1 ;
player - > mo - > momy > > = 1 ;
2016-12-23 23:13:31 +00:00
player - > mo - > momz > > = 1 ;
2016-12-23 17:31:07 +00:00
}
break ;
2016-07-16 20:05:00 +00:00
case CA_TWINSPIN :
2017-03-27 14:03:21 +00:00
if ( ! ( player - > pflags & PF_THOKKED ) | | player - > charflags & SF_MULTIABILITY )
2016-07-16 20:05:00 +00:00
{
player - > pflags | = PF_THOKKED ;
2016-07-16 12:55:12 +00:00
S_StartSound ( player - > mo , sfx_s3k42 ) ;
player - > mo - > frame = 0 ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_TWINSPIN ) ;
2016-07-16 20:05:00 +00:00
}
2016-07-16 12:55:12 +00:00
break ;
2014-08-04 03:49:33 +00:00
default :
break ;
}
}
else if ( player - > pflags & PF_THOKKED )
{
# ifdef HAVE_BLUA
if ( ! LUAh_AbilitySpecial ( player ) )
# endif
switch ( player - > charability )
{
case CA_FLY :
case CA_SWIM : // Swim
if ( player - > charability = = CA_SWIM & & ! ( player - > mo - > eflags & MFE_UNDERWATER ) )
; // Can't do anything if you're a fish out of water!
else if ( player - > powers [ pw_tailsfly ] ) // If currently flying, give an ascend boost.
{
if ( ! player - > fly1 )
player - > fly1 = 20 ;
else
player - > fly1 = 2 ;
if ( player - > charability = = CA_SWIM )
player - > fly1 / = 2 ;
// Slow down!
if ( player - > speed > FixedMul ( 8 * FRACUNIT , player - > mo - > scale ) & & player - > speed > FixedMul ( player - > normalspeed > > 1 , player - > mo - > scale ) )
P_Thrust ( player - > mo , R_PointToAngle2 ( 0 , 0 , player - > mo - > momx , player - > mo - > momy ) , FixedMul ( - 4 * FRACUNIT , player - > mo - > scale ) ) ;
}
2014-03-15 16:59:03 +00:00
break ;
default :
break ;
}
}
2016-10-13 14:13:33 +00:00
else if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_WHIRLWIND & & ! player - > powers [ pw_super ] )
2014-08-04 03:49:33 +00:00
P_DoJumpShield ( player ) ;
2014-03-15 16:59:03 +00:00
}
2019-09-06 18:01:46 +00:00
// HOMING option.
if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ATTRACT // Sonic 3D Blast.
& & player - > pflags & PF_SHIELDABILITY )
{
if ( player - > homing & & player - > mo - > tracer )
{
if ( ! P_HomingAttack ( player - > mo , player - > mo - > tracer ) )
{
P_SetObjectMomZ ( player - > mo , 6 * FRACUNIT , false ) ;
if ( player - > mo - > eflags & MFE_UNDERWATER )
player - > mo - > momz = FixedMul ( player - > mo - > momz , FRACUNIT / 3 ) ;
player - > homing = 0 ;
}
}
// If you're not jumping, then you obviously wouldn't be homing.
if ( ! ( player - > pflags & PF_JUMPED ) )
player - > homing = 0 ;
}
else if ( player - > charability = = CA_HOMINGTHOK ) // Sonic Adventure.
{
// If you've got a target, chase after it!
if ( player - > homing & & player - > mo - > tracer )
{
P_SpawnThokMobj ( player ) ;
// But if you don't, then stop homing.
if ( ! P_HomingAttack ( player - > mo , player - > mo - > tracer ) )
{
if ( player - > mo - > eflags & MFE_UNDERWATER )
P_SetObjectMomZ ( player - > mo , FixedDiv ( 457 * FRACUNIT , 72 * FRACUNIT ) , false ) ;
else
P_SetObjectMomZ ( player - > mo , 10 * FRACUNIT , false ) ;
player - > mo - > momx = player - > mo - > momy = player - > homing = 0 ;
if ( player - > mo - > tracer - > flags2 & MF2_FRET )
P_InstaThrust ( player - > mo , player - > mo - > angle , - ( player - > speed > > 3 ) ) ;
if ( ! ( player - > mo - > tracer - > flags & MF_BOSS ) )
player - > pflags & = ~ PF_THOKKED ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_SPRING ) ;
player - > pflags | = PF_NOJUMPDAMAGE ;
}
}
// If you're not jumping, then you obviously wouldn't be homing.
if ( ! ( player - > pflags & PF_JUMPED ) )
player - > homing = 0 ;
}
else
player - > homing = 0 ;
2014-08-04 03:49:33 +00:00
if ( cmd - > buttons & BT_JUMP )
{
player - > pflags | = PF_JUMPDOWN ;
if ( ( gametype ! = GT_CTF | | ! player - > gotflag ) & & ! player - > exiting )
{
2017-03-20 16:57:24 +00:00
if ( player - > secondjump = = 1 & & player - > charability ! = CA_DOUBLEJUMP )
2014-08-04 03:49:33 +00:00
{
2016-12-24 00:11:54 +00:00
fixed_t potentialmomz ;
if ( player - > charability = = CA_SLOWFALL )
potentialmomz = - gravity * 4 ;
else
potentialmomz = ( ( player - > speed < 10 * player - > mo - > scale )
? ( player - > speed - 10 * player - > mo - > scale ) / 5
2019-11-25 16:20:43 +00:00
: - 1 ) ; // Should be 0, but made negative to ensure P_PlayerHitFloor runs upon touching ground
2016-12-24 00:11:54 +00:00
if ( P_MobjFlip ( player - > mo ) * player - > mo - > momz < potentialmomz )
player - > mo - > momz = P_MobjFlip ( player - > mo ) * potentialmomz ;
2014-08-04 03:49:33 +00:00
player - > pflags & = ~ PF_SPINNING ;
}
}
}
else // If not pressing the jump button
2014-03-15 16:59:03 +00:00
{
player - > pflags & = ~ PF_JUMPDOWN ;
// Repeat abilities, but not double jump!
2019-09-06 18:01:46 +00:00
if ( player - > secondjump = = 1 & & player - > charability ! = CA_DOUBLEJUMP & & player - > charability ! = CA_AIRDRILL )
2016-12-24 00:11:54 +00:00
{
2017-03-27 14:03:21 +00:00
if ( player - > charflags & SF_MULTIABILITY )
2016-12-24 00:11:54 +00:00
{
2017-03-27 14:03:21 +00:00
player - > pflags | = ( PF_JUMPED | PF_NOJUMPDAMAGE ) ;
2016-12-24 00:11:54 +00:00
player - > secondjump = 0 ;
}
else
player - > secondjump = 2 ;
2014-03-15 16:59:03 +00:00
2017-03-27 14:03:21 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2016-12-24 00:11:54 +00:00
}
2014-03-15 16:59:03 +00:00
2016-10-21 10:31:44 +00:00
// If letting go of the jump button while still on ascent, cut the jump height.
2017-03-22 18:51:30 +00:00
if ( ( ( player - > pflags & ( PF_JUMPED | PF_STARTJUMP ) ) = = ( PF_JUMPED | PF_STARTJUMP ) ) & & ( P_MobjFlip ( player - > mo ) * player - > mo - > momz > 0 ) )
2014-08-04 03:49:33 +00:00
{
2016-10-21 10:31:44 +00:00
player - > mo - > momz > > = 1 ;
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ PF_STARTJUMP ;
2014-03-15 16:59:03 +00:00
}
}
2014-08-04 03:49:33 +00:00
}
2014-03-15 16:59:03 +00:00
2017-03-20 16:57:24 +00:00
#if 0
2016-04-05 19:56:48 +00:00
boolean P_AnalogMove ( player_t * player )
2014-08-04 03:49:33 +00:00
{
2014-11-12 00:55:07 +00:00
return player - > pflags & PF_ANALOGMODE ;
2014-03-15 16:59:03 +00:00
}
2017-03-20 16:57:24 +00:00
# endif
2014-03-15 16:59:03 +00:00
//
// P_GetPlayerControlDirection
//
// Determines if the player is pressing in the direction they are moving
//
2014-08-27 03:56:30 +00:00
// 0 = no controls pressed/no movement
2014-03-15 16:59:03 +00:00
// 1 = pressing in the direction of movement
// 2 = pressing in the opposite direction of movement
//
INT32 P_GetPlayerControlDirection ( player_t * player )
{
ticcmd_t * cmd = & player - > cmd ;
angle_t controllerdirection , controlplayerdirection ;
camera_t * thiscam ;
2014-08-04 03:49:33 +00:00
angle_t dangle ;
fixed_t tempx = 0 , tempy = 0 ;
angle_t tempangle , origtempangle ;
2014-03-15 16:59:03 +00:00
if ( splitscreen & & player = = & players [ secondarydisplayplayer ] )
thiscam = & camera2 ;
else
thiscam = & camera ;
2014-08-04 03:49:33 +00:00
if ( ! cmd - > forwardmove & & ! cmd - > sidemove )
return 0 ;
2014-03-15 16:59:03 +00:00
2014-08-27 03:56:30 +00:00
if ( ! player - > mo - > momx & & ! player - > mo - > momy )
return 0 ;
if ( twodlevel | | player - > mo - > flags2 & MF2_TWOD )
{
if ( ! cmd - > sidemove )
return 0 ;
if ( ! player - > mo - > momx )
return 0 ;
origtempangle = tempangle = 0 ; // relative to the axis rather than the player!
controlplayerdirection = R_PointToAngle2 ( 0 , 0 , player - > mo - > momx , player - > mo - > momy ) ;
}
else if ( P_AnalogMove ( player ) & & thiscam - > chase )
2014-08-04 03:49:33 +00:00
{
if ( player - > awayviewtics )
origtempangle = tempangle = player - > awayviewmobj - > angle ;
else
origtempangle = tempangle = thiscam - > angle ;
2014-03-15 16:59:03 +00:00
controlplayerdirection = player - > mo - > angle ;
}
else
{
2014-08-04 03:49:33 +00:00
origtempangle = tempangle = player - > mo - > angle ;
controlplayerdirection = R_PointToAngle2 ( 0 , 0 , player - > mo - > momx , player - > mo - > momy ) ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
// Calculate the angle at which the controls are pointing
// to figure out the proper mforward and mbackward.
tempangle > > = ANGLETOFINESHIFT ;
2014-08-27 03:56:30 +00:00
if ( ! ( twodlevel | | player - > mo - > flags2 & MF2_TWOD ) ) // in 2d mode, sidemove is treated as the forwards/backwards direction
{
tempx + = FixedMul ( cmd - > forwardmove * FRACUNIT , FINECOSINE ( tempangle ) ) ;
tempy + = FixedMul ( cmd - > forwardmove * FRACUNIT , FINESINE ( tempangle ) ) ;
2014-03-15 16:59:03 +00:00
2014-08-27 03:56:30 +00:00
tempangle = origtempangle - ANGLE_90 ;
tempangle > > = ANGLETOFINESHIFT ;
}
2014-08-04 03:49:33 +00:00
tempx + = FixedMul ( cmd - > sidemove * FRACUNIT , FINECOSINE ( tempangle ) ) ;
tempy + = FixedMul ( cmd - > sidemove * FRACUNIT , FINESINE ( tempangle ) ) ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
controllerdirection = R_PointToAngle2 ( 0 , 0 , tempx , tempy ) ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
dangle = controllerdirection - controlplayerdirection ;
if ( dangle > ANGLE_180 ) //flip to keep to one side
dangle = InvAngle ( dangle ) ;
if ( dangle > ANGLE_90 )
return 2 ; // Controls pointing backwards from player
else
return 1 ; // Controls pointing in player's general direction
2014-03-15 16:59:03 +00:00
}
// Control scheme for 2d levels.
static void P_2dMovement ( player_t * player )
{
ticcmd_t * cmd ;
INT32 topspeed , acceleration , thrustfactor ;
fixed_t movepushforward = 0 ;
angle_t movepushangle = 0 ;
fixed_t normalspd = FixedMul ( player - > normalspeed , player - > mo - > scale ) ;
cmd = & player - > cmd ;
if ( player - > exiting | | player - > pflags & PF_STASIS )
{
cmd - > forwardmove = cmd - > sidemove = 0 ;
2014-03-25 02:17:59 +00:00
if ( player - > pflags & PF_GLIDING )
{
if ( ! player - > skidtime )
player - > pflags & = ~ PF_GLIDING ;
else if ( player - > exiting )
{
player - > pflags & = ~ PF_GLIDING ;
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
2014-03-25 02:17:59 +00:00
player - > skidtime = 0 ;
}
}
2017-02-09 23:24:47 +00:00
if ( player - > pflags & PF_BOUNCING )
player - > pflags & = ~ PF_BOUNCING ;
2014-03-15 16:59:03 +00:00
if ( player - > pflags & PF_SPINNING & & ! player - > exiting )
{
player - > pflags & = ~ PF_SPINNING ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
}
// cmomx/cmomy stands for the conveyor belt speed.
if ( player - > onconveyor = = 2 ) // Wind/Current
{
//if (player->mo->z > player->mo->watertop || player->mo->z + player->mo->height < player->mo->waterbottom)
if ( ! ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_TOUCHWATER ) ) )
player - > cmomx = player - > cmomy = 0 ;
}
else if ( player - > onconveyor = = 4 & & ! P_IsObjectOnGround ( player - > mo ) ) // Actual conveyor belt
player - > cmomx = player - > cmomy = 0 ;
2014-11-12 00:55:07 +00:00
else if ( player - > onconveyor ! = 2 & & player - > onconveyor ! = 4
# ifdef POLYOBJECTS
& & player - > onconveyor ! = 1
# endif
)
2014-03-15 16:59:03 +00:00
player - > cmomx = player - > cmomy = 0 ;
player - > rmomx = player - > mo - > momx - player - > cmomx ;
player - > rmomy = player - > mo - > momy - player - > cmomy ;
// Calculates player's speed based on absolute-value-of-a-number formula
player - > speed = abs ( player - > rmomx ) ;
if ( player - > pflags & PF_GLIDING )
{
// Angle fix.
if ( player - > mo - > angle < ANGLE_180 & & player - > mo - > angle > ANGLE_90 )
player - > mo - > angle = ANGLE_180 ;
else if ( player - > mo - > angle < ANGLE_90 & & player - > mo - > angle > 0 )
player - > mo - > angle = 0 ;
if ( cmd - > sidemove > 0 & & player - > mo - > angle ! = 0 & & player - > mo - > angle > = ANGLE_180 )
player - > mo - > angle + = 1280 < < FRACBITS ;
else if ( cmd - > sidemove < 0 & & player - > mo - > angle ! = ANGLE_180 & & ( player - > mo - > angle > ANGLE_180 | | player - > mo - > angle = = 0 ) )
player - > mo - > angle - = 1280 < < FRACBITS ;
else if ( cmd - > sidemove = = 0 )
{
if ( player - > mo - > angle > = ANGLE_270 )
player - > mo - > angle + = 1280 < < FRACBITS ;
else if ( player - > mo - > angle < ANGLE_270 & & player - > mo - > angle > ANGLE_180 )
player - > mo - > angle - = 1280 < < FRACBITS ;
}
}
else if ( cmd - > sidemove & & ! ( player - > climbing ) & & ! P_PlayerInPain ( player ) )
{
if ( cmd - > sidemove > 0 )
player - > mo - > angle = 0 ;
else if ( cmd - > sidemove < 0 )
player - > mo - > angle = ANGLE_180 ;
}
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
if ( player - > pflags & PF_GLIDING )
movepushangle = player - > mo - > angle ;
else
{
if ( cmd - > sidemove > 0 )
movepushangle = 0 ;
else if ( cmd - > sidemove < 0 )
movepushangle = ANGLE_180 ;
else
movepushangle = player - > mo - > angle ;
}
// Do not let the player control movement if not onground.
onground = P_IsObjectOnGround ( player - > mo ) ;
player - > aiming = cmd - > aiming < < FRACBITS ;
// Set the player speeds.
if ( maptol & TOL_2D )
normalspd = FixedMul ( normalspd , 2 * FRACUNIT / 3 ) ;
if ( player - > powers [ pw_super ] | | player - > powers [ pw_sneakers ] )
{
thrustfactor = player - > thrustfactor * 2 ;
acceleration = player - > accelstart / 2 + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration / 2 ;
if ( player - > powers [ pw_tailsfly ] )
topspeed = normalspd ;
else if ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_GOOWATER ) & & ! ( player - > pflags & PF_SLIDING ) )
{
topspeed = normalspd ;
acceleration = 2 * acceleration / 3 ;
}
else
topspeed = normalspd * 2 ;
}
else
{
thrustfactor = player - > thrustfactor ;
acceleration = player - > accelstart + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration ;
if ( player - > powers [ pw_tailsfly ] )
topspeed = normalspd / 2 ;
else if ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_GOOWATER ) & & ! ( player - > pflags & PF_SLIDING ) )
{
topspeed = normalspd / 2 ;
acceleration = 2 * acceleration / 3 ;
}
else
topspeed = normalspd ;
}
//////////////////////////////////////
if ( player - > climbing )
{
if ( cmd - > forwardmove ! = 0 )
2019-09-23 18:17:20 +00:00
P_SetObjectMomZ ( player - > mo , FixedDiv ( cmd - > forwardmove * FRACUNIT , 15 * FRACUNIT > > 1 ) , false ) ;
2014-03-15 16:59:03 +00:00
player - > mo - > momx = 0 ;
}
2014-08-04 03:49:33 +00:00
else if ( cmd - > sidemove ! = 0 & & ! ( player - > pflags & PF_GLIDING | | player - > exiting
2014-03-15 16:59:03 +00:00
| | ( P_PlayerInPain ( player ) & & ! onground ) ) )
{
movepushforward = abs ( cmd - > sidemove ) * ( thrustfactor * acceleration ) ;
// allow very small movement while in air for gameplay
if ( ! onground )
movepushforward > > = 1 ; // Proper air movement
// Allow a bit of movement while spinning
2019-11-09 17:49:26 +00:00
if ( ( player - > pflags & ( PF_SPINNING | PF_THOKKED ) ) = = PF_SPINNING )
2014-03-15 16:59:03 +00:00
{
if ( ! ( player - > pflags & PF_STARTDASH ) )
movepushforward = movepushforward / 48 ;
else
movepushforward = 0 ;
}
movepushforward = FixedMul ( movepushforward , player - > mo - > scale ) ;
if ( player - > rmomx < topspeed & & cmd - > sidemove > 0 ) // Sonic's Speed
P_Thrust ( player - > mo , movepushangle , movepushforward ) ;
else if ( player - > rmomx > - topspeed & & cmd - > sidemove < 0 )
P_Thrust ( player - > mo , movepushangle , movepushforward ) ;
}
}
//#define OLD_MOVEMENT_CODE 1
static void P_3dMovement ( player_t * player )
{
ticcmd_t * cmd ;
angle_t movepushangle , movepushsideangle ; // Analog
INT32 topspeed , acceleration , thrustfactor ;
fixed_t movepushforward = 0 , movepushside = 0 ;
INT32 mforward = 0 , mbackward = 0 ;
angle_t dangle ; // replaces old quadrants bits
fixed_t normalspd = FixedMul ( player - > normalspeed , player - > mo - > scale ) ;
boolean analogmove = false ;
2019-11-09 17:49:26 +00:00
boolean spin = ( ( onground = P_IsObjectOnGround ( player - > mo ) ) & & ( player - > pflags & ( PF_SPINNING | PF_THOKKED ) ) = = PF_SPINNING & & ( player - > rmomx | | player - > rmomy ) & & ! ( player - > pflags & PF_STARTDASH ) ) ;
2014-03-15 16:59:03 +00:00
fixed_t oldMagnitude , newMagnitude ;
2015-04-30 05:32:44 +00:00
# ifdef ESLOPE
2015-05-23 03:07:07 +00:00
vector3_t totalthrust ;
2015-04-30 05:32:44 +00:00
totalthrust . x = totalthrust . y = 0 ; // I forget if this is needed
2015-05-13 21:02:19 +00:00
totalthrust . z = FRACUNIT * P_MobjFlip ( player - > mo ) / 3 ; // A bit of extra push-back on slopes
2015-04-30 05:32:44 +00:00
# endif // ESLOPE
2014-03-15 16:59:03 +00:00
// Get the old momentum; this will be needed at the end of the function! -SH
2014-11-12 00:55:07 +00:00
oldMagnitude = R_PointToDist2 ( player - > mo - > momx - player - > cmomx , player - > mo - > momy - player - > cmomy , 0 , 0 ) ;
2014-03-15 16:59:03 +00:00
2014-11-12 00:55:07 +00:00
analogmove = P_AnalogMove ( player ) ;
2014-03-15 16:59:03 +00:00
cmd = & player - > cmd ;
if ( player - > exiting | | player - > pflags & PF_STASIS )
{
cmd - > forwardmove = cmd - > sidemove = 0 ;
2014-03-25 02:17:59 +00:00
if ( player - > pflags & PF_GLIDING )
{
if ( ! player - > skidtime )
player - > pflags & = ~ PF_GLIDING ;
else if ( player - > exiting )
{
player - > pflags & = ~ PF_GLIDING ;
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
2014-03-25 02:17:59 +00:00
player - > skidtime = 0 ;
}
}
2017-02-09 23:24:47 +00:00
if ( player - > pflags & PF_BOUNCING )
player - > pflags & = ~ PF_BOUNCING ;
2014-03-15 16:59:03 +00:00
if ( player - > pflags & PF_SPINNING & & ! player - > exiting )
{
player - > pflags & = ~ PF_SPINNING ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
}
if ( analogmove )
{
2014-11-12 00:55:07 +00:00
movepushangle = ( cmd - > angleturn < < 16 /* not FRACBITS */ ) ;
2014-03-15 16:59:03 +00:00
}
else
{
movepushangle = player - > mo - > angle ;
}
2014-11-12 00:55:07 +00:00
movepushsideangle = movepushangle - ANGLE_90 ;
2014-03-15 16:59:03 +00:00
// cmomx/cmomy stands for the conveyor belt speed.
if ( player - > onconveyor = = 2 ) // Wind/Current
{
//if (player->mo->z > player->mo->watertop || player->mo->z + player->mo->height < player->mo->waterbottom)
if ( ! ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_TOUCHWATER ) ) )
player - > cmomx = player - > cmomy = 0 ;
}
else if ( player - > onconveyor = = 4 & & ! P_IsObjectOnGround ( player - > mo ) ) // Actual conveyor belt
player - > cmomx = player - > cmomy = 0 ;
2014-11-12 00:55:07 +00:00
else if ( player - > onconveyor ! = 2 & & player - > onconveyor ! = 4
# ifdef POLYOBJECTS
& & player - > onconveyor ! = 1
# endif
)
2014-03-15 16:59:03 +00:00
player - > cmomx = player - > cmomy = 0 ;
player - > rmomx = player - > mo - > momx - player - > cmomx ;
player - > rmomy = player - > mo - > momy - player - > cmomy ;
// Calculates player's speed based on distance-of-a-line formula
player - > speed = P_AproxDistance ( player - > rmomx , player - > rmomy ) ;
// Monster Iestyn - 04-11-13
// Quadrants are stupid, excessive and broken, let's do this a much simpler way!
// Get delta angle from rmom angle and player angle first
dangle = R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) - player - > mo - > angle ;
if ( dangle > ANGLE_180 ) //flip to keep to one side
dangle = InvAngle ( dangle ) ;
// now use it to determine direction!
if ( dangle < = ANGLE_45 ) // angles 0-45 or 315-360
mforward = 1 ; // going forwards
else if ( dangle > = ANGLE_135 ) // angles 135-225
mbackward = 1 ; // going backwards
// anything else will leave both at 0, so no need to do anything else
// When sliding, don't allow forward/back
if ( player - > pflags & PF_SLIDING )
cmd - > forwardmove = 0 ;
2019-11-26 10:11:52 +00:00
else if ( onground & & player - > mo - > state = = states + S_PLAY_PAIN )
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
2014-03-15 16:59:03 +00:00
player - > aiming = cmd - > aiming < < FRACBITS ;
// Set the player speeds.
if ( player - > pflags & PF_SLIDING )
{
normalspd = FixedMul ( 36 < < FRACBITS , player - > mo - > scale ) ;
thrustfactor = 5 ;
acceleration = 96 + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * 40 ;
topspeed = normalspd ;
}
else if ( player - > bot )
{ // Bot steals player 1's stats
normalspd = FixedMul ( players [ consoleplayer ] . normalspeed , player - > mo - > scale ) ;
thrustfactor = players [ consoleplayer ] . thrustfactor ;
acceleration = players [ consoleplayer ] . accelstart + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * players [ consoleplayer ] . acceleration ;
if ( player - > powers [ pw_tailsfly ] )
topspeed = normalspd / 2 ;
else if ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_GOOWATER ) )
{
topspeed = normalspd / 2 ;
acceleration = 2 * acceleration / 3 ;
}
else
topspeed = normalspd ;
}
2019-10-09 13:39:51 +00:00
else
2014-03-15 16:59:03 +00:00
{
2019-10-09 13:39:51 +00:00
if ( player - > powers [ pw_super ] | | player - > powers [ pw_sneakers ] )
2014-03-15 16:59:03 +00:00
{
2019-10-09 13:39:51 +00:00
topspeed = 5 * normalspd / 3 ; // 1.67x
thrustfactor = player - > thrustfactor * 2 ;
acceleration = player - > accelstart / 2 + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration / 2 ;
2014-03-15 16:59:03 +00:00
}
else
2019-10-09 13:39:51 +00:00
{
topspeed = normalspd ;
thrustfactor = player - > thrustfactor ;
acceleration = player - > accelstart + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration ;
}
2014-03-15 16:59:03 +00:00
if ( player - > powers [ pw_tailsfly ] )
2019-10-09 13:39:51 +00:00
topspeed > > = 1 ;
2014-03-15 16:59:03 +00:00
else if ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_GOOWATER ) )
{
2019-10-09 13:39:51 +00:00
topspeed > > = 1 ;
2014-03-15 16:59:03 +00:00
acceleration = 2 * acceleration / 3 ;
}
}
2017-02-09 23:24:47 +00:00
if ( spin ) // Prevent gaining speed whilst rolling!
{
const fixed_t ns = FixedDiv ( 549 * ORIG_FRICTION , 500 * FRACUNIT ) ; // P_XYFriction
2017-07-26 15:10:08 +00:00
topspeed = FixedMul ( oldMagnitude , ns ) ;
2017-02-09 23:24:47 +00:00
}
2014-03-15 16:59:03 +00:00
// Better maneuverability while flying
2016-12-23 17:31:07 +00:00
if ( player - > powers [ pw_tailsfly ] )
2014-03-15 16:59:03 +00:00
{
thrustfactor = player - > thrustfactor * 2 ;
acceleration = player - > accelstart + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration ;
}
2017-02-04 18:25:16 +00:00
else
2016-12-23 17:31:07 +00:00
{
2017-02-04 18:25:16 +00:00
if ( player - > pflags & PF_BOUNCING )
{
if ( player - > mo - > state - states = = S_PLAY_BOUNCE_LANDING )
{
2017-02-04 21:41:43 +00:00
thrustfactor = player - > thrustfactor * 8 ;
acceleration = player - > accelstart / 8 + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration / 8 ;
2017-02-04 18:25:16 +00:00
}
else
{
2017-02-04 21:41:43 +00:00
thrustfactor = ( 3 * player - > thrustfactor ) / 4 ;
acceleration = player - > accelstart + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration ;
2017-02-04 18:25:16 +00:00
}
}
2014-03-15 16:59:03 +00:00
2017-02-04 18:25:16 +00:00
if ( player - > mo - > movefactor ! = FRACUNIT ) // Friction-scaled acceleration...
acceleration = FixedMul ( acceleration < < FRACBITS , player - > mo - > movefactor ) > > FRACBITS ;
}
2016-06-03 16:26:50 +00:00
2014-03-15 16:59:03 +00:00
// Forward movement
if ( player - > climbing )
{
if ( cmd - > forwardmove )
2019-10-28 14:21:20 +00:00
{
if ( player - > mo - > eflags & MFE_UNDERWATER )
P_SetObjectMomZ ( player - > mo , FixedDiv ( cmd - > forwardmove * FRACUNIT , 10 * FRACUNIT ) , false ) ;
else
P_SetObjectMomZ ( player - > mo , FixedDiv ( cmd - > forwardmove * FRACUNIT , 15 * FRACUNIT > > 1 ) , false ) ;
}
2014-03-15 16:59:03 +00:00
}
else if ( ! analogmove
& & cmd - > forwardmove ! = 0 & & ! ( player - > pflags & PF_GLIDING | | player - > exiting
| | ( P_PlayerInPain ( player ) & & ! onground ) ) )
{
movepushforward = cmd - > forwardmove * ( thrustfactor * acceleration ) ;
// Allow a bit of movement while spinning
2019-11-09 17:49:26 +00:00
if ( ( player - > pflags & ( PF_SPINNING | PF_THOKKED ) ) = = PF_SPINNING )
2014-03-15 16:59:03 +00:00
{
2017-03-21 00:54:47 +00:00
if ( ( mforward & & cmd - > forwardmove > 0 ) | | ( mbackward & & cmd - > forwardmove < 0 )
| | ( player - > pflags & PF_STARTDASH ) )
2014-03-15 16:59:03 +00:00
movepushforward = 0 ;
2017-07-26 15:34:33 +00:00
else if ( onground )
2017-07-26 15:10:08 +00:00
movepushforward > > = 4 ;
2014-03-15 16:59:03 +00:00
else
2017-07-26 15:34:33 +00:00
movepushforward > > = 3 ;
2014-03-15 16:59:03 +00:00
}
2017-07-26 15:34:33 +00:00
// allow very small movement while in air for gameplay
else if ( ! onground )
movepushforward > > = 2 ; // proper air movement
2014-03-15 16:59:03 +00:00
movepushforward = FixedMul ( movepushforward , player - > mo - > scale ) ;
2015-04-30 05:32:44 +00:00
# ifdef ESLOPE
totalthrust . x + = P_ReturnThrustX ( player - > mo , movepushangle , movepushforward ) ;
totalthrust . y + = P_ReturnThrustY ( player - > mo , movepushangle , movepushforward ) ;
2014-03-15 16:59:03 +00:00
# else
P_Thrust ( player - > mo , movepushangle , movepushforward ) ;
# endif
}
// Sideways movement
if ( player - > climbing )
2019-10-28 14:21:20 +00:00
{
if ( player - > mo - > eflags & MFE_UNDERWATER )
P_InstaThrust ( player - > mo , player - > mo - > angle - ANGLE_90 , FixedDiv ( cmd - > sidemove * player - > mo - > scale , 10 * FRACUNIT ) ) ;
else
P_InstaThrust ( player - > mo , player - > mo - > angle - ANGLE_90 , FixedDiv ( cmd - > sidemove * player - > mo - > scale , 15 * FRACUNIT > > 1 ) ) ;
}
2014-03-15 16:59:03 +00:00
// Analog movement control
else if ( analogmove )
{
if ( ! ( player - > pflags & PF_GLIDING | | player - > exiting | | P_PlayerInPain ( player ) ) )
{
2014-08-04 03:49:33 +00:00
angle_t controldirection ;
2014-03-15 16:59:03 +00:00
// Calculate the angle at which the controls are pointing
// to figure out the proper mforward and mbackward.
2014-11-12 00:55:07 +00:00
// (Why was it so complicated before? ~Red)
controldirection = R_PointToAngle2 ( 0 , 0 , cmd - > forwardmove * FRACUNIT , - cmd - > sidemove * FRACUNIT ) + movepushangle ;
2014-03-15 16:59:03 +00:00
2019-12-05 07:59:16 +00:00
movepushforward = FixedHypot ( cmd - > sidemove , cmd - > forwardmove ) * ( thrustfactor * acceleration ) ;
2014-03-15 16:59:03 +00:00
// Allow a bit of movement while spinning
2019-11-09 17:49:26 +00:00
if ( ( player - > pflags & ( PF_SPINNING | PF_THOKKED ) ) = = PF_SPINNING )
2014-03-15 16:59:03 +00:00
{
2017-03-21 00:54:47 +00:00
if ( ( mforward & & cmd - > forwardmove > 0 ) | | ( mbackward & & cmd - > forwardmove < 0 )
| | ( player - > pflags & PF_STARTDASH ) )
2014-03-15 16:59:03 +00:00
movepushforward = 0 ;
2017-07-26 15:34:33 +00:00
else if ( onground )
2017-07-26 15:10:08 +00:00
movepushforward > > = 4 ;
2014-03-15 16:59:03 +00:00
else
2017-07-26 15:34:33 +00:00
movepushforward > > = 3 ;
2014-03-15 16:59:03 +00:00
}
2017-07-26 15:34:33 +00:00
// allow very small movement while in air for gameplay
else if ( ! onground )
movepushforward > > = 2 ; // proper air movement
2014-03-15 16:59:03 +00:00
movepushsideangle = controldirection ;
movepushforward = FixedMul ( movepushforward , player - > mo - > scale ) ;
2015-04-30 05:32:44 +00:00
# ifdef ESLOPE
totalthrust . x + = P_ReturnThrustX ( player - > mo , controldirection , movepushforward ) ;
totalthrust . y + = P_ReturnThrustY ( player - > mo , controldirection , movepushforward ) ;
2014-03-15 16:59:03 +00:00
# else
P_Thrust ( player - > mo , controldirection , movepushforward ) ;
# endif
}
}
2014-08-04 03:49:33 +00:00
else if ( cmd - > sidemove & & ! ( player - > pflags & PF_GLIDING ) & & ! player - > exiting & & ! P_PlayerInPain ( player ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
movepushside = cmd - > sidemove * ( thrustfactor * acceleration ) ;
2014-03-15 16:59:03 +00:00
2017-07-26 15:34:33 +00:00
// allow very small movement while in air for gameplay
2014-08-04 03:49:33 +00:00
if ( ! onground )
{
2017-07-26 15:34:33 +00:00
movepushside > > = 2 ; // proper air movement
2014-08-04 03:49:33 +00:00
// Reduce movepushslide even more if over "max" flight speed
2019-11-09 17:49:26 +00:00
if ( ( ( player - > pflags & ( PF_SPINNING | PF_THOKKED ) ) = = PF_SPINNING ) | | ( player - > powers [ pw_tailsfly ] & & player - > speed > topspeed ) )
2014-03-15 16:59:03 +00:00
movepushside > > = 2 ;
2014-08-04 03:49:33 +00:00
}
// Allow a bit of movement while spinning
2019-11-09 17:49:26 +00:00
else if ( ( player - > pflags & ( PF_SPINNING | PF_THOKKED ) ) = = PF_SPINNING )
2014-08-04 03:49:33 +00:00
{
2017-07-26 15:34:33 +00:00
if ( player - > pflags & PF_STARTDASH )
2014-08-04 03:49:33 +00:00
movepushside = 0 ;
2017-07-26 15:34:33 +00:00
else if ( onground )
movepushside > > = 4 ;
2017-03-21 00:54:47 +00:00
else
2017-07-26 15:34:33 +00:00
movepushside > > = 3 ;
2014-08-04 03:49:33 +00:00
}
2014-03-15 16:59:03 +00:00
2017-07-26 15:34:33 +00:00
// Finally move the player now that their speed/direction has been decided.
2014-08-04 03:49:33 +00:00
movepushside = FixedMul ( movepushside , player - > mo - > scale ) ;
2015-04-30 05:32:44 +00:00
# ifdef ESLOPE
totalthrust . x + = P_ReturnThrustX ( player - > mo , movepushsideangle , movepushside ) ;
totalthrust . y + = P_ReturnThrustY ( player - > mo , movepushsideangle , movepushside ) ;
2014-08-04 03:49:33 +00:00
# else
P_Thrust ( player - > mo , movepushsideangle , movepushside ) ;
2014-03-15 16:59:03 +00:00
# endif
}
2015-04-30 05:32:44 +00:00
# ifdef ESLOPE
if ( ( totalthrust . x | | totalthrust . y )
2016-05-31 14:01:19 +00:00
& & player - > mo - > standingslope & & ( ! ( player - > mo - > standingslope - > flags & SL_NOPHYSICS ) ) & & abs ( player - > mo - > standingslope - > zdelta ) > FRACUNIT / 2 ) {
2015-04-30 05:32:44 +00:00
// Factor thrust to slope, but only for the part pushing up it!
// The rest is unaffected.
angle_t thrustangle = R_PointToAngle2 ( 0 , 0 , totalthrust . x , totalthrust . y ) - player - > mo - > standingslope - > xydirection ;
if ( player - > mo - > standingslope - > zdelta < 0 ) { // Direction goes down, so thrustangle needs to face toward
if ( thrustangle < ANGLE_90 | | thrustangle > ANGLE_270 ) {
P_QuantizeMomentumToSlope ( & totalthrust , player - > mo - > standingslope ) ;
}
} else { // Direction goes up, so thrustangle needs to face away
if ( thrustangle > ANGLE_90 & & thrustangle < ANGLE_270 ) {
P_QuantizeMomentumToSlope ( & totalthrust , player - > mo - > standingslope ) ;
}
}
}
player - > mo - > momx + = totalthrust . x ;
player - > mo - > momy + = totalthrust . y ;
# endif
2014-03-15 16:59:03 +00:00
// Time to ask three questions:
// 1) Are we over topspeed?
// 2) If "yes" to 1, were we moving over topspeed to begin with?
// 3) If "yes" to 2, are we now going faster?
// If "yes" to 3, normalize to our initial momentum; this will allow thoks to stay as fast as they normally are.
// If "no" to 3, ignore it; the player might be going too fast, but they're slowing down, so let them.
// If "no" to 2, normalize to topspeed, so we can't suddenly run faster than it of our own accord.
// If "no" to 1, we're not reaching any limits yet, so ignore this entirely!
// -Shadow Hog
2014-11-12 00:55:07 +00:00
newMagnitude = R_PointToDist2 ( player - > mo - > momx - player - > cmomx , player - > mo - > momy - player - > cmomy , 0 , 0 ) ;
2014-03-15 16:59:03 +00:00
if ( newMagnitude > topspeed )
{
2014-11-12 00:55:07 +00:00
fixed_t tempmomx , tempmomy ;
2017-02-09 23:24:47 +00:00
if ( oldMagnitude > topspeed & & ! spin )
2014-03-15 16:59:03 +00:00
{
if ( newMagnitude > oldMagnitude )
{
2014-11-12 00:55:07 +00:00
tempmomx = FixedMul ( FixedDiv ( player - > mo - > momx - player - > cmomx , newMagnitude ) , oldMagnitude ) ;
tempmomy = FixedMul ( FixedDiv ( player - > mo - > momy - player - > cmomy , newMagnitude ) , oldMagnitude ) ;
player - > mo - > momx = tempmomx + player - > cmomx ;
player - > mo - > momy = tempmomy + player - > cmomy ;
2014-03-15 16:59:03 +00:00
}
// else do nothing
}
else
{
2014-11-12 00:55:07 +00:00
tempmomx = FixedMul ( FixedDiv ( player - > mo - > momx - player - > cmomx , newMagnitude ) , topspeed ) ;
tempmomy = FixedMul ( FixedDiv ( player - > mo - > momy - player - > cmomy , newMagnitude ) , topspeed ) ;
player - > mo - > momx = tempmomx + player - > cmomx ;
player - > mo - > momy = tempmomy + player - > cmomy ;
2014-03-15 16:59:03 +00:00
}
}
}
//
// P_SpectatorMovement
//
// Control for spectators in multiplayer
//
static void P_SpectatorMovement ( player_t * player )
{
ticcmd_t * cmd = & player - > cmd ;
player - > mo - > angle = ( cmd - > angleturn < < 16 /* not FRACBITS */ ) ;
ticruned + + ;
if ( ! ( cmd - > angleturn & TICCMD_RECEIVED ) )
ticmiss + + ;
if ( cmd - > buttons & BT_JUMP )
player - > mo - > z + = FRACUNIT * 16 ;
else if ( cmd - > buttons & BT_USE )
player - > mo - > z - = FRACUNIT * 16 ;
2017-07-08 10:41:20 +00:00
if ( player - > mo - > z > player - > mo - > ceilingz - player - > mo - > height )
player - > mo - > z = player - > mo - > ceilingz - player - > mo - > height ;
if ( player - > mo - > z < player - > mo - > floorz )
player - > mo - > z = player - > mo - > floorz ;
2014-03-15 16:59:03 +00:00
// Aiming needed for SEENAMES, etc.
// We may not need to fire as a spectator, but this is still handy!
player - > aiming = cmd - > aiming < < FRACBITS ;
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
if ( cmd - > forwardmove ! = 0 )
{
P_Thrust ( player - > mo , player - > mo - > angle , cmd - > forwardmove * ( FRACUNIT / 2 ) ) ;
// Quake-style flying spectators :D
player - > mo - > momz + = FixedMul ( cmd - > forwardmove * ( FRACUNIT / 2 ) , AIMINGTOSLOPE ( player - > aiming ) ) ;
}
if ( cmd - > sidemove ! = 0 )
{
P_Thrust ( player - > mo , player - > mo - > angle - ANGLE_90 , cmd - > sidemove * ( FRACUNIT / 2 ) ) ;
}
}
//
// P_ShootLine
//
// Fun and fancy
// graphical indicator
// for building/debugging
// NiGHTS levels!
static void P_ShootLine ( mobj_t * source , mobj_t * dest , fixed_t height )
{
mobj_t * mo ;
INT32 i ;
fixed_t temp ;
INT32 speed , seesound ;
temp = dest - > z ;
dest - > z = height ;
seesound = mobjinfo [ MT_REDRING ] . seesound ;
speed = mobjinfo [ MT_REDRING ] . speed ;
mobjinfo [ MT_REDRING ] . seesound = sfx_None ;
mobjinfo [ MT_REDRING ] . speed = 20 * FRACUNIT ;
mo = P_SpawnXYZMissile ( source , dest , MT_REDRING , source - > x , source - > y , height ) ;
dest - > z = temp ;
if ( mo )
{
mo - > flags2 | = MF2_RAILRING ;
mo - > flags2 | = MF2_DONTDRAW ;
mo - > flags | = MF_NOCLIPHEIGHT ;
mo - > flags | = MF_NOCLIP ;
mo - > flags & = ~ MF_MISSILE ;
mo - > fuse = 3 ;
}
for ( i = 0 ; i < 32 ; i + + )
{
if ( mo )
{
if ( ! ( mo - > flags & MF_NOBLOCKMAP ) )
{
P_UnsetThingPosition ( mo ) ;
mo - > flags | = MF_NOBLOCKMAP ;
P_SetThingPosition ( mo ) ;
}
if ( i & 1 )
P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_SPARK ) ;
P_UnsetThingPosition ( mo ) ;
mo - > x + = mo - > momx ;
mo - > y + = mo - > momy ;
mo - > z + = mo - > momz ;
P_SetThingPosition ( mo ) ;
}
else
{
mobjinfo [ MT_REDRING ] . seesound = seesound ;
mobjinfo [ MT_REDRING ] . speed = speed ;
return ;
}
}
mobjinfo [ MT_REDRING ] . seesound = seesound ;
mobjinfo [ MT_REDRING ] . speed = speed ;
}
# define MAXDRILLSPEED 14000
# define MAXNORMALSPEED 6250 //6000
static void P_NightsTransferPoints ( player_t * player , fixed_t xspeed , fixed_t radius )
{
if ( player - > pflags & PF_TRANSFERTOCLOSEST )
{
const angle_t fa = R_PointToAngle2 ( player - > axis1 - > x , player - > axis1 - > y , player - > axis2 - > x , player - > axis2 - > y ) ;
P_InstaThrust ( player - > mo , fa , xspeed / 10 ) ;
}
else
{
const angle_t fa = player - > angle_pos > > ANGLETOFINESHIFT ;
2016-05-14 22:57:56 +00:00
const angle_t faold = player - > old_angle_pos > > ANGLETOFINESHIFT ;
player - > mo - > momx = FixedMul ( FINECOSINE ( fa ) , radius ) - FixedMul ( FINECOSINE ( faold ) , radius ) ;
player - > mo - > momy = FixedMul ( FINESINE ( fa ) , radius ) - FixedMul ( FINESINE ( faold ) , radius ) ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
if ( player - > exiting )
return ;
2017-03-20 16:57:24 +00:00
{
2016-08-12 13:42:22 +00:00
boolean notallowed ;
2017-03-20 16:57:24 +00:00
mobj_t * hack = P_SpawnMobjFromMobj ( player - > mo , 0 , 0 , 0 , MT_NULL ) ;
hack - > flags = MF_NOGRAVITY ;
hack - > radius = player - > mo - > radius ;
hack - > height = player - > mo - > height ;
hack - > z = player - > mo - > z ;
P_SetThingPosition ( hack ) ;
notallowed = ( ! ( P_TryMove ( hack , player - > mo - > x + player - > mo - > momx , player - > mo - > y + player - > mo - > momy , true ) ) ) ;
P_RemoveMobj ( hack ) ;
2016-08-12 13:42:22 +00:00
if ( notallowed )
return ;
2014-08-04 03:49:33 +00:00
}
2016-08-12 13:42:22 +00:00
2014-03-15 16:59:03 +00:00
{
const INT32 sequence = player - > mo - > target - > threshold ;
mobj_t * transfer1 = NULL ;
mobj_t * transfer2 = NULL ;
mobj_t * axis ;
mobj_t * mo2 ;
thinker_t * th ;
line_t transfer1line ;
line_t transfer2line ;
boolean transfer1last = false ;
boolean transfer2last = false ;
vertex_t vertices [ 4 ] ;
2016-08-18 19:09:35 +00:00
fixed_t truexspeed = xspeed * ( ! ( player - > pflags & PF_TRANSFERTOCLOSEST ) & & player - > mo - > target - > flags2 & MF2_AMBUSH ? - 1 : 1 ) ;
2014-03-15 16:59:03 +00:00
// Find next waypoint
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
// Axis things are only at beginning of list.
if ( ! ( mo2 - > flags2 & MF2_AXIS ) )
break ;
2019-07-12 23:42:03 +00:00
if ( ! ( mo2 - > type = = MT_AXISTRANSFER | | mo2 - > type = = MT_AXISTRANSFERLINE ) )
continue ;
if ( mo2 - > threshold ! = sequence )
continue ;
2014-03-15 16:59:03 +00:00
2019-07-12 23:42:03 +00:00
if ( player - > pflags & PF_TRANSFERTOCLOSEST )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( mo2 - > health = = player - > axis1 - > health )
transfer1 = mo2 ;
else if ( mo2 - > health = = player - > axis2 - > health )
transfer2 = mo2 ;
}
else
{
if ( mo2 - > health = = player - > mo - > target - > health )
transfer1 = mo2 ;
else if ( mo2 - > health = = player - > mo - > target - > health + 1 )
transfer2 = mo2 ;
2014-03-15 16:59:03 +00:00
}
}
// It might be possible that one wasn't found.
// Is it because we're at the end of the track?
// Look for a wrapper point.
if ( ! transfer1 )
{
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
// Axis things are only at beginning of list.
if ( ! ( mo2 - > flags2 & MF2_AXIS ) )
break ;
2019-07-12 23:42:03 +00:00
if ( ! ( mo2 - > type = = MT_AXISTRANSFER | | mo2 - > type = = MT_AXISTRANSFERLINE ) )
continue ;
if ( mo2 - > threshold ! = sequence )
continue ;
2014-03-15 16:59:03 +00:00
2019-07-12 23:42:03 +00:00
if ( ! transfer1 )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
transfer1 = mo2 ;
transfer1last = true ;
}
else if ( mo2 - > health > transfer1 - > health )
{
transfer1 = mo2 ;
transfer1last = true ;
2014-03-15 16:59:03 +00:00
}
}
}
if ( ! transfer2 )
{
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
// Axis things are only at beginning of list.
if ( ! ( mo2 - > flags2 & MF2_AXIS ) )
break ;
2019-07-12 23:42:03 +00:00
if ( ! ( mo2 - > type = = MT_AXISTRANSFER | | mo2 - > type = = MT_AXISTRANSFERLINE ) )
continue ;
if ( mo2 - > threshold ! = sequence )
continue ;
2014-03-15 16:59:03 +00:00
2019-07-12 23:42:03 +00:00
if ( ! transfer2 )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
transfer2 = mo2 ;
transfer2last = true ;
}
else if ( mo2 - > health > transfer2 - > health )
{
transfer2 = mo2 ;
transfer2last = true ;
2014-03-15 16:59:03 +00:00
}
}
}
if ( ! ( transfer1 & & transfer2 ) ) // We can't continue...
I_Error ( " Mare does not form a complete circuit! \n " ) ;
transfer1line . v1 = & vertices [ 0 ] ;
transfer1line . v2 = & vertices [ 1 ] ;
transfer2line . v1 = & vertices [ 2 ] ;
transfer2line . v2 = & vertices [ 3 ] ;
if ( cv_debug & & ( leveltime % TICRATE = = 0 ) )
{
CONS_Debug ( DBG_NIGHTS , " Transfer1 : %d \n " , transfer1 - > health ) ;
CONS_Debug ( DBG_NIGHTS , " Transfer2 : %d \n " , transfer2 - > health ) ;
}
2014-08-04 03:49:33 +00:00
//CONS_Debug(DBG_NIGHTS, "Xspeed : %d", truexspeed);
2014-03-15 16:59:03 +00:00
//CONS_Debug(DBG_NIGHTS, "T1 is at %d, %d\n", transfer1->x>>FRACBITS, transfer1->y>>FRACBITS);
//CONS_Debug(DBG_NIGHTS, "T2 is at %d, %d\n", transfer2->x>>FRACBITS, transfer2->y>>FRACBITS);
//CONS_Debug(DBG_NIGHTS, "Distance from T1: %d\n", P_AproxDistance(transfer1->x - player->mo->x, transfer1->y - player->mo->y)>>FRACBITS);
//CONS_Debug(DBG_NIGHTS, "Distance from T2: %d\n", P_AproxDistance(transfer2->x - player->mo->x, transfer2->y - player->mo->y)>>FRACBITS);
// Transfer1 is closer to the player than transfer2
if ( P_AproxDistance ( transfer1 - > x - player - > mo - > x , transfer1 - > y - player - > mo - > y ) > > FRACBITS
< P_AproxDistance ( transfer2 - > x - player - > mo - > x , transfer2 - > y - player - > mo - > y ) > > FRACBITS )
{
2014-08-04 03:49:33 +00:00
//CONS_Debug(DBG_NIGHTS, " must be < 0 to transfer\n");
2014-03-15 16:59:03 +00:00
if ( transfer1 - > type = = MT_AXISTRANSFERLINE )
{
if ( transfer1last )
axis = P_FindAxis ( transfer1 - > threshold , transfer1 - > health - 2 ) ;
else if ( player - > pflags & PF_TRANSFERTOCLOSEST )
axis = P_FindAxis ( transfer1 - > threshold , transfer1 - > health - 1 ) ;
else
axis = P_FindAxis ( transfer1 - > threshold , transfer1 - > health ) ;
if ( ! axis )
{
CONS_Debug ( DBG_NIGHTS , " Unable to find an axis - error code #1 \n " ) ;
return ;
}
//CONS_Debug(DBG_NIGHTS, "Drawing a line from %d to ", axis->health);
transfer1line . v1 - > x = axis - > x ;
transfer1line . v1 - > y = axis - > y ;
transfer1line . v2 - > x = transfer1 - > x ;
transfer1line . v2 - > y = transfer1 - > y ;
if ( cv_debug & DBG_NIGHTS )
P_ShootLine ( axis , transfer1 , player - > mo - > z ) ;
//CONS_Debug(DBG_NIGHTS, "closest %d\n", transfer1->health);
transfer1line . dx = transfer1line . v2 - > x - transfer1line . v1 - > x ;
transfer1line . dy = transfer1line . v2 - > y - transfer1line . v1 - > y ;
if ( P_PointOnLineSide ( player - > mo - > x , player - > mo - > y , & transfer1line )
2014-08-04 03:49:33 +00:00
! = P_PointOnLineSide ( player - > mo - > x + player - > mo - > momx , player - > mo - > y + player - > mo - > momy , & transfer1line )
& & truexspeed < 0 )
2014-03-15 16:59:03 +00:00
{
if ( cv_debug & DBG_NIGHTS )
{
HU_SetCEchoDuration ( 1 ) ;
HU_DoCEcho ( " transfer! " ) ;
HU_SetCEchoDuration ( 5 ) ;
S_StartSound ( NULL , sfx_strpst ) ;
}
if ( player - > pflags & PF_TRANSFERTOCLOSEST )
{
player - > pflags & = ~ PF_TRANSFERTOCLOSEST ;
P_TransferToAxis ( player , transfer1 - > health - 1 ) ;
}
else
{
player - > pflags | = PF_TRANSFERTOCLOSEST ;
P_SetTarget ( & player - > axis2 , transfer1 ) ;
P_SetTarget ( & player - > axis1 , P_FindAxisTransfer ( transfer1 - > threshold , transfer1 - > health - 1 , MT_AXISTRANSFERLINE ) ) ; //P_FindAxis(transfer1->threshold, axis->health-2);
}
}
}
else
{
// Transfer1
if ( transfer1last )
axis = P_FindAxis ( transfer1 - > threshold , 1 ) ;
else
axis = P_FindAxis ( transfer1 - > threshold , transfer1 - > health ) ;
if ( ! axis )
{
CONS_Debug ( DBG_NIGHTS , " Unable to find an axis - error code #2 \n " ) ;
return ;
}
//CONS_Debug(DBG_NIGHTS, "Drawing a line from %d to ", axis->health);
transfer1line . v1 - > x = axis - > x ;
transfer1line . v1 - > y = axis - > y ;
if ( cv_debug & DBG_NIGHTS )
P_ShootLine ( transfer1 , P_FindAxis ( transfer1 - > threshold , transfer1 - > health - 1 ) , player - > mo - > z ) ;
//axis = P_FindAxis(transfer1->threshold, transfer1->health-1);
//CONS_Debug(DBG_NIGHTS, "%d\n", axis->health);
transfer1line . v2 - > x = transfer1 - > x ;
transfer1line . v2 - > y = transfer1 - > y ;
transfer1line . dx = transfer1line . v2 - > x - transfer1line . v1 - > x ;
transfer1line . dy = transfer1line . v2 - > y - transfer1line . v1 - > y ;
if ( P_PointOnLineSide ( player - > mo - > x , player - > mo - > y , & transfer1line )
2014-08-04 03:49:33 +00:00
! = P_PointOnLineSide ( player - > mo - > x + player - > mo - > momx , player - > mo - > y + player - > mo - > momy , & transfer1line )
& & truexspeed < 0 )
2014-03-15 16:59:03 +00:00
{
if ( cv_debug & DBG_NIGHTS )
{
HU_SetCEchoDuration ( 1 ) ;
HU_DoCEcho ( " transfer! " ) ;
HU_SetCEchoDuration ( 5 ) ;
S_StartSound ( NULL , sfx_strpst ) ;
}
if ( player - > mo - > target - > health < transfer1 - > health )
{
// Find the next axis with a ->health
// +1 from the current axis.
if ( transfer1last )
P_TransferToAxis ( player , transfer1 - > health - 1 ) ;
else
P_TransferToAxis ( player , transfer1 - > health ) ;
}
else if ( player - > mo - > target - > health > = transfer1 - > health )
{
// Find the next axis with a ->health
// -1 from the current axis.
P_TransferToAxis ( player , transfer1 - > health - 1 ) ;
}
}
}
}
else
{
2014-08-04 03:49:33 +00:00
//CONS_Debug(DBG_NIGHTS, " must be > 0 to transfer\n");
2014-03-15 16:59:03 +00:00
if ( transfer2 - > type = = MT_AXISTRANSFERLINE )
{
if ( transfer2last )
axis = P_FindAxis ( transfer2 - > threshold , 1 ) ;
else if ( player - > pflags & PF_TRANSFERTOCLOSEST )
axis = P_FindAxis ( transfer2 - > threshold , transfer2 - > health ) ;
else
axis = P_FindAxis ( transfer2 - > threshold , transfer2 - > health - 1 ) ;
if ( ! axis )
axis = P_FindAxis ( transfer2 - > threshold , 1 ) ;
if ( ! axis )
{
CONS_Debug ( DBG_NIGHTS , " Unable to find an axis - error code #3 \n " ) ;
return ;
}
//CONS_Debug(DBG_NIGHTS, "Drawing a line from %d to ", axis->health);
transfer2line . v1 - > x = axis - > x ;
transfer2line . v1 - > y = axis - > y ;
transfer2line . v2 - > x = transfer2 - > x ;
transfer2line . v2 - > y = transfer2 - > y ;
//CONS_Debug(DBG_NIGHTS, "closest %d\n", transfer2->health);
if ( cv_debug & DBG_NIGHTS )
P_ShootLine ( axis , transfer2 , player - > mo - > z ) ;
transfer2line . dx = transfer2line . v2 - > x - transfer2line . v1 - > x ;
transfer2line . dy = transfer2line . v2 - > y - transfer2line . v1 - > y ;
if ( P_PointOnLineSide ( player - > mo - > x , player - > mo - > y , & transfer2line )
2014-08-04 03:49:33 +00:00
! = P_PointOnLineSide ( player - > mo - > x + player - > mo - > momx , player - > mo - > y + player - > mo - > momy , & transfer2line )
& & truexspeed > 0 )
2014-03-15 16:59:03 +00:00
{
if ( cv_debug & DBG_NIGHTS )
{
HU_SetCEchoDuration ( 1 ) ;
HU_DoCEcho ( " transfer! " ) ;
HU_SetCEchoDuration ( 5 ) ;
S_StartSound ( NULL , sfx_strpst ) ;
}
if ( player - > pflags & PF_TRANSFERTOCLOSEST )
{
player - > pflags & = ~ PF_TRANSFERTOCLOSEST ;
if ( ! P_FindAxis ( transfer2 - > threshold , transfer2 - > health ) )
transfer2last = true ;
if ( transfer2last )
P_TransferToAxis ( player , 1 ) ;
else
P_TransferToAxis ( player , transfer2 - > health ) ;
}
else
{
player - > pflags | = PF_TRANSFERTOCLOSEST ;
P_SetTarget ( & player - > axis1 , transfer2 ) ;
P_SetTarget ( & player - > axis2 , P_FindAxisTransfer ( transfer2 - > threshold , transfer2 - > health + 1 , MT_AXISTRANSFERLINE ) ) ; //P_FindAxis(transfer2->threshold, axis->health + 2);
}
}
}
else
{
// Transfer2
if ( transfer2last )
axis = P_FindAxis ( transfer2 - > threshold , 1 ) ;
else
axis = P_FindAxis ( transfer2 - > threshold , transfer2 - > health ) ;
if ( ! axis )
axis = P_FindAxis ( transfer2 - > threshold , 1 ) ;
if ( ! axis )
{
CONS_Debug ( DBG_NIGHTS , " Unable to find an axis - error code #4 \n " ) ;
return ;
}
//CONS_Debug(DBG_NIGHTS, "Drawing a line from %d to ", axis->health);
transfer2line . v1 - > x = axis - > x ;
transfer2line . v1 - > y = axis - > y ;
if ( cv_debug & DBG_NIGHTS )
P_ShootLine ( transfer2 , P_FindAxis ( transfer2 - > threshold , transfer2 - > health - 1 ) , player - > mo - > z ) ;
//axis = P_FindAxis(transfer2->threshold, transfer2->health-1);
//CONS_Debug(DBG_NIGHTS, "%d\n", axis->health);
transfer2line . v2 - > x = transfer2 - > x ;
transfer2line . v2 - > y = transfer2 - > y ;
transfer2line . dx = transfer2line . v2 - > x - transfer2line . v1 - > x ;
transfer2line . dy = transfer2line . v2 - > y - transfer2line . v1 - > y ;
if ( P_PointOnLineSide ( player - > mo - > x , player - > mo - > y , & transfer2line )
2014-08-04 03:49:33 +00:00
! = P_PointOnLineSide ( player - > mo - > x + player - > mo - > momx , player - > mo - > y + player - > mo - > momy , & transfer2line )
& & truexspeed > 0 )
2014-03-15 16:59:03 +00:00
{
if ( cv_debug & DBG_NIGHTS )
{
HU_SetCEchoDuration ( 1 ) ;
HU_DoCEcho ( " transfer! " ) ;
HU_SetCEchoDuration ( 5 ) ;
S_StartSound ( NULL , sfx_strpst ) ;
}
if ( player - > mo - > target - > health < transfer2 - > health )
{
if ( ! P_FindAxis ( transfer2 - > threshold , transfer2 - > health ) )
transfer2last = true ;
if ( transfer2last )
P_TransferToAxis ( player , 1 ) ;
else
P_TransferToAxis ( player , transfer2 - > health ) ;
}
else if ( player - > mo - > target - > health > = transfer2 - > health )
P_TransferToAxis ( player , transfer2 - > health - 1 ) ;
}
}
}
}
}
//
// P_DoNiGHTSCapsule
//
// Handles blowing up the Ideya (emerald) capsule for NiGHTS mode
//
static void P_DoNiGHTSCapsule ( player_t * player )
{
2018-08-15 18:40:25 +00:00
INT32 i , spherecount , totalduration , popduration , deductinterval , deductquantity , sphereresult , firstpoptic , startingspheres ;
2018-08-15 17:38:15 +00:00
INT32 tictimer = + + player - > capsule - > extravalue2 ;
2018-08-14 15:06:09 +00:00
2018-08-14 23:39:25 +00:00
if ( abs ( player - > mo - > x - player - > capsule - > x ) < = 3 * FRACUNIT )
2014-03-15 16:59:03 +00:00
{
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x = player - > capsule - > x ;
P_SetThingPosition ( player - > mo ) ;
player - > mo - > momx = 0 ;
}
2018-08-14 23:39:25 +00:00
if ( abs ( player - > mo - > y - player - > capsule - > y ) < = 3 * FRACUNIT )
2014-03-15 16:59:03 +00:00
{
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > y = player - > capsule - > y ;
P_SetThingPosition ( player - > mo ) ;
player - > mo - > momy = 0 ;
}
2018-09-10 00:51:08 +00:00
if ( abs ( player - > mo - > z - ( player - > capsule - > z + ( player - > capsule - > height / 3 ) ) ) < = 3 * FRACUNIT )
2014-03-15 16:59:03 +00:00
{
player - > mo - > z = player - > capsule - > z + ( player - > capsule - > height / 3 ) ;
player - > mo - > momz = 0 ;
}
if ( player - > mo - > x > player - > capsule - > x )
2018-08-14 23:39:25 +00:00
player - > mo - > momx = - 3 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
else if ( player - > mo - > x < player - > capsule - > x )
2018-08-14 23:39:25 +00:00
player - > mo - > momx = 3 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
if ( player - > mo - > y > player - > capsule - > y )
2018-08-14 23:39:25 +00:00
player - > mo - > momy = - 3 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
else if ( player - > mo - > y < player - > capsule - > y )
2018-08-14 23:39:25 +00:00
player - > mo - > momy = 3 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
if ( player - > mo - > z > player - > capsule - > z + ( player - > capsule - > height / 3 ) )
2018-08-14 23:39:25 +00:00
player - > mo - > momz = - 3 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
else if ( player - > mo - > z < player - > capsule - > z + ( player - > capsule - > height / 3 ) )
2018-08-14 23:39:25 +00:00
player - > mo - > momz = 3 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2016-08-12 01:57:37 +00:00
{
if ( player - > mo - > momx | | player - > mo - > momy | | player - > mo - > momz )
{
if ( player - > mo - > state ! = & states [ S_PLAY_NIGHTS_PULL ] )
P_SetPlayerMobjState ( player - > mo , S_PLAY_NIGHTS_PULL ) ;
}
else if ( player - > mo - > state ! = & states [ S_PLAY_NIGHTS_ATTACK ] )
{
S_StartSound ( player - > mo , sfx_spin ) ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_NIGHTS_ATTACK ) ;
}
}
2018-08-16 03:11:32 +00:00
else
{
if ( ! ( player - > pflags & PF_JUMPED ) & & ! ( player - > pflags & PF_SPINNING ) )
player - > pflags | = PF_JUMPED ;
if ( player - > panim ! = PA_ROLL )
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
}
2016-08-12 01:57:37 +00:00
2019-11-14 15:27:22 +00:00
# ifdef ROTSPRITE
if ( ! ( player - > charflags & SF_NONIGHTSROTATION ) )
{
if ( ( player - > mo - > state = = & states [ S_PLAY_NIGHTS_PULL ] )
& & ( player - > mo - > sprite2 = = SPR2_NPUL ) )
player - > mo - > rollangle - = ANG30 ;
else
player - > mo - > rollangle = 0 ;
}
# endif
2014-03-15 16:59:03 +00:00
if ( G_IsSpecialStage ( gamemap ) )
{ // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here!
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2018-06-03 21:41:54 +00:00
if ( playeringame [ i ] & & ( & players [ i ] ! = player ) & & players [ i ] . spheres > 0 )
2014-03-15 16:59:03 +00:00
{
2018-06-03 21:41:54 +00:00
player - > spheres + = players [ i ] . spheres ;
players [ i ] . spheres = 0 ;
2014-03-15 16:59:03 +00:00
}
}
2018-08-14 16:48:00 +00:00
if ( player - > capsule - > extravalue2 < = 0 & & player - > capsule - > health > 0 )
2018-08-14 16:00:37 +00:00
P_RunNightsCapsuleTouchExecutors ( player - > mo , true , player - > spheres > = player - > capsule - > health ) ; // run capsule entrance executors
2018-08-14 15:06:09 +00:00
2014-03-15 16:59:03 +00:00
// Time to blow it up!
if ( player - > mo - > x = = player - > capsule - > x
& & player - > mo - > y = = player - > capsule - > y
& & player - > mo - > z = = player - > capsule - > z + ( player - > capsule - > height / 3 ) )
{
2018-08-15 00:10:32 +00:00
if ( player - > capsule - > lastlook < 0 )
2014-03-15 16:59:03 +00:00
{
2018-08-15 17:38:15 +00:00
// Stretch the sphere deduction across the capsule time!
// 1. Force the remaining capsule time to `popduration`
// 2. Given `popduration` and `spherecount`, at what tic interval do we deduct spheres? `deductinterval`
// 3. And on each deduction, how many spheres do we deduct? `deductquantity`
// 4. Store the expected capsule health upon completion: `sphereresult`
spherecount = min ( player - > spheres , player - > capsule - > health ) ;
totalduration = min ( 40 + spherecount , 60 ) ;
popduration = player - > capsule - > extravalue1 = max ( totalduration - tictimer , 1 ) ;
deductinterval = player - > capsule - > cvmem = max ( FixedFloor ( FixedDiv ( popduration , spherecount ) ) / FRACUNIT , 1 ) ;
deductquantity = player - > capsule - > cusval = max ( FixedRound ( FixedDiv ( spherecount , popduration ) ) / FRACUNIT , 1 ) ;
sphereresult = player - > capsule - > movecount = player - > capsule - > health - spherecount ;
firstpoptic = player - > capsule - > lastlook = tictimer ;
}
else
{
popduration = player - > capsule - > extravalue1 ;
deductinterval = player - > capsule - > cvmem ;
deductquantity = player - > capsule - > cusval ;
sphereresult = player - > capsule - > movecount ;
firstpoptic = player - > capsule - > lastlook ;
2018-08-15 00:10:32 +00:00
}
2014-03-15 16:59:03 +00:00
2018-08-15 17:38:15 +00:00
if ( tictimer - firstpoptic < popduration )
2014-03-15 16:59:03 +00:00
{
2018-08-15 18:40:25 +00:00
if ( ! ( ( tictimer - firstpoptic ) % deductinterval ) )
2018-08-15 00:10:32 +00:00
{
2018-08-15 18:40:25 +00:00
// Did you somehow get more spheres during destruct?
if ( player - > capsule - > health < = sphereresult & & player - > spheres > 0 & & player - > capsule - > health > 0 )
sphereresult = max ( sphereresult - player - > spheres , 0 ) ;
if ( player - > capsule - > health > sphereresult & & player - > spheres > 0 )
{
player - > spheres - = deductquantity ;
player - > capsule - > health - = deductquantity ;
}
2018-08-15 00:10:32 +00:00
2018-08-15 04:48:13 +00:00
if ( player - > spheres < 0 )
player - > spheres = 0 ;
2018-08-15 00:10:32 +00:00
2018-08-15 17:38:15 +00:00
if ( player - > capsule - > health < sphereresult )
player - > capsule - > health = sphereresult ;
2018-08-15 04:48:13 +00:00
}
2014-03-15 16:59:03 +00:00
2019-08-11 23:34:42 +00:00
// Spawn a 'pop' for every 2 tics
if ( ! ( ( tictimer - firstpoptic ) % 2 ) )
2014-03-15 16:59:03 +00:00
S_StartSound ( P_SpawnMobj ( player - > capsule - > x + ( ( P_SignedRandom ( ) / 2 ) < < FRACBITS ) ,
player - > capsule - > y + ( ( P_SignedRandom ( ) / 2 ) < < FRACBITS ) ,
player - > capsule - > z + ( player - > capsule - > height / 2 ) + ( ( P_SignedRandom ( ) / 2 ) < < FRACBITS ) ,
2019-08-13 19:24:24 +00:00
MT_SONIC3KBOSSEXPLODE ) , sfx_s3kb4 ) ;
2018-08-15 04:48:13 +00:00
}
else
{
2018-08-15 18:40:25 +00:00
if ( player - > spheres ! = 0 & & player - > capsule - > health > 0 )
{
if ( player - > spheres < player - > capsule - > health )
{
player - > capsule - > health - = player - > spheres ;
player - > spheres = 0 ;
}
else
{
startingspheres = player - > spheres - player - > capsule - > health ;
player - > capsule - > health = 0 ;
player - > spheres = startingspheres ;
}
}
2014-03-15 16:59:03 +00:00
if ( player - > capsule - > health < = 0 )
{
player - > capsule - > flags & = ~ MF_NOGRAVITY ;
player - > capsule - > momz = 5 * FRACUNIT ;
player - > capsule - > reactiontime = 0 ;
2018-08-15 17:38:15 +00:00
tictimer = - 1 ;
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
if ( playeringame [ i ] & & ! player - > exiting & & players [ i ] . mare = = player - > mare )
{
players [ i ] . bonustime = true ;
players [ i ] . texttimer = 4 * TICRATE ;
players [ i ] . textvar = 1 ; // Time Bonus
players [ i ] . finishedtime = players [ i ] . nightstime ;
if ( ! G_IsSpecialStage ( gamemap ) )
P_AddPlayerScore ( & players [ i ] , ( players [ i ] . finishedtime / TICRATE ) * 100 ) ;
P_FlashPal ( & players [ i ] , PAL_WHITE , 8 ) ;
}
if ( G_IsSpecialStage ( gamemap ) )
{
tic_t lowest_time ;
/*for (i = 0; i < MAXPLAYERS; i++)
{
if ( ! playeringame [ i ] | | players [ i ] . spectator | | ! players [ i ] . mo | | ! players [ i ] . mo - > tracer )
continue ;
emmo = P_SpawnMobj ( players [ i ] . mo - > x , players [ i ] . mo - > y , players [ i ] . mo - > z + players [ i ] . mo - > info - > height , MT_GOTEMERALD ) ;
P_SetTarget ( & emmo - > target , players [ i ] . mo ) ;
P_SetMobjState ( emmo , mobjinfo [ MT_GOTEMERALD ] . meleestate + em ) ;
} */
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
2018-06-03 21:41:54 +00:00
// The Chaos Emerald begins to orbit us!
UINT8 em = P_GetNextEmerald ( ) ;
2014-03-15 16:59:03 +00:00
// Only give it to ONE person, and THAT player has to get to the goal!
2018-06-03 21:41:54 +00:00
mobj_t * emmo = P_SpawnMobjFromMobj ( player - > mo , 0 , 0 , player - > mo - > height , MT_GOTEMERALD ) ;
2018-08-14 21:21:49 +00:00
emmo - > health = em ; // for identification
2014-03-15 16:59:03 +00:00
P_SetTarget ( & emmo - > target , player - > mo ) ;
P_SetMobjState ( emmo , mobjinfo [ MT_GOTEMERALD ] . meleestate + em ) ;
2016-08-12 01:57:37 +00:00
P_SetTarget ( & player - > mo - > tracer , emmo ) ;
2014-03-15 16:59:03 +00:00
}
// Okay, we're doing this down here because we're handling time weirdly for co-op special stages
// and because P_AddPlayerScore gives score to everyone in co-op special stages.
// Find the player with the lowest time remaining and award points based on that time instead.
lowest_time = player - > finishedtime ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2017-03-14 18:11:17 +00:00
if ( playeringame [ i ] & & players [ i ] . powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
if ( players [ i ] . finishedtime < lowest_time )
lowest_time = players [ i ] . finishedtime ;
P_AddPlayerScore ( player , ( lowest_time / TICRATE ) * 100 ) ;
}
else
{
2018-06-03 21:41:54 +00:00
/*for (i = 0; i < 16; i++)
2016-12-31 16:55:06 +00:00
{
2019-11-13 20:14:08 +00:00
mobj_t * flicky = P_InternalFlickySpawn ( player - > capsule , 0 , ( ( i % 4 ) + 1 ) * 2 * FRACUNIT , true , 0 ) ;
2016-12-31 16:55:06 +00:00
flicky - > z + = player - > capsule - > height / 2 ;
flicky - > angle = ( i * ( ANGLE_MAX / 16 ) ) ;
P_InstaThrust ( flicky , flicky - > angle , 8 * FRACUNIT ) ;
2018-06-03 21:41:54 +00:00
} */
mobj_t * idya = P_SpawnMobjFromMobj ( player - > mo , 0 , 0 , player - > mo - > height , MT_GOTEMERALD ) ;
idya - > extravalue2 = player - > mare / 5 ;
2018-08-14 21:21:49 +00:00
idya - > health = player - > mare + 1 ; // for identification
2018-06-03 21:41:54 +00:00
P_SetTarget ( & idya - > target , player - > mo ) ;
P_SetMobjState ( idya , mobjinfo [ MT_GOTEMERALD ] . missilestate + ( ( player - > mare + 1 ) % 5 ) ) ;
2018-08-14 21:21:49 +00:00
if ( player - > mo - > tracer )
{
P_SetTarget ( & idya - > hnext , player - > mo - > tracer ) ;
idya - > extravalue1 = ( angle_t ) ( player - > mo - > tracer - > extravalue1 - 72 * ANG1 ) ;
if ( idya - > extravalue1 > player - > mo - > tracer - > extravalue1 )
idya - > extravalue1 - = ( 72 * ANG1 ) / idya - > extravalue1 ;
}
2018-06-03 21:41:54 +00:00
P_SetTarget ( & player - > mo - > tracer , idya ) ;
2014-03-15 16:59:03 +00:00
}
for ( i = 0 ; i < MAXPLAYERS ; i + + )
if ( playeringame [ i ] & & players [ i ] . mare = = player - > mare )
P_SetTarget ( & players [ i ] . capsule , NULL ) ; // Remove capsule from everyone now that it is dead!
S_StartScreamSound ( player - > mo , sfx_ngdone ) ;
2018-06-03 21:41:54 +00:00
P_SwitchSpheresBonusMode ( true ) ;
2018-08-14 16:00:37 +00:00
P_RunNightsCapsuleTouchExecutors ( player - > mo , false , true ) ; // run capsule exit executors, and we destroyed it
2014-03-15 16:59:03 +00:00
}
2018-08-15 04:48:13 +00:00
else
{
S_StartScreamSound ( player - > mo , sfx_lose ) ;
player - > texttimer = 4 * TICRATE ;
player - > textvar = 3 ; // Get more rings!
player - > capsule - > reactiontime = 0 ;
2018-08-15 17:38:15 +00:00
player - > capsule - > extravalue1 = player - > capsule - > cvmem = \
player - > capsule - > cusval = player - > capsule - > movecount = \
player - > capsule - > lastlook = player - > capsule - > extravalue2 = - 1 ;
2018-09-07 12:56:02 +00:00
P_RunNightsCapsuleTouchExecutors ( player - > mo , false , false ) ; // run capsule exit executors, and we lacked rings
2018-08-15 04:48:13 +00:00
}
2014-03-15 16:59:03 +00:00
}
}
2018-08-15 17:59:27 +00:00
else if ( player - > capsule - > lastlook > - 1 )
// We somehow moved out of the capsule (OBJECTPLACE?)
// So recalculate all the timings
player - > capsule - > lastlook = player - > capsule - > extravalue2 = - 1 ;
2014-03-15 16:59:03 +00:00
}
2018-08-10 23:25:49 +00:00
//
// P_MoveNiGHTSToDrone
//
// Pull NiGHTS to the drone during Nightserizing
//
static void P_MoveNiGHTSToDrone ( player_t * player )
{
2019-02-13 18:06:56 +00:00
boolean flip , topaligned , middlealigned , bottomoffsetted ;
fixed_t droneboxmandiff , zofs ;
2018-08-10 23:25:49 +00:00
if ( ! player - > drone )
return ;
2018-08-11 19:49:34 +00:00
2019-02-13 18:06:56 +00:00
flip = player - > drone - > flags2 & MF2_OBJECTFLIP ;
topaligned = ( player - > drone - > flags & MF_SLIDEME ) & & ! ( player - > drone - > flags & MF_GRENADEBOUNCE ) ;
middlealigned = ( player - > drone - > flags & MF_GRENADEBOUNCE ) & & ! ( player - > drone - > flags & MF_SLIDEME ) ;
bottomoffsetted = ! ( player - > drone - > flags & MF_SLIDEME ) & & ! ( player - > drone - > flags & MF_GRENADEBOUNCE ) ;
droneboxmandiff = max ( player - > drone - > height - player - > mo - > height , 0 ) ;
2018-08-11 19:49:34 +00:00
if ( ! flip )
{
if ( topaligned )
zofs = droneboxmandiff ;
else if ( middlealigned )
zofs = droneboxmandiff / 2 ;
else if ( bottomoffsetted )
zofs = FixedMul ( 24 * FRACUNIT , player - > drone - > scale ) ;
else
zofs = 0 ;
}
else
{
if ( topaligned )
zofs = 0 ;
else if ( middlealigned )
zofs = droneboxmandiff / 2 ;
else if ( bottomoffsetted )
zofs = droneboxmandiff - FixedMul ( 24 * FRACUNIT , player - > drone - > scale ) ;
else
zofs = droneboxmandiff ;
}
2018-08-10 23:25:49 +00:00
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
2018-08-11 19:49:34 +00:00
P_TeleportMove ( player - > mo , player - > drone - > x , player - > drone - > y , player - > drone - > z + zofs ) ;
2018-08-10 23:25:49 +00:00
P_SetTarget ( & player - > drone , NULL ) ;
}
2014-03-15 16:59:03 +00:00
//
// P_NiGHTSMovement
//
// Movement code for NiGHTS!
//
static void P_NiGHTSMovement ( player_t * player )
{
fixed_t drillamt = 0 ;
boolean still = false , moved = false , backwardaxis = false , firstdrill ;
INT16 newangle = 0 ;
fixed_t xspeed , yspeed ;
thinker_t * th ;
mobj_t * mo2 ;
mobj_t * closestaxis = NULL ;
fixed_t newx , newy , radius ;
angle_t movingangle ;
ticcmd_t * cmd = & player - > cmd ;
INT32 thrustfactor ;
INT32 i ;
2016-08-12 01:57:37 +00:00
statenum_t flystate ;
UINT16 visangle ;
2019-08-18 17:16:48 +00:00
# ifdef ROTSPRITE
angle_t rollangle = 0 ;
# endif
2014-03-15 16:59:03 +00:00
player - > pflags & = ~ PF_DRILLING ;
firstdrill = false ;
if ( player - > drillmeter > 96 * 20 )
player - > drillmeter = 96 * 20 ;
if ( player - > drilldelay )
player - > drilldelay - - ;
if ( ! ( cmd - > buttons & BT_JUMP ) )
{
// Always have just a TINY bit of drill power.
if ( player - > drillmeter < = 0 )
player - > drillmeter = TICRATE / 10 ;
}
2017-03-14 18:11:17 +00:00
if ( ! ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) )
2014-03-15 16:59:03 +00:00
{
P_DeNightserizePlayer ( player ) ;
return ;
}
if ( G_IsSpecialStage ( gamemap ) )
{
boolean capsule = false ;
// NiGHTS special stages have a pseudo-shared timer, so check if ANYONE is feeding the capsule.
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2017-03-14 18:11:17 +00:00
if ( playeringame [ i ] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/
2014-03-15 16:59:03 +00:00
& & ( players [ i ] . capsule & & players [ i ] . capsule - > reactiontime ) )
capsule = true ;
if ( ! capsule
2017-10-04 16:45:03 +00:00
& & ! ( player - > mo - > state > = & states [ S_PLAY_NIGHTS_TRANS1 ]
& & player - > mo - > state < = & states [ S_PLAY_NIGHTS_TRANS6 ] )
2014-03-15 16:59:03 +00:00
& & ! player - > exiting )
player - > nightstime - - ;
}
else if ( gametype ! = GT_RACE & & gametype ! = GT_COMPETITION
2017-10-04 16:45:03 +00:00
& & ! ( player - > mo - > state > = & states [ S_PLAY_NIGHTS_TRANS1 ]
& & player - > mo - > state < = & states [ S_PLAY_NIGHTS_TRANS6 ] )
2014-03-15 16:59:03 +00:00
& & ! ( player - > capsule & & player - > capsule - > reactiontime )
& & ! player - > exiting )
player - > nightstime - - ;
if ( ! player - > nightstime )
{
P_DeNightserizePlayer ( player ) ;
S_StartScreamSound ( player - > mo , sfx_s3k66 ) ;
return ;
}
else if ( P_IsLocalPlayer ( player ) & & player - > nightstime = = 10 * TICRATE )
2019-03-15 03:10:14 +00:00
{
if ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_MIXNIGHTSCOUNTDOWN )
{
S_FadeMusic ( 0 , 10 * MUSICRATE ) ;
S_StartSound ( NULL , sfx_timeup ) ; // that creepy "out of time" music from NiGHTS.
}
else
2019-08-04 11:03:57 +00:00
P_PlayJingle ( player , ( ( maptol & TOL_NIGHTS ) & & ! G_IsSpecialStage ( gamemap ) ) ? JT_NIGHTSTIMEOUT : JT_SSTIMEOUT ) ;
2019-03-15 03:10:14 +00:00
}
2014-03-15 16:59:03 +00:00
if ( player - > mo - > z < player - > mo - > floorz )
player - > mo - > z = player - > mo - > floorz ;
if ( player - > mo - > z + player - > mo - > height > player - > mo - > ceilingz )
player - > mo - > z = player - > mo - > ceilingz - player - > mo - > height ;
newx = P_ReturnThrustX ( player - > mo , player - > mo - > angle , 3 * FRACUNIT ) + player - > mo - > x ;
newy = P_ReturnThrustY ( player - > mo , player - > mo - > angle , 3 * FRACUNIT ) + player - > mo - > y ;
if ( ! player - > mo - > target )
{
fixed_t dist1 , dist2 = 0 ;
// scan the thinkers
// to find the closest axis point
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > type ! = MT_AXIS )
continue ;
if ( mo2 - > threshold ! = player - > mare )
continue ;
if ( closestaxis = = NULL )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
closestaxis = mo2 ;
dist2 = R_PointToDist2 ( newx , newy , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
}
else
{
dist1 = R_PointToDist2 ( newx , newy , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
2014-03-15 16:59:03 +00:00
2019-07-12 23:42:03 +00:00
if ( dist1 < dist2 )
{
closestaxis = mo2 ;
dist2 = dist1 ;
2014-03-15 16:59:03 +00:00
}
}
}
P_SetTarget ( & player - > mo - > target , closestaxis ) ;
}
if ( ! player - > mo - > target ) // Uh-oh!
{
CONS_Debug ( DBG_NIGHTS , " No axis points found! \n " ) ;
return ;
}
// The 'ambush' flag says you should rotate
// the other way around the axis.
2016-08-18 19:09:35 +00:00
if ( player - > mo - > target - > flags2 & MF2_AMBUSH )
2014-03-15 16:59:03 +00:00
backwardaxis = true ;
player - > angle_pos = R_PointToAngle2 ( player - > mo - > target - > x , player - > mo - > target - > y , player - > mo - > x , player - > mo - > y ) ;
player - > old_angle_pos = player - > angle_pos ;
radius = player - > mo - > target - > radius ;
player - > mo - > flags | = MF_NOGRAVITY ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
cmd - > forwardmove = ( SINT8 ) ( - cmd - > forwardmove ) ;
2016-05-16 18:00:34 +00:00
if ( ! ( player - > pflags & PF_TRANSFERTOCLOSEST ) )
{
fixed_t realdist = R_PointToDist2 ( player - > mo - > x , player - > mo - > y , player - > mo - > target - > x , player - > mo - > target - > y ) ;
// teleport player to correct radius if neccessary
if ( realdist > > FRACBITS ! = radius > > FRACBITS )
{
CONS_Debug ( DBG_NIGHTS , " Aligning player with axis \n " ) ;
P_UnsetThingPosition ( player - > mo ) ;
if ( realdist = = 0 ) // other method won't work if we're exactly on the target lol
{
const angle_t fa = player - > old_angle_pos > > ANGLETOFINESHIFT ;
player - > mo - > x = player - > mo - > target - > x + FixedMul ( FINECOSINE ( fa ) , radius ) ;
player - > mo - > y = player - > mo - > target - > y + FixedMul ( FINESINE ( fa ) , radius ) ;
}
else
{
player - > mo - > x = player - > mo - > target - > x + FixedMul ( FixedDiv ( player - > mo - > x - player - > mo - > target - > x , realdist ) , radius ) ;
player - > mo - > y = player - > mo - > target - > y + FixedMul ( FixedDiv ( player - > mo - > y - player - > mo - > target - > y , realdist ) , radius ) ;
}
P_SetThingPosition ( player - > mo ) ;
}
}
2014-03-15 16:59:03 +00:00
// Currently reeling from being hit.
if ( player - > powers [ pw_flashing ] > ( 2 * flashingtics ) / 3 )
{
{
const angle_t fa = ( FixedAngle ( player - > flyangle * FRACUNIT ) > > ANGLETOFINESHIFT ) & FINEMASK ;
const fixed_t speed = FixedDiv ( player - > speed * FRACUNIT , 50 * FRACUNIT ) ;
xspeed = FixedMul ( FINECOSINE ( fa ) , speed ) ;
yspeed = FixedMul ( FINESINE ( fa ) , speed ) ;
}
if ( ! ( player - > pflags & PF_TRANSFERTOCLOSEST ) )
{
xspeed = FixedMul ( xspeed , FixedDiv ( 1024 * FRACUNIT , player - > mo - > target - > radius ) ) ;
if ( backwardaxis )
xspeed * = - 1 ;
player - > angle_pos + = FixedAngleC ( FixedDiv ( xspeed , 5 * FRACUNIT ) , 40 * FRACUNIT ) ;
}
player - > mo - > momz = 0 ;
P_NightsTransferPoints ( player , xspeed , radius ) ;
return ;
}
2017-10-04 16:45:03 +00:00
if ( player - > mo - > state > = & states [ S_PLAY_NIGHTS_TRANS1 ]
& & player - > mo - > state < = & states [ S_PLAY_NIGHTS_TRANS6 ] )
2014-03-15 16:59:03 +00:00
{
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
2019-08-18 17:16:48 +00:00
# ifdef ROTSPRITE
player - > mo - > rollangle = 0 ;
# endif
2014-03-15 16:59:03 +00:00
return ;
}
2016-08-12 14:40:17 +00:00
if ( player - > exiting > 0 ) // && player->exiting < 2*TICRATE)
2014-03-15 16:59:03 +00:00
{
player - > mo - > momx = player - > mo - > momy = 0 ;
2019-11-14 17:58:42 +00:00
if ( gametype ! = GT_RACE & & gametype ! = GT_COMPETITION )
P_SetObjectMomZ ( player - > mo , FRACUNIT / 2 , ( P_MobjFlip ( player - > mo ) * player - > mo - > momz > = 0 ) ) ;
2019-11-14 16:37:03 +00:00
else
player - > mo - > momz = 0 ;
2014-03-15 16:59:03 +00:00
2019-11-14 17:58:42 +00:00
#if 0 //def ROTSPRITE
if ( ! ( player - > charflags & SF_NONIGHTSROTATION ) & & player - > mo - > momz )
2019-11-14 16:37:03 +00:00
{
if ( player - > mo - > state ! = & states [ S_PLAY_NIGHTS_DRILL ] )
P_SetPlayerMobjState ( player - > mo , S_PLAY_NIGHTS_DRILL ) ;
player - > mo - > rollangle = ANGLE_90 ;
}
else
2019-08-18 17:16:48 +00:00
# endif
2019-11-14 16:37:03 +00:00
{
if ( player - > mo - > state ! = & states [ S_PLAY_NIGHTS_FLOAT ] )
P_SetPlayerMobjState ( player - > mo , S_PLAY_NIGHTS_FLOAT ) ;
player - > drawangle + = ANGLE_22h ;
}
2016-08-12 01:57:37 +00:00
2019-11-14 15:42:45 +00:00
player - > mo - > flags | = MF_NOCLIPHEIGHT ;
2014-03-15 16:59:03 +00:00
return ;
}
// Spawn the little sparkles on each side of the player.
if ( leveltime & 1 )
{
mobj_t * firstmobj ;
mobj_t * secondmobj ;
fixed_t spawndist = FixedMul ( 16 * FRACUNIT , player - > mo - > scale ) ;
2014-08-04 03:49:33 +00:00
fixed_t z = player - > mo - > z + player - > mo - > height / 2 ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
z - = FixedMul ( mobjinfo [ MT_NIGHTSPARKLE ] . height , player - > mo - > scale ) ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
firstmobj = P_SpawnMobj ( player - > mo - > x + P_ReturnThrustX ( player - > mo , player - > mo - > angle + ANGLE_90 , spawndist ) , player - > mo - > y + P_ReturnThrustY ( player - > mo , player - > mo - > angle + ANGLE_90 , spawndist ) , z , MT_NIGHTSPARKLE ) ;
secondmobj = P_SpawnMobj ( player - > mo - > x + P_ReturnThrustX ( player - > mo , player - > mo - > angle - ANGLE_90 , spawndist ) , player - > mo - > y + P_ReturnThrustY ( player - > mo , player - > mo - > angle - ANGLE_90 , spawndist ) , z , MT_NIGHTSPARKLE ) ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
firstmobj - > destscale = secondmobj - > destscale = player - > mo - > scale ;
2014-03-15 16:59:03 +00:00
P_SetTarget ( & firstmobj - > target , player - > mo ) ;
P_SetScale ( firstmobj , player - > mo - > scale ) ;
P_SetTarget ( & secondmobj - > target , player - > mo ) ;
P_SetScale ( secondmobj , player - > mo - > scale ) ;
// Superloop turns sparkles red
if ( player - > powers [ pw_nights_superloop ] )
{
P_SetMobjState ( firstmobj , mobjinfo [ MT_NIGHTSPARKLE ] . seestate ) ;
P_SetMobjState ( secondmobj , mobjinfo [ MT_NIGHTSPARKLE ] . seestate ) ;
}
}
// Paraloop helper is now separate from sparkles
// It also spawns every tic to avoid failed paraloops
{
mobj_t * helpermobj = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + player - > mo - > height / 2 , MT_NIGHTSLOOPHELPER ) ;
helpermobj - > fuse = player - > mo - > fuse = leveltime ;
P_SetTarget ( & helpermobj - > target , player - > mo ) ;
P_SetScale ( helpermobj , player - > mo - > scale ) ;
}
if ( player - > bumpertime )
{
2017-03-22 18:51:30 +00:00
player - > pflags | = ( PF_STARTJUMP | PF_DRILLING ) ;
2014-03-15 16:59:03 +00:00
newangle = ( INT16 ) player - > flyangle ;
}
else if ( cmd - > buttons & BT_JUMP & & player - > drillmeter & & player - > drilldelay = = 0 )
{
2017-03-22 18:51:30 +00:00
if ( ! ( player - > pflags & PF_STARTJUMP ) )
2014-03-15 16:59:03 +00:00
firstdrill = true ;
2017-03-22 18:51:30 +00:00
player - > pflags | = ( PF_STARTJUMP | PF_DRILLING ) ;
2014-03-15 16:59:03 +00:00
}
else
{
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ PF_STARTJUMP ;
2014-03-15 16:59:03 +00:00
if ( cmd - > sidemove ! = 0 )
moved = true ;
if ( player - > drillmeter & 1 )
player - > drillmeter + + ; // I'll be nice and give them one.
}
if ( cmd - > forwardmove ! = 0 )
moved = true ;
if ( ! player - > bumpertime )
{
if ( moved )
{
if ( player - > pflags & PF_DRILLING )
drillamt + = 100 * FRACUNIT ;
else
{
const fixed_t fforward = abs ( cmd - > forwardmove ) * FRACUNIT ;
const fixed_t fside = abs ( cmd - > sidemove ) * FRACUNIT ;
const fixed_t dist = FixedHypot ( fforward , fside ) ;
drillamt + = dist > 50 * FRACUNIT ? 50 * FRACUNIT : dist ;
// Accel up from 50 * 2.5
drillamt = FixedMul ( drillamt , 5 * FRACUNIT / 2 ) ;
}
if ( ( player - > pflags & PF_DRILLING & & player - > speed < MAXDRILLSPEED ) | | player - > speed < MAXNORMALSPEED )
player - > speed + = FixedInt ( drillamt ) ;
}
if ( player - > pflags & PF_DRILLING )
{
if ( player - > speed < MAXDRILLSPEED )
player - > speed + = 150 ;
if ( - - player - > drillmeter = = 0 )
player - > drilldelay = TICRATE * 2 ;
}
if ( player - > speed < 0 )
player - > speed = 0 ;
if ( ! cmd - > forwardmove )
{
if ( cmd - > sidemove > 0 )
newangle = 0 ;
else if ( cmd - > sidemove < 0 )
newangle = 180 ;
}
else if ( ! cmd - > sidemove )
{
if ( cmd - > forwardmove > 0 )
newangle = 90 ;
else if ( cmd - > forwardmove < 0 )
newangle = 270 ;
}
else // AngleFixed(R_PointToAngle2()) results in slight inaccuracy! Don't use it unless movement is on both axises.
newangle = ( INT16 ) FixedInt ( AngleFixed ( R_PointToAngle2 ( 0 , 0 , cmd - > sidemove * FRACUNIT , cmd - > forwardmove * FRACUNIT ) ) ) ;
if ( newangle < 0 & & moved )
newangle = ( INT16 ) ( 360 + newangle ) ;
}
if ( player - > pflags & PF_DRILLING )
thrustfactor = 2 ;
else
{
thrustfactor = 8 ;
// Decelerate while turning normally.
if ( moved & & player - > flyangle ! = newangle & & player - > speed > 12000 )
player - > speed - = 60 ;
}
for ( i = 0 ; i < thrustfactor ; i + + )
{
if ( moved & & player - > flyangle ! = newangle )
{
INT32 anglediff = ( ( ( newangle - player - > flyangle ) + 360 ) % 360 ) ;
INT32 angledif2 = ( ( ( player - > flyangle - newangle ) + 360 ) % 360 ) ;
// player->flyangle is the one to move
// newangle is the "move to"
if ( anglediff = = 0 & & angledif2 = = 0 )
break ;
if ( anglediff > angledif2 )
player - > flyangle - - ;
else // if (anglediff<angledif2)
player - > flyangle + + ;
}
// Buff out negatives, >360 angles...
player - > flyangle = ( ( player - > flyangle + 360 ) % 360 ) ;
}
if ( ! ( player - > speed )
& & cmd - > forwardmove = = 0 )
still = true ;
// No more bumper braking
if ( ! player - > bumpertime
& & ( ( cmd - > buttons & ( BT_CAMLEFT | BT_CAMRIGHT ) ) = = ( BT_CAMLEFT | BT_CAMRIGHT )
| | ( cmd - > buttons & BT_USE ) ) )
{
2017-09-15 19:34:46 +00:00
if ( ! ( player - > pflags & PF_STARTDASH ) )
2014-03-15 16:59:03 +00:00
S_StartSound ( player - > mo , sfx_ngskid ) ;
// You can tap the button to only slow down a bit,
// or hold it to slow to a crawl as before, your choice.
if ( player - > speed > 8000 )
player - > speed - = 2000 ;
else if ( player - > speed > 1000 )
player - > speed - = ( player - > speed / 4 ) ;
else {
player - > speed - = 60 ;
if ( player - > speed < 0 )
{
player - > speed = 0 ;
still = true ;
}
}
2017-09-15 19:34:46 +00:00
player - > pflags | = PF_STARTDASH ;
2014-03-15 16:59:03 +00:00
}
else
2017-09-15 19:34:46 +00:00
player - > pflags & = ~ PF_STARTDASH ;
2014-03-15 16:59:03 +00:00
{
const angle_t fa = ( FixedAngle ( player - > flyangle * FRACUNIT ) > > ANGLETOFINESHIFT ) & FINEMASK ;
const fixed_t speed = FixedDiv ( player - > speed * FRACUNIT , 50 * FRACUNIT ) ;
xspeed = FixedMul ( FINECOSINE ( fa ) , speed ) ;
yspeed = FixedMul ( FINESINE ( fa ) , speed ) ;
}
if ( ! ( player - > pflags & PF_TRANSFERTOCLOSEST ) )
{
xspeed = FixedMul ( xspeed , FixedDiv ( 1024 * FRACUNIT , player - > mo - > target - > radius ) ) ;
if ( backwardaxis )
xspeed * = - 1 ;
player - > angle_pos + = FixedAngleC ( FixedDiv ( xspeed , 5 * FRACUNIT ) , 40 * FRACUNIT ) ;
}
P_NightsTransferPoints ( player , xspeed , radius ) ;
if ( still )
player - > mo - > momz = - FRACUNIT ;
else
player - > mo - > momz = yspeed / 11 ;
if ( player - > mo - > momz > 20 * FRACUNIT )
player - > mo - > momz = 20 * FRACUNIT ;
else if ( player - > mo - > momz < - 20 * FRACUNIT )
player - > mo - > momz = - 20 * FRACUNIT ;
// You can create splashes as you fly across water.
2014-08-04 03:49:33 +00:00
if ( ( ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP )
& & player - > mo - > z + P_GetPlayerHeight ( player ) > = player - > mo - > watertop & & player - > mo - > z < = player - > mo - > watertop )
| | ( player - > mo - > eflags & MFE_VERTICALFLIP
& & player - > mo - > z + player - > mo - > height - P_GetPlayerHeight ( player ) < = player - > mo - > waterbottom & & player - > mo - > z + player - > mo - > height > = player - > mo - > waterbottom ) )
& & player - > speed > 9000 & & leveltime % ( TICRATE / 7 ) = = 0 & & ! player - > spectator )
2014-03-15 16:59:03 +00:00
{
2019-10-05 08:00:59 +00:00
mobjtype_t splishtype = ( player - > mo - > eflags & MFE_TOUCHLAVA ) ? MT_LAVASPLISH : MT_SPLISH ;
2014-08-04 03:49:33 +00:00
mobj_t * water = P_SpawnMobj ( player - > mo - > x , player - > mo - > y ,
2019-10-05 08:00:59 +00:00
( ( player - > mo - > eflags & MFE_VERTICALFLIP ) ? player - > mo - > waterbottom - FixedMul ( mobjinfo [ splishtype ] . height , player - > mo - > scale ) : player - > mo - > watertop ) , splishtype ) ;
2014-03-15 16:59:03 +00:00
if ( player - > mo - > eflags & MFE_GOOWATER )
S_StartSound ( water , sfx_ghit ) ;
2019-10-05 08:00:59 +00:00
else if ( player - > mo - > eflags & MFE_TOUCHLAVA )
S_StartSound ( water , sfx_splash ) ;
2014-03-15 16:59:03 +00:00
else
S_StartSound ( water , sfx_wslap ) ;
2014-08-04 03:49:33 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
water - > flags2 | = MF2_OBJECTFLIP ;
water - > eflags | = MFE_VERTICALFLIP ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
water - > destscale = player - > mo - > scale ;
P_SetScale ( water , player - > mo - > scale ) ;
2014-03-15 16:59:03 +00:00
}
if ( player - > mo - > momx | | player - > mo - > momy )
2019-08-04 14:25:13 +00:00
{
2014-03-15 16:59:03 +00:00
player - > mo - > angle = R_PointToAngle2 ( 0 , 0 , player - > mo - > momx , player - > mo - > momy ) ;
2019-08-04 14:25:13 +00:00
player - > drawangle = player - > mo - > angle ;
}
2014-03-15 16:59:03 +00:00
if ( still )
{
player - > anotherflyangle = 0 ;
movingangle = 0 ;
}
else
{
INT32 neg = 1 ;
// Special cases to prevent the angle from being
// calculated incorrectly when wrapped.
if ( backwardaxis & & ( player - > old_angle_pos > ANG350 & & player - > angle_pos < ANG10 ) )
neg = - 1 ;
else if ( backwardaxis ^ ( player - > old_angle_pos < ANG10 & & player - > angle_pos > ANG350 ) )
neg = - 1 ;
else if ( player - > angle_pos > player - > old_angle_pos )
neg = - 1 ;
2014-08-04 03:49:33 +00:00
movingangle = R_PointToAngle2 ( 0 , 0 , neg * R_PointToDist2 ( player - > mo - > momx , player - > mo - > momy , 0 , 0 ) , player - > mo - > momz ) ;
2014-03-15 16:59:03 +00:00
player - > anotherflyangle = ( movingangle > > ANGLETOFINESHIFT ) * 360 / FINEANGLES ;
}
// NiGHTS flying state
// Yep, I just ripped out almost 1000 lines of code.
2016-08-12 01:57:37 +00:00
// (and then toast revamped the entire thing again to be better, but not by much)
if ( still )
flystate = ( P_IsObjectOnGround ( player - > mo ) ) ? S_PLAY_NIGHTS_STAND : S_PLAY_NIGHTS_FLOAT ;
2014-03-15 16:59:03 +00:00
else
{
2019-11-14 16:37:03 +00:00
flystate = ( player - > pflags & PF_DRILLING ) ? S_PLAY_NIGHTS_DRILL : S_PLAY_NIGHTS_FLY ;
2019-11-14 15:27:22 +00:00
if ( player - > charflags & SF_NONIGHTSROTATION )
2014-03-15 16:59:03 +00:00
{
2019-11-14 16:37:03 +00:00
#if 0
2019-11-14 15:27:22 +00:00
visangle = ( ( player - > anotherflyangle + 7 ) % 360 ) / 15 ;
if ( visangle > 18 ) // Over 270 degrees.
visangle = 30 - visangle ;
else if ( visangle > 12 ) // Over 180 degrees.
visangle - = 6 ;
else if ( visangle > 6 ) // Over 90 degrees.
visangle = 12 - visangle ;
2016-08-12 01:57:37 +00:00
2019-11-14 15:27:22 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP & & visangle ) // S_PLAY_NIGHTS_FLY0 stays the same, even in reverse gravity
{
if ( visangle > 6 )
visangle - = 6 ; // shift to S_PLAY_NIGHTS_FLY1-6
else
visangle + = 6 ; // shift to S_PLAY_NIGHTS_FLY7-C
}
2016-08-12 01:57:37 +00:00
2019-11-14 16:37:03 +00:00
flystate + = ( visangle * 2 ) ; // S_PLAY_NIGHTS_FLY0-C - the *2 is to skip over drill states
# endif
2019-08-18 17:16:48 +00:00
}
2019-11-14 15:27:22 +00:00
# ifdef ROTSPRITE
else
{
angle_t a = R_PointToAngle ( player - > mo - > x , player - > mo - > y ) - player - > mo - > angle ;
visangle = ( player - > flyangle % 360 ) ;
if ( player - > flyangle > = 90 & & player - > flyangle < = 270 )
{
if ( player - > flyangle = = 270 & & ( a < ANGLE_180 ) )
;
else if ( player - > flyangle = = 90 & & ( a < ANGLE_180 ) )
;
else
visangle + = 180 ;
}
rollangle = FixedAngle ( visangle < < FRACBITS ) ;
}
2019-10-28 18:37:26 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
2016-08-12 01:57:37 +00:00
if ( player - > mo - > state ! = & states [ flystate ] )
P_SetPlayerMobjState ( player - > mo , flystate ) ;
2014-03-15 16:59:03 +00:00
2019-08-18 17:16:48 +00:00
# ifdef ROTSPRITE
2019-11-14 15:27:22 +00:00
if ( player - > charflags & SF_NONIGHTSROTATION )
player - > mo - > rollangle = 0 ;
else
player - > mo - > rollangle = rollangle ;
2019-10-28 18:37:26 +00:00
# endif
2019-08-18 17:16:48 +00:00
2014-03-15 16:59:03 +00:00
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
// Check for crushing in our new location
if ( ( player - > mo - > ceilingz - player - > mo - > floorz < player - > mo - > height )
& & ! ( player - > mo - > flags & MF_NOCLIP ) )
{
// Flashing won't run out until you STOP being crushed.
if ( player - > powers [ pw_flashing ] = = 1 )
player - > powers [ pw_flashing ] = 3 ;
else
2015-02-13 16:15:58 +00:00
P_DamageMobj ( player - > mo , NULL , NULL , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
}
if ( movingangle > = ANGLE_90 & & movingangle < = ANGLE_180 )
movingangle = movingangle - ANGLE_180 ;
else if ( movingangle > = ANGLE_180 & & movingangle < = ANGLE_270 )
movingangle = movingangle - ANGLE_180 ;
else if ( movingangle > = ANGLE_270 )
movingangle = InvAngle ( movingangle ) ;
if ( player = = & players [ consoleplayer ] )
localaiming = movingangle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localaiming2 = movingangle ;
if ( ( player - > pflags & PF_DRILLING ) & & ! player - > bumpertime )
{
if ( firstdrill )
{
S_StartSound ( player - > mo , sfx_drill1 ) ;
player - > drilltimer = 32 ;
}
2018-08-10 02:13:06 +00:00
else if ( player - > drilltimer = = 32 )
{
2018-08-30 13:09:19 +00:00
// drill mash penalty
2018-08-10 02:13:06 +00:00
player - > drilltimer = 31 ;
player - > drillmeter - = TICRATE / 2 ;
if ( player - > drillmeter < = 0 )
player - > drillmeter = TICRATE / 10 ;
}
2018-08-30 13:09:19 +00:00
else if ( - - player - > drilltimer = = 11 )
// give that drill mash penalty back (after 0.6 seconds)
player - > drillmeter + = TICRATE / 2 ;
else if ( player - > drilltimer < = 0 )
2014-03-15 16:59:03 +00:00
{
player - > drilltimer = 10 ;
S_StartSound ( player - > mo , sfx_drill2 ) ;
}
}
if ( objectplacing )
OP_NightsObjectplace ( player ) ;
}
// May be used in future for CTF
#if 0
static void P_PlayerDropWeapon ( player_t * player )
{
mobj_t * mo = NULL ;
if ( player - > powers [ pw_homingring ] )
{
mo = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + ( 60 * FRACUNIT ) , MT_HOMINGRING ) ;
player - > powers [ pw_homingring ] = 0 ;
}
else if ( player - > powers [ pw_railring ] )
{
mo = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + ( 60 * FRACUNIT ) , MT_RAILRING ) ;
player - > powers [ pw_railring ] = 0 ;
}
else if ( player - > powers [ pw_automaticring ] )
{
mo = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + ( 60 * FRACUNIT ) , MT_AUTOMATICRING ) ;
player - > powers [ pw_automaticring ] = 0 ;
}
else if ( player - > powers [ pw_explosionring ] )
{
mo = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + ( 60 * FRACUNIT ) , MT_EXPLOSIONRING ) ;
player - > powers [ pw_explosionring ] = 0 ;
}
else if ( player - > powers [ pw_scatterring ] )
{
mo = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + ( 60 * FRACUNIT ) , MT_SCATTERRING ) ;
player - > powers [ pw_scatterring ] = 0 ;
}
else if ( player - > powers [ pw_grenadering ] )
{
mo = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , player - > mo - > z + ( 60 * FRACUNIT ) , MT_GRENADERING ) ;
player - > powers [ pw_grenadering ] = 0 ;
}
if ( mo )
{
2015-08-15 20:07:16 +00:00
player - > rings - - ;
2014-03-15 16:59:03 +00:00
P_InstaThrust ( mo , player - > mo - > angle - ANGLE_180 , 8 * FRACUNIT ) ;
P_SetObjectMomZ ( mo , 4 * FRACUNIT , false ) ;
mo - > flags2 | = MF2_DONTRESPAWN ;
mo - > flags & = ~ MF_NOGRAVITY ;
mo - > flags & = ~ MF_NOCLIPHEIGHT ;
mo - > fuse = 12 * TICRATE ;
}
}
# endif
void P_BlackOw ( player_t * player )
{
INT32 i ;
S_StartSound ( player - > mo , sfx_bkpoof ) ; // Sound the BANG!
for ( i = 0 ; i < MAXPLAYERS ; i + + )
if ( playeringame [ i ] & & P_AproxDistance ( player - > mo - > x - players [ i ] . mo - > x ,
player - > mo - > y - players [ i ] . mo - > y ) < 1536 * FRACUNIT )
P_FlashPal ( & players [ i ] , PAL_NUKE , 10 ) ;
P_NukeEnemies ( player - > mo , player - > mo , 1536 * FRACUNIT ) ; // Search for all nearby enemies and nuke their pants off!
player - > powers [ pw_shield ] = player - > powers [ pw_shield ] & SH_STACK ;
}
2016-07-08 21:56:17 +00:00
void P_ElementalFire ( player_t * player , boolean cropcircle )
2014-03-15 16:59:03 +00:00
{
fixed_t newx ;
fixed_t newy ;
fixed_t ground ;
mobj_t * flame ;
angle_t travelangle ;
2014-08-04 03:49:33 +00:00
INT32 i ;
2014-03-15 16:59:03 +00:00
I_Assert ( player ! = NULL ) ;
I_Assert ( player - > mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( player - > mo ) ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2019-11-22 19:51:27 +00:00
ground = player - > mo - > ceilingz - FixedMul ( mobjinfo [ MT_SPINFIRE ] . height , player - > mo - > scale ) ;
2014-03-15 16:59:03 +00:00
else
2019-11-22 19:51:27 +00:00
ground = player - > mo - > floorz ;
if ( cropcircle )
ground + = P_MobjFlip ( player - > mo ) ;
2014-03-15 16:59:03 +00:00
2016-07-08 20:55:17 +00:00
if ( cropcircle )
2014-03-15 16:59:03 +00:00
{
2016-07-08 20:55:17 +00:00
# define numangles 8
2016-10-17 22:22:04 +00:00
# define limitangle (180 / numangles)
travelangle = player - > mo - > angle + P_RandomRange ( - limitangle , limitangle ) * ANG1 ;
2016-07-08 21:05:13 +00:00
for ( i = 0 ; i < numangles ; i + + )
2016-02-16 17:58:08 +00:00
{
2016-08-21 12:55:16 +00:00
flame = P_SpawnMobj ( player - > mo - > x , player - > mo - > y , ground , MT_SPINFIRE ) ;
flame - > flags & = ~ MF_NOGRAVITY ;
2016-07-08 20:55:17 +00:00
P_SetTarget ( & flame - > target , player - > mo ) ;
flame - > angle = travelangle + i * ( ANGLE_MAX / numangles ) ;
2016-08-21 12:55:16 +00:00
flame - > fuse = TICRATE * 7 ; // takes about an extra second to hit the ground
2016-07-08 20:55:17 +00:00
flame - > destscale = player - > mo - > scale ;
P_SetScale ( flame , player - > mo - > scale ) ;
flame - > eflags = ( flame - > eflags & ~ MFE_VERTICALFLIP ) | ( player - > mo - > eflags & MFE_VERTICALFLIP ) ;
P_InstaThrust ( flame , flame - > angle , FixedMul ( 3 * FRACUNIT , flame - > scale ) ) ;
P_SetObjectMomZ ( flame , 3 * FRACUNIT , false ) ;
2016-02-16 17:58:08 +00:00
}
2016-10-17 22:22:04 +00:00
# undef limitangle
2016-07-08 20:55:17 +00:00
# undef numangles
}
else
{
travelangle = R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) ;
for ( i = 0 ; i < 2 ; i + + )
{
newx = player - > mo - > x + P_ReturnThrustX ( player - > mo , ( travelangle + ( ( i & 1 ) ? - 1 : 1 ) * ANGLE_135 ) , FixedMul ( 24 * FRACUNIT , player - > mo - > scale ) ) ;
newy = player - > mo - > y + P_ReturnThrustY ( player - > mo , ( travelangle + ( ( i & 1 ) ? - 1 : 1 ) * ANGLE_135 ) , FixedMul ( 24 * FRACUNIT , player - > mo - > scale ) ) ;
# ifdef ESLOPE
if ( player - > mo - > standingslope )
{
ground = P_GetZAt ( player - > mo - > standingslope , newx , newy ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
ground - = FixedMul ( mobjinfo [ MT_SPINFIRE ] . height , player - > mo - > scale ) ;
}
2016-02-16 17:58:08 +00:00
# endif
2016-07-08 20:55:17 +00:00
flame = P_SpawnMobj ( newx , newy , ground , MT_SPINFIRE ) ;
P_SetTarget ( & flame - > target , player - > mo ) ;
flame - > angle = travelangle ;
2016-08-21 12:55:16 +00:00
flame - > fuse = TICRATE * 6 ;
2016-07-08 20:55:17 +00:00
flame - > destscale = player - > mo - > scale ;
P_SetScale ( flame , player - > mo - > scale ) ;
flame - > eflags = ( flame - > eflags & ~ MFE_VERTICALFLIP ) | ( player - > mo - > eflags & MFE_VERTICALFLIP ) ;
2016-09-29 20:25:15 +00:00
flame - > momx = 8 ; // this is a hack which is used to ensure it still behaves as a missile and can damage others
2016-07-08 20:55:17 +00:00
P_XYMovement ( flame ) ;
if ( P_MobjWasRemoved ( flame ) )
continue ;
2014-03-15 16:59:03 +00:00
2016-07-08 20:55:17 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
if ( flame - > z + flame - > height < flame - > ceilingz )
P_RemoveMobj ( flame ) ;
}
else if ( flame - > z > flame - > floorz )
2014-08-04 03:49:33 +00:00
P_RemoveMobj ( flame ) ;
}
2014-03-15 16:59:03 +00:00
}
}
static void P_SkidStuff ( player_t * player )
{
fixed_t pmx = player - > rmomx + player - > cmomx ;
fixed_t pmy = player - > rmomy + player - > cmomy ;
// Knuckles glides into the dirt.
if ( player - > pflags & PF_GLIDING & & player - > skidtime )
{
// Fell off a ledge...
if ( ! onground )
{
player - > skidtime = 0 ;
2017-03-18 21:06:06 +00:00
player - > pflags & = ~ ( PF_GLIDING | PF_JUMPED | PF_NOJUMPDAMAGE ) ;
2019-10-14 17:40:56 +00:00
player - > pflags | = PF_THOKKED ; // nice try, speedrunners (but for real this is just behavior from S3K)
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2014-03-15 16:59:03 +00:00
}
// Get up and brush yourself off, idiot.
2019-09-23 18:17:20 +00:00
else if ( player - > glidetime > 15 | | ! ( player - > cmd . buttons & BT_JUMP ) )
2014-03-15 16:59:03 +00:00
{
P_ResetPlayer ( player ) ;
2019-09-23 18:17:20 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_GLIDE_LANDING ) ;
2019-09-23 19:21:01 +00:00
player - > pflags | = PF_STASIS ;
2019-09-30 06:38:58 +00:00
player - > mo - > momx = ( ( player - > mo - > momx - player - > cmomx ) / 3 ) + player - > cmomx ;
player - > mo - > momy = ( ( player - > mo - > momy - player - > cmomy ) / 3 ) + player - > cmomy ;
2014-03-15 16:59:03 +00:00
}
// Didn't stop yet? Skid FOREVER!
else if ( player - > skidtime = = 1 )
player - > skidtime = 3 * TICRATE + 1 ;
// Spawn a particle every 3 tics.
else if ( ! ( player - > skidtime % 3 ) )
{
2019-10-13 20:08:07 +00:00
fixed_t radius = player - > mo - > radius > > FRACBITS ;
mobj_t * particle = P_SpawnMobjFromMobj ( player - > mo , P_RandomRange ( - radius , radius ) < < FRACBITS , P_RandomRange ( - radius , radius ) < < FRACBITS , 0 , MT_SPINDUST ) ;
2014-03-15 16:59:03 +00:00
particle - > tics = 10 ;
2017-04-03 18:01:30 +00:00
particle - > destscale = ( 2 * player - > mo - > scale ) / 3 ;
P_SetScale ( particle , particle - > destscale ) ;
2014-03-15 16:59:03 +00:00
P_SetObjectMomZ ( particle , FRACUNIT , false ) ;
2017-04-03 18:01:30 +00:00
if ( player - > mo - > eflags & ( MFE_TOUCHWATER | MFE_UNDERWATER ) ) // overrides fire version
P_SetMobjState ( particle , S_SPINDUST_BUBBLE1 ) ;
else if ( player - > powers [ pw_shield ] = = SH_ELEMENTAL )
P_SetMobjState ( particle , S_SPINDUST_FIRE1 ) ;
2014-03-15 16:59:03 +00:00
S_StartSound ( player - > mo , sfx_s3k7e ) ; // the proper "Knuckles eats dirt" sfx.
}
}
// Skidding!
else if ( onground & & ! ( player - > mo - > eflags & MFE_GOOWATER ) & & ! ( player - > pflags & ( PF_JUMPED | PF_SPINNING | PF_SLIDING ) ) & & ! ( player - > charflags & SF_NOSKID ) )
{
if ( player - > skidtime )
{
// Spawn a particle every 3 tics.
if ( ! ( player - > skidtime % 3 ) )
{
2017-04-03 18:01:30 +00:00
mobj_t * particle = P_SpawnMobjFromMobj ( player - > mo , 0 , 0 , 0 , MT_SPINDUST ) ;
2014-03-15 16:59:03 +00:00
particle - > tics = 10 ;
2017-04-03 18:01:30 +00:00
particle - > destscale = ( 2 * player - > mo - > scale ) / 3 ;
P_SetScale ( particle , particle - > destscale ) ;
2014-03-15 16:59:03 +00:00
P_SetObjectMomZ ( particle , FRACUNIT , false ) ;
2017-04-03 18:01:30 +00:00
if ( player - > mo - > eflags & ( MFE_TOUCHWATER | MFE_UNDERWATER ) ) // overrides fire version
P_SetMobjState ( particle , S_SPINDUST_BUBBLE1 ) ;
else if ( player - > powers [ pw_shield ] = = SH_ELEMENTAL )
P_SetMobjState ( particle , S_SPINDUST_FIRE1 ) ;
2014-03-15 16:59:03 +00:00
}
}
else if ( P_AproxDistance ( pmx , pmy ) > = FixedMul ( player - > runspeed / 2 , player - > mo - > scale ) // if you were moving faster than half your run speed last frame
2014-08-04 03:49:33 +00:00
& & ( player - > mo - > momx ! = pmx | | player - > mo - > momy ! = pmy ) // and you are moving differently this frame
& & P_GetPlayerControlDirection ( player ) = = 2 ) // and your controls are pointing in the opposite direction to your movement
2014-03-15 16:59:03 +00:00
{ // check for skidding
angle_t mang = R_PointToAngle2 ( 0 , 0 , pmx , pmy ) ; // movement angle
angle_t pang = R_PointToAngle2 ( pmx , pmy , player - > mo - > momx , player - > mo - > momy ) ; // push angle
angle_t dang = mang - pang ; // delta angle
if ( dang > ANGLE_180 ) // Make delta angle always positive, invert it if it's negative.
dang = InvAngle ( dang ) ;
// If your push angle is more than this close to a full 180 degrees, trigger a skid.
if ( dang > ANGLE_157h )
{
2017-09-09 21:12:23 +00:00
if ( player - > mo - > state - states ! = S_PLAY_SKID )
P_SetPlayerMobjState ( player - > mo , S_PLAY_SKID ) ;
2017-03-19 16:48:35 +00:00
player - > mo - > tics = player - > skidtime = ( player - > mo - > movefactor = = FRACUNIT ) ? TICRATE / 2 : ( FixedDiv ( 35 < < ( FRACBITS - 1 ) , FixedSqrt ( player - > mo - > movefactor ) ) ) > > FRACBITS ;
S_StartSound ( player - > mo , sfx_skid ) ;
2014-03-15 16:59:03 +00:00
}
}
}
else {
if ( player - > skidtime ) {
player - > skidtime = 0 ;
S_StopSound ( player - > mo ) ;
}
}
}
//
// P_MovePlayer
static void P_MovePlayer ( player_t * player )
{
ticcmd_t * cmd ;
INT32 i ;
fixed_t runspd ;
2017-10-04 16:45:03 +00:00
if ( player - > mo - > state > = & states [ S_PLAY_SUPER_TRANS1 ] & & player - > mo - > state < = & states [ S_PLAY_SUPER_TRANS6 ] )
2014-03-15 16:59:03 +00:00
{
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
return ;
}
cmd = & player - > cmd ;
runspd = FixedMul ( player - > runspeed , player - > mo - > scale ) ;
2019-11-22 21:06:25 +00:00
// This was done in Sonic 3 & Knuckles, but has been missed in Sonic Mania and the Taxman/Stealth mobile remakes. Thanks to NeoHazard for his 2017 blogpost on the matter, because this oversight otherwise almost made it all the way to 2.2's release.
//https://s3unlocked.blogspot.com/2017/12/over-threshold.html
if ( player - > powers [ pw_super ] )
runspd = FixedMul ( runspd , 5 * FRACUNIT / 3 ) ;
2016-06-03 16:26:50 +00:00
// Let's have some movement speed fun on low-friction surfaces, JUST for players... (high friction surfaces shouldn't have any adjustment, since the acceleration in this game is super high and that ends up cheesing high-friction surfaces.)
runspd = FixedMul ( runspd , player - > mo - > movefactor ) ;
2014-03-15 16:59:03 +00:00
// Control relinquishing stuff!
2017-03-20 19:04:33 +00:00
if ( ( player - > powers [ pw_carry ] = = CR_BRAKGOOP )
| | ( player - > pflags & PF_GLIDING & & player - > skidtime )
2017-03-21 16:04:49 +00:00
| | ( player - > charability2 = = CA2_GUNSLINGER & & player - > panim = = PA_ABILITY2 )
| | ( player - > charability2 = = CA2_MELEE & & player - > mo - > state - states = = S_PLAY_MELEE_LANDING ) )
2014-03-15 16:59:03 +00:00
player - > pflags | = PF_FULLSTASIS ;
else if ( player - > powers [ pw_nocontrol ] )
{
player - > pflags | = PF_STASIS ;
if ( ! ( player - > powers [ pw_nocontrol ] & ( 1 < < 15 ) ) )
player - > pflags | = PF_JUMPSTASIS ;
}
2019-10-28 18:37:26 +00:00
2019-09-30 06:38:58 +00:00
if ( player - > charability = = CA_GLIDEANDCLIMB & & player - > mo - > state - states = = S_PLAY_GLIDE_LANDING )
{
2019-09-23 19:21:01 +00:00
player - > pflags | = PF_STASIS ;
2019-09-30 06:38:58 +00:00
}
2019-09-23 19:21:01 +00:00
2016-02-14 20:28:03 +00:00
// note: don't unset stasis here
2014-03-15 16:59:03 +00:00
if ( ! player - > spectator & & G_TagGametype ( ) )
{
// If we have stasis already here, it's because it's forced on us
// by a linedef executor or what have you
boolean forcestasis = false ;
//During hide time, taggers cannot move.
if ( leveltime < hidetime * TICRATE )
{
if ( player - > pflags & PF_TAGIT )
forcestasis = true ;
}
else if ( gametype = = GT_HIDEANDSEEK )
{
if ( ! ( player - > pflags & PF_TAGIT ) )
{
forcestasis = true ;
2017-09-15 19:34:46 +00:00
if ( player - > pflags & PF_GAMETYPEOVER ) // Already hit.
2014-03-15 16:59:03 +00:00
player - > powers [ pw_flashing ] = 5 ;
}
}
if ( forcestasis )
{
player - > pflags | = PF_FULLSTASIS ;
// If you're in stasis in tag, you don't drown.
if ( player - > powers [ pw_underwater ] < = 12 * TICRATE + 1 )
P_RestoreMusic ( player ) ;
player - > powers [ pw_underwater ] = player - > powers [ pw_spacetime ] = 0 ;
}
}
2014-08-04 03:49:33 +00:00
if ( player - > spectator )
2014-03-15 16:59:03 +00:00
{
2017-07-08 10:41:20 +00:00
player - > mo - > eflags & = ~ MFE_VERTICALFLIP ; // deflip...
2014-08-04 03:49:33 +00:00
P_SpectatorMovement ( player ) ;
return ;
2014-03-15 16:59:03 +00:00
}
// Locate the capsule for this mare.
2014-08-04 03:49:33 +00:00
else if ( maptol & TOL_NIGHTS )
2014-03-15 16:59:03 +00:00
{
2017-03-14 18:11:17 +00:00
if ( ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2017-10-04 16:45:03 +00:00
& & ( player - > exiting
| | ! ( player - > mo - > state > = & states [ S_PLAY_NIGHTS_TRANS1 ]
2018-06-05 16:22:28 +00:00
& & player - > mo - > state < & states [ S_PLAY_NIGHTS_TRANS6 ] ) ) ) // Note the < instead of <=
2016-08-12 01:57:37 +00:00
{
skin_t * skin = ( ( skin_t * ) ( player - > mo - > skin ) ) ;
2018-06-05 16:22:28 +00:00
if ( skin - > flags & SF_SUPER )
{
player - > mo - > color = skin - > supercolor
+ ( ( player - > nightstime = = player - > startedtime )
? 4
: abs ( ( ( ( signed ) leveltime > > 1 ) % 9 ) - 4 ) ) ; // This is where super flashing is handled.
2017-10-10 16:56:38 +00:00
G_GhostAddColor ( GHC_SUPER ) ;
2018-06-05 16:22:28 +00:00
}
2016-08-12 01:57:37 +00:00
}
2014-03-15 16:59:03 +00:00
if ( ! player - > capsule & & ! player - > bonustime )
{
thinker_t * th ;
mobj_t * mo2 ;
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = MT_EGGCAPSULE
& & mo2 - > threshold = = player - > mare )
P_SetTarget ( & player - > capsule , mo2 ) ;
}
}
else if ( player - > capsule & & player - > capsule - > reactiontime > 0 & & player = = & players [ player - > capsule - > reactiontime - 1 ] )
{
P_DoNiGHTSCapsule ( player ) ;
return ;
}
2018-08-10 23:25:49 +00:00
// Suck player into their drone
if ( player - > drone )
{
P_MoveNiGHTSToDrone ( player ) ;
return ;
}
2014-03-15 16:59:03 +00:00
// Test revamped NiGHTS movement.
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
P_NiGHTSMovement ( player ) ;
// No more goto blockchecking, let's just do all that here =D
if ( CheckForBustableBlocks )
P_CheckBustableBlocks ( player ) ;
if ( CheckForBouncySector )
P_CheckBouncySectors ( player ) ;
if ( CheckForQuicksand )
P_CheckQuicksand ( player ) ;
return ;
}
2017-09-15 19:34:46 +00:00
else if ( player - > powers [ pw_carry ] = = CR_NIGHTSFALL & & P_IsObjectOnGround ( player - > mo ) )
2014-03-15 16:59:03 +00:00
{
if ( G_IsSpecialStage ( gamemap ) )
{
if ( player = = & players [ displayplayer ] ) // only play the sound for yourself landing
S_StartSound ( NULL , sfx_s3k6a ) ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
if ( playeringame [ i ] )
players [ i ] . exiting = ( 14 * TICRATE ) / 5 + 1 ;
}
2018-08-13 15:12:53 +00:00
else {
// Damage whether or not we have spheres, as player should recoil upon losing points
2015-02-13 16:15:58 +00:00
P_DamageMobj ( player - > mo , NULL , NULL , 1 , 0 ) ;
2018-08-13 15:12:53 +00:00
// Now deduct our mare score!
2018-09-07 12:19:22 +00:00
player - > marescore = player - > spheres = \
player - > rings = 0 ;
2018-08-13 15:12:53 +00:00
}
2017-09-15 19:34:46 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
}
}
//////////////////////
// MOVEMENT CODE //
//////////////////////
2014-08-04 03:49:33 +00:00
if ( twodlevel | | player - > mo - > flags2 & MF2_TWOD ) // 2d-level, so special control applies.
2014-03-15 16:59:03 +00:00
P_2dMovement ( player ) ;
else
{
2014-11-12 00:55:07 +00:00
if ( ! player - > climbing & & ( ! P_AnalogMove ( player ) ) )
2014-03-15 16:59:03 +00:00
player - > mo - > angle = ( cmd - > angleturn < < 16 /* not FRACBITS */ ) ;
ticruned + + ;
if ( ( cmd - > angleturn & TICCMD_RECEIVED ) = = 0 )
ticmiss + + ;
P_3dMovement ( player ) ;
}
if ( maptol & TOL_2D )
runspd = FixedMul ( runspd , 2 * FRACUNIT / 3 ) ;
P_SkidStuff ( player ) ;
/////////////////////////
// MOVEMENT ANIMATIONS //
/////////////////////////
2015-06-19 05:30:06 +00:00
if ( ( cmd - > forwardmove ! = 0 | | cmd - > sidemove ! = 0 ) | | ( player - > powers [ pw_super ] & & ! onground ) )
2014-03-15 16:59:03 +00:00
{
2016-07-09 13:52:49 +00:00
// If the player is in dashmode, here's their peelout.
2019-10-23 04:35:17 +00:00
if ( player - > charflags & SF_DASHMODE & & player - > dashmode > = DASHMODE_THRESHOLD & & player - > panim = = PA_RUN & & ! player - > skidtime & & ( onground | | ( ( player - > charability = = CA_FLOAT | | player - > charability = = CA_SLOWFALL ) & & player - > secondjump = = 1 ) | | player - > powers [ pw_super ] ) )
2017-03-11 02:09:01 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_DASH ) ;
2014-03-15 16:59:03 +00:00
// If the player is moving fast enough,
// break into a run!
2016-12-24 00:11:54 +00:00
else if ( player - > speed > = runspd & & player - > panim = = PA_WALK & & ! player - > skidtime
& & ( onground | | ( ( player - > charability = = CA_FLOAT | | player - > charability = = CA_SLOWFALL ) & & player - > secondjump = = 1 ) | | player - > powers [ pw_super ] ) )
{
if ( ! onground )
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLOAT_RUN ) ;
else
P_SetPlayerMobjState ( player - > mo , S_PLAY_RUN ) ;
}
2014-03-15 16:59:03 +00:00
2016-12-24 00:11:54 +00:00
// Floating at slow speeds has its own special animation.
else if ( ( ( ( player - > charability = = CA_FLOAT | | player - > charability = = CA_SLOWFALL ) & & player - > secondjump = = 1 ) | | player - > powers [ pw_super ] ) & & player - > panim = = PA_IDLE & & ! onground )
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLOAT ) ;
2015-06-19 05:30:06 +00:00
2014-03-15 16:59:03 +00:00
// Otherwise, just walk.
else if ( ( player - > rmomx | | player - > rmomy ) & & player - > panim = = PA_IDLE )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
2014-03-15 16:59:03 +00:00
}
2016-07-09 13:52:49 +00:00
// If your peelout animation is playing, and you're
// going too slow, switch back to the run.
2019-10-23 04:35:17 +00:00
if ( player - > charflags & SF_DASHMODE & & player - > panim = = PA_DASH & & player - > dashmode < DASHMODE_THRESHOLD )
2016-07-09 13:52:49 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_RUN ) ;
2014-03-15 16:59:03 +00:00
// If your running animation is playing, and you're
// going too slow, switch back to the walking frames.
if ( player - > panim = = PA_RUN & & player - > speed < runspd )
2015-06-19 05:30:06 +00:00
{
2017-03-11 17:14:39 +00:00
if ( ! onground & & ( ( ( player - > charability = = CA_FLOAT | | player - > charability = = CA_SLOWFALL ) & & player - > secondjump = = 1 ) | | player - > powers [ pw_super ] ) )
2016-12-24 00:11:54 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLOAT ) ;
2015-06-19 05:30:06 +00:00
else
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
}
2014-03-15 16:59:03 +00:00
2017-03-11 17:14:39 +00:00
// Correct floating when ending up on the ground.
if ( onground )
{
if ( player - > mo - > state - states = = S_PLAY_FLOAT )
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
else if ( player - > mo - > state - states = = S_PLAY_FLOAT_RUN )
P_SetPlayerMobjState ( player - > mo , S_PLAY_RUN ) ;
}
2016-10-23 16:05:17 +00:00
// If Springing (or nojumpspinning), but travelling DOWNWARD, change back!
A thorough reimplementation of Nojumpspin for the SPR2_ age.
* SF_NOJUMPSPIN - Player's height is full whilst jumping, SPR2_JUMP defaults to SPR2_SPNG instead of SPR2_SPIN, and the player goes into fall frames if they start moving downwards or use their ability.
* PA_JUMP - for jumping (upwards in the case of SF_NOJUMPSPIN.
* SF_NOJUMPDAMAGE - Ala rosy.wad, don't damage enemies, etc when jumping into them.
* SF_STOMPDAMAGE - Just for fun. Ala in Mario, always damage enemies when you land on top of them (your gravity reference, not theirs).
* SF_MARIODAMAGE - SF_NOJUMPDAMAGE|SF_STOMPDAMAGE is reasonably accurate to the Mario games, and might as well be surfaced as such.
Also, a minor change:
* Instead of not spawning the revitem if your SPR2_ is SPR2_DASH, don't spawn it if it's set to 0. This requires the player.dta I uploaded a couple days ago to behave as it was previously.
* Don't get stuck in spindash frames if your maxdash is 0, and don't flash rolling frames if you're on goop.
2016-07-10 17:41:38 +00:00
if ( ( player - > panim = = PA_SPRING & & P_MobjFlip ( player - > mo ) * player - > mo - > momz < 0 )
| | ( ( ( ( player - > charflags & SF_NOJUMPSPIN ) & & ( player - > pflags & PF_JUMPED ) & & player - > panim = = PA_JUMP ) )
2016-07-17 17:57:03 +00:00
& & ( P_MobjFlip ( player - > mo ) * player - > mo - > momz < 0 ) ) )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2016-07-13 14:15:45 +00:00
// If doing an air animation but on the ground, change back!
else if ( onground & & ( player - > panim = = PA_SPRING | | player - > panim = = PA_FALL | | player - > panim = = PA_RIDE | | player - > panim = = PA_JUMP ) & & ! player - > mo - > momz )
2014-03-15 16:59:03 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
// If you are stopped and are still walking, stand still!
if ( ! player - > mo - > momx & & ! player - > mo - > momy & & ! player - > mo - > momz & & player - > panim = = PA_WALK )
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
//////////////////
//GAMEPLAY STUFF//
//////////////////
// Make sure you're not "jumping" on the ground
if ( onground & & player - > pflags & PF_JUMPED & & ! ( player - > pflags & PF_GLIDING )
& & P_MobjFlip ( player - > mo ) * player - > mo - > momz < 0 )
{
2017-03-22 18:51:30 +00:00
player - > pflags & = ~ ( PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_THOKKED | PF_SHIELDABILITY ) ;
2014-03-15 16:59:03 +00:00
player - > secondjump = 0 ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
}
2016-09-10 20:13:51 +00:00
if ( ( ! ( player - > charability = = CA_GLIDEANDCLIMB ) | | player - > gotflag ) // If you can't glide, then why the heck would you be gliding?
& & ( player - > pflags & PF_GLIDING | | player - > climbing ) )
2014-08-04 03:49:33 +00:00
{
2016-09-10 20:13:51 +00:00
if ( onground )
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
else
2014-08-04 03:49:33 +00:00
{
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-09-10 20:13:51 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-08-04 03:49:33 +00:00
}
player - > pflags & = ~ PF_GLIDING ;
player - > glidetime = 0 ;
player - > climbing = 0 ;
}
2016-12-23 17:31:07 +00:00
if ( ( ! ( player - > charability = = CA_BOUNCE ) | | player - > gotflag ) // If you can't bounce, then why the heck would you be bouncing?
& & ( player - > pflags & PF_BOUNCING ) )
{
if ( onground )
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
else
{
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-12-23 17:31:07 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
}
player - > pflags & = ~ PF_BOUNCING ;
}
2014-03-15 16:59:03 +00:00
// Glide MOMZ
// AKA my own gravity. =)
if ( player - > pflags & PF_GLIDING )
{
2019-09-22 13:11:49 +00:00
mobj_t * mo = player - > mo ; // seriously why isn't this at the top of the function hngngngng
2019-12-05 07:59:16 +00:00
fixed_t leeway = ! P_AnalogMove ( player ) ? FixedAngle ( cmd - > sidemove * ( FRACUNIT ) ) : 0 ;
2014-04-14 05:14:58 +00:00
fixed_t glidespeed = player - > actionspd ;
2019-09-23 18:17:20 +00:00
fixed_t momx = mo - > momx - player - > cmomx , momy = mo - > momy - player - > cmomy ;
2019-09-22 16:21:28 +00:00
angle_t angle , moveangle = R_PointToAngle2 ( 0 , 0 , momx , momy ) ;
2014-04-14 05:14:58 +00:00
2019-09-22 18:56:01 +00:00
if ( player - > powers [ pw_super ] | | player - > powers [ pw_sneakers ] )
2014-04-14 05:14:58 +00:00
glidespeed * = 2 ;
2014-03-15 16:59:03 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
if ( player - > mo - > momz > FixedMul ( 2 * FRACUNIT , player - > mo - > scale ) )
player - > mo - > momz - = FixedMul ( 3 * ( FRACUNIT / 4 ) , player - > mo - > scale ) ;
}
else
{
if ( player - > mo - > momz < FixedMul ( - 2 * FRACUNIT , player - > mo - > scale ) )
player - > mo - > momz + = FixedMul ( 3 * ( FRACUNIT / 4 ) , player - > mo - > scale ) ;
}
// Strafing while gliding.
2019-09-22 16:21:28 +00:00
angle = mo - > angle - leeway ;
2014-03-15 16:59:03 +00:00
2019-09-23 19:10:41 +00:00
if ( ! player - > skidtime ) // TODO: make sure this works in 2D!
2014-03-15 16:59:03 +00:00
{
2019-09-22 16:21:28 +00:00
fixed_t speed , scale = mo - > scale ;
2019-09-23 18:17:20 +00:00
fixed_t newMagnitude , oldMagnitude = R_PointToDist2 ( momx , momy , 0 , 0 ) ;
2019-09-22 16:21:28 +00:00
fixed_t accelfactor = 4 * FRACUNIT - 3 * FINECOSINE ( ( ( angle - moveangle ) > > ANGLETOFINESHIFT ) & FINEMASK ) ; // mamgic number BAD but this feels right
2019-09-22 13:11:49 +00:00
if ( mo - > eflags & MFE_UNDERWATER )
speed = FixedMul ( ( glidespeed > > 1 ) + player - > glidetime * 750 , scale ) ;
else
speed = FixedMul ( glidespeed + player - > glidetime * 1500 , scale ) ;
P_Thrust ( mo , angle , FixedMul ( accelfactor , scale ) ) ;
2019-09-23 18:17:20 +00:00
newMagnitude = R_PointToDist2 ( player - > mo - > momx - player - > cmomx , player - > mo - > momy - player - > cmomy , 0 , 0 ) ;
if ( newMagnitude > speed )
2019-09-22 13:11:49 +00:00
{
2019-09-23 18:17:20 +00:00
fixed_t tempmomx , tempmomy ;
if ( oldMagnitude > speed )
{
if ( newMagnitude > oldMagnitude )
{
tempmomx = FixedMul ( FixedDiv ( player - > mo - > momx - player - > cmomx , newMagnitude ) , oldMagnitude ) ;
tempmomy = FixedMul ( FixedDiv ( player - > mo - > momy - player - > cmomy , newMagnitude ) , oldMagnitude ) ;
player - > mo - > momx = tempmomx + player - > cmomx ;
player - > mo - > momy = tempmomy + player - > cmomy ;
}
// else do nothing
}
else
{
tempmomx = FixedMul ( FixedDiv ( player - > mo - > momx - player - > cmomx , newMagnitude ) , speed ) ;
tempmomy = FixedMul ( FixedDiv ( player - > mo - > momy - player - > cmomy , newMagnitude ) , speed ) ;
player - > mo - > momx = tempmomx + player - > cmomx ;
player - > mo - > momy = tempmomy + player - > cmomy ;
}
2019-09-22 13:11:49 +00:00
}
2014-03-15 16:59:03 +00:00
}
player - > glidetime + + ;
if ( ! ( player - > pflags & PF_JUMPDOWN ) ) // If not holding the jump button
{
P_ResetPlayer ( player ) ; // down, stop gliding.
2014-08-04 03:49:33 +00:00
if ( onground )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
2017-03-27 14:03:21 +00:00
else if ( player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
{
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-01-14 14:35:10 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-03-15 16:59:03 +00:00
}
else
{
2014-04-14 05:14:58 +00:00
player - > pflags | = PF_THOKKED ;
2014-03-15 16:59:03 +00:00
player - > mo - > momx > > = 1 ;
player - > mo - > momy > > = 1 ;
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2014-03-15 16:59:03 +00:00
}
}
}
else if ( player - > climbing ) // 'Deceleration' for climbing on walls.
{
2019-09-23 18:17:20 +00:00
if ( ! player - > cmd . forwardmove )
player - > mo - > momz = 0 ;
2014-03-15 16:59:03 +00:00
}
2017-03-18 21:06:06 +00:00
else if ( player - > pflags & PF_BOUNCING )
{
2019-09-19 12:20:05 +00:00
if ( ! ( player - > pflags & PF_JUMPDOWN ) ) // If not holding the jump button
2017-03-18 21:06:06 +00:00
{
P_ResetPlayer ( player ) ; // down, stop bouncing.
player - > pflags | = PF_THOKKED ;
if ( onground )
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
2017-03-27 14:03:21 +00:00
else if ( player - > charflags & SF_MULTIABILITY )
2017-03-18 21:06:06 +00:00
{
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2017-03-18 21:06:06 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
}
else
{
player - > mo - > momx > > = 1 ;
player - > mo - > momy > > = 1 ;
player - > mo - > momz > > = 1 ;
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
}
}
}
else if ( player - > mo - > state - states = = S_PLAY_BOUNCE )
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2014-03-15 16:59:03 +00:00
// If you're running fast enough, you can create splashes as you run in shallow water.
if ( ! player - > climbing
& & ( ( ! ( player - > mo - > eflags & MFE_VERTICALFLIP ) & & player - > mo - > z + player - > mo - > height > = player - > mo - > watertop & & player - > mo - > z < = player - > mo - > watertop )
| | ( player - > mo - > eflags & MFE_VERTICALFLIP & & player - > mo - > z + player - > mo - > height > = player - > mo - > waterbottom & & player - > mo - > z < = player - > mo - > waterbottom ) )
& & ( player - > speed > runspd | | ( player - > pflags & PF_STARTDASH ) )
& & leveltime % ( TICRATE / 7 ) = = 0 & & player - > mo - > momz = = 0 & & ! ( player - > pflags & PF_SLIDING ) & & ! player - > spectator )
{
2019-10-05 08:00:59 +00:00
mobjtype_t splishtype = ( player - > mo - > eflags & MFE_TOUCHLAVA ) ? MT_LAVASPLISH : MT_SPLISH ;
2016-09-03 19:00:29 +00:00
mobj_t * water = P_SpawnMobj ( player - > mo - > x - P_ReturnThrustX ( NULL , player - > mo - > angle , player - > mo - > radius ) , player - > mo - > y - P_ReturnThrustY ( NULL , player - > mo - > angle , player - > mo - > radius ) ,
2019-10-05 08:00:59 +00:00
( ( player - > mo - > eflags & MFE_VERTICALFLIP ) ? player - > mo - > waterbottom - FixedMul ( mobjinfo [ splishtype ] . height , player - > mo - > scale ) : player - > mo - > watertop ) , splishtype ) ;
2014-03-15 16:59:03 +00:00
if ( player - > mo - > eflags & MFE_GOOWATER )
S_StartSound ( water , sfx_ghit ) ;
2019-10-05 08:00:59 +00:00
else if ( player - > mo - > eflags & MFE_TOUCHLAVA )
S_StartSound ( water , sfx_splash ) ;
2014-03-15 16:59:03 +00:00
else
S_StartSound ( water , sfx_wslap ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
water - > flags2 | = MF2_OBJECTFLIP ;
water - > eflags | = MFE_VERTICALFLIP ;
}
water - > destscale = player - > mo - > scale ;
P_SetScale ( water , player - > mo - > scale ) ;
}
// Little water sound while touching water - just a nicety.
if ( ( player - > mo - > eflags & MFE_TOUCHWATER ) & & ! ( player - > mo - > eflags & MFE_UNDERWATER ) & & ! player - > spectator )
{
2016-03-27 14:33:15 +00:00
if ( P_RandomChance ( FRACUNIT / 2 ) & & leveltime % TICRATE = = 0 )
2014-03-15 16:59:03 +00:00
S_StartSound ( player - > mo , sfx_floush ) ;
}
2014-08-04 03:49:33 +00:00
////////////////
//TAILS FLYING//
////////////////
if ( ! ( player - > charability = = CA_FLY | | player - > charability = = CA_SWIM ) ) // why are you flying when you cannot fly?!
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( player - > powers [ pw_tailsfly ]
2015-01-22 15:23:45 +00:00
| | player - > mo - > state - states = = S_PLAY_FLY_TIRED )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( onground )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
2014-08-04 03:49:33 +00:00
else
{
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2016-01-14 14:35:10 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-08-04 03:49:33 +00:00
}
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
player - > powers [ pw_tailsfly ] = 0 ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
if ( player - > gotflag & & player - > powers [ pw_tailsfly ] )
player - > powers [ pw_tailsfly ] = 1 ;
2014-03-15 16:59:03 +00:00
// If not in a fly position, don't think you're flying!
if ( player - > panim ! = PA_ABILITY )
player - > powers [ pw_tailsfly ] = 0 ;
2014-08-04 03:49:33 +00:00
if ( player - > charability = = CA_FLY | | ( player - > charability = = CA_SWIM & & player - > mo - > eflags & MFE_UNDERWATER ) )
2014-03-15 16:59:03 +00:00
{
// Fly counter for Tails.
if ( player - > powers [ pw_tailsfly ] )
{
const fixed_t actionspd = player - > actionspd / 100 ;
2017-03-27 14:03:21 +00:00
if ( player - > charflags & SF_MULTIABILITY )
2014-03-15 16:59:03 +00:00
{
// Adventure-style flying by just holding the button down
2014-08-04 03:49:33 +00:00
if ( cmd - > buttons & BT_JUMP & & ! ( player - > pflags & PF_STASIS ) & & ! player - > exiting )
2014-03-15 16:59:03 +00:00
P_SetObjectMomZ ( player - > mo , actionspd / 4 , true ) ;
}
else
{
// Classic flying
if ( player - > fly1 )
{
if ( P_MobjFlip ( player - > mo ) * player - > mo - > momz < FixedMul ( 5 * actionspd , player - > mo - > scale ) )
P_SetObjectMomZ ( player - > mo , actionspd / 2 , true ) ;
2019-09-19 11:30:30 +00:00
P_SetPlayerMobjState ( player - > mo , player - > mo - > state - > nextstate ) ;
2014-03-15 16:59:03 +00:00
player - > fly1 - - ;
}
}
// Tails Put-Put noise
2019-09-19 11:30:30 +00:00
if ( player - > charability = = CA_FLY
2019-11-18 07:55:55 +00:00
& & ( player - > pflags & PF_CANCARRY )
2019-09-19 11:30:30 +00:00
& & ! ( player - > mo - > eflags & MFE_UNDERWATER )
& & leveltime % 10 = = 0
& & ! player - > spectator )
2014-03-15 16:59:03 +00:00
S_StartSound ( player - > mo , sfx_putput ) ;
// Descend
2019-09-06 18:01:46 +00:00
if ( cmd - > buttons & BT_USE & & ! ( player - > pflags & PF_STASIS ) & & ! player - > exiting & & ! ( player - > mo - > eflags & MFE_GOOWATER ) )
2014-03-15 16:59:03 +00:00
if ( P_MobjFlip ( player - > mo ) * player - > mo - > momz > - FixedMul ( 5 * actionspd , player - > mo - > scale ) )
P_SetObjectMomZ ( player - > mo , - actionspd / 2 , true ) ;
}
else
{
// Tails-gets-tired Stuff
2019-09-18 11:46:18 +00:00
if ( player - > panim = = PA_ABILITY & & player - > mo - > state - states ! = S_PLAY_FLY_TIRED )
2015-01-22 15:23:45 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_FLY_TIRED ) ;
2014-03-15 16:59:03 +00:00
if ( player - > charability = = CA_FLY & & ( leveltime % 10 = = 0 )
2015-01-22 15:23:45 +00:00
& & player - > mo - > state - states = = S_PLAY_FLY_TIRED
2019-09-19 11:30:30 +00:00
& & ! ( player - > mo - > eflags & MFE_UNDERWATER )
2014-03-15 16:59:03 +00:00
& & ! player - > spectator )
S_StartSound ( player - > mo , sfx_pudpud ) ;
}
}
// End your chain if you're on the ground or climbing a wall.
// But not if invincible! Allow for some crazy long chains with it.
// Also keep in mind the PF_JUMPED check.
// If we lacked this, stepping up while jumping up would reset score.
// (for instance, when climbing up off a wall.)
if ( ( onground | | player - > climbing ) & & ! ( player - > pflags & PF_JUMPED ) & & player - > powers [ pw_invulnerability ] < = 1 )
P_ResetScore ( player ) ;
// Show the "THOK!" graphic when spinning quickly across the ground. (even applies to non-spinners, in the case of zoom tubes)
2017-01-23 01:39:12 +00:00
if ( player - > pflags & PF_SPINNING & & P_AproxDistance ( player - > speed , player - > mo - > momz ) > FixedMul ( 15 < < FRACBITS , player - > mo - > scale ) & & ! ( player - > pflags & PF_JUMPED ) )
2014-04-14 05:14:58 +00:00
{
2014-03-15 16:59:03 +00:00
P_SpawnSpinMobj ( player , player - > spinitem ) ;
2019-10-29 15:32:22 +00:00
G_GhostAddSpin ( ) ;
2014-04-14 05:14:58 +00:00
}
2014-03-15 16:59:03 +00:00
////////////////////////////
//SPINNING AND SPINDASHING//
////////////////////////////
// If the player isn't on the ground, make sure they aren't in a "starting dash" position.
2017-09-15 19:34:46 +00:00
if ( ! onground & & player - > powers [ pw_carry ] ! = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
player - > pflags & = ~ PF_STARTDASH ;
player - > dashspeed = 0 ;
}
if ( ( player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL
& & ( player - > pflags & PF_SPINNING ) & & player - > speed > FixedMul ( 4 < < FRACBITS , player - > mo - > scale ) & & onground & & ( leveltime & 1 )
& & ! ( player - > mo - > eflags & ( MFE_UNDERWATER | MFE_TOUCHWATER ) ) )
2016-07-08 21:56:17 +00:00
P_ElementalFire ( player , false ) ;
2014-03-15 16:59:03 +00:00
2016-07-17 20:31:15 +00:00
P_DoSpinAbility ( player , cmd ) ;
2014-03-15 16:59:03 +00:00
// jumping
P_DoJumpStuff ( player , cmd ) ;
// If you're not spinning, you'd better not be spindashing!
2017-09-15 19:34:46 +00:00
if ( ! ( player - > pflags & PF_SPINNING ) & & player - > powers [ pw_carry ] ! = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
player - > pflags & = ~ PF_STARTDASH ;
//////////////////
//ANALOG CONTROL//
//////////////////
2014-08-04 03:49:33 +00:00
// This really looks like it should be moved to P_3dMovement. -Red
2014-11-12 00:55:07 +00:00
if ( P_AnalogMove ( player )
2014-08-04 03:49:33 +00:00
& & ( cmd - > forwardmove ! = 0 | | cmd - > sidemove ! = 0 ) & & ! player - > climbing & & ! twodlevel & & ! ( player - > mo - > flags2 & MF2_TWOD ) )
2014-03-15 16:59:03 +00:00
{
// If travelling slow enough, face the way the controls
// point and not your direction of movement.
2014-08-04 03:49:33 +00:00
if ( player - > speed < FixedMul ( 5 * FRACUNIT , player - > mo - > scale ) | | player - > pflags & PF_GLIDING | | ! onground )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
angle_t tempangle ;
2014-03-15 16:59:03 +00:00
2014-11-12 00:55:07 +00:00
tempangle = ( cmd - > angleturn < < 16 ) ;
# ifdef REDSANALOG // Ease to it. Chillax. ~Red
tempangle + = R_PointToAngle2 ( 0 , 0 , cmd - > forwardmove * FRACUNIT , - cmd - > sidemove * FRACUNIT ) ;
{
fixed_t tweenvalue = max ( abs ( cmd - > forwardmove ) , abs ( cmd - > sidemove ) ) ;
if ( tweenvalue < 10 & & ( cmd - > buttons & ( BT_CAMLEFT | BT_CAMRIGHT ) ) = = ( BT_CAMLEFT | BT_CAMRIGHT ) ) {
tempangle = ( cmd - > angleturn < < 16 ) ;
tweenvalue = 16 ;
}
2014-03-15 16:59:03 +00:00
2014-11-12 00:55:07 +00:00
tweenvalue * = tweenvalue * tweenvalue * 1536 ;
2014-03-15 16:59:03 +00:00
2014-11-12 00:55:07 +00:00
//if (player->pflags & PF_GLIDING)
//tweenvalue >>= 1;
tempangle - = player - > mo - > angle ;
if ( tempangle < ANGLE_180 & & tempangle > tweenvalue )
player - > mo - > angle + = tweenvalue ;
else if ( tempangle > = ANGLE_180 & & InvAngle ( tempangle ) > tweenvalue )
player - > mo - > angle - = tweenvalue ;
else
player - > mo - > angle + = tempangle ;
}
# else
// Less math this way ~Red
player - > mo - > angle = R_PointToAngle2 ( 0 , 0 , cmd - > forwardmove * FRACUNIT , - cmd - > sidemove * FRACUNIT ) + tempangle ;
# endif
2014-03-15 16:59:03 +00:00
}
// Otherwise, face the direction you're travelling.
2017-03-11 02:09:01 +00:00
else if ( player - > panim = = PA_WALK | | player - > panim = = PA_RUN | | player - > panim = = PA_DASH | | player - > panim = = PA_ROLL | | player - > panim = = PA_JUMP
2016-09-08 16:48:54 +00:00
| | ( player - > panim = = PA_ABILITY & & player - > mo - > state - states = = S_PLAY_GLIDE ) )
2014-08-04 03:49:33 +00:00
player - > mo - > angle = R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) ;
2014-03-15 16:59:03 +00:00
// Update the local angle control.
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
}
if ( player - > climbing = = 1 )
P_DoClimbing ( player ) ;
if ( player - > climbing > 1 )
{
P_InstaThrust ( player - > mo , player - > mo - > angle , FixedMul ( 4 * FRACUNIT , player - > mo - > scale ) ) ; // Shove up against the wall
player - > climbing - - ;
}
if ( ! player - > climbing )
{
player - > lastsidehit = - 1 ;
player - > lastlinehit = - 1 ;
}
// Make sure you're not teetering when you shouldn't be.
2015-06-18 15:36:08 +00:00
if ( player - > panim = = PA_EDGE
2014-03-15 16:59:03 +00:00
& & ( player - > mo - > momx | | player - > mo - > momy | | player - > mo - > momz ) )
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
// Check for teeter!
if ( ! ( player - > mo - > momz | | player - > mo - > momx | | player - > mo - > momy ) & & ! ( player - > mo - > eflags & MFE_GOOWATER )
2016-09-23 22:48:48 +00:00
& & player - > panim = = PA_IDLE & & ! ( player - > powers [ pw_carry ] ) )
2014-03-15 16:59:03 +00:00
P_DoTeeter ( player ) ;
// Toss a flag
if ( G_GametypeHasTeams ( ) & & ( cmd - > buttons & BT_TOSSFLAG ) & & ! ( player - > powers [ pw_super ] ) & & ! ( player - > tossdelay ) )
{
if ( ! ( player - > gotflag & ( GF_REDFLAG | GF_BLUEFLAG ) ) )
P_PlayerEmeraldBurst ( player , true ) ; // Toss emeralds
else
P_PlayerFlagBurst ( player , true ) ;
}
// check for fire
if ( ! player - > exiting )
P_DoFiring ( player , cmd ) ;
{
fixed_t oldheight = player - > mo - > height ;
// Less height while spinning. Good for spinning under things...?
2017-03-11 02:09:01 +00:00
if ( ( player - > mo - > state = = & states [ player - > mo - > info - > painstate ] )
2019-09-06 18:01:46 +00:00
| | ( ( player - > pflags & PF_JUMPED ) & & ! ( player - > pflags & PF_NOJUMPDAMAGE ) )
2016-07-10 19:03:08 +00:00
| | ( player - > pflags & PF_SPINNING )
2014-03-15 16:59:03 +00:00
| | player - > powers [ pw_tailsfly ] | | player - > pflags & PF_GLIDING
2015-01-22 15:23:45 +00:00
| | ( player - > charability = = CA_FLY & & player - > mo - > state - states = = S_PLAY_FLY_TIRED ) )
2014-03-15 16:59:03 +00:00
player - > mo - > height = P_GetPlayerSpinHeight ( player ) ;
else
player - > mo - > height = P_GetPlayerHeight ( player ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP & & player - > mo - > height ! = oldheight ) // adjust z height for reverse gravity, similar to how it's done for scaling
player - > mo - > z - = player - > mo - > height - oldheight ;
}
// Crush test...
if ( ( player - > mo - > ceilingz - player - > mo - > floorz < player - > mo - > height )
& & ! ( player - > mo - > flags & MF_NOCLIP ) )
{
if ( ( player - > charability2 = = CA2_SPINDASH ) & & ! ( player - > pflags & PF_SPINNING ) )
{
player - > pflags | = PF_SPINNING ;
2017-03-11 02:09:01 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
2014-03-15 16:59:03 +00:00
}
else if ( player - > mo - > ceilingz - player - > mo - > floorz < player - > mo - > height )
{
if ( ( netgame | | multiplayer ) & & player - > spectator )
2015-02-13 16:15:58 +00:00
P_DamageMobj ( player - > mo , 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 ( player - > mo , NULL , NULL , 1 , DMG_CRUSHED ) ;
2014-03-15 16:59:03 +00:00
if ( player - > playerstate = = PST_DEAD )
return ;
}
}
# ifdef HWRENDER
if ( rendermode ! = render_soft & & rendermode ! = render_none & & cv_grfovchange . value )
{
fixed_t speed ;
const fixed_t runnyspeed = 20 * FRACUNIT ;
2014-08-04 03:49:33 +00:00
speed = R_PointToDist2 ( player - > rmomx , player - > rmomy , 0 , 0 ) ;
2014-03-15 16:59:03 +00:00
if ( speed > player - > normalspeed - 5 * FRACUNIT )
speed = player - > normalspeed - 5 * FRACUNIT ;
if ( speed > = runnyspeed )
player - > fovadd = speed - runnyspeed ;
else
2014-08-04 03:49:33 +00:00
player - > fovadd = 0 ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( player - > fovadd < 0 )
player - > fovadd = 0 ;
2014-03-15 16:59:03 +00:00
}
else
2014-08-04 03:49:33 +00:00
player - > fovadd = 0 ;
2014-03-15 16:59:03 +00:00
# endif
# ifdef FLOORSPLATS
if ( cv_shadow . value & & rendermode = = render_soft )
R_AddFloorSplat ( player - > mo - > subsector , player - > mo , " SHADOW " , player - > mo - > x ,
player - > mo - > y , player - > mo - > floorz , SPLATDRAWMODE_OPAQUE ) ;
# endif
// Look for blocks to bust up
// Because of FF_SHATTER, we should look for blocks constantly,
// not just when spinning or playing as Knuckles
if ( CheckForBustableBlocks )
P_CheckBustableBlocks ( player ) ;
// Special handling for
// gliding in 2D mode
if ( ( twodlevel | | player - > mo - > flags2 & MF2_TWOD ) & & player - > pflags & PF_GLIDING & & player - > charability = = CA_GLIDEANDCLIMB
& & ! ( player - > mo - > flags & MF_NOCLIP ) )
{
msecnode_t * node ; // only place it's being used in P_MovePlayer now
fixed_t oldx ;
fixed_t oldy ;
2016-09-01 20:21:20 +00:00
fixed_t floorz , ceilingz ;
2014-03-15 16:59:03 +00:00
oldx = player - > mo - > x ;
oldy = player - > mo - > y ;
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x + = player - > mo - > momx ;
player - > mo - > y + = player - > mo - > momy ;
P_SetThingPosition ( player - > mo ) ;
2016-06-09 13:56:24 +00:00
for ( node = player - > mo - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
if ( ! node - > m_sector )
break ;
if ( node - > m_sector - > ffloors )
{
ffloor_t * rover ;
2016-09-01 20:21:20 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
for ( rover = node - > m_sector - > ffloors ; rover ; rover = rover - > next )
{
2016-09-01 20:21:20 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_BLOCKPLAYER ) )
continue ;
2014-03-15 16:59:03 +00:00
2016-09-01 20:21:20 +00:00
topheight = P_GetFOFTopZ ( player - > mo , node - > m_sector , rover , player - > mo - > x , player - > mo - > y , NULL ) ;
bottomheight = P_GetFOFBottomZ ( player - > mo , node - > m_sector , rover , player - > mo - > x , player - > mo - > y , NULL ) ;
if ( topheight > player - > mo - > z & & bottomheight < player - > mo - > z )
2014-03-15 16:59:03 +00:00
{
2016-09-01 20:21:20 +00:00
P_ResetPlayer ( player ) ;
S_StartSound ( player - > mo , sfx_s3k4a ) ;
player - > climbing = 5 ;
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
break ;
2014-03-15 16:59:03 +00:00
}
}
}
2016-09-01 20:21:20 +00:00
floorz = P_GetFloorZ ( player - > mo , node - > m_sector , player - > mo - > x , player - > mo - > y , NULL ) ;
ceilingz = P_GetCeilingZ ( player - > mo , node - > m_sector , player - > mo - > x , player - > mo - > y , NULL ) ;
if ( player - > mo - > z + player - > mo - > height > ceilingz
2014-03-15 16:59:03 +00:00
& & node - > m_sector - > ceilingpic = = skyflatnum )
continue ;
2016-09-01 20:21:20 +00:00
if ( floorz > player - > mo - > z | | ceilingz < player - > mo - > z )
2014-03-15 16:59:03 +00:00
{
P_ResetPlayer ( player ) ;
S_StartSound ( player - > mo , sfx_s3k4a ) ;
player - > climbing = 5 ;
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
break ;
}
}
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x = oldx ;
player - > mo - > y = oldy ;
P_SetThingPosition ( player - > mo ) ;
}
// Check for a BOUNCY sector!
if ( CheckForBouncySector )
P_CheckBouncySectors ( player ) ;
// Look for Quicksand!
if ( CheckForQuicksand )
P_CheckQuicksand ( player ) ;
2019-11-07 17:10:59 +00:00
if ( P_IsObjectOnGround ( player - > mo ) )
player - > mo - > pmomz = 0 ;
2014-03-15 16:59:03 +00:00
}
static void P_DoZoomTube ( player_t * player )
{
INT32 sequence ;
fixed_t speed ;
thinker_t * th ;
mobj_t * mo2 ;
mobj_t * waypoint = NULL ;
fixed_t dist ;
boolean reverse ;
player - > mo - > height = P_GetPlayerSpinHeight ( player ) ;
if ( player - > speed > 0 )
reverse = false ;
else
reverse = true ;
player - > powers [ pw_flashing ] = 1 ;
speed = abs ( player - > speed ) ;
sequence = player - > mo - > tracer - > threshold ;
// change slope
dist = P_AproxDistance ( P_AproxDistance ( player - > mo - > tracer - > x - player - > mo - > x , player - > mo - > tracer - > y - player - > mo - > y ) , player - > mo - > tracer - > z - player - > mo - > z ) ;
if ( dist < 1 )
dist = 1 ;
2016-09-25 14:07:00 +00:00
player - > mo - > momx = FixedMul ( FixedDiv ( player - > mo - > tracer - > x - player - > mo - > x , dist ) , ( speed ) ) ;
player - > mo - > momy = FixedMul ( FixedDiv ( player - > mo - > tracer - > y - player - > mo - > y , dist ) , ( speed ) ) ;
player - > mo - > momz = FixedMul ( FixedDiv ( player - > mo - > tracer - > z - player - > mo - > z , dist ) , ( speed ) ) ;
2014-03-15 16:59:03 +00:00
// Calculate the distance between the player and the waypoint
// 'dist' already equals this.
2016-09-23 23:37:18 +00:00
// Will the player go past the waypoint?
2016-09-25 14:07:00 +00:00
if ( speed > dist )
2014-03-15 16:59:03 +00:00
{
2016-09-25 14:07:00 +00:00
speed - = dist ;
2014-03-15 16:59:03 +00:00
// If further away, set XYZ of player to waypoint location
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x = player - > mo - > tracer - > x ;
player - > mo - > y = player - > mo - > tracer - > y ;
player - > mo - > z = player - > mo - > tracer - > z ;
P_SetThingPosition ( player - > mo ) ;
// ugh, duh!!
player - > mo - > floorz = player - > mo - > subsector - > sector - > floorheight ;
player - > mo - > ceilingz = player - > mo - > subsector - > sector - > ceilingheight ;
CONS_Debug ( DBG_GAMELOGIC , " Looking for next waypoint... \n " ) ;
// Find next waypoint
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type ! = MT_TUBEWAYPOINT )
continue ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > threshold ! = sequence )
continue ;
if ( reverse & & mo2 - > health ! = player - > mo - > tracer - > health - 1 )
continue ;
if ( ! reverse & & mo2 - > health ! = player - > mo - > tracer - > health + 1 )
continue ;
waypoint = mo2 ;
break ;
2014-03-15 16:59:03 +00:00
}
if ( waypoint )
{
CONS_Debug ( DBG_GAMELOGIC , " Found waypoint (sequence %d, number %d). \n " , waypoint - > threshold , waypoint - > health ) ;
2016-09-23 23:37:18 +00:00
P_SetTarget ( & player - > mo - > tracer , waypoint ) ;
2014-03-15 16:59:03 +00:00
// calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
dist = P_AproxDistance ( P_AproxDistance ( player - > mo - > tracer - > x - player - > mo - > x , player - > mo - > tracer - > y - player - > mo - > y ) , player - > mo - > tracer - > z - player - > mo - > z ) ;
if ( dist < 1 )
dist = 1 ;
player - > mo - > momx = FixedMul ( FixedDiv ( player - > mo - > tracer - > x - player - > mo - > x , dist ) , ( speed ) ) ;
player - > mo - > momy = FixedMul ( FixedDiv ( player - > mo - > tracer - > y - player - > mo - > y , dist ) , ( speed ) ) ;
player - > mo - > momz = FixedMul ( FixedDiv ( player - > mo - > tracer - > z - player - > mo - > z , dist ) , ( speed ) ) ;
}
else
{
2016-09-24 12:18:08 +00:00
P_SetTarget ( & player - > mo - > tracer , NULL ) ; // Else, we just let them fly.
2016-09-23 22:48:48 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
CONS_Debug ( DBG_GAMELOGIC , " Next waypoint not found, releasing from track... \n " ) ;
}
}
2016-12-01 14:40:58 +00:00
// change angle
if ( player - > mo - > tracer )
{
player - > mo - > angle = R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , player - > mo - > tracer - > x , player - > mo - > tracer - > y ) ;
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
}
2014-03-15 16:59:03 +00:00
}
//
// P_DoRopeHang
//
// Kinda like P_DoZoomTube
// but a little different.
//
static void P_DoRopeHang ( player_t * player )
{
INT32 sequence ;
fixed_t speed ;
thinker_t * th ;
mobj_t * mo2 ;
mobj_t * waypoint = NULL ;
fixed_t dist ;
fixed_t playerz ;
player - > mo - > height = P_GetPlayerHeight ( player ) ;
// Play the 'clink' sound only if the player is moving.
if ( ! ( leveltime & 7 ) & & player - > speed )
S_StartSound ( player - > mo , sfx_s3k55 ) ;
playerz = player - > mo - > z + player - > mo - > height ;
speed = abs ( player - > speed ) ;
sequence = player - > mo - > tracer - > threshold ;
// change slope
dist = P_AproxDistance ( P_AproxDistance ( player - > mo - > tracer - > x - player - > mo - > x , player - > mo - > tracer - > y - player - > mo - > y ) , player - > mo - > tracer - > z - playerz ) ;
if ( dist < 1 )
dist = 1 ;
2016-09-25 14:07:00 +00:00
player - > mo - > momx = FixedMul ( FixedDiv ( player - > mo - > tracer - > x - player - > mo - > x , dist ) , ( speed ) ) ;
player - > mo - > momy = FixedMul ( FixedDiv ( player - > mo - > tracer - > y - player - > mo - > y , dist ) , ( speed ) ) ;
player - > mo - > momz = FixedMul ( FixedDiv ( player - > mo - > tracer - > z - playerz , dist ) , ( speed ) ) ;
if ( player - > cmd . buttons & BT_USE & & ! ( player - > pflags & PF_STASIS ) ) // Drop off of the rope
{
2019-09-25 15:09:05 +00:00
player - > pflags | = ( P_GetJumpFlags ( player ) | PF_USEDOWN ) ;
2018-06-05 16:22:28 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2016-09-25 14:07:00 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
return ;
}
2014-03-15 16:59:03 +00:00
2018-06-05 16:22:28 +00:00
if ( player - > mo - > state - states ! = S_PLAY_RIDE )
P_SetPlayerMobjState ( player - > mo , S_PLAY_RIDE ) ;
2014-03-15 16:59:03 +00:00
// If not allowed to move, we're done here.
if ( ! speed )
return ;
// Calculate the distance between the player and the waypoint
// 'dist' already equals this.
2016-09-23 22:48:48 +00:00
// Will the player go past the waypoint?
2016-09-25 14:07:00 +00:00
if ( speed > dist )
2014-03-15 16:59:03 +00:00
{
2016-09-25 14:07:00 +00:00
speed - = dist ;
2014-03-15 16:59:03 +00:00
// If further away, set XYZ of player to waypoint location
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x = player - > mo - > tracer - > x ;
player - > mo - > y = player - > mo - > tracer - > y ;
player - > mo - > z = player - > mo - > tracer - > z - player - > mo - > height ;
2016-09-23 22:48:48 +00:00
playerz = player - > mo - > tracer - > z ;
2014-03-15 16:59:03 +00:00
P_SetThingPosition ( player - > mo ) ;
CONS_Debug ( DBG_GAMELOGIC , " Looking for next waypoint... \n " ) ;
// Find next waypoint
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type ! = MT_TUBEWAYPOINT )
continue ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > threshold ! = sequence )
continue ;
if ( mo2 - > health ! = player - > mo - > tracer - > health + 1 )
continue ;
waypoint = mo2 ;
break ;
2014-03-15 16:59:03 +00:00
}
if ( ! ( player - > mo - > tracer - > flags & MF_SLIDEME ) & & ! waypoint )
{
CONS_Debug ( DBG_GAMELOGIC , " Next waypoint not found, wrapping to start... \n " ) ;
// Wrap around back to first waypoint
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type ! = MT_TUBEWAYPOINT )
continue ;
2019-07-12 23:42:03 +00:00
if ( mo2 - > threshold ! = sequence )
continue ;
if ( mo2 - > health ! = 0 )
continue ;
waypoint = mo2 ;
break ;
2014-03-15 16:59:03 +00:00
}
}
if ( waypoint )
{
CONS_Debug ( DBG_GAMELOGIC , " Found waypoint (sequence %d, number %d). \n " , waypoint - > threshold , waypoint - > health ) ;
2016-09-23 22:48:48 +00:00
P_SetTarget ( & player - > mo - > tracer , waypoint ) ;
2014-03-15 16:59:03 +00:00
// calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
dist = P_AproxDistance ( P_AproxDistance ( player - > mo - > tracer - > x - player - > mo - > x , player - > mo - > tracer - > y - player - > mo - > y ) , player - > mo - > tracer - > z - playerz ) ;
if ( dist < 1 )
dist = 1 ;
player - > mo - > momx = FixedMul ( FixedDiv ( player - > mo - > tracer - > x - player - > mo - > x , dist ) , ( speed ) ) ;
player - > mo - > momy = FixedMul ( FixedDiv ( player - > mo - > tracer - > y - player - > mo - > y , dist ) , ( speed ) ) ;
player - > mo - > momz = FixedMul ( FixedDiv ( player - > mo - > tracer - > z - playerz , dist ) , ( speed ) ) ;
}
else
{
if ( player - > mo - > tracer - > flags & MF_SLIDEME )
{
2017-04-03 17:28:02 +00:00
player - > pflags | = P_GetJumpFlags ( player ) ;
2018-06-05 16:22:28 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_JUMP ) ;
2014-03-15 16:59:03 +00:00
}
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2016-09-23 22:48:48 +00:00
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
CONS_Debug ( DBG_GAMELOGIC , " Next waypoint not found! \n " ) ;
}
}
}
#if 0
//
// P_NukeAllPlayers
//
// Hurts all players
// source = guy who gets the credit
//
static void P_NukeAllPlayers ( player_t * player )
{
mobj_t * mo ;
2019-07-12 23:42:03 +00:00
UINT8 i ;
2014-03-15 16:59:03 +00:00
2019-07-12 23:42:03 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( ! playeringame [ i ] )
2014-03-15 16:59:03 +00:00
continue ;
2019-07-12 23:42:03 +00:00
if ( players [ i ] . spectator )
2014-03-15 16:59:03 +00:00
continue ;
2019-07-12 23:42:03 +00:00
if ( ! players [ i ] . mo )
continue ;
if ( players [ i ] . mo = = player - > mo )
continue ;
if ( players [ i ] . mo - > health < = 0 )
2014-03-15 16:59:03 +00:00
continue ;
2019-07-12 23:42:03 +00:00
P_DamageMobj ( players [ i ] . mo , player - > mo , player - > mo , 1 , 0 ) ;
2014-03-15 16:59:03 +00:00
}
CONS_Printf ( M_GetText ( " %s caused a world of pain. \n " ) , player_names [ player - players ] ) ;
return ;
}
# endif
//
// P_NukeEnemies
// Looks for something you can hit - Used for bomb shield
//
void P_NukeEnemies ( mobj_t * inflictor , mobj_t * source , fixed_t radius )
{
const fixed_t ns = 60 < < FRACBITS ;
mobj_t * mo ;
angle_t fa ;
thinker_t * think ;
INT32 i ;
for ( i = 0 ; i < 16 ; i + + )
{
fa = ( i * ( FINEANGLES / 16 ) ) ;
mo = P_SpawnMobj ( inflictor - > x , inflictor - > y , inflictor - > z , MT_SUPERSPARK ) ;
2014-08-05 23:59:40 +00:00
if ( ! P_MobjWasRemoved ( mo ) )
{
mo - > momx = FixedMul ( FINESINE ( fa ) , ns ) ;
mo - > momy = FixedMul ( FINECOSINE ( fa ) , ns ) ;
}
2014-03-15 16:59:03 +00:00
}
2019-04-20 21:29:20 +00:00
for ( think = thlist [ THINK_MOBJ ] . next ; think ! = & thlist [ THINK_MOBJ ] ; think = think - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( think - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
continue ;
2014-03-15 16:59:03 +00:00
mo = ( mobj_t * ) think ;
if ( ! ( mo - > flags & MF_SHOOTABLE ) & & ! ( mo - > type = = MT_EGGGUARD | | mo - > type = = MT_MINUS ) )
continue ;
if ( mo - > flags & MF_MONITOR )
continue ; // Monitors cannot be 'nuked'.
if ( ! G_RingSlingerGametype ( ) & & mo - > type = = MT_PLAYER )
continue ; // Don't hurt players in Co-Op!
2014-08-04 03:49:33 +00:00
if ( abs ( inflictor - > x - mo - > x ) > radius | | abs ( inflictor - > y - mo - > y ) > radius | | abs ( inflictor - > z - mo - > z ) > radius )
continue ; // Workaround for possible integer overflow in the below -Red
2014-03-15 16:59:03 +00:00
if ( P_AproxDistance ( P_AproxDistance ( inflictor - > x - mo - > x , inflictor - > y - mo - > y ) , inflictor - > z - mo - > z ) > radius )
continue ;
if ( mo - > type = = MT_MINUS & & ! ( mo - > flags & ( MF_SPECIAL | MF_SHOOTABLE ) ) )
2019-10-06 15:17:11 +00:00
mo - > flags = ( mo - > flags & ~ MF_NOCLIPTHING ) | MF_SPECIAL | MF_SHOOTABLE ;
2014-03-15 16:59:03 +00:00
if ( mo - > type = = MT_EGGGUARD & & mo - > tracer ) //nuke Egg Guard's shield!
2016-04-07 21:02:52 +00:00
P_KillMobj ( mo - > tracer , inflictor , source , DMG_NUKE ) ;
2014-03-15 16:59:03 +00:00
if ( mo - > flags & MF_BOSS | | mo - > type = = MT_PLAYER ) //don't OHKO bosses nor players!
2016-04-07 21:02:52 +00:00
P_DamageMobj ( mo , inflictor , source , 1 , DMG_NUKE ) ;
2014-03-15 16:59:03 +00:00
else
2016-04-07 21:02:52 +00:00
P_DamageMobj ( mo , inflictor , source , 1000 , DMG_NUKE ) ;
2014-03-15 16:59:03 +00:00
}
}
2019-12-12 06:48:15 +00:00
//
// P_LookForFocusTarget
// Looks for a target for a player to focus on, for Z-targeting etc.
// exclude would be the current focus target, to ignore.
// direction, if set, requires the target to be to the left (1) or right (-1) of the angle
// mobjflags can be used to limit the flags of objects that can be focused
//
2019-12-13 05:03:51 +00:00
mobj_t * P_LookForFocusTarget ( player_t * player , mobj_t * exclude , SINT8 direction , UINT8 lockonflags )
2019-12-12 06:48:15 +00:00
{
mobj_t * mo ;
thinker_t * think ;
mobj_t * closestmo = NULL ;
const fixed_t maxdist = 2560 * player - > mo - > scale ;
const angle_t span = ANGLE_45 ;
fixed_t dist , closestdist = 0 ;
angle_t dangle , closestdangle = 0 ;
for ( think = thlist [ THINK_MOBJ ] . next ; think ! = & thlist [ THINK_MOBJ ] ; think = think - > next )
{
if ( think - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
continue ;
mo = ( mobj_t * ) think ;
if ( mo - > flags & MF_NOCLIPTHING )
continue ;
2019-12-13 05:52:13 +00:00
if ( mo = = player - > mo | | mo = = exclude )
2019-12-13 05:03:51 +00:00
continue ;
2019-12-12 06:48:15 +00:00
if ( mo - > health < = 0 ) // dead
continue ;
2019-12-13 05:03:51 +00:00
switch ( mo - > type )
{
case MT_TNTBARREL :
if ( lockonflags & LOCK_INTERESTS )
break ;
/*fallthru*/
case MT_PLAYER : // Don't chase other players!
case MT_DETON :
continue ; // Don't be STUPID, Sonic!
2019-12-12 06:48:15 +00:00
2019-12-13 05:03:51 +00:00
case MT_FAKEMOBILE :
if ( ! ( lockonflags & LOCK_BOSS ) )
continue ;
break ;
2019-12-12 06:48:15 +00:00
2019-12-13 05:03:51 +00:00
case MT_EGGSHIELD :
if ( ! ( lockonflags & LOCK_ENEMY ) )
continue ;
break ;
2019-12-12 06:48:15 +00:00
2019-12-13 05:03:51 +00:00
case MT_EGGSTATUE :
if ( tutorialmode )
break ; // Always focus egg statue in the tutorial
/*fallthru*/
default :
if ( ( lockonflags & LOCK_BOSS ) & & ( ( mo - > flags & ( MF_BOSS | MF_SHOOTABLE ) ) = = ( MF_BOSS | MF_SHOOTABLE ) ) ) // allows if it has the flags desired XOR it has the invert aimable flag
{
if ( mo - > flags2 & MF2_FRET )
continue ;
break ;
}
if ( ( lockonflags & LOCK_ENEMY ) & & ( ! ( ( mo - > flags & ( MF_ENEMY | MF_SHOOTABLE ) ) = = ( MF_ENEMY | MF_SHOOTABLE ) ) ! = ! ( mo - > flags2 & MF2_INVERTAIMABLE ) ) ) // allows if it has the flags desired XOR it has the invert aimable flag
break ;
if ( ( lockonflags & LOCK_INTERESTS ) & & ( mo - > flags & ( MF_PUSHABLE | MF_MONITOR ) ) ) // allows if it has the flags desired XOR it has the invert aimable flag
break ;
continue ; // not a valid object
}
2019-12-12 06:48:15 +00:00
{
fixed_t zdist = ( player - > mo - > z + player - > mo - > height / 2 ) - ( mo - > z + mo - > height / 2 ) ;
dist = P_AproxDistance ( player - > mo - > x - mo - > x , player - > mo - > y - mo - > y ) ;
if ( abs ( zdist ) > dist )
continue ; // Don't home outside of desired angle!
dist = P_AproxDistance ( dist , zdist ) ;
if ( dist > maxdist )
continue ; // out of range
}
if ( ( twodlevel | | player - > mo - > flags2 & MF2_TWOD )
& & abs ( player - > mo - > y - mo - > y ) > player - > mo - > radius )
continue ; // not in your 2d plane
2019-12-13 05:03:51 +00:00
dangle = R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , mo - > x , mo - > y ) - (
! exclude ? player - > mo - > angle : R_PointToAngle2 ( player - > mo - > x , player - > mo - > y , exclude - > x , exclude - > y )
) ;
2019-12-12 06:48:15 +00:00
if ( direction )
{
if ( direction = = 1 & & dangle > ANGLE_180 )
continue ; // To the right of the player
if ( direction = = - 1 & & dangle < ANGLE_180 )
continue ; // To the left of the player
}
2019-12-13 05:03:51 +00:00
if ( dangle > ANGLE_180 )
dangle = InvAngle ( dangle ) ;
if ( dangle > span )
continue ; // behind back
// Inflate dist by angle difference to bias toward objects at a closer angle
dist = FixedDiv ( dist , FINECOSINE ( dangle > > ANGLETOFINESHIFT ) * 3 ) ;
2019-12-12 06:48:15 +00:00
if ( closestmo & & ( exclude ? ( dangle > closestdangle ) : ( dist > closestdist ) ) )
continue ;
if ( ! P_CheckSight ( player - > mo , mo ) )
continue ; // out of sight
closestmo = mo ;
closestdist = dist ;
closestdangle = dangle ;
}
return closestmo ;
}
2014-03-15 16:59:03 +00:00
//
// P_LookForEnemies
// Looks for something you can hit - Used for homing attack
2015-05-27 09:24:31 +00:00
// If nonenemies is true, includes monitors and springs!
2017-03-21 16:04:49 +00:00
// If bullet is true, you can look up and the distance is further,
2019-09-07 10:33:26 +00:00
// but your total angle span you can look is limited to compensate. (Also, allows monitors.)
2014-03-15 16:59:03 +00:00
//
2017-03-22 18:51:30 +00:00
mobj_t * P_LookForEnemies ( player_t * player , boolean nonenemies , boolean bullet )
2014-03-15 16:59:03 +00:00
{
mobj_t * mo ;
thinker_t * think ;
mobj_t * closestmo = NULL ;
2017-03-21 16:04:49 +00:00
const fixed_t maxdist = FixedMul ( ( bullet ? RING_DIST * 2 : RING_DIST ) , player - > mo - > scale ) ;
const angle_t span = ( bullet ? ANG30 : ANGLE_90 ) ;
fixed_t dist , closestdist = 0 ;
2019-09-07 10:33:26 +00:00
const mobjflag_t nonenemiesdisregard = ( bullet ? 0 : MF_MONITOR ) | MF_SPRING ;
2014-03-15 16:59:03 +00:00
2019-04-20 21:29:20 +00:00
for ( think = thlist [ THINK_MOBJ ] . next ; think ! = & thlist [ THINK_MOBJ ] ; think = think - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( think - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
continue ;
2014-03-15 16:59:03 +00:00
mo = ( mobj_t * ) think ;
2019-09-25 14:12:19 +00:00
if ( mo - > flags & MF_NOCLIPTHING )
continue ;
2014-03-15 16:59:03 +00:00
if ( mo - > health < = 0 ) // dead
continue ;
2019-09-25 14:12:19 +00:00
if ( ! ( ( mo - > flags & ( MF_ENEMY | MF_BOSS | MF_MONITOR ) & & ( mo - > flags & MF_SHOOTABLE ) ) | | ( mo - > flags & MF_SPRING ) ) = = ! ( mo - > flags2 & MF2_INVERTAIMABLE ) ) // allows if it has the flags desired XOR it has the invert aimable flag
continue ; // not a valid target
2014-03-15 16:59:03 +00:00
if ( mo = = player - > mo )
continue ;
if ( mo - > flags2 & MF2_FRET )
continue ;
2019-09-07 10:33:26 +00:00
if ( ! nonenemies & & mo - > flags & nonenemiesdisregard )
2018-05-19 23:04:39 +00:00
continue ;
2017-03-21 23:24:57 +00:00
if ( ! bullet & & mo - > type = = MT_DETON ) // Don't be STUPID, Sonic!
2014-03-15 16:59:03 +00:00
continue ;
2017-03-21 00:54:47 +00:00
{
2017-03-21 16:04:49 +00:00
fixed_t zdist = ( player - > mo - > z + player - > mo - > height / 2 ) - ( mo - > z + mo - > height / 2 ) ;
dist = P_AproxDistance ( player - > mo - > x - mo - > x , player - > mo - > y - mo - > y ) ;
if ( bullet )
2017-03-21 00:54:47 +00:00
{
2017-03-22 18:51:30 +00:00
if ( ( R_PointToAngle2 ( 0 , 0 , dist , zdist ) + span ) > span * 2 )
2017-03-21 00:54:47 +00:00
continue ; // Don't home outside of desired angle!
}
else // Don't home upwards!
{
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
2017-03-21 16:04:49 +00:00
if ( mo - > z + mo - > height < player - > mo - > z + player - > mo - > height - FixedMul ( MAXSTEPMOVE , player - > mo - > scale ) )
continue ;
2017-03-21 00:54:47 +00:00
}
2017-03-21 16:04:49 +00:00
else if ( mo - > z > player - > mo - > z + FixedMul ( MAXSTEPMOVE , player - > mo - > scale ) )
2017-03-21 00:54:47 +00:00
continue ;
}
2014-03-15 16:59:03 +00:00
2017-03-21 16:04:49 +00:00
dist = P_AproxDistance ( dist , zdist ) ;
if ( dist > maxdist )
2017-03-21 00:54:47 +00:00
continue ; // out of range
}
2014-03-15 16:59:03 +00:00
if ( ( twodlevel | | player - > mo - > flags2 & MF2_TWOD )
& & abs ( player - > mo - > y - mo - > y ) > player - > mo - > radius )
continue ; // not in your 2d plane
if ( mo - > type = = MT_PLAYER ) // Don't chase after other players!
continue ;
2017-03-21 16:04:49 +00:00
if ( closestmo & & dist > closestdist )
2014-03-15 16:59:03 +00:00
continue ;
2018-05-19 23:04:39 +00:00
if ( ( R_PointToAngle2 ( player - > mo - > x + P_ReturnThrustX ( player - > mo , player - > mo - > angle , player - > mo - > radius ) , player - > mo - > y + P_ReturnThrustY ( player - > mo , player - > mo - > angle , player - > mo - > radius ) , mo - > x , mo - > y ) - player - > mo - > angle + span ) > span * 2 )
2014-03-15 16:59:03 +00:00
continue ; // behind back
if ( ! P_CheckSight ( player - > mo , mo ) )
continue ; // out of sight
closestmo = mo ;
2017-03-21 16:04:49 +00:00
closestdist = dist ;
2014-03-15 16:59:03 +00:00
}
2017-03-22 18:51:30 +00:00
return closestmo ;
2014-03-15 16:59:03 +00:00
}
2019-07-02 23:58:02 +00:00
boolean P_HomingAttack ( mobj_t * source , mobj_t * enemy ) // Home in on your target
2014-03-15 16:59:03 +00:00
{
2017-03-21 16:04:49 +00:00
fixed_t zdist ;
2014-03-15 16:59:03 +00:00
fixed_t dist ;
2014-08-04 03:49:33 +00:00
fixed_t ns = 0 ;
2014-03-15 16:59:03 +00:00
if ( ! enemy )
2019-07-02 23:58:02 +00:00
return false ;
2014-03-15 16:59:03 +00:00
2019-07-02 23:58:02 +00:00
if ( ! enemy - > health )
return false ;
if ( enemy - > flags2 & MF2_FRET )
return false ;
if ( ! ( enemy - > flags & ( MF_SHOOTABLE | MF_SPRING ) ) = = ! ( enemy - > flags2 & MF2_INVERTAIMABLE ) ) // allows if it has the flags desired XOR it has the invert aimable flag
return false ;
2014-03-15 16:59:03 +00:00
// change angle
source - > angle = R_PointToAngle2 ( source - > x , source - > y , enemy - > x , enemy - > y ) ;
2017-02-06 17:31:48 +00:00
if ( source - > player )
2014-03-15 16:59:03 +00:00
{
2017-02-06 17:31:48 +00:00
source - > player - > drawangle = source - > angle ;
if ( ! demoplayback | | P_AnalogMove ( source - > player ) )
{
if ( source - > player = = & players [ consoleplayer ] )
localangle = source - > angle ;
else if ( source - > player = = & players [ secondarydisplayplayer ] )
localangle2 = source - > angle ;
}
2014-03-15 16:59:03 +00:00
}
// change slope
2017-03-23 19:11:22 +00:00
zdist = ( ( P_MobjFlip ( source ) = = - 1 ) ? ( enemy - > z + enemy - > height ) - ( source - > z + source - > height ) : ( enemy - > z - source - > z ) ) ;
2017-03-21 16:04:49 +00:00
dist = P_AproxDistance ( P_AproxDistance ( enemy - > x - source - > x , enemy - > y - source - > y ) , zdist ) ;
2014-03-15 16:59:03 +00:00
if ( dist < 1 )
dist = 1 ;
2014-04-14 05:14:58 +00:00
if ( source - > type = = MT_DETON & & enemy - > player ) // For Deton Chase (Unused)
2014-08-04 03:49:33 +00:00
ns = FixedDiv ( FixedMul ( enemy - > player - > normalspeed , enemy - > scale ) , FixedDiv ( 20 * FRACUNIT , 17 * FRACUNIT ) ) ;
2014-03-15 16:59:03 +00:00
else if ( source - > type ! = MT_PLAYER )
{
if ( source - > threshold = = 32000 )
2014-08-04 03:49:33 +00:00
ns = FixedMul ( source - > info - > speed / 2 , source - > scale ) ;
2014-03-15 16:59:03 +00:00
else
2014-08-04 03:49:33 +00:00
ns = FixedMul ( source - > info - > speed , source - > scale ) ;
2014-03-15 16:59:03 +00:00
}
else if ( source - > player )
2015-05-27 09:24:31 +00:00
{
2015-05-27 09:59:42 +00:00
if ( source - > player - > charability = = CA_HOMINGTHOK & & ! ( source - > player - > pflags & PF_SHIELDABILITY ) )
2015-05-27 09:24:31 +00:00
ns = FixedDiv ( FixedMul ( source - > player - > actionspd , source - > scale ) , 3 * FRACUNIT / 2 ) ;
2015-05-27 09:59:42 +00:00
else
2015-05-28 02:06:27 +00:00
ns = FixedMul ( 45 * FRACUNIT , source - > scale ) ;
2015-05-27 09:24:31 +00:00
}
2014-08-04 03:49:33 +00:00
source - > momx = FixedMul ( FixedDiv ( enemy - > x - source - > x , dist ) , ns ) ;
source - > momy = FixedMul ( FixedDiv ( enemy - > y - source - > y , dist ) , ns ) ;
2017-03-21 16:04:49 +00:00
source - > momz = FixedMul ( FixedDiv ( zdist , dist ) , ns ) ;
2019-07-02 23:58:02 +00:00
return true ;
2014-03-15 16:59:03 +00:00
}
// Search for emeralds
void P_FindEmerald ( void )
{
thinker_t * th ;
mobj_t * mo2 ;
hunt1 = hunt2 = hunt3 = NULL ;
// scan the remaining thinkers
// to find all emeralds
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-03-15 16:59:03 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = MT_EMERHUNT )
{
if ( ! hunt1 )
hunt1 = mo2 ;
else if ( ! hunt2 )
hunt2 = mo2 ;
else if ( ! hunt3 )
hunt3 = mo2 ;
}
}
return ;
}
2017-05-28 20:55:41 +00:00
//
// P_GetLives
2017-07-04 12:17:29 +00:00
// Get extra lives in new co-op if you're allowed to.
2017-05-28 20:55:41 +00:00
//
boolean P_GetLives ( player_t * player )
{
INT32 i , maxlivesplayer = - 1 , livescheck = 1 ;
2017-07-04 12:17:29 +00:00
if ( ! ( netgame | | multiplayer )
| | ( gametype ! = GT_COOP )
2018-08-23 19:09:39 +00:00
| | ( player - > lives = = INFLIVES ) )
2017-07-04 12:17:29 +00:00
return true ;
if ( cv_cooplives . value = = 0 ) // infinite lives
{
2019-09-01 14:55:23 +00:00
if ( player - > lives < 1 )
player - > lives = 1 ;
2017-05-28 20:55:41 +00:00
return true ;
2017-07-04 12:17:29 +00:00
}
2017-05-28 20:55:41 +00:00
2019-09-01 14:55:23 +00:00
if ( ( cv_cooplives . value = = 2 | | cv_cooplives . value = = 1 ) & & player - > lives > 0 )
return true ;
if ( cv_cooplives . value = = 1 )
return false ;
2017-05-28 20:55:41 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
if ( players [ i ] . lives > livescheck )
{
maxlivesplayer = i ;
livescheck = players [ i ] . lives ;
}
}
2017-06-03 11:26:42 +00:00
if ( maxlivesplayer ! = - 1 & & & players [ maxlivesplayer ] ! = player )
2017-05-28 20:55:41 +00:00
{
2017-07-08 10:41:20 +00:00
if ( cv_cooplives . value = = 2 & & ( P_IsLocalPlayer ( player ) | | P_IsLocalPlayer ( & players [ maxlivesplayer ] ) ) )
2017-06-03 11:26:42 +00:00
S_StartSound ( NULL , sfx_jshard ) ; // placeholder
2018-08-23 19:09:39 +00:00
if ( players [ maxlivesplayer ] . lives ! = INFLIVES )
2017-08-17 23:58:16 +00:00
players [ maxlivesplayer ] . lives - - ;
2017-06-01 17:44:19 +00:00
player - > lives + + ;
if ( player - > lives < 1 )
player - > lives = 1 ;
2017-05-28 20:55:41 +00:00
return true ;
}
2017-06-03 11:26:42 +00:00
return ( player - > lives > 0 ) ;
2017-05-28 20:55:41 +00:00
}
2017-05-29 20:23:00 +00:00
//
// P_ConsiderAllGone
// Shamelessly lifted from TD. Thanks, Sryder!
//
static void P_ConsiderAllGone ( void )
{
INT32 i , lastdeadplayer = - 1 , deadtimercheck = INT32_MAX ;
2017-07-26 15:10:08 +00:00
if ( countdown2 )
return ;
2017-05-29 20:23:00 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
if ( players [ i ] . playerstate ! = PST_DEAD & & ! players [ i ] . spectator & & players [ i ] . mo & & players [ i ] . mo - > health )
break ;
2017-07-26 15:10:08 +00:00
if ( players [ i ] . spectator )
{
if ( lastdeadplayer = = - 1 )
lastdeadplayer = i ;
}
else if ( players [ i ] . lives > 0 )
2017-05-29 20:23:00 +00:00
{
lastdeadplayer = i ;
2017-07-26 15:10:08 +00:00
if ( players [ i ] . deadtimer < deadtimercheck )
deadtimercheck = players [ i ] . deadtimer ;
2017-05-29 20:23:00 +00:00
}
}
if ( i = = MAXPLAYERS & & lastdeadplayer ! = - 1 & & deadtimercheck > 2 * TICRATE ) // the last killed player will reset the level in G_DoReborn
{
2017-07-03 14:43:29 +00:00
//players[lastdeadplayer].spectator = true;
players [ lastdeadplayer ] . outofcoop = true ;
2017-05-29 20:23:00 +00:00
players [ lastdeadplayer ] . playerstate = PST_REBORN ;
}
}
2017-06-01 17:44:19 +00:00
void P_RestoreMultiMusic ( player_t * player )
{
if ( netgame )
{
if ( P_IsLocalPlayer ( player ) )
S_ChangeMusic ( mapmusname , mapmusflags , true ) ;
}
else if ( multiplayer ) // local multiplayer only
{
// Restore the other player's music once we're dead for long enough
// -- that is, as long as they aren't dead too
if ( player = = & players [ displayplayer ] & & players [ secondarydisplayplayer ] . lives > 0 )
P_RestoreMusic ( & players [ secondarydisplayplayer ] ) ;
else if ( player = = & players [ secondarydisplayplayer ] & & players [ displayplayer ] . lives > 0 )
P_RestoreMusic ( & players [ displayplayer ] ) ;
}
}
2014-03-15 16:59:03 +00:00
//
// P_DeathThink
// Fall on your face when dying.
// Decrease POV height to floor height.
//
static void P_DeathThink ( player_t * player )
{
2017-05-28 20:55:41 +00:00
INT32 j = MAXPLAYERS ;
2014-03-15 16:59:03 +00:00
ticcmd_t * cmd = & player - > cmd ;
player - > deltaviewheight = 0 ;
if ( player - > deadtimer < INT32_MAX )
player - > deadtimer + + ;
2018-12-24 17:59:12 +00:00
if ( player - > bot ) // don't allow bots to do any of the below, B_CheckRespawn does all they need for respawning already
goto notrealplayer ;
2014-03-15 16:59:03 +00:00
// continue logic
if ( ! ( netgame | | multiplayer ) & & player - > lives < = 0 )
{
2019-09-01 14:55:23 +00:00
if ( player - > deadtimer > ( 3 * TICRATE ) & & ( cmd - > buttons & BT_USE | | cmd - > buttons & BT_JUMP ) & & player - > continues > 0 )
2014-03-15 16:59:03 +00:00
G_UseContinue ( ) ;
else if ( player - > deadtimer > = gameovertics )
G_UseContinue ( ) ; // Even if we don't have one this handles ending the game
}
2017-07-04 12:17:29 +00:00
if ( ( cv_cooplives . value ! = 1 )
2017-05-28 20:55:41 +00:00
& & ( gametype = = GT_COOP )
& & ( netgame | | multiplayer )
& & ( player - > lives < = 0 ) )
{
2017-05-29 20:24:09 +00:00
for ( j = 0 ; j < MAXPLAYERS ; j + + )
2017-05-28 20:55:41 +00:00
{
if ( ! playeringame [ j ] )
continue ;
if ( players [ j ] . lives > 1 )
break ;
}
}
2014-03-15 16:59:03 +00:00
// Force respawn if idle for more than 30 seconds in shooter modes.
if ( player - > deadtimer > 30 * TICRATE & & ! G_PlatformGametype ( ) )
player - > playerstate = PST_REBORN ;
2019-09-04 14:51:14 +00:00
else if ( ( player - > lives > 0 | | j ! = MAXPLAYERS ) & & ! ( ! ( netgame | | multiplayer ) & & G_IsSpecialStage ( gamemap ) ) ) // Don't allow "click to respawn" in special stages!
2014-03-15 16:59:03 +00:00
{
2017-06-03 16:55:03 +00:00
if ( gametype = = GT_COOP & & ( netgame | | multiplayer ) & & cv_coopstarposts . value = = 2 )
2017-05-31 16:07:24 +00:00
{
2017-05-29 20:23:00 +00:00
P_ConsiderAllGone ( ) ;
2019-09-01 14:55:23 +00:00
if ( ( player - > deadtimer > TICRATE < < 1 ) | | ( ( cmd - > buttons & BT_JUMP ) & & ( player - > deadtimer > TICRATE ) ) )
2017-05-28 14:33:35 +00:00
{
2017-07-03 14:43:29 +00:00
//player->spectator = true;
player - > outofcoop = true ;
2017-05-29 20:23:00 +00:00
player - > playerstate = PST_REBORN ;
2017-05-28 14:33:35 +00:00
}
2017-05-31 16:07:24 +00:00
}
2017-05-28 14:33:35 +00:00
else
{
// Respawn with jump button, force respawn time (3 second default, cheat protected) in shooter modes.
if ( cmd - > buttons & BT_JUMP )
{
2017-05-29 20:23:00 +00:00
if ( gametype ! = GT_COOP & & player - > spectator )
2017-05-28 14:33:35 +00:00
player - > playerstate = PST_REBORN ;
else switch ( gametype ) {
case GT_COOP :
case GT_COMPETITION :
2019-09-01 14:55:23 +00:00
case GT_RACE :
2017-05-28 14:33:35 +00:00
if ( player - > deadtimer > TICRATE )
player - > playerstate = PST_REBORN ;
break ;
default :
if ( player - > deadtimer > cv_respawntime . value * TICRATE )
player - > playerstate = PST_REBORN ;
break ;
}
}
2014-03-15 16:59:03 +00:00
2017-05-28 14:33:35 +00:00
// Single player auto respawn
2019-09-01 14:55:23 +00:00
if ( ! ( netgame | | multiplayer ) & & player - > deadtimer > TICRATE < < 1 )
2017-05-28 14:33:35 +00:00
player - > playerstate = PST_REBORN ;
}
2014-03-15 16:59:03 +00:00
}
2017-05-30 16:07:37 +00:00
else if ( ( netgame | | multiplayer ) & & player - > deadtimer > = 8 * TICRATE )
2014-03-15 16:59:03 +00:00
{
2017-05-29 20:23:00 +00:00
INT32 i , deadtimercheck = INT32_MAX ;
2014-03-15 16:59:03 +00:00
// In a net/multiplayer game, and out of lives
if ( gametype = = GT_COMPETITION )
{
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2017-05-29 20:23:00 +00:00
{
2017-05-30 16:07:37 +00:00
if ( ! playeringame [ i ] )
continue ;
if ( ! players [ i ] . exiting & & players [ i ] . lives )
2014-03-15 16:59:03 +00:00
break ;
2017-05-29 20:23:00 +00:00
if ( players [ i ] . deadtimer < deadtimercheck )
deadtimercheck = players [ i ] . deadtimer ;
}
2014-03-15 16:59:03 +00:00
2017-05-29 20:23:00 +00:00
if ( i = = MAXPLAYERS & & deadtimercheck = = 8 * TICRATE )
2014-03-15 16:59:03 +00:00
{
// Everyone's either done with the race, or dead.
if ( ! countdown2 | | countdown2 > 1 * TICRATE )
countdown2 = 1 * TICRATE ;
}
}
2017-06-01 17:44:19 +00:00
//else if (gametype == GT_COOP) -- moved to G_DoReborn
2017-05-30 19:31:51 +00:00
}
2014-03-15 16:59:03 +00:00
2017-07-04 13:57:22 +00:00
if ( gametype = = GT_COOP & & ( multiplayer | | netgame ) & & ( player - > lives < = 0 ) & & ( player - > deadtimer > = 8 * TICRATE | | ( ( cmd - > buttons & BT_JUMP ) & & ( player - > deadtimer > TICRATE ) ) ) )
2017-05-30 19:31:51 +00:00
{
2017-07-03 14:43:29 +00:00
//player->spectator = true;
player - > outofcoop = true ;
2017-05-30 19:31:51 +00:00
player - > playerstate = PST_REBORN ;
2014-03-15 16:59:03 +00:00
}
if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION | | ( gametype = = GT_COOP & & ( multiplayer | | netgame ) ) )
{
// Keep time rolling in race mode
2019-11-08 15:47:12 +00:00
if ( ! ( countdown2 & & ! countdown ) & & ! player - > exiting & & ! ( player - > pflags & PF_GAMETYPEOVER ) & & ! stoppedclock )
2014-03-15 16:59:03 +00:00
{
if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION )
{
if ( leveltime > = 4 * TICRATE )
player - > realtime = leveltime - 4 * TICRATE ;
else
player - > realtime = 0 ;
}
else
player - > realtime = leveltime ;
}
// Return to level music
2017-06-03 11:26:42 +00:00
if ( gametype ! = GT_COOP & & player - > lives < = 0 & & player - > deadtimer = = gameovertics )
2017-06-01 17:44:19 +00:00
P_RestoreMultiMusic ( player ) ;
2014-03-15 16:59:03 +00:00
}
2018-12-24 17:59:12 +00:00
notrealplayer :
2014-03-15 16:59:03 +00:00
if ( ! player - > mo )
return ;
P_CalcHeight ( player ) ;
}
//
// P_MoveCamera: make sure the camera is not outside the world and looks at the player avatar
//
camera_t camera , camera2 ; // Two cameras.. one for split!
static void CV_CamRotate_OnChange ( void )
{
if ( cv_cam_rotate . value < 0 )
CV_SetValue ( & cv_cam_rotate , cv_cam_rotate . value + 360 ) ;
else if ( cv_cam_rotate . value > 359 )
CV_SetValue ( & cv_cam_rotate , cv_cam_rotate . value % 360 ) ;
}
static void CV_CamRotate2_OnChange ( void )
{
if ( cv_cam2_rotate . value < 0 )
CV_SetValue ( & cv_cam2_rotate , cv_cam2_rotate . value + 360 ) ;
else if ( cv_cam2_rotate . value > 359 )
CV_SetValue ( & cv_cam2_rotate , cv_cam2_rotate . value % 360 ) ;
}
2014-11-12 00:55:07 +00:00
static CV_PossibleValue_t CV_CamSpeed [ ] = { { 0 , " MIN " } , { 1 * FRACUNIT , " MAX " } , { 0 , NULL } } ;
2019-12-10 04:06:50 +00:00
static CV_PossibleValue_t rotation_cons_t [ ] = { { 1 , " MIN " } , { 25 , " MAX " } , { 0 , NULL } } ;
2014-03-15 16:59:03 +00:00
static CV_PossibleValue_t CV_CamRotate [ ] = { { - 720 , " MIN " } , { 720 , " MAX " } , { 0 , NULL } } ;
2017-03-25 07:13:02 +00:00
consvar_t cv_cam_dist = { " cam_dist " , " 160 " , CV_FLOAT | CV_SAVE , NULL , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2017-03-29 22:30:45 +00:00
consvar_t cv_cam_height = { " cam_height " , " 25 " , CV_FLOAT | CV_SAVE , NULL , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2014-03-15 16:59:03 +00:00
consvar_t cv_cam_still = { " cam_still " , " Off " , 0 , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2017-03-25 07:13:02 +00:00
consvar_t cv_cam_speed = { " cam_speed " , " 0.3 " , CV_FLOAT | CV_SAVE , CV_CamSpeed , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2014-03-15 16:59:03 +00:00
consvar_t cv_cam_rotate = { " cam_rotate " , " 0 " , CV_CALL | CV_NOINIT , CV_CamRotate , CV_CamRotate_OnChange , 0 , NULL , NULL , 0 , 0 , NULL } ;
2017-03-25 07:13:02 +00:00
consvar_t cv_cam_rotspeed = { " cam_rotspeed " , " 10 " , CV_SAVE , rotation_cons_t , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2019-06-20 11:33:31 +00:00
consvar_t cv_cam_orbit = { " cam_orbit " , " Off " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2019-09-19 18:02:17 +00:00
consvar_t cv_cam_adjust = { " cam_adjust " , " On " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2017-03-25 07:13:02 +00:00
consvar_t cv_cam2_dist = { " cam2_dist " , " 160 " , CV_FLOAT | CV_SAVE , NULL , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2017-03-29 22:30:45 +00:00
consvar_t cv_cam2_height = { " cam2_height " , " 25 " , CV_FLOAT | CV_SAVE , NULL , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2014-03-15 16:59:03 +00:00
consvar_t cv_cam2_still = { " cam2_still " , " Off " , 0 , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2017-03-25 07:13:02 +00:00
consvar_t cv_cam2_speed = { " cam2_speed " , " 0.3 " , CV_FLOAT | CV_SAVE , CV_CamSpeed , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2014-03-15 16:59:03 +00:00
consvar_t cv_cam2_rotate = { " cam2_rotate " , " 0 " , CV_CALL | CV_NOINIT , CV_CamRotate , CV_CamRotate2_OnChange , 0 , NULL , NULL , 0 , 0 , NULL } ;
2017-03-25 07:13:02 +00:00
consvar_t cv_cam2_rotspeed = { " cam2_rotspeed " , " 10 " , CV_SAVE , rotation_cons_t , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2019-06-20 11:33:31 +00:00
consvar_t cv_cam2_orbit = { " cam2_orbit " , " Off " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2019-09-19 18:02:17 +00:00
consvar_t cv_cam2_adjust = { " cam2_adjust " , " On " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2014-03-15 16:59:03 +00:00
fixed_t t_cam_dist = - 42 ;
fixed_t t_cam_height = - 42 ;
fixed_t t_cam_rotate = - 42 ;
fixed_t t_cam2_dist = - 42 ;
fixed_t t_cam2_height = - 42 ;
fixed_t t_cam2_rotate = - 42 ;
# define MAXCAMERADIST 140*FRACUNIT // Max distance the camera can be in front of the player (2D mode)
void P_ResetCamera ( player_t * player , camera_t * thiscam )
{
tic_t tries = 0 ;
fixed_t x , y , z ;
if ( ! player - > mo )
return ;
if ( thiscam - > chase & & player - > mo - > health < = 0 )
return ;
thiscam - > chase = true ;
x = player - > mo - > x - P_ReturnThrustX ( player - > mo , thiscam - > angle , player - > mo - > radius ) ;
y = player - > mo - > y - P_ReturnThrustY ( player - > mo , thiscam - > angle , player - > mo - > radius ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
2017-10-14 20:11:08 +00:00
z = player - > mo - > z + player - > mo - > height - ( 41 * player - > height / 48 ) - 16 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
else
2017-10-14 20:11:08 +00:00
z = player - > mo - > z + ( 41 * player - > height / 48 ) ;
2014-03-15 16:59:03 +00:00
// set bits for the camera
thiscam - > x = x ;
thiscam - > y = y ;
thiscam - > z = z ;
2019-12-12 03:09:23 +00:00
if ( ! ( thiscam = = & camera & & ( cv_cam_still . value | | cv_analog . value ) )
2014-03-15 16:59:03 +00:00
& & ! ( thiscam = = & camera2 & & ( cv_cam2_still . value | | cv_analog2 . value ) ) )
{
thiscam - > angle = player - > mo - > angle ;
thiscam - > aiming = 0 ;
}
thiscam - > relativex = 0 ;
thiscam - > subsector = R_PointInSubsector ( thiscam - > x , thiscam - > y ) ;
thiscam - > radius = 20 * FRACUNIT ;
thiscam - > height = 16 * FRACUNIT ;
while ( ! P_MoveChaseCamera ( player , thiscam , true ) & & + + tries < 2 * TICRATE ) ;
}
boolean P_MoveChaseCamera ( player_t * player , camera_t * thiscam , boolean resetcalled )
{
angle_t angle = 0 , focusangle = 0 , focusaiming = 0 ;
2019-09-11 14:45:59 +00:00
fixed_t x , y , z , dist , distxy , distz , checkdist , viewpointx , viewpointy , camspeed , camdist , camheight , pviewheight , slopez = 0 ;
2014-03-15 16:59:03 +00:00
INT32 camrotate ;
2019-09-19 18:02:17 +00:00
boolean camstill , cameranoclip , camorbit ;
2019-11-08 16:47:51 +00:00
mobj_t * mo , * sign = NULL ;
2014-03-15 16:59:03 +00:00
subsector_t * newsubsec ;
fixed_t f1 , f2 ;
2019-12-08 21:54:16 +00:00
static fixed_t camsideshift [ 2 ] = { 0 , 0 } ;
fixed_t shiftx = 0 , shifty = 0 ;
2018-09-30 21:18:48 +00:00
// We probably shouldn't move the camera if there is no player or player mobj somehow
2019-11-27 13:37:03 +00:00
if ( ! player | | ! player - > mo )
2018-09-30 21:18:48 +00:00
return true ;
2014-03-15 16:59:03 +00:00
2018-09-30 21:18:48 +00:00
mo = player - > mo ;
2019-11-27 13:37:03 +00:00
if ( player - > playerstate = = PST_REBORN )
{
P_CalcChasePostImg ( player , thiscam ) ;
return true ;
}
2019-11-23 15:40:32 +00:00
if ( player - > exiting )
{
2019-11-25 16:23:35 +00:00
if ( mo - > target & & mo - > target - > type = = MT_SIGN & & mo - > target - > spawnpoint
2019-12-05 04:58:44 +00:00
& & ! ( gametype = = GT_COOP & & ( netgame | | multiplayer ) & & cv_exitmove . value )
& & ! ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) )
2019-11-23 15:40:32 +00:00
sign = mo - > target ;
else if ( ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
& & ! ( player - > mo - > state > = & states [ S_PLAY_NIGHTS_TRANS1 ]
& & player - > mo - > state < = & states [ S_PLAY_NIGHTS_TRANS6 ] ) )
2019-11-27 13:37:03 +00:00
{
P_CalcChasePostImg ( player , thiscam ) ;
2019-11-23 15:40:32 +00:00
return true ;
2019-11-27 13:37:03 +00:00
}
2019-11-23 15:40:32 +00:00
}
2019-11-08 16:47:51 +00:00
2019-11-20 13:02:34 +00:00
cameranoclip = ( sign | | player - > powers [ pw_carry ] = = CR_NIGHTSMODE | | player - > pflags & PF_NOCLIP ) | | ( mo - > flags & ( MF_NOCLIP | MF_NOCLIPHEIGHT ) ) ; // Noclipping player camera noclips too!!
2014-03-15 16:59:03 +00:00
2018-11-13 01:37:55 +00:00
if ( ! ( player - > climbing | | ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) | | player - > playerstate = = PST_DEAD | | tutorialmode ) )
2015-02-20 13:00:40 +00:00
{
if ( player - > spectator ) // force cam off for spectators
return true ;
2014-03-15 16:59:03 +00:00
2015-02-20 13:00:40 +00:00
if ( ! cv_chasecam . value & & thiscam = = & camera )
return true ;
2014-03-15 16:59:03 +00:00
2015-02-20 13:00:40 +00:00
if ( ! cv_chasecam2 . value & & thiscam = = & camera2 )
return true ;
}
2014-03-15 16:59:03 +00:00
if ( ! thiscam - > chase & & ! resetcalled )
{
if ( player = = & players [ consoleplayer ] )
focusangle = localangle ;
else if ( player = = & players [ secondarydisplayplayer ] )
focusangle = localangle2 ;
else
2018-09-30 21:18:48 +00:00
focusangle = mo - > angle ;
2014-03-15 16:59:03 +00:00
if ( thiscam = = & camera )
camrotate = cv_cam_rotate . value ;
else if ( thiscam = = & camera2 )
camrotate = cv_cam2_rotate . value ;
else
camrotate = 0 ;
thiscam - > angle = focusangle + FixedAngle ( camrotate * FRACUNIT ) ;
P_ResetCamera ( player , thiscam ) ;
return true ;
}
thiscam - > radius = FixedMul ( 20 * FRACUNIT , mo - > scale ) ;
thiscam - > height = FixedMul ( 16 * FRACUNIT , mo - > scale ) ;
// Don't run while respawning from a starpost
// Inu 4/8/13 Why not?!
// if (leveltime > 0 && timeinmap <= 0)
// return true;
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
2018-09-30 21:18:48 +00:00
focusangle = mo - > angle ;
2014-03-15 16:59:03 +00:00
focusaiming = 0 ;
}
2019-11-08 16:47:51 +00:00
else if ( sign )
{
focusangle = FixedAngle ( sign - > spawnpoint - > angle < < FRACBITS ) + ANGLE_180 ;
focusaiming = 0 ;
}
2014-03-15 16:59:03 +00:00
else if ( player = = & players [ consoleplayer ] )
{
focusangle = localangle ;
focusaiming = localaiming ;
}
else if ( player = = & players [ secondarydisplayplayer ] )
{
focusangle = localangle2 ;
focusaiming = localaiming2 ;
}
else
{
2018-09-30 21:18:48 +00:00
focusangle = mo - > angle ;
2014-03-15 16:59:03 +00:00
focusaiming = player - > aiming ;
}
if ( P_CameraThinker ( player , thiscam , resetcalled ) )
return true ;
2018-11-10 06:31:30 +00:00
if ( tutorialmode )
{
// force defaults because we have a camera look section
2018-11-12 23:08:24 +00:00
camspeed = ( INT32 ) ( atof ( cv_cam_speed . defaultvalue ) * FRACUNIT ) ;
camstill = ( ! stricmp ( cv_cam_still . defaultvalue , " off " ) ) ? false : true ;
2019-09-19 18:02:17 +00:00
camorbit = ( ! stricmp ( cv_cam_orbit . defaultvalue , " off " ) ) ? false : true ;
2018-11-12 23:08:24 +00:00
camrotate = atoi ( cv_cam_rotate . defaultvalue ) ;
camdist = FixedMul ( ( INT32 ) ( atof ( cv_cam_dist . defaultvalue ) * FRACUNIT ) , mo - > scale ) ;
2019-11-27 12:54:00 +00:00
camheight = FixedMul ( ( INT32 ) ( atof ( cv_cam_height . defaultvalue ) * FRACUNIT ) , mo - > scale ) ;
2018-11-10 06:31:30 +00:00
}
else if ( thiscam = = & camera )
2014-03-15 16:59:03 +00:00
{
camspeed = cv_cam_speed . value ;
camstill = cv_cam_still . value ;
2019-09-19 18:02:17 +00:00
camorbit = cv_cam_orbit . value ;
2014-03-15 16:59:03 +00:00
camrotate = cv_cam_rotate . value ;
2017-04-03 12:33:05 +00:00
camdist = FixedMul ( cv_cam_dist . value , mo - > scale ) ;
2019-11-27 12:29:31 +00:00
camheight = FixedMul ( cv_cam_height . value , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
}
else // Camera 2
{
camspeed = cv_cam2_speed . value ;
camstill = cv_cam2_still . value ;
2019-09-19 18:02:17 +00:00
camorbit = cv_cam2_orbit . value ;
2014-03-15 16:59:03 +00:00
camrotate = cv_cam2_rotate . value ;
2017-04-03 12:33:05 +00:00
camdist = FixedMul ( cv_cam2_dist . value , mo - > scale ) ;
2019-11-27 12:29:31 +00:00
camheight = FixedMul ( cv_cam2_height . value , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
}
2019-11-27 12:29:31 +00:00
if ( ! ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) & & ! ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) )
camheight = FixedMul ( camheight , player - > camerascale ) ;
2014-11-12 00:55:07 +00:00
# ifdef REDSANALOG
if ( P_AnalogMove ( player ) & & ( player - > cmd . buttons & ( BT_CAMLEFT | BT_CAMRIGHT ) ) = = ( BT_CAMLEFT | BT_CAMRIGHT ) ) {
camstill = true ;
if ( camspeed < 4 * FRACUNIT / 5 )
camspeed = 4 * FRACUNIT / 5 ;
}
# endif // REDSANALOG
2014-03-15 16:59:03 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
camheight + = thiscam - > height ;
if ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) )
angle = ANGLE_90 ;
else if ( camstill | | resetcalled | | player - > playerstate = = PST_DEAD )
angle = thiscam - > angle ;
2017-03-14 18:11:17 +00:00
else if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) // NiGHTS Level
2014-03-15 16:59:03 +00:00
{
if ( ( player - > pflags & PF_TRANSFERTOCLOSEST ) & & player - > axis1 & & player - > axis2 )
{
angle = R_PointToAngle2 ( player - > axis1 - > x , player - > axis1 - > y , player - > axis2 - > x , player - > axis2 - > y ) ;
angle + = ANGLE_90 ;
}
2018-09-30 21:18:48 +00:00
else if ( mo - > target )
2014-03-15 16:59:03 +00:00
{
2018-10-10 13:51:34 +00:00
if ( mo - > target - > flags2 & MF2_AMBUSH )
2018-09-30 21:18:48 +00:00
angle = R_PointToAngle2 ( mo - > target - > x , mo - > target - > y , mo - > x , mo - > y ) ;
2014-03-15 16:59:03 +00:00
else
2018-09-30 21:18:48 +00:00
angle = R_PointToAngle2 ( mo - > x , mo - > y , mo - > target - > x , mo - > target - > y ) ;
2014-03-15 16:59:03 +00:00
}
}
2019-12-05 04:36:25 +00:00
else if ( P_AnalogMove ( player ) & & ! sign ) // Analog
2016-04-05 19:56:48 +00:00
angle = R_PointToAngle2 ( thiscam - > x , thiscam - > y , mo - > x , mo - > y ) ;
2014-03-15 16:59:03 +00:00
else if ( demoplayback )
{
angle = focusangle ;
focusangle = R_PointToAngle2 ( thiscam - > x , thiscam - > y , mo - > x , mo - > y ) ;
if ( player = = & players [ consoleplayer ] )
{
if ( focusangle > = localangle )
2016-03-30 15:47:27 +00:00
localangle + = abs ( ( signed ) ( focusangle - localangle ) ) > > 5 ;
2014-03-15 16:59:03 +00:00
else
2016-03-30 15:47:27 +00:00
localangle - = abs ( ( signed ) ( focusangle - localangle ) ) > > 5 ;
2014-03-15 16:59:03 +00:00
}
}
else
angle = focusangle + FixedAngle ( camrotate * FRACUNIT ) ;
if ( ! resetcalled & & ( cv_analog . value | | demoplayback ) & & ( ( thiscam = = & camera & & t_cam_rotate ! = - 42 ) | | ( thiscam = = & camera2
& & t_cam2_rotate ! = - 42 ) ) )
{
angle = FixedAngle ( camrotate * FRACUNIT ) ;
thiscam - > angle = angle ;
}
2019-12-05 04:36:25 +00:00
if ( ( ( ( thiscam = = & camera ) & & cv_analog . value ) | | ( ( thiscam ! = & camera ) & & cv_analog2 . value ) | | demoplayback ) & & ! sign & & ! objectplacing & & ! ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) & & ( player - > powers [ pw_carry ] ! = CR_NIGHTSMODE ) & & displayplayer = = consoleplayer )
2014-03-15 16:59:03 +00:00
{
2014-11-12 00:55:07 +00:00
# ifdef REDSANALOG
if ( ( player - > cmd . buttons & ( BT_CAMLEFT | BT_CAMRIGHT ) ) = = ( BT_CAMLEFT | BT_CAMRIGHT ) ) ; else
# endif
2017-04-14 19:29:08 +00:00
if ( player - > cmd . buttons & BT_CAMRIGHT )
2014-03-15 16:59:03 +00:00
{
if ( thiscam = = & camera )
2017-04-14 19:29:08 +00:00
angle - = FixedAngle ( cv_cam_rotspeed . value * FRACUNIT ) ;
2014-03-15 16:59:03 +00:00
else
2017-04-14 19:29:08 +00:00
angle - = FixedAngle ( cv_cam2_rotspeed . value * FRACUNIT ) ;
2014-03-15 16:59:03 +00:00
}
2017-04-14 19:29:08 +00:00
else if ( player - > cmd . buttons & BT_CAMLEFT )
2014-03-15 16:59:03 +00:00
{
if ( thiscam = = & camera )
2017-04-14 19:29:08 +00:00
angle + = FixedAngle ( cv_cam_rotspeed . value * FRACUNIT ) ;
2014-03-15 16:59:03 +00:00
else
2017-04-14 19:29:08 +00:00
angle + = FixedAngle ( cv_cam2_rotspeed . value * FRACUNIT ) ;
2014-03-15 16:59:03 +00:00
}
}
2019-12-14 02:17:31 +00:00
if ( cv_abilitydirection [ ( thiscam = = & camera ) ? 0 : 1 ] . value & & ! sign )
2019-12-08 21:54:16 +00:00
{
// Shift the camera slightly to the sides depending on the player facing direction
UINT8 forplayer = ( thiscam = = & camera ) ? 0 : 1 ;
fixed_t shift = FixedMul ( FINESINE ( ( player - > drawangle - angle ) > > ANGLETOFINESHIFT ) , cv_cam_shiftfacing [ forplayer ] . value ) ;
2019-12-11 07:26:43 +00:00
if ( player - > powers [ pw_carry ] = = CR_ROLLOUT )
shift = - shift ;
2019-12-14 02:17:31 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
{
fixed_t cos = FINECOSINE ( ( angle_t ) ( player - > flyangle * ANG1 ) > > ANGLETOFINESHIFT ) ;
shift = FixedMul ( shift , min ( FRACUNIT , player - > speed * abs ( cos ) / 6000 ) ) ;
}
2019-12-12 03:09:23 +00:00
if ( ticcmd_centerviewdown [ ( thiscam = = & camera ) ? 0 : 1 ] )
2019-12-10 02:21:32 +00:00
shift = FixedMul ( camsideshift [ forplayer ] , FRACUNIT - camspeed ) ;
else
shift + = FixedMul ( camsideshift [ forplayer ] - shift , FRACUNIT - ( camspeed > > 3 ) ) ;
2019-12-08 21:54:16 +00:00
camsideshift [ forplayer ] = shift ;
shift = FixedMul ( shift , camdist ) ;
shiftx = - FixedMul ( FINESINE ( angle > > ANGLETOFINESHIFT ) , shift ) ;
shifty = FixedMul ( FINECOSINE ( angle > > ANGLETOFINESHIFT ) , shift ) ;
}
2014-03-15 16:59:03 +00:00
// sets ideal cam pos
if ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) )
dist = 480 < < FRACBITS ;
2018-08-15 16:29:06 +00:00
else if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE
| | ( ( maptol & TOL_NIGHTS ) & & player - > capsule & & player - > capsule - > reactiontime > 0 & & player = = & players [ player - > capsule - > reactiontime - 1 ] ) )
2014-08-04 03:49:33 +00:00
dist = 320 < < FRACBITS ;
2014-03-15 16:59:03 +00:00
else
{
dist = camdist ;
2017-09-21 20:43:55 +00:00
// x1.5 dist for splitscreen
if ( splitscreen )
{
dist = FixedMul ( dist , 3 * FRACUNIT / 2 ) ;
2018-12-16 23:18:59 +00:00
camheight = FixedMul ( camheight , 3 * FRACUNIT / 2 ) ;
2017-09-21 20:43:55 +00:00
}
2019-12-05 04:58:44 +00:00
if ( sign ) // signpost camera has specific placement
2019-11-08 16:47:51 +00:00
{
camheight = mo - > scale < < 7 ;
camspeed = FRACUNIT / 12 ;
}
2019-12-05 04:58:44 +00:00
else if ( P_AnalogMove ( player ) ) // x1.2 dist for analog
{
dist = FixedMul ( dist , 6 * FRACUNIT / 5 ) ;
camheight = FixedMul ( camheight , 6 * FRACUNIT / 5 ) ;
}
2019-11-08 16:47:51 +00:00
2017-03-14 18:11:17 +00:00
if ( player - > climbing | | player - > exiting | | player - > playerstate = = PST_DEAD | | ( player - > powers [ pw_carry ] = = CR_ROPEHANG | | player - > powers [ pw_carry ] = = CR_GENERIC | | player - > powers [ pw_carry ] = = CR_MACESPIN ) )
2014-03-15 16:59:03 +00:00
dist < < = 1 ;
}
2019-12-05 04:36:25 +00:00
if ( ! sign & & ! ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) & & ! ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) )
2019-11-27 12:29:31 +00:00
dist = FixedMul ( dist , player - > camerascale ) ;
2019-06-20 11:33:31 +00:00
2019-11-27 12:29:31 +00:00
checkdist = dist ;
2014-03-15 16:59:03 +00:00
if ( checkdist < 128 * FRACUNIT )
checkdist = 128 * FRACUNIT ;
2019-09-10 14:11:03 +00:00
if ( ! ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) ) & & ! ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) ) // This block here is like 90% Lach's work, thanks bud
{
2019-09-25 13:15:19 +00:00
if ( ! resetcalled & & ( ( thiscam = = & camera & & cv_cam_adjust . value ) | | ( thiscam = = & camera2 & & cv_cam2_adjust . value ) ) )
2019-09-10 14:11:03 +00:00
{
if ( ! ( mo - > eflags & MFE_JUSTHITFLOOR ) & & ( P_IsObjectOnGround ( mo ) ) // Check that player is grounded
& & thiscam - > ceilingz - thiscam - > floorz > = P_GetPlayerHeight ( player ) ) // Check that camera's sector is large enough for the player to fit into, at least
{
if ( mo - > eflags & MFE_VERTICALFLIP ) // if player is upside-down
{
//z = min(z, thiscam->ceilingz); // solution 1: change new z coordinate to be at LEAST its ground height
2019-09-11 14:45:59 +00:00
slopez + = min ( thiscam - > ceilingz - mo - > z , 0 ) ; // solution 2: change new z coordinate by the difference between camera's ground and top of player
2019-09-10 14:11:03 +00:00
}
else // player is not upside-down
{
//z = max(z, thiscam->floorz); // solution 1: change new z coordinate to be at LEAST its ground height
2019-09-11 14:45:59 +00:00
slopez + = max ( thiscam - > floorz - mo - > z - mo - > height , 0 ) ; // solution 2: change new z coordinate by the difference between camera's ground and top of player
2019-09-10 14:11:03 +00:00
}
}
}
}
2019-09-20 04:07:57 +00:00
if ( camorbit ) //Sev here, I'm guessing this is where orbital cam lives
2019-06-20 11:33:31 +00:00
{
2019-09-19 18:02:17 +00:00
if ( rendermode = = render_opengl )
distxy = FixedMul ( dist , FINECOSINE ( ( focusaiming > > ANGLETOFINESHIFT ) & FINEMASK ) ) ;
else
distxy = dist ;
2019-09-11 14:45:59 +00:00
distz = - FixedMul ( dist , FINESINE ( ( focusaiming > > ANGLETOFINESHIFT ) & FINEMASK ) ) + slopez ;
2019-06-20 11:33:31 +00:00
}
else
{
distxy = dist ;
2019-09-11 14:45:59 +00:00
distz = slopez ;
2019-06-20 11:33:31 +00:00
}
2019-11-08 16:47:51 +00:00
if ( sign )
{
x = sign - > x - FixedMul ( FINECOSINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , distxy ) ;
y = sign - > y - FixedMul ( FINESINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , distxy ) ;
}
else
{
x = mo - > x - FixedMul ( FINECOSINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , distxy ) ;
y = mo - > y - FixedMul ( FINESINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , distxy ) ;
}
2014-03-15 16:59:03 +00:00
#if 0
if ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) )
{
// Camera doesn't ALWAYS need to move, only when running...
2018-09-30 21:18:48 +00:00
if ( abs ( mo - > momx ) > 10 )
2014-03-15 16:59:03 +00:00
{
// Move the camera all smooth-like, not jerk it around...
if ( mo - > momx > 0 )
{
if ( thiscam - > relativex < MAXCAMERADIST )
thiscam - > relativex + = 4 * FRACUNIT ;
}
else if ( mo - > momx < 0 )
{
if ( thiscam - > relativex > - MAXCAMERADIST )
thiscam - > relativex - = 4 * FRACUNIT ;
}
}
else // If speed is less than required, start moving the camera back.
{
if ( thiscam - > relativex > 0 )
thiscam - > relativex - = 4 * FRACUNIT ;
else if ( thiscam - > relativex < 0 )
thiscam - > relativex + = 4 * FRACUNIT ;
}
// Add the relative x to the global x
x + = thiscam - > relativex ;
y + = mo - > momy < < 1 ;
}
# endif // bad 2D camera code
2017-10-14 20:11:08 +00:00
pviewheight = FixedMul ( 41 * player - > height / 48 , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
2019-11-18 08:22:12 +00:00
if ( sign )
{
2019-12-05 04:36:25 +00:00
if ( sign - > eflags & MFE_VERTICALFLIP )
2019-11-18 08:22:12 +00:00
z = sign - > ceilingz - pviewheight - camheight ;
else
z = sign - > floorz + pviewheight + camheight ;
}
2014-03-15 16:59:03 +00:00
else
2019-11-18 08:22:12 +00:00
{
if ( mo - > eflags & MFE_VERTICALFLIP )
2019-11-18 08:26:15 +00:00
z = mo - > z + mo - > height - pviewheight - camheight + distz ;
2019-11-18 08:22:12 +00:00
else
2019-11-18 08:26:15 +00:00
z = mo - > z + pviewheight + camheight + distz ;
2019-11-18 08:22:12 +00:00
}
2014-03-15 16:59:03 +00:00
// move camera down to move under lower ceilings
newsubsec = R_IsPointInSubsector ( ( ( mo - > x > > FRACBITS ) + ( thiscam - > x > > FRACBITS ) ) < < ( FRACBITS - 1 ) , ( ( mo - > y > > FRACBITS ) + ( thiscam - > y > > FRACBITS ) ) < < ( FRACBITS - 1 ) ) ;
if ( ! newsubsec )
newsubsec = thiscam - > subsector ;
if ( newsubsec )
{
fixed_t myfloorz , myceilingz ;
fixed_t midz = thiscam - > z + ( thiscam - > z - mo - > z ) / 2 ;
2016-05-25 20:10:46 +00:00
fixed_t midx = ( ( mo - > x > > FRACBITS ) + ( thiscam - > x > > FRACBITS ) ) < < ( FRACBITS - 1 ) ;
fixed_t midy = ( ( mo - > y > > FRACBITS ) + ( thiscam - > y > > FRACBITS ) ) < < ( FRACBITS - 1 ) ;
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?
2014-08-04 03:49:33 +00:00
if ( newsubsec - > sector - > camsec > = 0 )
{
myfloorz = sectors [ newsubsec - > sector - > camsec ] . floorheight ;
myceilingz = sectors [ newsubsec - > sector - > camsec ] . ceilingheight ;
}
else if ( newsubsec - > sector - > heightsec > = 0 )
2014-03-15 16:59:03 +00:00
{
myfloorz = sectors [ newsubsec - > sector - > heightsec ] . floorheight ;
myceilingz = sectors [ newsubsec - > sector - > heightsec ] . ceilingheight ;
}
else
{
2016-05-25 20:10:46 +00:00
myfloorz = P_CameraGetFloorZ ( thiscam , newsubsec - > sector , midx , midy , NULL ) ;
myceilingz = P_CameraGetCeilingZ ( thiscam , newsubsec - > sector , midx , midy , NULL ) ;
2014-03-15 16:59:03 +00:00
}
// Check list of fake floors and see if floorz/ceilingz need to be altered.
if ( newsubsec - > sector - > ffloors )
{
ffloor_t * rover ;
fixed_t delta1 , delta2 ;
INT32 thingtop = midz + thiscam - > height ;
for ( rover = newsubsec - > sector - > ffloors ; rover ; rover = rover - > next )
{
2016-05-25 20:10:46 +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 ;
2016-05-25 20:10:46 +00:00
topheight = P_CameraGetFOFTopZ ( thiscam , newsubsec - > sector , rover , midx , midy , NULL ) ;
bottomheight = P_CameraGetFOFBottomZ ( thiscam , newsubsec - > sector , rover , midx , midy , NULL ) ;
delta1 = midz - ( bottomheight
+ ( ( topheight - bottomheight ) / 2 ) ) ;
delta2 = thingtop - ( bottomheight
+ ( ( topheight - bottomheight ) / 2 ) ) ;
if ( topheight > myfloorz & & abs ( delta1 ) < abs ( delta2 ) )
myfloorz = topheight ;
if ( bottomheight < myceilingz & & abs ( delta1 ) > = abs ( delta2 ) )
myceilingz = bottomheight ;
2014-03-15 16:59:03 +00:00
}
}
# ifdef POLYOBJECTS
2014-03-21 18:42:55 +00:00
// Check polyobjects and see if floorz/ceilingz need to be altered
2014-03-15 16:59:03 +00:00
{
INT32 xl , xh , yl , yh , bx , by ;
validcount + + ;
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 ( 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 = midz + thiscam - > height ;
delta1 = midz - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
delta2 = thingtop - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
2014-03-21 18:42:55 +00:00
if ( polytop > myfloorz & & abs ( delta1 ) < abs ( delta2 ) )
2014-03-15 16:59:03 +00:00
myfloorz = polytop ;
2014-03-21 18:42:55 +00:00
if ( polybottom < myceilingz & & abs ( delta1 ) > = abs ( delta2 ) )
2014-03-15 16:59:03 +00:00
myceilingz = polybottom ;
}
plink = ( polymaplink_t * ) ( plink - > link . next ) ;
}
}
}
# endif
// crushed camera
2014-03-21 18:42:55 +00:00
if ( myceilingz < = myfloorz + thiscam - > height & & ! resetcalled & & ! cameranoclip )
2014-03-15 16:59:03 +00:00
{
P_ResetCamera ( player , thiscam ) ;
return true ;
}
// camera fit?
if ( myceilingz ! = myfloorz
& & myceilingz - thiscam - > height < z )
{
/* // no fit
if ( ! resetcalled & & ! cameranoclip )
{
P_ResetCamera ( player , thiscam ) ;
return true ;
}
*/
z = myceilingz - thiscam - > height - FixedMul ( 11 * FRACUNIT , mo - > scale ) ;
// is the camera fit is there own sector
}
// Make the camera a tad smarter with 3d floors
if ( newsubsec - > sector - > ffloors & & ! cameranoclip )
{
ffloor_t * rover ;
for ( rover = newsubsec - > sector - > ffloors ; rover ; rover = rover - > next )
{
2016-05-25 20:10:46 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( ( rover - > flags & FF_BLOCKOTHERS ) & & ( rover - > flags & FF_RENDERALL ) & & ( rover - > flags & FF_EXISTS ) & & GETSECSPECIAL ( rover - > master - > frontsector - > special , 4 ) ! = 12 )
{
2016-05-25 20:10:46 +00:00
topheight = P_CameraGetFOFTopZ ( thiscam , newsubsec - > sector , rover , midx , midy , NULL ) ;
bottomheight = P_CameraGetFOFBottomZ ( thiscam , newsubsec - > sector , rover , midx , midy , NULL ) ;
2014-03-15 16:59:03 +00:00
2016-05-25 20:10:46 +00:00
if ( bottomheight - thiscam - > height < z
& & midz < bottomheight )
z = bottomheight - thiscam - > height - FixedMul ( 11 * FRACUNIT , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
2016-05-25 20:10:46 +00:00
else if ( topheight + thiscam - > height > z
& & midz > topheight )
z = topheight ;
if ( ( mo - > z > = topheight & & midz < bottomheight )
| | ( ( mo - > z < bottomheight & & mo - > z + mo - > height < topheight ) & & midz > = topheight ) )
2014-03-15 16:59:03 +00:00
{
// Can't see
if ( ! resetcalled )
P_ResetCamera ( player , thiscam ) ;
return true ;
}
}
}
}
}
if ( mo - > type = = MT_EGGTRAP )
2019-01-07 20:43:58 +00:00
z = mo - > z + 128 * FRACUNIT + pviewheight + camheight ;
2014-03-15 16:59:03 +00:00
if ( thiscam - > z < thiscam - > floorz & & ! cameranoclip )
thiscam - > z = thiscam - > floorz ;
// point viewed by the camera
// this point is just 64 unit forward the player
dist = FixedMul ( 64 < < FRACBITS , mo - > scale ) ;
2019-11-08 16:47:51 +00:00
if ( sign )
{
viewpointx = sign - > x + FixedMul ( FINECOSINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , dist ) ;
viewpointy = sign - > y + FixedMul ( FINESINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , dist ) ;
}
else
{
2019-12-08 21:54:16 +00:00
viewpointx = mo - > x + shiftx + FixedMul ( FINECOSINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , dist ) ;
viewpointy = mo - > y + shifty + FixedMul ( FINESINE ( ( angle > > ANGLETOFINESHIFT ) & FINEMASK ) , dist ) ;
2019-11-08 16:47:51 +00:00
}
2014-03-15 16:59:03 +00:00
if ( ! camstill & & ! resetcalled & & ! paused )
thiscam - > angle = R_PointToAngle2 ( thiscam - > x , thiscam - > y , viewpointx , viewpointy ) ;
/*
if ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) )
thiscam - > angle = angle ;
*/
// follow the player
/*if (player->playerstate != PST_DEAD && (camspeed) != 0)
{
if ( P_AproxDistance ( mo - > x - thiscam - > x , mo - > y - thiscam - > y ) > ( checkdist + P_AproxDistance ( mo - > momx , mo - > momy ) ) * 4
| | abs ( mo - > z - thiscam - > z ) > checkdist * 3 )
{
if ( ! resetcalled )
P_ResetCamera ( player , thiscam ) ;
return true ;
}
} */
if ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) )
{
thiscam - > momx = x - thiscam - > x ;
thiscam - > momy = y - thiscam - > y ;
thiscam - > momz = z - thiscam - > z ;
}
else
{
thiscam - > momx = FixedMul ( x - thiscam - > x , camspeed ) ;
thiscam - > momy = FixedMul ( y - thiscam - > y , camspeed ) ;
if ( GETSECSPECIAL ( thiscam - > subsector - > sector - > special , 1 ) = = 6
& & thiscam - > z < thiscam - > subsector - > sector - > floorheight + 256 * FRACUNIT
& & FixedMul ( z - thiscam - > z , camspeed ) < 0 )
{
thiscam - > momz = 0 ; // Don't go down a death pit
}
else
thiscam - > momz = FixedMul ( z - thiscam - > z , camspeed ) ;
2019-12-08 21:54:16 +00:00
thiscam - > momx + = FixedMul ( shiftx , camspeed ) ;
thiscam - > momy + = FixedMul ( shifty , camspeed ) ;
2014-03-15 16:59:03 +00:00
}
// compute aming to look the viewed point
f1 = viewpointx - thiscam - > x ;
f2 = viewpointy - thiscam - > y ;
dist = FixedHypot ( f1 , f2 ) ;
if ( mo - > eflags & MFE_VERTICALFLIP )
2019-11-23 15:11:11 +00:00
angle = R_PointToAngle2 ( 0 , thiscam - > z + thiscam - > height , dist , ( sign ? sign - > ceilingz : mo - > z + mo - > height ) - P_GetPlayerHeight ( player ) ) ;
2014-03-15 16:59:03 +00:00
else
2019-11-23 15:11:11 +00:00
angle = R_PointToAngle2 ( 0 , thiscam - > z , dist , ( sign ? sign - > floorz : mo - > z ) + P_GetPlayerHeight ( player ) ) ;
2016-08-12 20:24:17 +00:00
if ( player - > playerstate ! = PST_DEAD )
2014-03-15 16:59:03 +00:00
angle + = ( focusaiming < ANGLE_180 ? focusaiming / 2 : InvAngle ( InvAngle ( focusaiming ) / 2 ) ) ; // overcomplicated version of '((signed)focusaiming)/2;'
if ( twodlevel | | ( mo - > flags2 & MF2_TWOD ) | | ! camstill ) // Keep the view still...
{
G_ClipAimingPitch ( ( INT32 * ) & angle ) ;
dist = thiscam - > aiming - angle ;
thiscam - > aiming - = ( dist > > 3 ) ;
}
// Make player translucent if camera is too close (only in single player).
2014-04-17 18:46:40 +00:00
if ( ! ( multiplayer | | netgame ) & & ! splitscreen )
{
2018-11-05 22:40:51 +00:00
fixed_t vx = thiscam - > x , vy = thiscam - > y ;
2018-12-11 18:38:35 +00:00
if ( player - > awayviewtics & & player - > awayviewmobj ! = NULL & & ! P_MobjWasRemoved ( player - > awayviewmobj ) ) // Camera must obviously exist
2018-11-05 22:40:51 +00:00
{
2014-04-17 21:51:56 +00:00
vx = player - > awayviewmobj - > x ;
vy = player - > awayviewmobj - > y ;
2014-04-17 18:46:40 +00:00
}
2014-04-17 21:47:51 +00:00
2018-09-30 21:18:48 +00:00
if ( P_AproxDistance ( vx - mo - > x , vy - mo - > y ) < FixedMul ( 48 * FRACUNIT , mo - > scale ) )
mo - > flags2 | = MF2_SHADOW ;
2014-04-17 18:46:40 +00:00
else
2018-09-30 21:18:48 +00:00
mo - > flags2 & = ~ MF2_SHADOW ;
2014-04-17 18:46:40 +00:00
}
2014-03-15 16:59:03 +00:00
else
2018-09-30 21:18:48 +00:00
mo - > flags2 & = ~ MF2_SHADOW ;
2014-03-15 16:59:03 +00:00
2017-03-14 18:11:17 +00:00
/* if (!resetcalled && (player->powers[pw_carry] == CR_NIGHTSMODE && player->exiting))
2014-03-15 16:59:03 +00:00
{
// Don't let the camera match your movement.
thiscam - > momz = 0 ;
// Only let the camera go a little bit upwards.
if ( mo - > eflags & MFE_VERTICALFLIP & & thiscam - > aiming < ANGLE_315 & & thiscam - > aiming > ANGLE_180 )
thiscam - > aiming = ANGLE_315 ;
else if ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & thiscam - > aiming > ANGLE_45 & & thiscam - > aiming < ANGLE_180 )
thiscam - > aiming = ANGLE_45 ;
}
else */ if ( ! resetcalled & & ( player - > playerstate = = PST_DEAD | | player - > playerstate = = PST_REBORN ) )
{
// Don't let the camera match your movement.
thiscam - > momz = 0 ;
// Only let the camera go a little bit downwards.
if ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & thiscam - > aiming < ANGLE_337h & & thiscam - > aiming > ANGLE_180 )
thiscam - > aiming = ANGLE_337h ;
else if ( mo - > eflags & MFE_VERTICALFLIP & & thiscam - > aiming > ANGLE_22h & & thiscam - > aiming < ANGLE_180 )
thiscam - > aiming = ANGLE_22h ;
}
return ( x = = thiscam - > x & & y = = thiscam - > y & & z = = thiscam - > z & & angle = = thiscam - > aiming ) ;
2019-08-31 21:06:01 +00:00
2014-03-15 16:59:03 +00:00
}
2017-05-29 20:23:00 +00:00
boolean P_SpectatorJoinGame ( player_t * player )
2014-08-04 03:49:33 +00:00
{
2017-05-29 20:23:00 +00:00
if ( gametype ! = GT_COOP & & ! cv_allowteamchange . value )
2014-08-04 03:49:33 +00:00
{
if ( P_IsLocalPlayer ( player ) )
CONS_Printf ( M_GetText ( " Server does not allow team change. \n " ) ) ;
player - > powers [ pw_flashing ] + = 2 * TICRATE ; //to prevent message spam.
}
// Team changing in Team Match and CTF
// Pressing fire assigns you to a team that needs players if allowed.
// Partial code reproduction from p_tick.c autobalance code.
else if ( G_GametypeHasTeams ( ) )
{
INT32 changeto = 0 ;
INT32 z , numplayersred = 0 , numplayersblue = 0 ;
//find a team by num players, score, or random if all else fails.
for ( z = 0 ; z < MAXPLAYERS ; + + z )
if ( playeringame [ z ] )
{
if ( players [ z ] . ctfteam = = 1 )
+ + numplayersred ;
else if ( players [ z ] . ctfteam = = 2 )
+ + numplayersblue ;
}
// for z
if ( numplayersblue > numplayersred )
changeto = 1 ;
else if ( numplayersred > numplayersblue )
changeto = 2 ;
else if ( bluescore > redscore )
changeto = 1 ;
else if ( redscore > bluescore )
changeto = 2 ;
else
2016-03-27 14:33:15 +00:00
changeto = ( P_RandomFixed ( ) & 1 ) + 1 ;
2014-08-04 03:49:33 +00:00
if ( player - > mo )
{
P_RemoveMobj ( player - > mo ) ;
player - > mo = NULL ;
}
player - > spectator = false ;
player - > ctfteam = changeto ;
player - > playerstate = PST_REBORN ;
//Reset away view
if ( P_IsLocalPlayer ( player ) & & displayplayer ! = consoleplayer )
displayplayer = consoleplayer ;
if ( changeto = = 1 )
2016-04-07 02:55:58 +00:00
CONS_Printf ( M_GetText ( " %s switched to the %c%s%c. \n " ) , player_names [ player - players ] , ' \x85 ' , M_GetText ( " Red team " ) , ' \x80 ' ) ;
2014-08-04 03:49:33 +00:00
else if ( changeto = = 2 )
2016-04-07 02:55:58 +00:00
CONS_Printf ( M_GetText ( " %s switched to the %c%s%c. \n " ) , player_names [ player - players ] , ' \x84 ' , M_GetText ( " Blue team " ) , ' \x80 ' ) ;
2014-08-04 03:49:33 +00:00
return true ; // no more player->mo, cannot continue.
}
// Joining in game from firing.
else
{
// Exception for hide and seek. Don't join a game when you simply
// respawn in place and sit there for the rest of the round.
if ( ! ( gametype = = GT_HIDEANDSEEK & & leveltime > ( hidetime * TICRATE ) ) )
{
if ( player - > mo )
{
P_RemoveMobj ( player - > mo ) ;
player - > mo = NULL ;
}
2017-07-03 14:43:29 +00:00
player - > spectator = player - > outofcoop = false ;
2014-08-04 03:49:33 +00:00
player - > playerstate = PST_REBORN ;
if ( gametype = = GT_TAG )
{
//Make joining players "it" after hidetime.
if ( leveltime > ( hidetime * TICRATE ) )
{
CONS_Printf ( M_GetText ( " %s is now IT! \n " ) , player_names [ player - players ] ) ; // Tell everyone who is it!
player - > pflags | = PF_TAGIT ;
}
P_CheckSurvivors ( ) ;
}
//Reset away view
if ( P_IsLocalPlayer ( player ) & & displayplayer ! = consoleplayer )
displayplayer = consoleplayer ;
2017-05-29 20:23:00 +00:00
if ( gametype ! = GT_COOP )
CONS_Printf ( M_GetText ( " %s entered the game. \n " ) , player_names [ player - players ] ) ;
2014-08-04 03:49:33 +00:00
return true ; // no more player->mo, cannot continue.
}
else
{
if ( P_IsLocalPlayer ( player ) )
CONS_Printf ( M_GetText ( " You must wait until next round to enter the game. \n " ) ) ;
player - > powers [ pw_flashing ] + = 2 * TICRATE ; //to prevent message spam.
}
}
return false ;
}
2019-11-27 13:37:03 +00:00
// the below is first person only, if you're curious. check out P_CalcChasePostImg in p_mobj.c for chasecam
2014-03-15 16:59:03 +00:00
static void P_CalcPostImg ( player_t * player )
{
sector_t * sector = player - > mo - > subsector - > sector ;
postimg_t * type ;
INT32 * param ;
2014-08-04 03:49:33 +00:00
fixed_t pviewheight ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
pviewheight = player - > mo - > z + player - > mo - > height - player - > viewheight ;
else
pviewheight = player - > mo - > z + player - > viewheight ;
2018-12-11 18:38:35 +00:00
if ( player - > awayviewtics & & player - > awayviewmobj & & ! P_MobjWasRemoved ( player - > awayviewmobj ) )
2014-08-04 03:49:33 +00:00
{
sector = player - > awayviewmobj - > subsector - > sector ;
pviewheight = player - > awayviewmobj - > z + 20 * FRACUNIT ;
}
2014-03-15 16:59:03 +00:00
if ( splitscreen & & player = = & players [ secondarydisplayplayer ] )
{
type = & postimgtype2 ;
param = & postimgparam2 ;
}
else
{
type = & postimgtype ;
param = & postimgparam ;
}
// see if we are in heat (no, not THAT kind of heat...)
if ( P_FindSpecialLineFromTag ( 13 , sector - > tag , - 1 ) ! = - 1 )
* type = postimg_heat ;
else if ( sector - > ffloors )
{
ffloor_t * rover ;
2016-10-31 22:14:34 +00:00
fixed_t topheight ;
fixed_t bottomheight ;
2014-03-15 16:59:03 +00:00
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
2016-10-31 22:14:34 +00:00
# ifdef ESLOPE
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) : * rover - > topheight ;
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , player - > mo - > x , player - > mo - > y ) : * rover - > bottomheight ;
# else
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# endif
if ( pviewheight > = topheight | | pviewheight < = bottomheight )
2014-08-04 03:49:33 +00:00
continue ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( P_FindSpecialLineFromTag ( 13 , rover - > master - > frontsector - > tag , - 1 ) ! = - 1 )
* type = postimg_heat ;
2014-03-15 16:59:03 +00:00
}
}
// see if we are in water (water trumps heat)
if ( sector - > ffloors )
{
ffloor_t * rover ;
2016-10-31 22:14:34 +00:00
fixed_t topheight ;
fixed_t bottomheight ;
2014-03-15 16:59:03 +00:00
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_SWIMMABLE ) | | rover - > flags & FF_BLOCKPLAYER )
continue ;
2016-10-31 22:14:34 +00:00
# ifdef ESLOPE
topheight = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) : * rover - > topheight ;
bottomheight = * rover - > b_slope ? P_GetZAt ( * rover - > b_slope , player - > mo - > x , player - > mo - > y ) : * rover - > bottomheight ;
# else
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# endif
if ( pviewheight > = topheight | | pviewheight < = bottomheight )
2014-08-04 03:49:33 +00:00
continue ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
* type = postimg_water ;
2014-03-15 16:59:03 +00:00
}
}
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
* type = postimg_flip ;
# if 1
( void ) param ;
# else
// Motion blur
if ( player - > speed > ( 35 < < FRACBITS ) )
{
* type = postimg_motion ;
* param = ( player - > speed - 32 ) / 4 ;
if ( * param > 5 )
* param = 5 ;
}
# endif
}
void P_DoPityCheck ( player_t * player )
{
// No pity outside of match or CTF.
if ( player - > spectator
| | ! ( gametype = = GT_MATCH | | gametype = = GT_TEAMMATCH | | gametype = = GT_CTF ) )
return ;
// Apply pity shield if available.
if ( ( player - > pity > = 3 | | player - > pity < 0 ) & & player - > powers [ pw_shield ] = = SH_NONE )
{
2019-06-19 22:20:24 +00:00
P_SwitchShield ( player , SH_PITY ) ;
2014-03-15 16:59:03 +00:00
if ( player - > pity > 0 )
2015-12-31 16:38:23 +00:00
S_StartSound ( player - > mo , mobjinfo [ MT_PITY_ICON ] . seesound ) ;
2014-03-15 16:59:03 +00:00
player - > pity = 0 ;
}
}
2018-11-11 21:01:55 +00:00
2019-06-16 20:00:50 +00:00
static sector_t * P_GetMinecartSector ( fixed_t x , fixed_t y , fixed_t z , fixed_t * nz )
2019-06-14 19:19:52 +00:00
{
sector_t * sec = R_PointInSubsector ( x , y ) - > sector ;
if ( ( sec - > ceilingheight - sec - > floorheight ) < 64 * FRACUNIT )
return NULL ;
if ( sec - > ffloors )
{
ffloor_t * rover ;
for ( rover = sec - > ffloors ; rover ; rover = rover - > next )
{
2019-10-06 14:44:24 +00:00
if ( ! ( rover - > flags & ( FF_EXISTS | FF_BLOCKOTHERS ) ) )
2019-06-14 19:19:52 +00:00
continue ;
2019-06-16 20:00:50 +00:00
* nz = * rover - > t_slope ? P_GetZAt ( * rover - > t_slope , x , y ) : * rover - > topheight ;
2019-06-17 06:41:51 +00:00
if ( abs ( z - * nz ) < = 56 * FRACUNIT )
2019-06-14 19:19:52 +00:00
{
sec = & sectors [ rover - > secnum ] ;
2019-06-16 20:00:50 +00:00
return sec ;
2019-06-14 19:19:52 +00:00
}
}
}
2019-06-16 20:00:50 +00:00
* nz = sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) : sec - > floorheight ;
2019-06-17 06:41:51 +00:00
if ( abs ( z - * nz ) > 56 * FRACUNIT )
2019-06-16 20:00:50 +00:00
return NULL ;
2019-06-14 19:19:52 +00:00
return sec ;
}
2019-06-20 19:05:07 +00:00
static INT32 P_GetMinecartSpecialLine ( sector_t * sec )
2019-06-14 19:19:52 +00:00
{
2019-06-20 19:05:07 +00:00
INT32 line = - 1 ;
2019-06-14 22:59:13 +00:00
2019-06-14 19:19:52 +00:00
if ( ! sec )
2019-06-14 22:59:13 +00:00
return line ;
2019-06-14 19:19:52 +00:00
if ( sec - > tag ! = 0 )
2019-06-14 22:59:13 +00:00
line = P_FindSpecialLineFromTag ( 16 , sec - > tag , - 1 ) ;
2019-06-14 19:19:52 +00:00
// Also try for lines facing the sector itself, with tag 0.
{
UINT32 i ;
for ( i = 0 ; i < sec - > linecount ; i + + )
{
line_t * li = sec - > lines [ i ] ;
if ( li - > tag = = 0 & & li - > special = = 16 & & li - > frontsector = = sec )
2019-06-14 22:59:13 +00:00
line = li - lines ;
2019-06-14 19:19:52 +00:00
}
}
2019-06-14 22:59:13 +00:00
return line ;
2019-06-14 19:19:52 +00:00
}
// Get an axis of a certain ID number
2019-06-14 22:04:50 +00:00
static mobj_t * P_GetAxis ( INT32 num )
2019-06-14 19:19:52 +00:00
{
thinker_t * th ;
mobj_t * mobj ;
2019-07-02 21:08:37 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2019-06-14 19:19:52 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2019-06-14 19:19:52 +00:00
continue ;
mobj = ( mobj_t * ) th ;
// NiGHTS axes spawn before anything else. If this mobj doesn't have MF2_AXIS, it means we reached the axes' end.
if ( ! ( mobj - > flags2 & MF2_AXIS ) )
break ;
// Skip if this axis isn't the one we want.
2019-06-14 22:04:50 +00:00
if ( mobj - > health ! = num )
2019-06-14 19:19:52 +00:00
continue ;
return mobj ;
}
2019-07-12 23:42:03 +00:00
2019-06-14 22:04:50 +00:00
CONS_Alert ( CONS_WARNING , " P_GetAxis: Track segment %d is missing! \n " , num ) ;
2019-06-14 19:19:52 +00:00
return NULL ;
}
// Auxiliary function. For a given position and axis, it calculates the nearest "valid" snap-on position.
static void P_GetAxisPosition ( fixed_t x , fixed_t y , mobj_t * amo , fixed_t * newx , fixed_t * newy , angle_t * targetangle , angle_t * grind )
{
fixed_t ax = amo - > x ;
fixed_t ay = amo - > y ;
angle_t ang ;
angle_t gr = 0 ;
if ( amo - > type = = MT_AXISTRANSFERLINE )
{
ang = amo - > angle ;
// Extra security for cardinal directions.
if ( ang = = ANGLE_90 | | ang = = ANGLE_270 ) // Vertical lines
x = ax ;
else if ( ang = = 0 | | ang = = ANGLE_180 ) // Horizontal lines
y = ay ;
else // Diagonal lines
{
fixed_t distance = R_PointToDist2 ( ax , ay , x , y ) ;
angle_t fad = ( ( R_PointToAngle2 ( ax , ay , x , y ) - ang ) > > ANGLETOFINESHIFT ) & FINEMASK ;
fixed_t cosine = FINECOSINE ( fad ) ;
angle_t fa = ( ang > > ANGLETOFINESHIFT ) & FINEMASK ;
distance = FixedMul ( distance , cosine ) ;
x = ax + FixedMul ( distance , FINECOSINE ( fa ) ) ;
y = ay + FixedMul ( distance , FINESINE ( fa ) ) ;
}
}
else // Keep minecart to circle
{
2019-06-14 22:04:50 +00:00
fixed_t rad = amo - > radius ;
fixed_t distfactor = FixedDiv ( rad , R_PointToDist2 ( ax , ay , x , y ) ) ;
2019-06-14 19:19:52 +00:00
gr = R_PointToAngle2 ( ax , ay , x , y ) ;
ang = gr + ANGLE_90 ;
x = ax + FixedMul ( x - ax , distfactor ) ;
y = ay + FixedMul ( y - ay , distfactor ) ;
}
* newx = x ;
* newy = y ;
* targetangle = ang ;
* grind = gr ;
}
static void P_SpawnSparks ( mobj_t * mo , angle_t maindir )
{
angle_t fa = ( mo - > angle > > ANGLETOFINESHIFT ) & FINEMASK ;
fixed_t c = FixedMul ( FINECOSINE ( fa ) , mo - > radius ) ;
fixed_t s = FixedMul ( FINESINE ( fa ) , mo - > radius ) ;
mobj_t * spark ;
2019-06-15 18:21:18 +00:00
SINT8 b1 = ( leveltime & 1 ) ? 1 : - 1 ;
SINT8 b2 = ( leveltime & 2 ) ? 1 : - 1 ;
fixed_t r1 = FRACUNIT * P_RandomRange ( - 1 , 1 ) ;
fixed_t r2 = FRACUNIT * P_RandomRange ( - 1 , 1 ) ;
fixed_t r3 = FRACUNIT * P_RandomRange ( - 1 , 1 ) ;
fixed_t fm = ( maindir > > ANGLETOFINESHIFT ) & FINEMASK ;
2019-06-14 19:19:52 +00:00
spark = P_SpawnMobj ( mo - > x - b2 * s + b1 * c , mo - > y + b2 * c + b1 * s , mo - > z , MT_MINECARTSPARK ) ;
2019-06-15 18:21:18 +00:00
spark - > momx = mo - > momx + r1 + 8 * FINECOSINE ( fm ) ;
spark - > momy = mo - > momy + r2 + 8 * FINESINE ( fm ) ;
spark - > momz = mo - > momz + r3 ;
2019-06-14 19:19:52 +00:00
P_Thrust ( spark , R_PointToAngle2 ( mo - > x , mo - > y , spark - > x , spark - > y ) , 8 * FRACUNIT ) ;
P_SetScale ( spark , FRACUNIT / 4 ) ;
2019-06-15 18:21:18 +00:00
spark - > destscale = spark - > scale ;
2019-06-14 19:19:52 +00:00
spark - > fuse = TICRATE / 3 ;
}
// Performs a proximity check on a given direction looking for rails.
static mobj_t * P_LookForRails ( mobj_t * mobj , fixed_t c , fixed_t s , angle_t targetangle , fixed_t xcom , fixed_t ycom )
{
INT16 interval = 16 ;
INT16 fwooffset = FixedHypot ( mobj - > momx , mobj - > momy ) > > FRACBITS ;
fixed_t x = mobj - > x ;
fixed_t y = mobj - > y ;
2019-06-16 20:00:50 +00:00
fixed_t z = mobj - > z ;
2019-06-14 19:19:52 +00:00
UINT8 i ;
for ( i = 4 ; i < = 10 ; i + + )
{
fixed_t nz ;
2019-06-20 19:05:07 +00:00
INT32 lline ;
2019-06-14 19:19:52 +00:00
x + = interval * xcom * i + fwooffset * c * i ;
y + = interval * ycom * i + fwooffset * s * i ;
2019-06-16 20:00:50 +00:00
lline = P_GetMinecartSpecialLine ( P_GetMinecartSector ( x , y , z , & nz ) ) ;
2019-06-14 19:19:52 +00:00
if ( lline ! = - 1 )
{
fixed_t nx , ny ;
angle_t nang , dummy , angdiff ;
mobj_t * mark ;
mobj_t * snax = P_GetAxis ( sides [ lines [ lline ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ) ;
2019-06-14 22:04:50 +00:00
if ( ! snax )
return NULL ;
2019-06-14 22:12:58 +00:00
P_GetAxisPosition ( x , y , snax , & nx , & ny , & nang , & dummy ) ;
2019-06-15 11:49:30 +00:00
angdiff = ( ( nang - targetangle ) + ANG10 / 2 ) & ~ ANGLE_180 ;
//Axes must be directly parallel or antiparallel, give or take 5 degrees.
if ( angdiff < ANG10 )
2019-06-14 19:19:52 +00:00
{
2019-10-23 02:18:56 +00:00
mark = P_SpawnMobj ( nx , ny , nz , ( mobjtype_t ) mobj - > info - > raisestate ) ;
2019-06-14 19:19:52 +00:00
return mark ;
}
}
}
return NULL ;
}
2019-06-20 19:05:07 +00:00
static void P_ParabolicMove ( mobj_t * mo , fixed_t x , fixed_t y , fixed_t z , fixed_t g , fixed_t speed )
2019-06-14 19:19:52 +00:00
{
fixed_t dx = x - mo - > x ;
fixed_t dy = y - mo - > y ;
fixed_t dz = z - mo - > z ;
fixed_t dh = P_AproxDistance ( dx , dy ) ;
fixed_t c = FixedDiv ( dx , dh ) ;
fixed_t s = FixedDiv ( dy , dh ) ;
2019-06-20 19:05:07 +00:00
fixed_t fixConst = FixedDiv ( speed , g ) ;
2019-06-14 19:19:52 +00:00
mo - > momx = FixedMul ( c , speed ) ;
mo - > momy = FixedMul ( s , speed ) ;
mo - > momz = FixedDiv ( dh , 2 * fixConst ) + FixedDiv ( dz , FixedDiv ( dh , fixConst / 2 ) ) ;
}
static void P_MinecartThink ( player_t * player )
{
mobj_t * minecart = player - > mo - > tracer ;
angle_t fa ;
2019-06-14 22:04:50 +00:00
if ( ! minecart | | P_MobjWasRemoved ( minecart ) | | ! minecart - > health )
2019-06-14 19:19:52 +00:00
{
// Minecart died on you, so kill yourself.
P_KillMobj ( player - > mo , NULL , NULL , 0 ) ;
return ;
}
//Limit player's angle to a cone.
# define MINECARTCONEMAX FixedAngle(20*FRACUNIT)
{
angle_t angdiff = player - > mo - > angle - minecart - > angle ;
if ( angdiff < ANGLE_180 & & angdiff > MINECARTCONEMAX )
player - > mo - > angle = minecart - > angle + MINECARTCONEMAX ;
else if ( angdiff > ANGLE_180 & & angdiff < InvAngle ( MINECARTCONEMAX ) )
player - > mo - > angle = minecart - > angle - MINECARTCONEMAX ;
2019-06-15 18:21:18 +00:00
if ( angdiff + minecart - > angle ! = player - > mo - > angle & & ( ! demoplayback | | P_AnalogMove ( player ) ) )
2019-06-14 19:19:52 +00:00
{
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
}
}
// Player holding jump?
2019-06-15 19:58:58 +00:00
if ( ! ( player - > cmd . buttons & BT_JUMP ) )
2019-06-14 19:19:52 +00:00
player - > pflags & = ~ PF_JUMPDOWN ;
// Handle segments.
P_HandleMinecartSegments ( minecart ) ;
// Force 0 friction.
minecart - > friction = FRACUNIT ;
fa = ( minecart - > angle > > ANGLETOFINESHIFT ) & FINEMASK ;
if ( ! P_TryMove ( minecart , minecart - > x + FINECOSINE ( fa ) , minecart - > y + FINESINE ( fa ) , true ) )
{
P_KillMobj ( minecart , NULL , NULL , 0 ) ;
return ;
}
if ( P_IsObjectOnGround ( minecart ) )
{
sector_t * sec ;
2019-08-11 21:14:50 +00:00
INT32 lnum = - 1 ;
2019-06-16 20:00:50 +00:00
fixed_t dummy ;
2019-06-14 19:19:52 +00:00
// Just hit floor.
if ( minecart - > eflags & MFE_JUSTHITFLOOR )
{
S_StopSound ( minecart ) ;
S_StartSound ( minecart , sfx_s3k96 ) ;
}
2019-06-16 20:00:50 +00:00
sec = P_GetMinecartSector ( minecart - > x , minecart - > y , minecart - > z , & dummy ) ;
2019-06-14 19:19:52 +00:00
if ( sec )
lnum = P_GetMinecartSpecialLine ( sec ) ;
// Update axis if the cart is standing on a rail.
if ( sec & & lnum ! = - 1 )
{
mobj_t * axis = P_GetAxis ( sides [ lines [ lnum ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ) ;
fixed_t newx , newy ;
angle_t targetangle , grind ;
angle_t prevangle , angdiff ;
mobj_t * detleft = NULL ;
mobj_t * detright = NULL ;
mobj_t * sidelock = NULL ;
boolean jumped = false ;
fixed_t currentSpeed ;
2019-06-14 22:04:50 +00:00
if ( ! axis )
{
2019-06-15 19:43:36 +00:00
P_KillMobj ( minecart , NULL , NULL , 0 ) ;
2019-06-14 22:04:50 +00:00
return ;
}
2019-06-14 19:19:52 +00:00
minecart - > movefactor = 0 ;
P_ResetScore ( player ) ;
// Handle angle and position
P_GetAxisPosition ( minecart - > x , minecart - > y , axis , & newx , & newy , & targetangle , & grind ) ;
2019-06-15 18:21:18 +00:00
if ( axis - > type ! = MT_AXISTRANSFERLINE )
2019-06-14 19:19:52 +00:00
P_SpawnSparks ( minecart , grind ) ;
P_TryMove ( minecart , newx , newy , true ) ;
// Set angle based on target
prevangle = minecart - > angle ;
angdiff = targetangle - minecart - > angle ;
if ( angdiff < ANGLE_90 + ANG2 | | angdiff > ANGLE_270 - ANG2 )
minecart - > angle = targetangle ;
else
minecart - > angle = targetangle + ANGLE_180 ;
2019-06-15 18:21:18 +00:00
angdiff = ( minecart - > angle - prevangle ) ;
if ( angdiff & & ( ! demoplayback | | P_AnalogMove ( player ) ) ) // maintain relative angle on turns
2019-06-14 19:19:52 +00:00
{
2019-06-15 18:21:18 +00:00
player - > mo - > angle + = angdiff ;
2019-06-14 19:19:52 +00:00
if ( player = = & players [ consoleplayer ] )
2019-06-15 18:21:18 +00:00
localangle + = angdiff ;
2019-06-14 19:19:52 +00:00
else if ( player = = & players [ secondarydisplayplayer ] )
2019-06-15 18:21:18 +00:00
localangle2 + = angdiff ;
2019-06-14 19:19:52 +00:00
}
// Sideways detection
if ( minecart - > flags2 & MF2_AMBUSH )
{
2019-06-20 19:05:07 +00:00
angle_t fa2 = ( minecart - > angle > > ANGLETOFINESHIFT ) & FINEMASK ;
fixed_t c = FINECOSINE ( fa2 ) ;
fixed_t s = FINESINE ( fa2 ) ;
2019-06-14 19:19:52 +00:00
detleft = P_LookForRails ( minecart , c , s , targetangle , - s , c ) ;
detright = P_LookForRails ( minecart , c , s , targetangle , s , - c ) ;
}
// How fast are we going?
currentSpeed = FixedHypot ( minecart - > momx , minecart - > momy ) ;
angdiff = R_PointToAngle2 ( 0 , 0 , minecart - > momx , minecart - > momy ) - minecart - > angle ;
if ( angdiff > ANGLE_90 & & angdiff < ANGLE_270 )
currentSpeed * = - 1 ;
// Player-specific behavior.
if ( detleft & & player - > cmd . sidemove < 0 )
sidelock = detleft ;
else if ( detright & & player - > cmd . sidemove > 0 )
sidelock = detright ;
//if (player->cmd.buttons & BT_USE && currentSpeed > 4*FRACUNIT)
// currentSpeed -= FRACUNIT/8;
// Jumping
2019-06-21 18:13:30 +00:00
if ( sidelock | | ( ( player - > cmd . buttons & BT_JUMP ) & & ! ( player - > pflags & PF_JUMPDOWN ) ) )
2019-06-14 19:19:52 +00:00
{
2019-06-15 19:58:58 +00:00
player - > pflags | = PF_JUMPDOWN ;
2019-06-14 19:19:52 +00:00
if ( minecart - > eflags & MFE_ONGROUND )
minecart - > eflags & = ~ MFE_ONGROUND ;
minecart - > z + = P_MobjFlip ( minecart ) ;
if ( sidelock )
P_ParabolicMove ( minecart , sidelock - > x , sidelock - > y , sidelock - > z , gravity , max ( currentSpeed , 10 * FRACUNIT ) ) ;
else
minecart - > momz = 10 * FRACUNIT ;
S_StartSound ( minecart , sfx_s3k51 ) ;
jumped = true ;
}
if ( ! jumped )
{
// Natural acceleration and boosters
2019-06-14 22:04:50 +00:00
if ( currentSpeed < minecart - > info - > speed )
2019-06-14 19:19:52 +00:00
currentSpeed + = FRACUNIT / 4 ;
if ( minecart - > standingslope )
{
2019-06-20 19:05:07 +00:00
fixed_t fa2 = ( minecart - > angle > > ANGLETOFINESHIFT ) & FINEMASK ;
2019-06-14 19:19:52 +00:00
fixed_t front = P_GetZAt ( minecart - > standingslope , minecart - > x , minecart - > y ) ;
2019-06-20 19:05:07 +00:00
fixed_t back = P_GetZAt ( minecart - > standingslope , minecart - > x - FINECOSINE ( fa2 ) , minecart - > y - FINESINE ( fa2 ) ) ;
2019-06-14 19:19:52 +00:00
if ( abs ( front - back ) < 3 * FRACUNIT )
currentSpeed + = ( back - front ) / 3 ;
}
// Go forward at our current speed
P_InstaThrust ( minecart , minecart - > angle , currentSpeed ) ;
// On-track ka-klong sound FX.
minecart - > movecount + = abs ( currentSpeed ) ;
if ( minecart - > movecount > 128 * FRACUNIT )
{
minecart - > movecount % = 128 * FRACUNIT ;
S_StartSound ( minecart , minecart - > info - > activesound ) ;
}
}
}
else
{
minecart - > movefactor + + ;
if ( ( P_IsObjectOnGround ( minecart ) & & minecart - > movefactor > = 5 ) // off rail
| | ( abs ( minecart - > momx ) < minecart - > scale / 2 & & abs ( minecart - > momy ) < minecart - > scale / 2 ) ) // hit a wall
{
P_KillMobj ( minecart , NULL , NULL , 0 ) ;
return ;
}
}
}
2019-10-24 17:51:12 +00:00
if ( player - > mo - > state - states ! = S_PLAY_STND )
{
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
player - > mo - > tics = - 1 ;
}
2019-06-14 19:19:52 +00:00
// Move player to minecart.
P_TeleportMove ( player - > mo , minecart - > x - minecart - > momx , minecart - > y - minecart - > momy , minecart - > z + max ( minecart - > momz , 0 ) + 8 * FRACUNIT ) ;
2019-06-15 18:21:18 +00:00
if ( player - > powers [ pw_carry ] ! = CR_MINECART )
return ;
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
2019-06-14 19:19:52 +00:00
P_TryMove ( player - > mo , player - > mo - > x + minecart - > momx , player - > mo - > y + minecart - > momy , true ) ;
2019-06-14 22:59:13 +00:00
if ( player - > powers [ pw_flashing ] = = flashingtics )
player - > powers [ pw_flashing ] - - ;
2019-06-14 19:19:52 +00:00
}
2018-11-11 21:01:55 +00:00
// Handle Tails' fluff
static void P_DoTailsOverlay ( player_t * player , mobj_t * tails )
{
// init...
boolean smilesonground = P_IsObjectOnGround ( player - > mo ) ;
angle_t horizangle = player - > drawangle ;
fixed_t zoffs = 0 ;
fixed_t backwards = - 1 * FRACUNIT ;
2019-09-18 12:46:17 +00:00
boolean doswim = ( player - > panim = = PA_ABILITY & & ( player - > mo - > eflags & MFE_UNDERWATER ) ) ;
boolean doroll = ( player - > panim = = PA_ROLL | | ( player - > panim = = PA_JUMP & & ! ( player - > charflags & SF_NOJUMPSPIN ) ) | | doswim ) ;
2018-11-11 21:01:55 +00:00
angle_t rollangle ;
boolean panimchange ;
INT32 ticnum = 0 ;
statenum_t chosenstate ;
if ( ! tails - > skin )
{
tails - > skin = player - > mo - > skin ;
P_SetMobjState ( tails , S_TAILSOVERLAY_STAND ) ;
tails - > movecount = - 1 ;
}
panimchange = ( tails - > movecount ! = ( INT32 ) player - > panim ) ;
// initial position...
if ( doroll )
{
fixed_t testval , zdist ;
if ( player - > speed < FRACUNIT )
testval = FRACUNIT ;
else
{
testval = ( FixedMul ( player - > speed , FINECOSINE ( ( horizangle - R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) ) > > ANGLETOFINESHIFT ) ) ) ;
if ( testval < FRACUNIT )
testval = FRACUNIT ;
}
2019-09-18 12:46:17 +00:00
if ( doswim )
zdist = player - > mo - > momz < < 1 ;
else if ( smilesonground & & ! player - > mo - > reactiontime )
2018-11-11 21:01:55 +00:00
zdist = ( player - > mo - > z - tails - > threshold ) ;
else
zdist = player - > mo - > momz ;
2019-09-18 12:46:17 +00:00
2018-11-11 21:01:55 +00:00
rollangle = R_PointToAngle2 ( 0 , 0 , testval , - P_MobjFlip ( player - > mo ) * zdist ) ;
2019-09-18 12:46:17 +00:00
if ( ! doswim )
2019-09-18 11:46:18 +00:00
{
zoffs = 3 * FRACUNIT + 12 * FINESINE ( rollangle > > ANGLETOFINESHIFT ) ;
backwards = - 12 * FINECOSINE ( rollangle > > ANGLETOFINESHIFT ) ;
}
2018-11-11 21:01:55 +00:00
}
else if ( player - > panim = = PA_RUN )
backwards = - 5 * FRACUNIT ;
2019-09-18 11:46:18 +00:00
else if ( player - > panim = = PA_SPRING | | player - > panim = = PA_JUMP )
2018-11-11 21:01:55 +00:00
{
zoffs + = 4 * FRACUNIT ;
backwards / = 2 ;
}
else if ( player - > panim = = PA_PAIN )
backwards / = 16 ;
else if ( player - > mo - > state - states = = S_PLAY_GASP )
{
backwards / = 16 ;
zoffs + = 12 * FRACUNIT ;
}
else if ( player - > mo - > state - states = = S_PLAY_EDGE )
{
backwards / = 16 ;
zoffs = 3 * FRACUNIT ;
}
else if ( player - > panim = = PA_ABILITY2 )
{
zoffs = - 7 * FRACUNIT ;
backwards = - 9 * FRACUNIT ;
}
2019-09-18 11:46:18 +00:00
else if ( player - > panim = = PA_ABILITY )
2018-11-11 21:01:55 +00:00
backwards = - 5 * FRACUNIT ;
// sprite...
if ( doroll )
{
statenum_t add = ( ( rollangle > ANGLE_180 ) ? 2 : 0 ) ;
if ( add )
rollangle = InvAngle ( rollangle ) ;
rollangle + = ANG15 ; // modify the thresholds to be nice clean numbers
if ( rollangle > ANG60 )
chosenstate = S_TAILSOVERLAY_PLUS60DEGREES + add ;
else if ( rollangle > ANG30 )
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES + add ;
else
chosenstate = S_TAILSOVERLAY_0DEGREES ;
}
2019-09-18 11:46:18 +00:00
else if ( player - > panim = = PA_SPRING | | player - > panim = = PA_JUMP )
2018-11-11 21:01:55 +00:00
chosenstate = S_TAILSOVERLAY_MINUS60DEGREES ;
else if ( player - > panim = = PA_FALL | | player - > mo - > state - states = = S_PLAY_RIDE )
chosenstate = S_TAILSOVERLAY_PLUS60DEGREES ;
else if ( player - > panim = = PA_PAIN )
chosenstate = S_TAILSOVERLAY_PAIN ;
else if ( player - > mo - > state - states = = S_PLAY_GASP )
chosenstate = S_TAILSOVERLAY_GASP ;
else if ( player - > mo - > state - states = = S_PLAY_EDGE )
chosenstate = S_TAILSOVERLAY_EDGE ;
else if ( player - > panim = = PA_RUN )
chosenstate = S_TAILSOVERLAY_RUN ;
else if ( player - > panim = = PA_WALK )
{
if ( ! smilesonground | | player - > mo - > state - states = = S_PLAY_SKID )
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES ;
else if ( player - > speed > = FixedMul ( player - > runspeed / 2 , player - > mo - > scale ) )
chosenstate = S_TAILSOVERLAY_0DEGREES ;
else
chosenstate = S_TAILSOVERLAY_MINUS30DEGREES ;
}
else if ( player - > mo - > sprite2 = = SPR2_FLY )
chosenstate = S_TAILSOVERLAY_FLY ;
2019-09-18 11:46:18 +00:00
else if ( player - > mo - > sprite2 = = SPR2_SWIM )
chosenstate = S_TAILSOVERLAY_FLY ;
2018-11-11 21:01:55 +00:00
else if ( player - > mo - > sprite2 = = SPR2_TIRE )
chosenstate = S_TAILSOVERLAY_TIRE ;
else if ( player - > panim = = PA_ABILITY2 )
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES ;
else if ( player - > panim = = PA_IDLE )
chosenstate = S_TAILSOVERLAY_STAND ;
else
chosenstate = S_INVISIBLE ;
// state...
if ( panimchange )
{
tails - > sprite2 = - 1 ;
P_SetMobjState ( tails , chosenstate ) ;
}
else
{
if ( tails - > state ! = states + chosenstate )
{
if ( states [ chosenstate ] . sprite = = SPR_PLAY )
tails - > sprite2 = P_GetSkinSprite2 ( ( ( skin_t * ) tails - > skin ) , ( states [ chosenstate ] . frame & FF_FRAMEMASK ) , player ) ;
P_SetMobjState ( tails , chosenstate ) ;
}
}
2019-09-19 11:30:30 +00:00
#if 0
2018-11-11 21:01:55 +00:00
if ( player - > fly1 ! = 0 & & player - > powers [ pw_tailsfly ] ! = 0 & & ! smilesonground )
P_SetMobjState ( tails , chosenstate ) ;
2019-09-19 11:30:30 +00:00
# endif
2018-11-11 21:01:55 +00:00
// animation...
if ( player - > panim = = PA_SPRING | | player - > panim = = PA_FALL | | player - > mo - > state - states = = S_PLAY_RIDE )
{
if ( FixedDiv ( abs ( player - > mo - > momz ) , player - > mo - > scale ) < 20 < < FRACBITS )
ticnum = 2 ;
else
ticnum = 1 ;
}
else if ( player - > panim = = PA_PAIN )
ticnum = 2 ;
else if ( player - > mo - > state - states = = S_PLAY_GASP )
tails - > tics = - 1 ;
else if ( player - > mo - > sprite2 = = SPR2_TIRE )
2019-09-19 11:30:30 +00:00
ticnum = ( doswim ? 2 : 4 ) ;
2018-11-11 21:01:55 +00:00
else if ( player - > panim ! = PA_IDLE )
ticnum = player - > mo - > tics ;
if ( ticnum & & tails - > tics > ticnum )
tails - > tics = ticnum ;
// final handling...
tails - > color = player - > mo - > color ;
tails - > threshold = player - > mo - > z ;
tails - > movecount = player - > panim ;
tails - > angle = horizangle ;
P_SetScale ( tails , player - > mo - > scale ) ;
tails - > destscale = player - > mo - > destscale ;
tails - > radius = player - > mo - > radius ;
tails - > height = player - > mo - > height ;
zoffs = FixedMul ( zoffs , tails - > scale ) ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
tails - > eflags | = MFE_VERTICALFLIP ;
tails - > flags2 | = MF2_OBJECTFLIP ;
zoffs = player - > mo - > height - tails - > height - zoffs ;
}
else
{
tails - > eflags & = ~ MFE_VERTICALFLIP ;
tails - > flags2 & = ~ MF2_OBJECTFLIP ;
}
P_UnsetThingPosition ( tails ) ;
tails - > x = player - > mo - > x + P_ReturnThrustX ( tails , tails - > angle , FixedMul ( backwards , tails - > scale ) ) ;
tails - > y = player - > mo - > y + P_ReturnThrustY ( tails , tails - > angle , FixedMul ( backwards , tails - > scale ) ) ;
tails - > z = player - > mo - > z + zoffs ;
P_SetThingPosition ( tails ) ;
}
2019-10-23 04:35:17 +00:00
// Metal Sonic's jet fume
static void P_DoMetalJetFume ( player_t * player , mobj_t * fume )
{
static const UINT8 FUME_SKINCOLORS [ ] =
{
SKINCOLOR_ICY ,
SKINCOLOR_SKY ,
SKINCOLOR_CYAN ,
SKINCOLOR_WAVE ,
SKINCOLOR_TEAL ,
SKINCOLOR_AQUA ,
SKINCOLOR_SEAFOAM ,
SKINCOLOR_MINT ,
SKINCOLOR_PERIDOT ,
SKINCOLOR_LIME ,
SKINCOLOR_YELLOW ,
SKINCOLOR_SANDY ,
SKINCOLOR_GOLD ,
SKINCOLOR_APRICOT ,
SKINCOLOR_SUNSET
} ;
mobj_t * mo = player - > mo ;
angle_t angle = player - > drawangle ;
fixed_t dist ;
panim_t panim = player - > panim ;
tic_t dashmode = player - > dashmode ;
boolean underwater = mo - > eflags & MFE_UNDERWATER ;
2019-10-27 11:18:37 +00:00
statenum_t stat = fume - > state - states ;
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
if ( panim ! = PA_WALK & & panim ! = PA_RUN & & panim ! = PA_DASH ) // turn invisible when not in a coherent movement state
{
2019-10-27 11:18:37 +00:00
if ( stat ! = fume - > info - > spawnstate )
2019-10-26 00:32:36 +00:00
P_SetMobjState ( fume , fume - > info - > spawnstate ) ;
2019-10-23 04:35:17 +00:00
return ;
}
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
if ( underwater ) // No fume underwater; spawn bubbles instead!
{
fume - > movedir + = FixedAngle ( FixedDiv ( 2 * player - > speed , 3 * mo - > scale ) ) ;
fume - > movefactor + = player - > speed ;
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
if ( fume - > movefactor > FixedDiv ( 2 * player - > normalspeed , 3 * mo - > scale ) )
{
INT16 i ;
fixed_t radiusV = 4 * FRACUNIT ;
fixed_t radiusX = P_ReturnThrustX ( mo , angle , - mo - > radius > > ( panim = = PA_WALK ? 1 : 0 ) ) ;
fixed_t radiusY = P_ReturnThrustY ( mo , angle , - mo - > radius > > ( panim = = PA_WALK ? 1 : 0 ) ) ;
fixed_t factorX = P_ReturnThrustX ( mo , angle + ANGLE_90 , mo - > scale ) ;
fixed_t factorY = P_ReturnThrustY ( mo , angle + ANGLE_90 , mo - > scale ) ;
fixed_t offsetH , offsetV , x , y , z ;
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
for ( i = - 1 ; i < 2 ; i + = 2 )
{
offsetH = i * P_ReturnThrustX ( fume , fume - > movedir , radiusV ) ;
offsetV = i * P_ReturnThrustY ( fume , fume - > movedir , radiusV ) ;
x = mo - > x + radiusX + FixedMul ( offsetH , factorX ) ;
y = mo - > y + radiusY + FixedMul ( offsetH , factorY ) ;
z = mo - > z + ( mo - > height > > 1 ) + offsetV ;
P_SpawnMobj ( x , y , z , MT_SMALLBUBBLE ) - > scale = mo - > scale > > 1 ;
}
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
fume - > movefactor = 0 ;
}
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
if ( panim = = PA_WALK )
{
2019-10-27 11:18:37 +00:00
if ( stat ! = fume - > info - > spawnstate )
2019-10-26 00:32:36 +00:00
P_SetMobjState ( fume , fume - > info - > spawnstate ) ;
2019-10-23 04:35:17 +00:00
return ;
}
}
2019-10-28 18:37:26 +00:00
2019-10-27 11:18:37 +00:00
if ( stat = = fume - > info - > spawnstate ) // If currently inivisble, activate!
2019-10-23 04:35:17 +00:00
{
2019-10-27 11:18:37 +00:00
P_SetMobjState ( fume , ( stat = fume - > info - > seestate ) ) ;
2019-10-23 04:35:17 +00:00
P_SetScale ( fume , mo - > scale ) ;
}
2019-10-28 18:37:26 +00:00
2019-10-27 11:18:37 +00:00
if ( dashmode > DASHMODE_THRESHOLD & & stat ! = fume - > info - > seestate ) // If in dashmode, grow really big and flash
2019-10-23 04:35:17 +00:00
{
fume - > destscale = mo - > scale ;
fume - > flags2 ^ = MF2_DONTDRAW ;
fume - > flags2 | = mo - > flags2 & MF2_DONTDRAW ;
}
else // Otherwise, pick a size and color depending on speed and proximity to dashmode
{
2019-10-27 11:18:37 +00:00
if ( dashmode = = DASHMODE_THRESHOLD & & dashmode > ( tic_t ) fume - > movecount ) // If just about to enter dashmode, play the startup animation again
2019-10-23 04:35:17 +00:00
{
2019-10-27 11:18:37 +00:00
P_SetMobjState ( fume , ( stat = fume - > info - > seestate ) ) ;
2019-10-23 04:35:17 +00:00
P_SetScale ( fume , mo - > scale < < 1 ) ;
}
fume - > flags2 = ( fume - > flags2 & ~ MF2_DONTDRAW ) | ( mo - > flags2 & MF2_DONTDRAW ) ;
fume - > destscale = ( mo - > scale + FixedDiv ( player - > speed , player - > normalspeed ) ) / ( underwater ? 6 : 3 ) ;
fume - > color = FUME_SKINCOLORS [ ( dashmode * sizeof ( FUME_SKINCOLORS ) ) / ( DASHMODE_MAX + 1 ) ] ;
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
if ( underwater )
{
fume - > frame = ( fume - > frame & FF_FRAMEMASK ) | FF_ANIMATE | ( P_RandomRange ( 0 , 9 ) * FF_TRANS10 ) ;
}
}
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
fume - > movecount = dashmode ; // keeps track of previous dashmode value so we know whether Metal is entering or leaving it
2019-10-29 15:32:22 +00:00
fume - > eflags = ( fume - > flags2 & ~ MF2_OBJECTFLIP ) | ( mo - > flags2 & MF2_OBJECTFLIP ) ; // Make sure to flip in reverse gravity!
2019-10-23 04:35:17 +00:00
fume - > eflags = ( fume - > eflags & ~ MFE_VERTICALFLIP ) | ( mo - > eflags & MFE_VERTICALFLIP ) ; // Make sure to flip in reverse gravity!
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
// Finally, set its position
dist = - mo - > radius - FixedMul ( fume - > info - > radius , fume - > destscale - mo - > scale / 3 ) ;
2019-10-28 18:37:26 +00:00
2019-10-23 04:35:17 +00:00
P_UnsetThingPosition ( fume ) ;
fume - > x = mo - > x + P_ReturnThrustX ( fume , angle , dist ) ;
fume - > y = mo - > y + P_ReturnThrustY ( fume , angle , dist ) ;
2019-10-29 15:32:22 +00:00
fume - > z = mo - > z + ( ( mo - > height - fume - > height ) > > 1 ) ;
2019-10-23 04:35:17 +00:00
P_SetThingPosition ( fume ) ;
}
2014-03-15 16:59:03 +00:00
//
// P_PlayerThink
//
void P_PlayerThink ( player_t * player )
{
ticcmd_t * cmd ;
const size_t playeri = ( size_t ) ( player - players ) ;
# ifdef PARANOIA
if ( ! player - > mo )
I_Error ( " p_playerthink: players[%s].mo == NULL " , sizeu1 ( playeri ) ) ;
# endif
// todo: Figure out what is actually causing these problems in the first place...
2015-08-15 20:07:16 +00:00
if ( player - > mo - > health < = 0 & & player - > playerstate = = PST_LIVE ) //you should be DEAD!
2014-03-15 16:59:03 +00:00
{
CONS_Debug ( DBG_GAMELOGIC , " P_PlayerThink: Player %s in PST_LIVE with 0 health. ( \" Zombie bug \" ) \n " , sizeu1 ( playeri ) ) ;
player - > playerstate = PST_DEAD ;
}
if ( player - > bot )
{
2019-02-26 21:14:22 +00:00
if ( player - > playerstate = = PST_LIVE | | player - > playerstate = = PST_DEAD )
{
if ( B_CheckRespawn ( player ) )
player - > playerstate = PST_REBORN ;
}
2014-03-15 16:59:03 +00:00
if ( player - > playerstate = = PST_REBORN )
return ;
}
# ifdef SEENAMES
if ( netgame & & player = = & players [ displayplayer ] & & ! ( leveltime % ( TICRATE / 5 ) ) )
{
seenplayer = NULL ;
if ( cv_seenames . value & & cv_allowseenames . value & &
! ( G_TagGametype ( ) & & ( player - > pflags & PF_TAGIT ) ) )
{
mobj_t * mo = P_SpawnNameFinder ( player - > mo , MT_NAMECHECK ) ;
if ( mo )
{
short int i ;
mo - > flags | = MF_NOCLIPHEIGHT ;
for ( i = 0 ; i < 32 ; i + + )
{
// Debug drawing
// if (i&1)
// P_SpawnMobj(mo->x, mo->y, mo->z, MT_SPARK);
if ( P_RailThinker ( mo ) )
break ; // mobj was removed (missile hit a wall) or couldn't move
}
}
}
}
# endif
2018-12-11 18:38:35 +00:00
if ( player - > awayviewmobj & & P_MobjWasRemoved ( player - > awayviewmobj ) )
{
P_SetTarget ( & player - > awayviewmobj , NULL ) ; // remove awayviewmobj asap if invalid
player - > awayviewtics = 0 ; // reset to zero
}
2014-03-15 16:59:03 +00:00
if ( player - > flashcount )
player - > flashcount - - ;
2019-03-07 00:40:38 +00:00
if ( player - > awayviewtics & & player - > awayviewtics ! = - 1 )
2018-12-11 23:27:26 +00:00
player - > awayviewtics - - ;
2014-03-15 16:59:03 +00:00
/// \note do this in the cheat code
if ( player - > pflags & PF_NOCLIP )
player - > mo - > flags | = MF_NOCLIP ;
else
player - > mo - > flags & = ~ MF_NOCLIP ;
cmd = & player - > cmd ;
// Add some extra randomization.
if ( cmd - > forwardmove )
2016-03-27 14:33:15 +00:00
P_RandomFixed ( ) ;
2014-03-15 16:59:03 +00:00
# ifdef PARANOIA
if ( player - > playerstate = = PST_REBORN )
I_Error ( " player %s is in PST_REBORN \n " , sizeu1 ( playeri ) ) ;
# endif
if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION )
{
INT32 i ;
// Check if all the players in the race have finished. If so, end the level.
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( playeringame [ i ] )
{
if ( ! players [ i ] . exiting & & players [ i ] . lives > 0 )
break ;
}
}
if ( i = = MAXPLAYERS & & player - > exiting = = 3 * TICRATE ) // finished
player - > exiting = ( 14 * TICRATE ) / 5 + 1 ;
2018-03-21 18:18:45 +00:00
// If 11 seconds are left on the timer,
2014-03-15 16:59:03 +00:00
// begin the drown music for countdown!
2018-06-03 21:41:54 +00:00
if ( countdown = = 11 * TICRATE - 1 & & P_IsLocalPlayer ( player ) )
2019-08-04 11:03:57 +00:00
P_PlayJingle ( player , JT_DROWN ) ;
2014-03-15 16:59:03 +00:00
// If you've hit the countdown and you haven't made
// it to the exit, you're a goner!
else if ( countdown = = 1 & & ! player - > exiting & & player - > lives > 0 )
{
2015-08-15 20:07:16 +00:00
if ( netgame & & player - > mo - > health > 0 )
2014-03-15 16:59:03 +00:00
CONS_Printf ( M_GetText ( " %s ran out of time. \n " ) , player_names [ player - players ] ) ;
2017-09-15 19:34:46 +00:00
player - > pflags | = PF_GAMETYPEOVER ;
2014-03-15 16:59:03 +00:00
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
P_DeNightserizePlayer ( player ) ;
S_StartScreamSound ( player - > mo , sfx_s3k66 ) ;
}
player - > lives = 2 ; // Don't start the game over music!
2015-02-13 16:15:58 +00:00
P_DamageMobj ( player - > mo , NULL , NULL , 1 , DMG_INSTAKILL ) ;
2014-03-15 16:59:03 +00:00
player - > lives = 0 ;
if ( player - > playerstate = = PST_DEAD )
return ;
}
}
// If it is set, start subtracting
// Don't allow it to go back to 0
if ( player - > exiting > 1 & & player - > exiting < 3 * TICRATE )
player - > exiting - - ;
if ( player - > exiting & & countdown2 )
player - > exiting = 5 ;
2019-08-16 22:19:43 +00:00
// The following code is disabled for now as this causes the game to freeze sometimes
// Monster Iestyn -- 16/08/19
#if 0
2018-09-18 19:50:12 +00:00
// Same check as below, just at 1 second before
// so we can fade music
if ( ! exitfadestarted & &
2018-09-19 03:27:00 +00:00
player - > exiting > 0 & & player - > exiting < = 1 * TICRATE & &
2019-03-15 06:06:44 +00:00
( ! multiplayer | | gametype = = GT_COOP ? ! mapheaderinfo [ gamemap - 1 ] - > musinterfadeout : true ) & &
2018-09-18 19:50:12 +00:00
// don't fade if we're fading during intermission. follows Y_StartIntermission intertype = int_coop
( gametype = = GT_RACE | | gametype = = GT_COMPETITION ? countdown2 = = 0 : true ) & & // don't fade on timeout
player - > lives > 0 & & // don't fade on game over (competition)
P_IsLocalPlayer ( player ) )
{
if ( cv_playersforexit . value )
{
2019-03-15 07:47:30 +00:00
INT32 i ;
2018-09-18 19:50:12 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator | | players [ i ] . bot )
continue ;
if ( players [ i ] . lives < = 0 )
continue ;
2019-03-15 07:47:30 +00:00
if ( ! players [ i ] . exiting | | players [ i ] . exiting > 1 * TICRATE )
break ;
2018-09-18 19:50:12 +00:00
}
2019-03-15 07:47:30 +00:00
if ( i = = MAXPLAYERS )
2018-09-18 19:50:12 +00:00
{
exitfadestarted = true ;
S_FadeOutStopMusic ( 1 * MUSICRATE ) ;
}
}
else
{
exitfadestarted = true ;
S_FadeOutStopMusic ( 1 * MUSICRATE ) ;
}
}
2019-08-16 22:19:43 +00:00
# endif
2018-09-18 19:50:12 +00:00
2014-03-15 16:59:03 +00:00
if ( player - > exiting = = 2 | | countdown2 = = 2 )
{
2019-09-19 17:44:55 +00:00
UINT8 numneeded = ( G_IsSpecialStage ( gamemap ) ? 4 : cv_playersforexit . value ) ;
if ( numneeded ) // Count to be sure everyone's exited
2014-03-15 16:59:03 +00:00
{
2017-07-04 13:58:58 +00:00
INT32 i , total = 0 , exiting = 0 ;
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator | | players [ i ] . bot )
continue ;
if ( players [ i ] . lives < = 0 )
continue ;
2017-07-04 13:58:58 +00:00
total + + ;
2017-07-04 13:58:58 +00:00
if ( players [ i ] . exiting & & players [ i ] . exiting < 4 )
2017-07-04 13:58:58 +00:00
exiting + + ;
2014-03-15 16:59:03 +00:00
}
2019-09-19 17:44:55 +00:00
if ( ! total | | ( ( 4 * exiting ) / total ) > = numneeded )
2014-03-15 16:59:03 +00:00
{
if ( server )
SendNetXCmd ( XD_EXITLEVEL , NULL , 0 ) ;
}
else
player - > exiting = 3 ;
}
else
{
if ( server )
SendNetXCmd ( XD_EXITLEVEL , NULL , 0 ) ;
}
}
2019-11-15 14:35:28 +00:00
if ( player - > pflags & PF_FINISHED )
{
2019-11-24 13:35:26 +00:00
if ( ( gametype = = GT_COOP & & cv_exitmove . value ) & & ! G_EnoughPlayersFinished ( ) )
2019-11-15 14:35:28 +00:00
player - > exiting = 0 ;
else
P_DoPlayerExit ( player ) ;
}
2014-03-15 16:59:03 +00:00
// check water content, set stuff in mobj
P_MobjCheckWater ( player - > mo ) ;
2016-10-31 20:15:11 +00:00
# ifndef SECTORSPECIALSAFTERTHINK
2014-11-12 00:55:07 +00:00
# ifdef POLYOBJECTS
if ( player - > onconveyor ! = 1 | | ! P_IsObjectOnGround ( player - > mo ) )
# endif
2014-03-15 16:59:03 +00:00
player - > onconveyor = 0 ;
// check special sectors : damage & secrets
if ( ! player - > spectator )
P_PlayerInSpecialSector ( player ) ;
2017-07-03 14:41:00 +00:00
else if (
# else
if ( player - > spectator & &
2016-10-31 20:15:11 +00:00
# endif
2017-07-03 14:41:00 +00:00
gametype = = GT_COOP & & ( netgame | | multiplayer ) & & cv_coopstarposts . value = = 2 )
2017-05-29 20:23:00 +00:00
P_ConsiderAllGone ( ) ;
2014-03-15 16:59:03 +00:00
if ( player - > playerstate = = PST_DEAD )
{
player - > mo - > flags2 & = ~ MF2_SHADOW ;
P_DeathThink ( player ) ;
return ;
}
// Make sure spectators always have a score and ring count of 0.
if ( player - > spectator )
{
2017-05-30 19:31:51 +00:00
if ( gametype ! = GT_COOP )
player - > score = 0 ;
2014-03-15 16:59:03 +00:00
}
2017-05-31 16:07:24 +00:00
else if ( ( netgame | | multiplayer ) & & player - > lives < = 0 & & gametype ! = GT_COOP )
2014-03-15 16:59:03 +00:00
{
2017-05-31 16:07:24 +00:00
// Outside of Co-Op, replenish a user's lives if they are depleted.
2014-03-15 16:59:03 +00:00
// of course, this is just a cheap hack, meh...
player - > lives = cv_startinglives . value ;
}
if ( ( gametype = = GT_RACE | | gametype = = GT_COMPETITION ) & & leveltime < 4 * TICRATE )
{
cmd - > buttons & = BT_USE ; // Remove all buttons except BT_USE
cmd - > forwardmove = 0 ;
cmd - > sidemove = 0 ;
}
// Synchronizes the "real" amount of time spent in the level.
2019-11-08 15:47:12 +00:00
if ( ! player - > exiting & & ! stoppedclock )
2014-03-15 16:59:03 +00:00
{
if ( gametype = = GT_RACE | | gametype = = GT_COMPETITION )
{
if ( leveltime > = 4 * TICRATE )
player - > realtime = leveltime - 4 * TICRATE ;
else
player - > realtime = 0 ;
}
else
player - > realtime = leveltime ;
}
2017-06-03 11:26:42 +00:00
if ( player - > spectator & & cmd - > buttons & BT_ATTACK & & ! player - > powers [ pw_flashing ] & & G_GametypeHasSpectators ( ) )
2014-08-04 03:49:33 +00:00
{
if ( P_SpectatorJoinGame ( player ) )
return ; // player->mo was removed.
}
// Even if not NiGHTS, pull in nearby objects when walking around as John Q. Elliot.
if ( ! objectplacing & & ! ( ( netgame | | multiplayer ) & & player - > spectator )
2017-03-14 18:11:17 +00:00
& & maptol & TOL_NIGHTS & & ( player - > powers [ pw_carry ] ! = CR_NIGHTSMODE | | player - > powers [ pw_nights_helper ] ) )
2014-08-04 03:49:33 +00:00
{
thinker_t * th ;
mobj_t * mo2 ;
fixed_t x = player - > mo - > x ;
fixed_t y = player - > mo - > y ;
fixed_t z = player - > mo - > z ;
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-08-04 03:49:33 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
2014-08-04 03:49:33 +00:00
continue ;
mo2 = ( mobj_t * ) th ;
2018-06-05 16:22:28 +00:00
if ( ! ( mo2 - > type = = MT_RING | | mo2 - > type = = MT_COIN
| | mo2 - > type = = MT_BLUESPHERE | | mo2 - > type = = MT_BOMBSPHERE
2018-06-03 21:41:54 +00:00
| | mo2 - > type = = MT_NIGHTSCHIP | | mo2 - > type = = MT_NIGHTSSTAR ) )
2014-08-04 03:49:33 +00:00
continue ;
2018-08-13 03:03:12 +00:00
if ( mo2 - > flags2 & MF2_NIGHTSPULL )
continue ;
2014-08-04 03:49:33 +00:00
if ( P_AproxDistance ( P_AproxDistance ( mo2 - > x - x , mo2 - > y - y ) , mo2 - > z - z ) > FixedMul ( 128 * FRACUNIT , player - > mo - > scale ) )
continue ;
// Yay! The thing's in reach! Pull it in!
mo2 - > flags | = MF_NOCLIP | MF_NOCLIPHEIGHT ;
mo2 - > flags2 | = MF2_NIGHTSPULL ;
2018-08-30 14:50:03 +00:00
// New NiGHTS attract speed dummied out because the older behavior
// is exploited as a mechanic. Uncomment to enable.
mo2 - > movefactor = 0 ; // 40*FRACUNIT; // initialize the NightsItemChase timer
2014-08-04 03:49:33 +00:00
P_SetTarget ( & mo2 - > tracer , player - > mo ) ;
}
}
2018-03-30 15:39:59 +00:00
if ( player - > linktimer & & ! player - > powers [ pw_nights_linkfreeze ] )
2014-08-04 03:49:33 +00:00
{
if ( - - player - > linktimer < = 0 ) // Link timer
player - > linkcount = 0 ;
}
2014-03-15 16:59:03 +00:00
// Move around.
// Reactiontime is used to prevent movement
// for a bit after a teleport.
if ( player - > mo - > reactiontime )
player - > mo - > reactiontime - - ;
2019-06-14 19:19:52 +00:00
else if ( player - > powers [ pw_carry ] = = CR_MINECART )
2019-06-21 21:34:49 +00:00
{
if ( ! P_AnalogMove ( player ) )
player - > mo - > angle = ( cmd - > angleturn < < 16 /* not FRACBITS */ ) ;
2019-06-21 21:42:48 +00:00
ticruned + + ;
if ( ( cmd - > angleturn & TICCMD_RECEIVED ) = = 0 )
ticmiss + + ;
2019-06-14 19:19:52 +00:00
P_MinecartThink ( player ) ;
2019-06-21 21:34:49 +00:00
}
2016-09-23 22:48:48 +00:00
else if ( player - > mo - > tracer & & player - > mo - > tracer - > type = = MT_TUBEWAYPOINT & & ( player - > powers [ pw_carry ] = = CR_ROPEHANG | | player - > powers [ pw_carry ] = = CR_ZOOMTUBE ) )
2014-03-15 16:59:03 +00:00
{
2016-09-23 22:48:48 +00:00
if ( player - > powers [ pw_carry ] = = CR_ROPEHANG )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( ! P_AnalogMove ( player ) )
2014-03-15 16:59:03 +00:00
player - > mo - > angle = ( cmd - > angleturn < < 16 /* not FRACBITS */ ) ;
ticruned + + ;
if ( ( cmd - > angleturn & TICCMD_RECEIVED ) = = 0 )
ticmiss + + ;
P_DoRopeHang ( player ) ;
P_DoJumpStuff ( player , & player - > cmd ) ;
}
2016-09-23 23:37:18 +00:00
else //if (player->powers[pw_carry] == CR_ZOOMTUBE)
2014-03-15 16:59:03 +00:00
{
P_DoZoomTube ( player ) ;
A thorough reimplementation of Nojumpspin for the SPR2_ age.
* SF_NOJUMPSPIN - Player's height is full whilst jumping, SPR2_JUMP defaults to SPR2_SPNG instead of SPR2_SPIN, and the player goes into fall frames if they start moving downwards or use their ability.
* PA_JUMP - for jumping (upwards in the case of SF_NOJUMPSPIN.
* SF_NOJUMPDAMAGE - Ala rosy.wad, don't damage enemies, etc when jumping into them.
* SF_STOMPDAMAGE - Just for fun. Ala in Mario, always damage enemies when you land on top of them (your gravity reference, not theirs).
* SF_MARIODAMAGE - SF_NOJUMPDAMAGE|SF_STOMPDAMAGE is reasonably accurate to the Mario games, and might as well be surfaced as such.
Also, a minor change:
* Instead of not spawning the revitem if your SPR2_ is SPR2_DASH, don't spawn it if it's set to 0. This requires the player.dta I uploaded a couple days ago to behave as it was previously.
* Don't get stuck in spindash frames if your maxdash is 0, and don't flash rolling frames if you're on goop.
2016-07-10 17:41:38 +00:00
if ( ! ( player - > panim = = PA_ROLL ) )
2017-03-11 02:09:01 +00:00
P_SetPlayerMobjState ( player - > mo , S_PLAY_ROLL ) ;
2014-03-15 16:59:03 +00:00
}
player - > rmomx = player - > rmomy = 0 ; // no actual momentum from your controls
P_ResetScore ( player ) ;
}
else
2018-08-15 23:09:54 +00:00
{
if ( player - > bumpertime = = TICRATE / 2 & & player - > mo - > hnext )
{
// Center player to NiGHTS bumper here because if you try to set player's position in
// P_TouchSpecialThing case MT_NIGHTSBUMPER, that position is fudged in the time
// between that routine in the previous tic
// and reaching here in the current tic
P_TeleportMove ( player - > mo , player - > mo - > hnext - > x , player - > mo - > hnext - > y
, player - > mo - > hnext - > z + FixedMul ( player - > mo - > hnext - > height / 4 , player - > mo - > hnext - > scale ) ) ;
P_SetTarget ( & player - > mo - > hnext , NULL ) ;
}
2014-03-15 16:59:03 +00:00
P_MovePlayer ( player ) ;
2018-08-15 23:09:54 +00:00
}
2014-03-15 16:59:03 +00:00
if ( ! player - > mo )
return ; // P_MovePlayer removed player->mo.
2017-09-15 19:34:46 +00:00
// deez New User eXperiences.
2017-02-06 17:31:48 +00:00
{
* Improve the Metal Sonic recording/playback system.
* Make the skin to record with Metal rather than Flesh Sonic. (Allowed even if not unlocked!)
* Make the object that plays back the recording actually use the Metal skin, rather than just a seperate spriteset. (The boss will still need the spriteset, though.)
* Actively record the player's sprite2, frame, and followmobj, just like regular ghosts do.
* Disable dashmode while recording, for a fairer race.
* Fix a probably long-standing bug where, while recording, being "hurt" would get Metal stuck in pain frames until they physically left the area of hurt.
* Always start Metal recording in wait frames for bonus taunting.
Other relevant changes:
* Increment DEMOVERSION *again*.
* Improve the Record Attack ghost followmobj recording to accomodate Metal's jet.
* Increase the datatype width of spritenum_t read/write for Record Attack ghosts because SUGOI 4: Back With A Revengance will probably also use more than 255 sprites alone.
* Return to standing frames (or prolong them if you're in them, rather than going to wait frames) if the player rotates on the spot with enough force.
* This was specifically done *for* Metal recording, but I decided it looked good enough to enable all the time.
2019-10-28 22:12:47 +00:00
angle_t oldang = player - > drawangle , diff = 0 ;
2019-09-29 12:18:40 +00:00
UINT8 factor ;
2017-09-15 19:34:46 +00:00
// Directionchar!
// Camera angle stuff.
2019-08-04 14:25:13 +00:00
if ( player - > exiting // no control, no modification
| | player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2017-09-15 19:34:46 +00:00
;
else if ( ! ( player - > pflags & PF_DIRECTIONCHAR )
2019-09-30 06:38:58 +00:00
| | ( player - > climbing ) // stuff where the direction is forced at all times
2017-09-15 19:34:46 +00:00
| | ( P_AnalogMove ( player ) | | twodlevel | | player - > mo - > flags2 & MF2_TWOD ) // keep things synchronised up there, since the camera IS seperate from player motion when that happens
| | G_RingSlingerGametype ( ) ) // no firing rings in directions your player isn't aiming
player - > drawangle = player - > mo - > angle ;
else if ( P_PlayerInPain ( player ) )
;
2019-11-02 11:56:51 +00:00
else if ( player - > powers [ pw_justsprung ] ) // restricted, potentially by lua
{
# ifdef SPRINGSPIN
if ( player - > powers [ pw_justsprung ] & ( 1 < < 15 ) )
player - > drawangle + = ( player - > powers [ pw_justsprung ] & ~ ( 1 < < 15 ) ) * ( ANG2 + ANG1 ) ;
# endif
}
2017-09-15 19:34:46 +00:00
else if ( player - > powers [ pw_carry ] & & player - > mo - > tracer ) // carry
2017-02-06 17:31:48 +00:00
{
2017-09-15 19:34:46 +00:00
switch ( player - > powers [ pw_carry ] )
{
case CR_PLAYER :
2019-06-14 19:19:52 +00:00
if ( player - > mo - > tracer - > player )
{
player - > drawangle = player - > mo - > tracer - > player - > drawangle ;
break ;
}
/* FALLTHRU */
case CR_MINECART :
case CR_GENERIC :
2019-10-05 18:29:47 +00:00
case CR_PTERABYTE :
2019-06-14 19:19:52 +00:00
player - > drawangle = player - > mo - > tracer - > angle ;
2017-09-15 19:34:46 +00:00
break ;
2019-09-29 12:18:40 +00:00
case CR_ROLLOUT :
if ( cmd - > forwardmove | | cmd - > sidemove ) // only when you're pressing movement keys
{ // inverse direction!
diff = ( ( player - > mo - > angle + R_PointToAngle2 ( 0 , 0 , - cmd - > forwardmove < < FRACBITS , cmd - > sidemove < < FRACBITS ) ) - player - > drawangle ) ;
factor = 4 ;
}
break ;
2017-09-15 19:34:46 +00:00
/* -- in case we wanted to have the camera freely movable during zoom tubes
case CR_ZOOMTUBE : */
2017-09-15 19:34:46 +00:00
case CR_ROPEHANG :
2017-09-15 19:34:46 +00:00
if ( player - > mo - > momx | | player - > mo - > momy )
{
player - > drawangle = R_PointToAngle2 ( 0 , 0 , player - > mo - > momx , player - > mo - > momy ) ;
break ;
}
2017-09-28 15:01:52 +00:00
/* FALLTHRU */
2017-09-15 19:34:46 +00:00
default :
player - > drawangle = player - > mo - > angle ;
break ;
}
2017-02-06 17:31:48 +00:00
}
2017-09-15 19:34:46 +00:00
else if ( ( player - > skidtime > ( TICRATE / 2 - 2 ) | | ( ( player - > pflags & ( PF_SPINNING | PF_STARTDASH ) ) = = PF_SPINNING ) ) & & ( abs ( player - > rmomx ) > 5 * player - > mo - > scale | | abs ( player - > rmomy ) > 5 * player - > mo - > scale ) ) // spin/skid force
player - > drawangle = R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) ;
else if ( ( ( player - > charability2 = = CA2_GUNSLINGER | | player - > charability2 = = CA2_MELEE ) & & player - > panim = = PA_ABILITY2 ) | | player - > pflags & PF_STASIS | | player - > skidtime )
;
2017-04-05 15:01:02 +00:00
else
2017-09-15 19:34:46 +00:00
{
2019-09-22 13:11:49 +00:00
if ( player - > pflags & PF_GLIDING )
{
2019-09-22 16:21:28 +00:00
if ( player - > speed < player - > mo - > scale )
diff = player - > mo - > angle - player - > drawangle ;
else
diff = ( R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) - player - > drawangle ) ;
2019-09-22 13:11:49 +00:00
factor = 4 ;
}
else if ( player - > pflags & PF_SLIDING )
2017-09-15 19:34:46 +00:00
{
#if 0 // fun hydrocity style horizontal spin
if ( player - > mo - > eflags & MFE_TOUCHWATER | | player - > powers [ pw_flashing ] > ( flashingtics / 4 ) * 3 )
{
diff = ( player - > mo - > angle - player - > drawangle ) ;
2019-10-19 13:32:34 +00:00
factor = 16 ;
2017-09-15 19:34:46 +00:00
}
else
{
diff = factor = 0 ;
player - > drawangle + = ANGLE_22h ;
}
# else
diff = ( player - > mo - > angle - player - > drawangle ) ;
2019-10-19 13:32:34 +00:00
factor = 16 ;
2017-09-15 19:34:46 +00:00
# endif
}
2017-08-16 19:01:24 +00:00
else if ( player - > pflags & PF_STARTDASH )
{
diff = ( player - > mo - > angle - player - > drawangle ) ;
factor = 4 ;
}
2017-09-15 19:34:46 +00:00
else if ( cmd - > forwardmove | | cmd - > sidemove ) // only when you're pressing movement keys
{
diff = ( ( player - > mo - > angle + R_PointToAngle2 ( 0 , 0 , cmd - > forwardmove < < FRACBITS , - cmd - > sidemove < < FRACBITS ) ) - player - > drawangle ) ;
factor = 4 ;
}
else if ( player - > rmomx | | player - > rmomy )
diff = factor = 0 ;
else
{
diff = ( player - > mo - > angle - player - > drawangle ) ;
2017-08-16 19:01:24 +00:00
factor = 8 ;
2017-09-15 19:34:46 +00:00
}
2019-09-29 12:18:40 +00:00
}
2017-02-05 18:15:20 +00:00
2019-09-29 12:18:40 +00:00
if ( diff )
{
if ( diff > ANGLE_180 )
diff = InvAngle ( InvAngle ( diff ) / factor ) ;
else
diff / = factor ;
player - > drawangle + = diff ;
2017-09-15 19:34:46 +00:00
}
* Improve the Metal Sonic recording/playback system.
* Make the skin to record with Metal rather than Flesh Sonic. (Allowed even if not unlocked!)
* Make the object that plays back the recording actually use the Metal skin, rather than just a seperate spriteset. (The boss will still need the spriteset, though.)
* Actively record the player's sprite2, frame, and followmobj, just like regular ghosts do.
* Disable dashmode while recording, for a fairer race.
* Fix a probably long-standing bug where, while recording, being "hurt" would get Metal stuck in pain frames until they physically left the area of hurt.
* Always start Metal recording in wait frames for bonus taunting.
Other relevant changes:
* Increment DEMOVERSION *again*.
* Improve the Record Attack ghost followmobj recording to accomodate Metal's jet.
* Increase the datatype width of spritenum_t read/write for Record Attack ghosts because SUGOI 4: Back With A Revengance will probably also use more than 255 sprites alone.
* Return to standing frames (or prolong them if you're in them, rather than going to wait frames) if the player rotates on the spot with enough force.
* This was specifically done *for* Metal recording, but I decided it looked good enough to enable all the time.
2019-10-28 22:12:47 +00:00
// reset from waiting to standing when turning on the spot
if ( player - > panim = = PA_IDLE )
{
diff = player - > drawangle - oldang ;
if ( diff > ANGLE_180 )
diff = InvAngle ( diff ) ;
if ( diff > ANG10 / 2 )
{
statenum_t stat = player - > mo - > state - states ;
if ( stat = = S_PLAY_WAIT )
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
2019-11-02 11:56:51 +00:00
else if ( stat = = S_PLAY_STND & & player - > mo - > tics ! = - 1 )
* Improve the Metal Sonic recording/playback system.
* Make the skin to record with Metal rather than Flesh Sonic. (Allowed even if not unlocked!)
* Make the object that plays back the recording actually use the Metal skin, rather than just a seperate spriteset. (The boss will still need the spriteset, though.)
* Actively record the player's sprite2, frame, and followmobj, just like regular ghosts do.
* Disable dashmode while recording, for a fairer race.
* Fix a probably long-standing bug where, while recording, being "hurt" would get Metal stuck in pain frames until they physically left the area of hurt.
* Always start Metal recording in wait frames for bonus taunting.
Other relevant changes:
* Increment DEMOVERSION *again*.
* Improve the Record Attack ghost followmobj recording to accomodate Metal's jet.
* Increase the datatype width of spritenum_t read/write for Record Attack ghosts because SUGOI 4: Back With A Revengance will probably also use more than 255 sprites alone.
* Return to standing frames (or prolong them if you're in them, rather than going to wait frames) if the player rotates on the spot with enough force.
* This was specifically done *for* Metal recording, but I decided it looked good enough to enable all the time.
2019-10-28 22:12:47 +00:00
player - > mo - > tics + + ;
}
}
2017-10-15 12:37:05 +00:00
// Autobrake! check ST_drawInput if you modify this
2017-09-15 19:34:46 +00:00
{
boolean currentlyonground = P_IsObjectOnGround ( player - > mo ) ;
* New object types!
* Red and yellow Boost panels!
* Added because SUBARASHII and KIMOKAWAIII had several levels using them, and I wanted to make them look better.
* https://cdn.discordapp.com/attachments/359091121789468672/634486669202161674/srb20015.gif
* Uses the mapthingnums of Glaber's SOC resource boosters, but absolutely nothing else - not even the magnitudes.
* Apply MF_AMBUSH to force the player into a spin - even if they don't have a spin ability!
* Banpyura!
* A Crushstacean with a spring instead of a crushclaw.
* https://cdn.discordapp.com/attachments/428262628893261828/634432099306176512/srb20019.gif
* Wanted this for a while, finally added it.
* Improved springs.
* Add pw_noautobrake to disable autobrake for half a second when touching yellow horizontal springs, and a second when touching red ones, even on the ground.
* Add pw_justsprung to disable directionchar for a few tics while touching any springs with a horizontal component to their velocity.
* Add the diagonal spring flag options Red and Yellow Diagonal Springs have to the Blue Diagonal Spring as well.
* Started but decided against a tip of the hat to the CD spring spin, hidden behind #define SPRINGSPIN.
* Make directionchar "lag behind" a little bit in waterslides.
* Improved flame jets.
* They now use new sprites for having their flames move upwards and sideways, instead of having them always face downwards like in 2.1!
* Fixed a mixed declaration and code error in A_RolloutRock. (Sorry Lach!)
* Make the Amy Cameo only spawn in SP, Record Attack, or Co-op unless it's the Clone Mode.
* Improved ZB config.
* Add above new types.
* Add Blue Diagonal Spring, which existed in the source but not the config.
* Re-order enemies in ZB config by zone (but keep them in the Enemies section only).
2019-10-17 20:50:26 +00:00
if ( player - > powers [ pw_noautobrake ] )
;
else if ( ! player - > powers [ pw_carry ] & & ! player - > powers [ pw_nocontrol ]
2019-09-18 11:46:18 +00:00
& & ( ( player - > pflags & ( PF_AUTOBRAKE | PF_APPLYAUTOBRAKE | PF_STASIS ) ) = = ( PF_AUTOBRAKE | PF_APPLYAUTOBRAKE ) )
2017-09-15 19:34:46 +00:00
& & ! ( cmd - > forwardmove | | cmd - > sidemove )
2018-06-05 16:22:28 +00:00
& & ( player - > rmomx | | player - > rmomy )
& & ( ! player - > capsule | | ( player - > capsule - > reactiontime ! = ( player - players ) + 1 ) ) )
2017-09-15 19:34:46 +00:00
{
2017-09-15 19:34:46 +00:00
fixed_t acceleration = ( player - > accelstart + ( FixedDiv ( player - > speed , player - > mo - > scale ) > > FRACBITS ) * player - > acceleration ) * player - > thrustfactor * 20 ;
2017-09-15 19:34:46 +00:00
angle_t moveAngle = R_PointToAngle2 ( 0 , 0 , player - > rmomx , player - > rmomy ) ;
if ( ! currentlyonground )
acceleration / = 2 ;
2019-08-22 15:13:00 +00:00
// fake skidding! see P_SkidStuff for reference on conditionals
2019-09-18 13:16:52 +00:00
else if ( ! player - > skidtime & & ! ( player - > mo - > eflags & MFE_GOOWATER ) & & ! ( player - > pflags & ( PF_JUMPED | PF_SPINNING | PF_SLIDING ) ) & & ! ( player - > charflags & SF_NOSKID ) & & P_AproxDistance ( player - > mo - > momx , player - > mo - > momy ) > = FixedMul ( player - > runspeed , player - > mo - > scale ) ) // modified from player->runspeed/2 'cuz the skid was just TOO frequent ngl
2019-08-22 15:13:00 +00:00
{
if ( player - > mo - > state - states ! = S_PLAY_SKID )
P_SetPlayerMobjState ( player - > mo , S_PLAY_SKID ) ;
player - > mo - > tics = player - > skidtime = ( player - > mo - > movefactor = = FRACUNIT ) ? TICRATE / 2 : ( FixedDiv ( 35 < < ( FRACBITS - 1 ) , FixedSqrt ( player - > mo - > movefactor ) ) ) > > FRACBITS ;
if ( P_IsLocalPlayer ( player ) ) // the sound happens way more frequently now, so give co-op players' ears a brake...
S_StartSound ( player - > mo , sfx_skid ) ;
}
2017-09-15 19:34:46 +00:00
2017-09-15 19:34:46 +00:00
if ( player - > mo - > movefactor ! = FRACUNIT ) // Friction-scaled acceleration...
acceleration = FixedMul ( acceleration < < FRACBITS , player - > mo - > movefactor ) > > FRACBITS ;
2017-09-15 19:34:46 +00:00
P_Thrust ( player - > mo , moveAngle , - acceleration ) ;
}
if ( ! ( player - > pflags & PF_AUTOBRAKE )
2017-09-15 19:34:46 +00:00
| | player - > powers [ pw_carry ]
2017-09-15 19:34:46 +00:00
| | player - > panim = = PA_SPRING
| | player - > panim = = PA_PAIN
| | ! player - > mo - > health
2017-09-15 19:34:46 +00:00
| | player - > climbing
2018-08-16 03:40:42 +00:00
| | player - > pflags & ( PF_SPINNING | PF_SLIDING )
| | player - > bumpertime )
2017-09-15 19:34:46 +00:00
player - > pflags & = ~ PF_APPLYAUTOBRAKE ;
2018-06-05 16:22:28 +00:00
else if ( currentlyonground | | player - > powers [ pw_tailsfly ] )
2017-09-15 19:34:46 +00:00
player - > pflags | = PF_APPLYAUTOBRAKE ;
}
}
2017-02-06 20:19:17 +00:00
2017-02-06 18:11:33 +00:00
player - > mo - > movefactor = FRACUNIT ; // We're not going to do any more with this, so let's change it back for the next frame.
2016-02-14 20:28:03 +00:00
// Unset statis flags after moving.
// In other words, if you manually set stasis via code,
// it lasts for one tic.
player - > pflags & = ~ PF_FULLSTASIS ;
2014-11-12 00:55:07 +00:00
# ifdef POLYOBJECTS
if ( player - > onconveyor = = 1 )
player - > cmomy = player - > cmomx = 0 ;
# endif
2014-08-04 03:49:33 +00:00
P_DoSuperStuff ( player ) ;
P_CheckSneakerAndLivesTimer ( player ) ;
P_DoBubbleBreath ( player ) ; // Spawn Sonic's bubbles
P_CheckUnderwaterAndSpaceTimer ( player ) ; // Display the countdown drown numbers!
P_CheckInvincibilityTimer ( player ) ; // Spawn Invincibility Sparkles
P_DoPlayerHeadSigns ( player ) ; // Spawn Tag/CTF signs over player's head
# if 1
// "Blur" a bit when you have speed shoes and are going fast enough
if ( ( player - > powers [ pw_super ] | | player - > powers [ pw_sneakers ] ) & & ( player - > speed + abs ( player - > mo - > momz ) ) > FixedMul ( 20 * FRACUNIT , player - > mo - > scale ) )
{
mobj_t * gmobj = P_SpawnGhostMobj ( player - > mo ) ;
gmobj - > fuse = 2 ;
2017-10-02 15:01:10 +00:00
if ( gmobj - > tracer )
gmobj - > tracer - > fuse = 2 ;
2014-08-04 03:49:33 +00:00
if ( leveltime & 1 )
{
gmobj - > frame & = ~ FF_TRANSMASK ;
gmobj - > frame | = tr_trans70 < < FF_TRANSSHIFT ;
2017-10-02 15:01:10 +00:00
if ( gmobj - > tracer )
{
gmobj - > tracer - > frame & = ~ FF_TRANSMASK ;
gmobj - > tracer - > frame | = tr_trans70 < < FF_TRANSSHIFT ;
}
2014-08-04 03:49:33 +00:00
}
// Hide the mobj from our sights if we're the displayplayer and chasecam is off,
// or secondarydisplayplayer and chasecam2 is off.
// Why not just not spawn the mobj? Well, I'd rather only flirt with
// consistency so much...
if ( ( player = = & players [ displayplayer ] & & ! camera . chase )
| | ( splitscreen & & player = = & players [ secondarydisplayplayer ] & & ! camera2 . chase ) )
gmobj - > flags2 | = MF2_DONTDRAW ;
}
# endif
2014-03-15 16:59:03 +00:00
// check for use
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] ! = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
if ( cmd - > buttons & BT_USE )
2014-08-27 03:56:30 +00:00
player - > pflags | = PF_USEDOWN ;
2014-03-15 16:59:03 +00:00
else
player - > pflags & = ~ PF_USEDOWN ;
}
// Counters, time dependent power ups.
// Time Bonus & Ring Bonus count settings
2019-08-26 23:07:17 +00:00
if ( player - > ammoremovaltimer )
{
if ( - - player - > ammoremovaltimer = = 0 )
player - > ammoremoval = 0 ;
}
2014-03-15 16:59:03 +00:00
// Strength counts up to diminish fade.
if ( player - > powers [ pw_sneakers ] & & player - > powers [ pw_sneakers ] < UINT16_MAX )
player - > powers [ pw_sneakers ] - - ;
if ( player - > powers [ pw_invulnerability ] & & player - > powers [ pw_invulnerability ] < UINT16_MAX )
player - > powers [ pw_invulnerability ] - - ;
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_flashing ] & & player - > powers [ pw_flashing ] < UINT16_MAX & & ( ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE ) | | player - > powers [ pw_flashing ] < flashingtics ) )
2014-03-15 16:59:03 +00:00
player - > powers [ pw_flashing ] - - ;
2015-05-27 06:08:18 +00:00
if ( player - > powers [ pw_tailsfly ] & & player - > powers [ pw_tailsfly ] < UINT16_MAX & & player - > charability ! = CA_SWIM ) // tails fly counter
2014-03-15 16:59:03 +00:00
player - > powers [ pw_tailsfly ] - - ;
* New object types!
* Red and yellow Boost panels!
* Added because SUBARASHII and KIMOKAWAIII had several levels using them, and I wanted to make them look better.
* https://cdn.discordapp.com/attachments/359091121789468672/634486669202161674/srb20015.gif
* Uses the mapthingnums of Glaber's SOC resource boosters, but absolutely nothing else - not even the magnitudes.
* Apply MF_AMBUSH to force the player into a spin - even if they don't have a spin ability!
* Banpyura!
* A Crushstacean with a spring instead of a crushclaw.
* https://cdn.discordapp.com/attachments/428262628893261828/634432099306176512/srb20019.gif
* Wanted this for a while, finally added it.
* Improved springs.
* Add pw_noautobrake to disable autobrake for half a second when touching yellow horizontal springs, and a second when touching red ones, even on the ground.
* Add pw_justsprung to disable directionchar for a few tics while touching any springs with a horizontal component to their velocity.
* Add the diagonal spring flag options Red and Yellow Diagonal Springs have to the Blue Diagonal Spring as well.
* Started but decided against a tip of the hat to the CD spring spin, hidden behind #define SPRINGSPIN.
* Make directionchar "lag behind" a little bit in waterslides.
* Improved flame jets.
* They now use new sprites for having their flames move upwards and sideways, instead of having them always face downwards like in 2.1!
* Fixed a mixed declaration and code error in A_RolloutRock. (Sorry Lach!)
* Make the Amy Cameo only spawn in SP, Record Attack, or Co-op unless it's the Clone Mode.
* Improved ZB config.
* Add above new types.
* Add Blue Diagonal Spring, which existed in the source but not the config.
* Re-order enemies in ZB config by zone (but keep them in the Enemies section only).
2019-10-17 20:50:26 +00:00
if ( player - > powers [ pw_pushing ] & & player - > powers [ pw_pushing ] < UINT16_MAX )
player - > powers [ pw_pushing ] - - ;
if ( player - > powers [ pw_justsprung ] & ( ( 1 < < 15 ) - 1 ) & & player - > powers [ pw_justsprung ] < UINT16_MAX )
player - > powers [ pw_justsprung ] - - ;
else
player - > powers [ pw_justsprung ] = 0 ;
2019-10-28 12:54:55 +00:00
if ( player - > powers [ pw_noautobrake ] & & player - > powers [ pw_noautobrake ] < UINT16_MAX )
player - > powers [ pw_noautobrake ] - - ;
2016-10-13 14:13:33 +00:00
if ( player - > powers [ pw_underwater ] & & ( player - > pflags & PF_GODMODE | | ( player - > powers [ pw_shield ] & SH_PROTECTWATER ) ) )
2014-03-15 16:59:03 +00:00
{
if ( player - > powers [ pw_underwater ] < = 12 * TICRATE + 1 )
2019-08-04 11:03:57 +00:00
{
player - > powers [ pw_underwater ] = 0 ;
2014-03-15 16:59:03 +00:00
P_RestoreMusic ( player ) ; //incase they were about to drown
2019-08-04 11:03:57 +00:00
}
else
player - > powers [ pw_underwater ] = 0 ;
2014-03-15 16:59:03 +00:00
}
else if ( player - > powers [ pw_underwater ] & & ! ( maptol & TOL_NIGHTS ) & & ! ( ( netgame | | multiplayer ) & & player - > spectator ) ) // underwater timer
player - > powers [ pw_underwater ] - - ;
2016-10-13 14:13:33 +00:00
if ( player - > powers [ pw_spacetime ] & & ( player - > pflags & PF_GODMODE | | ( player - > powers [ pw_shield ] & SH_PROTECTWATER ) ) )
2014-03-15 16:59:03 +00:00
player - > powers [ pw_spacetime ] = 0 ;
else if ( player - > powers [ pw_spacetime ] & & ! ( maptol & TOL_NIGHTS ) & & ! ( ( netgame | | multiplayer ) & & player - > spectator ) ) // underwater timer
player - > powers [ pw_spacetime ] - - ;
if ( player - > powers [ pw_gravityboots ] & & player - > powers [ pw_gravityboots ] < UINT16_MAX )
player - > powers [ pw_gravityboots ] - - ;
if ( player - > powers [ pw_extralife ] & & player - > powers [ pw_extralife ] < UINT16_MAX )
player - > powers [ pw_extralife ] - - ;
if ( player - > powers [ pw_nights_linkfreeze ] & & player - > powers [ pw_nights_linkfreeze ] < UINT16_MAX )
player - > powers [ pw_nights_linkfreeze ] - - ;
if ( player - > powers [ pw_nights_superloop ] & & player - > powers [ pw_nights_superloop ] < UINT16_MAX )
player - > powers [ pw_nights_superloop ] - - ;
if ( player - > powers [ pw_nights_helper ] & & player - > powers [ pw_nights_helper ] < UINT16_MAX )
player - > powers [ pw_nights_helper ] - - ;
if ( player - > powers [ pw_nocontrol ] & ( ( 1 < < 15 ) - 1 ) & & player - > powers [ pw_nocontrol ] < UINT16_MAX )
player - > powers [ pw_nocontrol ] - - ;
else
player - > powers [ pw_nocontrol ] = 0 ;
//pw_super acts as a timer now
2017-10-04 16:45:03 +00:00
if ( player - > powers [ pw_super ]
& & ( player - > mo - > state < & states [ S_PLAY_SUPER_TRANS1 ]
| | player - > mo - > state > & states [ S_PLAY_SUPER_TRANS6 ] ) )
2014-03-15 16:59:03 +00:00
player - > powers [ pw_super ] + + ;
2017-03-15 21:51:35 +00:00
if ( player - > powers [ pw_carry ] = = CR_BRAKGOOP )
2014-03-15 16:59:03 +00:00
{
2017-03-15 21:51:35 +00:00
if ( ! player - > powers [ pw_flashing ] )
{
if ( player - > mo - > state ! = & states [ S_PLAY_STND ] )
P_SetPlayerMobjState ( player - > mo , S_PLAY_STND ) ;
else
player - > mo - > tics = 2 ;
}
else
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2014-03-15 16:59:03 +00:00
2017-03-15 21:51:35 +00:00
if ( ! player - > mo - > tracer )
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
}
if ( player - > bumpertime )
player - > bumpertime - - ;
if ( player - > skidtime )
player - > skidtime - - ;
if ( player - > weapondelay )
player - > weapondelay - - ;
if ( player - > tossdelay )
player - > tossdelay - - ;
if ( player - > homing )
player - > homing - - ;
if ( player - > texttimer )
{
- - player - > texttimer ;
if ( ! player - > texttimer & & ! player - > exiting & & player - > textvar > = 4 )
{
player - > texttimer = 4 * TICRATE ;
player - > textvar = 2 ; // GET n RINGS!
if ( player - > capsule & & player - > capsule - > health ! = player - > capsule - > spawnpoint - > angle )
player - > textvar + + ; // GET n MORE RINGS!
}
}
if ( player - > losstime & & ! player - > powers [ pw_flashing ] )
player - > losstime - - ;
// Flash player after being hit.
2016-10-24 11:35:40 +00:00
if ( player - > powers [ pw_flashing ] > 0 & & player - > powers [ pw_flashing ] < flashingtics & & ( leveltime & 1 ) )
2016-08-12 01:57:37 +00:00
player - > mo - > flags2 | = MF2_DONTDRAW ;
else
player - > mo - > flags2 & = ~ MF2_DONTDRAW ;
2014-03-15 16:59:03 +00:00
player - > pflags & = ~ PF_SLIDING ;
2016-01-25 11:47:33 +00:00
# define dashmode player->dashmode
2019-10-27 12:47:58 +00:00
// Dash mode - thanks be to VelocitOni
2019-11-12 21:56:46 +00:00
if ( ( player - > charflags & SF_DASHMODE ) & & ! player - > gotflag & & ! player - > powers [ pw_carry ] & & ! player - > exiting & & ! ( maptol & TOL_NIGHTS ) & & ! metalrecording ) // woo, dashmode! no nights tho.
2016-01-01 20:53:29 +00:00
{
2017-02-08 16:46:16 +00:00
boolean totallyradical = player - > speed > = FixedMul ( player - > runspeed , player - > mo - > scale ) ;
boolean floating = ( player - > secondjump = = 1 ) ;
if ( ( totallyradical & & ! floating ) | | ( player - > pflags & PF_STARTDASH ) )
2016-01-01 20:53:29 +00:00
{
2019-10-23 04:35:17 +00:00
if ( dashmode < DASHMODE_MAX )
2016-12-24 00:11:54 +00:00
dashmode + + ; // Counter. Adds 1 to dash mode per tic in top speed.
2019-10-23 04:35:17 +00:00
if ( dashmode = = DASHMODE_THRESHOLD ) // This isn't in the ">=" equation because it'd cause the sound to play infinitely.
2019-10-30 17:37:42 +00:00
S_StartSound ( player - > mo , ( player - > charflags & SF_MACHINE ) ? sfx_kc4d : sfx_cdfm40 ) ; // If the player enters dashmode, play this sound on the the tic it starts.
2016-01-01 20:53:29 +00:00
}
2017-02-08 16:46:16 +00:00
else if ( ( ! totallyradical | | ! floating ) & & ! ( player - > pflags & PF_SPINNING ) )
2016-01-01 20:53:29 +00:00
{
2016-01-03 04:58:35 +00:00
if ( dashmode > 3 )
2019-10-27 12:47:58 +00:00
{
2016-07-07 00:40:28 +00:00
dashmode - = 3 ; // Rather than lose it all, it gently counts back down!
2019-10-27 12:47:58 +00:00
if ( ( dashmode + 3 ) > = DASHMODE_THRESHOLD & & dashmode < DASHMODE_THRESHOLD )
2019-10-30 17:37:42 +00:00
S_StartSound ( player - > mo , sfx_kc65 ) ;
2019-10-27 12:47:58 +00:00
}
2016-01-03 04:58:35 +00:00
else
2016-01-01 20:53:29 +00:00
dashmode = 0 ;
}
2016-01-25 11:47:33 +00:00
2019-10-23 04:35:17 +00:00
if ( dashmode < DASHMODE_THRESHOLD ) // Exits Dash Mode if you drop below speed/dash counter tics. Not in the above block so it doesn't keep disabling in midair.
2016-01-01 20:53:29 +00:00
{
2016-07-07 00:40:28 +00:00
player - > normalspeed = skins [ player - > skin ] . normalspeed ; // Reset to default if not capable of entering dash mode.
2016-01-03 04:58:35 +00:00
player - > jumpfactor = skins [ player - > skin ] . jumpfactor ;
2016-01-01 20:53:29 +00:00
}
2016-07-07 00:40:28 +00:00
else if ( P_IsObjectOnGround ( player - > mo ) ) // Activate dash mode if we're on the ground.
2016-01-01 20:53:29 +00:00
{
2016-12-24 00:11:54 +00:00
if ( player - > normalspeed < skins [ player - > skin ] . normalspeed * 2 ) // If the player normalspeed is not currently at normalspeed*2 in dash mode, add speed each tic
player - > normalspeed + = FRACUNIT / 5 ; // Enter Dash Mode smoothly.
2016-01-03 04:58:35 +00:00
if ( player - > jumpfactor < FixedMul ( skins [ player - > skin ] . jumpfactor , 5 * FRACUNIT / 4 ) ) // Boost jump height.
2016-12-24 00:11:54 +00:00
player - > jumpfactor + = FRACUNIT / 300 ;
2016-01-01 20:53:29 +00:00
}
2016-01-03 04:58:35 +00:00
2016-12-24 00:11:54 +00:00
if ( player - > normalspeed > = skins [ player - > skin ] . normalspeed * 2 )
2016-01-01 20:53:29 +00:00
{
2016-07-07 00:40:28 +00:00
mobj_t * ghost = P_SpawnGhostMobj ( player - > mo ) ; // Spawns afterimages
ghost - > fuse = 2 ; // Makes the images fade quickly
2016-01-01 20:53:29 +00:00
}
}
2017-02-08 16:46:16 +00:00
else if ( dashmode )
{
2019-10-23 04:35:17 +00:00
if ( dashmode > = DASHMODE_THRESHOLD ) // catch getting the flag!
2017-02-08 16:46:16 +00:00
{
player - > normalspeed = skins [ player - > skin ] . normalspeed ;
player - > jumpfactor = skins [ player - > skin ] . jumpfactor ;
2019-10-30 17:37:42 +00:00
S_StartSound ( player - > mo , sfx_kc65 ) ;
2017-02-08 16:46:16 +00:00
}
2016-01-25 11:47:33 +00:00
dashmode = 0 ;
2017-02-08 16:46:16 +00:00
}
2016-01-25 11:47:33 +00:00
# undef dashmode
2014-03-15 16:59:03 +00:00
/*
// Colormap verification
{
INT32 i , j ;
sector_t * controlsec ;
for ( j = 0 ; j < numsectors ; j + + )
{
controlsec = NULL ;
// Does this sector have a water linedef?
for ( i = 0 ; i < numlines ; i + + )
{
if ( ( lines [ i ] . special = = 121 | | lines [ i ] . special = = 123 )
& & lines [ i ] . tag = = sectors [ j ] . tag )
{
controlsec = lines [ i ] . frontsector ;
break ;
}
}
if ( i < numlines & & controlsec )
{
// Does this sector have a colormap?
for ( i = 0 ; i < numlines ; i + + )
{
if ( lines [ i ] . special = = 606 & & lines [ i ] . tag = = controlsec - > tag )
break ;
}
if ( i = = numlines )
CONS_Debug ( DBG_GAMELOGIC , " %d, %d \n " , j , sectors [ j ] . tag ) ;
}
}
I_Error ( " I'm done! \n " ) ;
} */
}
2019-09-29 16:42:17 +00:00
// Checks if the mobj is above lava. Used by Pterabyte.
static boolean P_MobjAboveLava ( mobj_t * mobj )
{
sector_t * sector = mobj - > subsector - > sector ;
if ( sector - > ffloors )
{
ffloor_t * rover ;
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_SWIMMABLE ) | | GETSECSPECIAL ( rover - > master - > frontsector - > special , 1 ) ! = 3 )
continue ;
if ( mobj - > eflags & MFE_VERTICALFLIP )
{
if ( * rover - > bottomheight < = mobj - > ceilingz & & * rover - > bottomheight > = mobj - > z )
return true ;
}
else
{
if ( * rover - > topheight > = mobj - > floorz & & * rover - > topheight < = mobj - > z )
return true ;
}
}
}
return false ;
}
2014-03-15 16:59:03 +00:00
//
// P_PlayerAfterThink
//
// Thinker for player after all other thinkers have run
//
void P_PlayerAfterThink ( player_t * player )
{
ticcmd_t * cmd ;
INT32 oldweapon = player - > currentweapon ;
2015-02-20 13:00:40 +00:00
camera_t * thiscam = NULL ; // if not one of the displayed players, just don't bother
2014-03-15 16:59:03 +00:00
# ifdef PARANOIA
if ( ! player - > mo )
{
const size_t playeri = ( size_t ) ( player - players ) ;
I_Error ( " P_PlayerAfterThink: players[%s].mo == NULL " , sizeu1 ( playeri ) ) ;
}
# endif
cmd = & player - > cmd ;
2016-10-31 20:15:11 +00:00
# ifdef SECTORSPECIALSAFTERTHINK
# ifdef POLYOBJECTS
if ( player - > onconveyor ! = 1 | | ! P_IsObjectOnGround ( player - > mo ) )
# endif
player - > onconveyor = 0 ;
// check special sectors : damage & secrets
if ( ! player - > spectator )
P_PlayerInSpecialSector ( player ) ;
# endif
2014-03-15 16:59:03 +00:00
if ( splitscreen & & player = = & players [ secondarydisplayplayer ] )
thiscam = & camera2 ;
2015-02-20 13:00:40 +00:00
else if ( player = = & players [ displayplayer ] )
2014-03-15 16:59:03 +00:00
thiscam = & camera ;
if ( player - > playerstate = = PST_DEAD )
{
// camera may still move when guy is dead
//if (!netgame)
{
2015-02-20 13:00:40 +00:00
if ( thiscam & & thiscam - > chase )
2014-03-15 16:59:03 +00:00
P_MoveChaseCamera ( player , thiscam , false ) ;
}
2017-10-02 13:08:58 +00:00
if ( player - > followmobj )
{
P_RemoveMobj ( player - > followmobj ) ;
2018-06-03 21:41:54 +00:00
P_SetTarget ( & player - > followmobj , NULL ) ;
2017-10-02 13:08:58 +00:00
}
2014-03-15 16:59:03 +00:00
return ;
}
2017-03-14 18:11:17 +00:00
if ( player - > powers [ pw_carry ] = = CR_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
player - > powers [ pw_gravityboots ] = 0 ;
2014-08-04 03:49:33 +00:00
//player->mo->eflags &= ~MFE_VERTICALFLIP;
2014-03-15 16:59:03 +00:00
}
if ( ! ( player - > pflags & PF_WPNDOWN ) )
{
if ( cmd - > buttons & BT_WEAPONNEXT )
{
player - > currentweapon + + ;
player - > currentweapon % = NUM_WEAPONS ;
player - > pflags | = PF_WPNDOWN ;
}
if ( cmd - > buttons & BT_WEAPONPREV )
{
player - > currentweapon - - ;
if ( player - > currentweapon < 0 )
player - > currentweapon = NUM_WEAPONS - 1 ;
player - > pflags | = PF_WPNDOWN ;
if ( player - > currentweapon = = WEP_RAIL & & ( ! ( player - > ringweapons & RW_RAIL ) | | ! player - > powers [ pw_railring ] ) )
player - > currentweapon - - ;
if ( player - > currentweapon = = WEP_EXPLODE & & ( ! ( player - > ringweapons & RW_EXPLODE ) | | ! player - > powers [ pw_explosionring ] ) )
player - > currentweapon - - ;
if ( player - > currentweapon = = WEP_GRENADE & & ( ! ( player - > ringweapons & RW_GRENADE ) | | ! player - > powers [ pw_grenadering ] ) )
player - > currentweapon - - ;
if ( player - > currentweapon = = WEP_SCATTER & & ( ! ( player - > ringweapons & RW_SCATTER ) | | ! player - > powers [ pw_scatterring ] ) )
player - > currentweapon - - ;
if ( player - > currentweapon = = WEP_BOUNCE & & ( ! ( player - > ringweapons & RW_BOUNCE ) | | ! player - > powers [ pw_bouncering ] ) )
player - > currentweapon - - ;
if ( player - > currentweapon = = WEP_AUTO & & ( ! ( player - > ringweapons & RW_AUTO ) | | ! player - > powers [ pw_automaticring ] ) )
player - > currentweapon = 0 ;
}
if ( cmd - > buttons & BT_WEAPONMASK )
{
//Read the bits to determine individual weapon ring selection.
INT32 weapon = ( cmd - > buttons & BT_WEAPONMASK ) ;
switch ( weapon )
{
case 1 : //normal / infinity
player - > currentweapon = 0 ;
player - > pflags | = PF_WPNDOWN ;
break ;
case 2 : //automatic
if ( ( player - > ringweapons & RW_AUTO ) & & player - > powers [ pw_automaticring ] )
{
player - > currentweapon = WEP_AUTO ;
player - > pflags | = PF_WPNDOWN ;
}
break ;
case 3 : //bounce
if ( ( player - > ringweapons & RW_BOUNCE ) & & player - > powers [ pw_bouncering ] )
{
player - > currentweapon = WEP_BOUNCE ;
player - > pflags | = PF_WPNDOWN ;
}
break ;
case 4 : //scatter
if ( ( player - > ringweapons & RW_SCATTER ) & & player - > powers [ pw_scatterring ] )
{
player - > currentweapon = WEP_SCATTER ;
player - > pflags | = PF_WPNDOWN ;
}
break ;
case 5 : //grenade
if ( ( player - > ringweapons & RW_GRENADE ) & & player - > powers [ pw_grenadering ] )
{
player - > currentweapon = WEP_GRENADE ;
player - > pflags | = PF_WPNDOWN ;
}
break ;
case 6 : //explosion
if ( ( player - > ringweapons & RW_EXPLODE ) & & player - > powers [ pw_explosionring ] )
{
player - > currentweapon = WEP_EXPLODE ;
player - > pflags | = PF_WPNDOWN ;
}
break ;
case 7 : //rail
if ( ( player - > ringweapons & RW_RAIL ) & & player - > powers [ pw_railring ] )
{
player - > currentweapon = WEP_RAIL ;
player - > pflags | = PF_WPNDOWN ;
}
break ;
}
}
}
2014-08-27 03:56:30 +00:00
if ( ! ( cmd - > buttons & ( BT_WEAPONNEXT | BT_WEAPONPREV | BT_WEAPONMASK ) ) )
2014-03-15 16:59:03 +00:00
player - > pflags & = ~ PF_WPNDOWN ;
// Weapon cycling if out of ammo for a certain weapon
if ( player - > currentweapon = = WEP_AUTO & & ( ! ( player - > ringweapons & RW_AUTO ) | | ! player - > powers [ pw_automaticring ] ) )
player - > currentweapon + + ;
if ( player - > currentweapon = = WEP_BOUNCE & & ( ! ( player - > ringweapons & RW_BOUNCE ) | | ! player - > powers [ pw_bouncering ] ) )
player - > currentweapon + + ;
if ( player - > currentweapon = = WEP_SCATTER & & ( ! ( player - > ringweapons & RW_SCATTER ) | | ! player - > powers [ pw_scatterring ] ) )
player - > currentweapon + + ;
if ( player - > currentweapon = = WEP_GRENADE & & ( ! ( player - > ringweapons & RW_GRENADE ) | | ! player - > powers [ pw_grenadering ] ) )
player - > currentweapon + + ;
if ( player - > currentweapon = = WEP_EXPLODE & & ( ! ( player - > ringweapons & RW_EXPLODE ) | | ! player - > powers [ pw_explosionring ] ) )
player - > currentweapon + + ;
if ( player - > currentweapon = = WEP_RAIL & & ( ! ( player - > ringweapons & RW_RAIL ) | | ! player - > powers [ pw_railring ] ) )
player - > currentweapon = 0 ;
if ( P_IsLocalPlayer ( player ) & & ( player - > pflags & PF_WPNDOWN ) & & player - > currentweapon ! = oldweapon )
S_StartSound ( NULL , sfx_wepchg ) ;
2018-06-05 16:22:28 +00:00
if ( ( player - > pflags & PF_SLIDING ) & & ( ( player - > pflags & ( PF_JUMPED | PF_NOJUMPDAMAGE ) ) ! = PF_JUMPED ) )
2014-03-15 16:59:03 +00:00
P_SetPlayerMobjState ( player - > mo , player - > mo - > info - > painstate ) ;
2017-03-15 21:51:35 +00:00
/* if (player->powers[pw_carry] == CR_NONE && player->mo->tracer && !player->homing)
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
else */
2018-11-12 11:30:51 +00:00
if ( player - > mo - > tracer )
2014-03-15 16:59:03 +00:00
{
2018-11-12 11:30:51 +00:00
switch ( player - > powers [ pw_carry ] )
{
case CR_PLAYER : // being carried by a flying character (such as Tails)
{
mobj_t * tails = player - > mo - > tracer ;
player - > mo - > height = FixedDiv ( P_GetPlayerHeight ( player ) , FixedDiv ( 14 * FRACUNIT , 10 * FRACUNIT ) ) ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( tails - > player & & ! ( tails - > player - > pflags & PF_CANCARRY ) )
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
if ( ( tails - > z + tails - > height + player - > mo - > height + FixedMul ( FRACUNIT , player - > mo - > scale ) ) < = tails - > ceilingz
& & ( tails - > eflags & MFE_VERTICALFLIP ) ) // Reverse gravity check for the carrier - Flame
2019-09-07 10:33:26 +00:00
player - > mo - > z = tails - > z + tails - > height + 12 * player - > mo - > scale ;
2018-11-12 11:30:51 +00:00
else
player - > powers [ pw_carry ] = CR_NONE ;
}
else
{
if ( ( tails - > z - player - > mo - > height - FixedMul ( FRACUNIT , player - > mo - > scale ) ) > = tails - > floorz
& & ! ( tails - > eflags & MFE_VERTICALFLIP ) ) // Correct gravity check for the carrier - Flame
2019-09-07 10:33:26 +00:00
player - > mo - > z = tails - > z - player - > mo - > height - 12 * player - > mo - > scale ;
2018-11-12 11:30:51 +00:00
else
player - > powers [ pw_carry ] = CR_NONE ;
}
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( tails - > health < = 0 )
player - > powers [ pw_carry ] = CR_NONE ;
else
{
2019-09-07 10:33:26 +00:00
P_TryMove ( player - > mo , tails - > x + P_ReturnThrustX ( tails , tails - > player - > drawangle , 4 * FRACUNIT ) , tails - > y + P_ReturnThrustY ( tails , tails - > player - > drawangle , 4 * FRACUNIT ) , true ) ;
2018-11-12 11:30:51 +00:00
player - > mo - > momx = tails - > momx ;
player - > mo - > momy = tails - > momy ;
player - > mo - > momz = tails - > momz ;
}
2014-03-15 16:59:03 +00:00
2019-11-18 05:30:07 +00:00
if ( gametype = = GT_COOP & & ( ! tails - > player | | tails - > player - > bot ! = 1 ) )
2018-11-12 11:30:51 +00:00
{
player - > mo - > angle = tails - > angle ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( ! demoplayback | | P_AnalogMove ( player ) )
{
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ;
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
}
}
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( P_AproxDistance ( player - > mo - > x - tails - > x , player - > mo - > y - tails - > y ) > player - > mo - > radius )
player - > powers [ pw_carry ] = CR_NONE ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( player - > powers [ pw_carry ] ! = CR_NONE )
{
if ( player - > mo - > state - states ! = S_PLAY_RIDE )
P_SetPlayerMobjState ( player - > mo , S_PLAY_RIDE ) ;
2019-09-18 13:11:06 +00:00
if ( ( tails - > skin & & ( ( skin_t * ) ( tails - > skin ) ) - > sprites [ SPR2_SWIM ] . numframes ) & & ( tails - > eflags & MFE_UNDERWATER ) )
2019-09-18 12:46:17 +00:00
tails - > player - > powers [ pw_tailsfly ] = 0 ;
2018-11-12 11:30:51 +00:00
}
else
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( player - players = = consoleplayer & & botingame )
CV_SetValue ( & cv_analog2 , ( player - > powers [ pw_carry ] ! = CR_PLAYER ) ) ;
break ;
}
case CR_GENERIC : // being carried by some generic item
{
mobj_t * item = player - > mo - > tracer ;
// tracer is what you're hanging onto
P_UnsetThingPosition ( player - > mo ) ;
player - > mo - > x = item - > x ;
player - > mo - > y = item - > y ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
player - > mo - > z = item - > z + item - > height - FixedDiv ( player - > mo - > height , 3 * FRACUNIT ) ;
else
player - > mo - > z = item - > z - FixedDiv ( player - > mo - > height , 3 * FRACUNIT / 2 ) ;
player - > mo - > momx = player - > mo - > momy = player - > mo - > momz = 0 ;
P_SetThingPosition ( player - > mo ) ;
if ( player - > mo - > state - states ! = S_PLAY_RIDE )
P_SetPlayerMobjState ( player - > mo , S_PLAY_RIDE ) ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
// Controllable missile
if ( item - > type = = MT_BLACKEGGMAN_MISSILE )
{
if ( cmd - > forwardmove > 0 )
item - > momz + = FixedMul ( FRACUNIT / 4 , item - > scale ) ;
else if ( cmd - > forwardmove < 0 )
item - > momz - = FixedMul ( FRACUNIT / 4 , item - > scale ) ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
item - > angle = player - > mo - > angle ;
P_InstaThrust ( item , item - > angle , FixedMul ( item - > info - > speed , item - > scale ) ) ;
2014-03-15 16:59:03 +00:00
2018-11-12 11:30:51 +00:00
if ( player - > mo - > z < = player - > mo - > floorz | | item - > health < = 0 )
{
player - > powers [ pw_carry ] = CR_NONE ;
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
}
}
break ;
2014-03-15 16:59:03 +00:00
}
2018-11-12 11:30:51 +00:00
case CR_MACESPIN : // being carried by a spinning chain
2016-04-05 19:56:48 +00:00
{
2018-11-12 11:30:51 +00:00
mobj_t * chain ;
mobj_t * macecenter ;
if ( ! player - > mo - > tracer - > tracer ) // can't spin around a point if... there is no point in doing so
break ;
chain = player - > mo - > tracer ;
macecenter = player - > mo - > tracer - > tracer ;
player - > mo - > height = P_GetPlayerSpinHeight ( player ) ;
// tracer is what you're hanging onto....
player - > mo - > momx = ( chain - > x - player - > mo - > x ) * 2 ;
player - > mo - > momy = ( chain - > y - player - > mo - > y ) * 2 ;
player - > mo - > momz = ( chain - > z - ( player - > mo - > height - chain - > height / 2 ) - player - > mo - > z ) * 2 ;
P_TeleportMove ( player - > mo , chain - > x , chain - > y , chain - > z - ( player - > mo - > height - chain - > height / 2 ) ) ;
if ( ! player - > powers [ pw_flashing ] ) // handle getting hurt
2017-04-03 17:28:02 +00:00
{
2018-11-12 11:30:51 +00:00
player - > pflags | = PF_JUMPED ;
player - > pflags & = ~ PF_NOJUMPDAMAGE ;
player - > secondjump = 0 ;
player - > pflags & = ~ PF_THOKKED ;
if ( ( macecenter - > flags & MF_SLIDEME ) // Noclimb on chain parameters gives this
& & ! ( twodlevel | | player - > mo - > flags2 & MF2_TWOD ) ) // why on earth would you want to turn them in 2D mode?
{
macecenter - > angle + = cmd - > sidemove < < ANGLETOFINESHIFT ;
player - > mo - > angle + = cmd - > sidemove < < ANGLETOFINESHIFT ; // 2048 --> ANGLE_MAX
if ( ! demoplayback | | P_AnalogMove ( player ) )
{
if ( player = = & players [ consoleplayer ] )
localangle = player - > mo - > angle ; // Adjust the local control angle.
else if ( player = = & players [ secondarydisplayplayer ] )
localangle2 = player - > mo - > angle ;
}
}
2017-04-03 17:28:02 +00:00
}
2018-11-12 11:30:51 +00:00
break ;
2016-04-05 19:56:48 +00:00
}
2019-09-29 12:18:40 +00:00
case CR_ROLLOUT :
{
mobj_t * mo = player - > mo , * rock = player - > mo - > tracer ;
UINT8 walktics = mo - > state - > tics - P_GetPlayerControlDirection ( player ) ;
if ( ! rock | | P_MobjWasRemoved ( rock ) )
{
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
player - > powers [ pw_carry ] = CR_NONE ;
break ;
}
if ( player - > cmd . forwardmove | | player - > cmd . sidemove )
{
rock - > movedir = ( player - > cmd . angleturn < < FRACBITS ) + R_PointToAngle2 ( 0 , 0 , player - > cmd . forwardmove < < FRACBITS , - player - > cmd . sidemove < < FRACBITS ) ;
P_Thrust ( rock , rock - > movedir , rock - > scale > > 1 ) ;
}
mo - > momx = rock - > momx ;
mo - > momy = rock - > momy ;
mo - > momz = 0 ;
2019-10-16 23:01:40 +00:00
2019-10-07 07:25:32 +00:00
if ( player - > panim = = PA_IDLE & & ( mo - > momx | | mo - > momy ) )
{
P_SetPlayerMobjState ( player - > mo , S_PLAY_WALK ) ;
}
2019-09-29 12:18:40 +00:00
if ( player - > panim = = PA_WALK & & mo - > tics > walktics )
{
mo - > tics = walktics ;
}
P_TeleportMove ( player - > mo , rock - > x , rock - > y , rock - > z + rock - > height ) ;
break ;
}
2019-09-29 16:42:17 +00:00
case CR_PTERABYTE : // being carried by a Pterabyte
{
mobj_t * ptera = player - > mo - > tracer ;
mobj_t * spawnpoint = ptera - > tracer - > tracer ;
player - > mo - > height = FixedDiv ( P_GetPlayerHeight ( player ) , FixedDiv ( 14 * FRACUNIT , 10 * FRACUNIT ) ) ;
if ( ptera - > health < = 0 )
goto dropoff ;
2019-09-29 17:51:27 +00:00
if ( P_MobjAboveLava ( ptera ) & & ptera - > movefactor < = 3 * TICRATE - 10 )
2019-09-29 16:42:17 +00:00
goto dropoff ;
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
{
if ( ( ptera - > z + ptera - > height + player - > mo - > height + FixedMul ( FRACUNIT , player - > mo - > scale ) ) < = ptera - > ceilingz
& & ( ptera - > eflags & MFE_VERTICALFLIP ) ) // Reverse gravity check for the carrier - Flame
player - > mo - > z = ptera - > z + ptera - > height + FixedMul ( FRACUNIT , player - > mo - > scale ) ;
2019-09-29 17:51:27 +00:00
if ( ptera - > ceilingz - ptera - > z > spawnpoint - > ceilingz - spawnpoint - > z + 512 * FRACUNIT & & ptera - > movefactor < = 3 * TICRATE - 10 )
2019-09-29 16:42:17 +00:00
goto dropoff ;
}
else
{
if ( ( ptera - > z - player - > mo - > height - FixedMul ( FRACUNIT , player - > mo - > scale ) ) > = ptera - > floorz
& & ! ( ptera - > eflags & MFE_VERTICALFLIP ) ) // Correct gravity check for the carrier - Flame
player - > mo - > z = ptera - > z - player - > mo - > height - FixedMul ( FRACUNIT , player - > mo - > scale ) ;
2019-09-29 17:51:27 +00:00
if ( ptera - > z - ptera - > floorz > spawnpoint - > z - spawnpoint - > floorz + 512 * FRACUNIT & & ptera - > movefactor < = 3 * TICRATE - 10 )
2019-09-29 16:42:17 +00:00
goto dropoff ;
}
ptera - > movefactor - - ;
if ( ! ptera - > movefactor )
goto dropoff ;
2019-10-07 22:00:41 +00:00
if ( ptera - > cusval > = 50 )
{
player - > powers [ pw_carry ] = CR_NONE ;
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
P_KillMobj ( ptera , player - > mo , player - > mo , 0 ) ;
player - > mo - > momz = 9 * FRACUNIT ;
player - > pflags | = PF_APPLYAUTOBRAKE | PF_JUMPED | PF_THOKKED ;
P_SetMobjState ( player - > mo , S_PLAY_ROLL ) ;
break ;
}
if ( ptera - > cusval )
ptera - > cusval - - ;
P_TryMove ( player - > mo , ptera - > x + ptera - > watertop , ptera - > y + ptera - > waterbottom , true ) ;
player - > mo - > z + = ptera - > cvmem ;
2019-09-29 16:42:17 +00:00
player - > mo - > momx = ptera - > momx ;
player - > mo - > momy = ptera - > momy ;
player - > mo - > momz = ptera - > momz ;
2019-10-07 22:00:41 +00:00
if ( P_AproxDistance ( player - > mo - > x - ptera - > x - ptera - > watertop , player - > mo - > y - ptera - > y - ptera - > waterbottom ) > player - > mo - > radius )
2019-09-29 16:42:17 +00:00
goto dropoff ;
2019-10-07 22:00:41 +00:00
ptera - > watertop > > = 1 ;
ptera - > waterbottom > > = 1 ;
ptera - > cvmem > > = 1 ;
2019-10-05 18:29:47 +00:00
if ( player - > mo - > state - states ! = S_PLAY_FALL )
P_SetPlayerMobjState ( player - > mo , S_PLAY_FALL ) ;
2019-09-29 16:42:17 +00:00
break ;
dropoff :
player - > powers [ pw_carry ] = CR_NONE ;
P_SetTarget ( & player - > mo - > tracer , NULL ) ;
ptera - > movefactor = TICRATE ;
ptera - > extravalue1 | = 4 ;
break ;
}
2018-11-12 11:30:51 +00:00
default :
break ;
2014-03-15 16:59:03 +00:00
}
}
2015-02-20 13:00:40 +00:00
if ( thiscam )
2014-03-15 16:59:03 +00:00
{
2014-08-27 03:56:30 +00:00
if ( ! thiscam - > chase ) // bob view only if looking through the player's eyes
2014-03-15 16:59:03 +00:00
{
P_CalcHeight ( player ) ;
P_CalcPostImg ( player ) ;
}
else
{
// defaults to make sure 1st person cam doesn't do anything weird on startup
player - > deltaviewheight = 0 ;
2017-10-14 20:11:08 +00:00
player - > viewheight = FixedMul ( 41 * player - > height / 48 , player - > mo - > scale ) ;
2014-03-15 16:59:03 +00:00
if ( player - > mo - > eflags & MFE_VERTICALFLIP )
player - > viewz = player - > mo - > z + player - > mo - > height - player - > viewheight ;
else
player - > viewz = player - > mo - > z + player - > viewheight ;
if ( server | | addedtogame )
P_MoveChaseCamera ( player , thiscam , false ) ; // calculate the camera movement
}
}
// spectator invisibility and nogravity.
if ( ( netgame | | multiplayer ) & & player - > spectator )
{
player - > mo - > flags2 | = MF2_DONTDRAW ;
player - > mo - > flags | = MF_NOGRAVITY ;
}
2015-06-09 10:59:34 +00:00
2017-10-02 13:08:58 +00:00
if ( player - > followmobj & & ( player - > spectator | | player - > mo - > health < = 0 | | player - > followmobj - > type ! = player - > followitem ) )
{
P_RemoveMobj ( player - > followmobj ) ;
2018-06-03 21:41:54 +00:00
P_SetTarget ( & player - > followmobj , NULL ) ;
2017-10-02 13:08:58 +00:00
}
if ( ! player - > spectator & & player - > mo - > health & & player - > followitem )
{
if ( ! player - > followmobj | | P_MobjWasRemoved ( player - > followmobj ) )
2017-10-02 15:01:10 +00:00
{
2018-06-03 21:41:54 +00:00
P_SetTarget ( & player - > followmobj , P_SpawnMobjFromMobj ( player - > mo , 0 , 0 , 0 , player - > followitem ) ) ;
2017-10-02 15:01:10 +00:00
P_SetTarget ( & player - > followmobj - > tracer , player - > mo ) ;
2019-10-23 04:35:17 +00:00
switch ( player - > followmobj - > type )
{
case MT_METALJETFUME :
player - > followmobj - > colorized = true ;
break ;
default :
player - > followmobj - > flags2 | = MF2_LINKDRAW ;
break ;
}
2017-10-02 15:01:10 +00:00
}
2017-10-02 13:08:58 +00:00
if ( player - > followmobj )
{
# ifdef HAVE_BLUA
if ( LUAh_FollowMobj ( player , player - > followmobj ) | | P_MobjWasRemoved ( player - > followmobj ) )
{ ; }
2017-10-02 15:01:10 +00:00
else
2017-10-02 13:08:58 +00:00
# endif
{
2017-10-03 17:18:18 +00:00
switch ( player - > followmobj - > type )
2017-10-02 15:01:10 +00:00
{
2017-10-03 17:18:18 +00:00
case MT_TAILSOVERLAY : // c:
2018-11-11 21:01:55 +00:00
P_DoTailsOverlay ( player , player - > followmobj ) ;
2017-10-02 15:01:10 +00:00
break ;
2019-10-23 04:35:17 +00:00
case MT_METALJETFUME :
P_DoMetalJetFume ( player , player - > followmobj ) ;
break ;
2017-10-03 17:18:18 +00:00
default :
var1 = 1 ;
var2 = 0 ;
A_CapeChase ( player - > followmobj ) ;
break ;
}
2017-10-02 15:01:10 +00:00
}
2017-10-02 13:08:58 +00:00
}
}
2014-03-15 16:59:03 +00:00
}