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.
2016-07-06 04:09:17 +00:00
// Copyright (C) 1999-2016 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_mobj.c
/// \brief Moving object handling. Spawn functions
# include "doomdef.h"
# include "g_game.h"
# include "g_input.h"
# include "st_stuff.h"
# include "hu_stuff.h"
# include "p_local.h"
# include "p_setup.h"
# include "r_main.h"
# include "r_things.h"
# include "r_sky.h"
# include "r_splats.h"
# include "s_sound.h"
# include "z_zone.h"
# include "m_random.h"
# include "m_cheat.h"
# include "m_misc.h"
# include "info.h"
# include "i_video.h"
# include "lua_hook.h"
# include "b_bot.h"
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
# include "p_slopes.h"
# endif
2014-03-15 16:59:03 +00:00
2017-10-22 21:08:07 +00:00
# include "k_kart.h"
2014-03-15 16:59:03 +00:00
// protos.
2018-06-26 15:33:54 +00:00
//static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}};
//consvar_t cv_viewheight = {"viewheight", VIEWHEIGHTS, 0, viewheight_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
2016-07-06 04:09:17 +00:00
# ifdef WALLSPLATS
2014-03-15 16:59:03 +00:00
consvar_t cv_splats = { " splats " , " On " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2016-07-06 04:09:17 +00:00
# endif
2014-03-15 16:59:03 +00:00
actioncache_t actioncachehead ;
static mobj_t * overlaycap = NULL ;
2018-03-13 05:58:57 +00:00
static mobj_t * shadowcap = NULL ;
2018-09-29 19:28:27 +00:00
mobj_t * waypointcap = NULL ;
2014-03-15 16:59:03 +00:00
void P_InitCachedActions ( void )
{
actioncachehead . prev = actioncachehead . next = & actioncachehead ;
}
void P_RunCachedActions ( void )
{
actioncache_t * ac ;
actioncache_t * next ;
for ( ac = actioncachehead . next ; ac ! = & actioncachehead ; ac = next )
{
var1 = states [ ac - > statenum ] . var1 ;
var2 = states [ ac - > statenum ] . var2 ;
# ifdef HAVE_BLUA
astate = & states [ ac - > statenum ] ;
# endif
2014-03-18 17:56:54 +00:00
if ( ac - > mobj & & ! P_MobjWasRemoved ( ac - > mobj ) ) // just in case...
2014-03-15 16:59:03 +00:00
states [ ac - > statenum ] . action . acp1 ( ac - > mobj ) ;
next = ac - > next ;
Z_Free ( ac ) ;
}
}
void P_AddCachedAction ( mobj_t * mobj , INT32 statenum )
{
actioncache_t * newaction = Z_Calloc ( sizeof ( actioncache_t ) , PU_LEVEL , NULL ) ;
newaction - > mobj = mobj ;
newaction - > statenum = statenum ;
actioncachehead . prev - > next = newaction ;
newaction - > next = & actioncachehead ;
newaction - > prev = actioncachehead . prev ;
actioncachehead . prev = newaction ;
}
2016-07-06 04:09:17 +00:00
//
// P_CycleStateAnimation
//
FUNCINLINE static ATTRINLINE void P_CycleStateAnimation ( mobj_t * mobj )
{
// var2 determines delay between animation frames
if ( ! ( mobj - > frame & FF_ANIMATE ) | | - - mobj - > anim_duration ! = 0 )
return ;
mobj - > anim_duration = ( UINT16 ) mobj - > state - > var2 ;
// compare the current sprite frame to the one we started from
// if more than var1 away from it, swap back to the original
// else just advance by one
if ( ( ( + + mobj - > frame ) & FF_FRAMEMASK ) - ( mobj - > state - > frame & FF_FRAMEMASK ) > ( UINT32 ) mobj - > state - > var1 )
mobj - > frame = ( mobj - > state - > frame & FF_FRAMEMASK ) | ( mobj - > frame & ~ FF_FRAMEMASK ) ;
}
2014-03-15 16:59:03 +00:00
//
// P_CycleMobjState
//
static void P_CycleMobjState ( mobj_t * mobj )
{
2016-07-06 04:09:17 +00:00
// state animations
P_CycleStateAnimation ( mobj ) ;
2014-03-15 16:59:03 +00:00
// cycle through states,
// calling action functions at transitions
if ( mobj - > tics ! = - 1 )
{
mobj - > tics - - ;
// you can cycle through multiple states in a tic
if ( ! mobj - > tics & & mobj - > state )
if ( ! P_SetMobjState ( mobj , mobj - > state - > nextstate ) )
return ; // freed itself
}
}
//
// P_CycleMobjState for players.
//
static void P_CyclePlayerMobjState ( mobj_t * mobj )
{
2016-07-06 04:09:17 +00:00
// state animations
P_CycleStateAnimation ( mobj ) ;
2014-03-15 16:59:03 +00:00
// cycle through states,
// calling action functions at transitions
if ( mobj - > tics ! = - 1 )
{
mobj - > tics - - ;
// you can cycle through multiple states in a tic
if ( ! mobj - > tics & & mobj - > state )
if ( ! P_SetPlayerMobjState ( mobj , mobj - > state - > nextstate ) )
return ; // freed itself
}
}
//
// P_SetPlayerMobjState
// Returns true if the mobj is still present.
//
// Separate from P_SetMobjState because of the pw_flashing check and Super states
//
boolean P_SetPlayerMobjState ( mobj_t * mobj , statenum_t state )
{
state_t * st ;
player_t * player = mobj - > player ;
// remember states seen, to detect cycles:
static statenum_t seenstate_tab [ NUMSTATES ] ; // fast transition table
statenum_t * seenstate = seenstate_tab ; // pointer to table
static INT32 recursion ; // detects recursion
statenum_t i ; // initial state
statenum_t tempstate [ NUMSTATES ] ; // for use with recursion
# ifdef PARANOIA
if ( player = = NULL )
I_Error ( " P_SetPlayerMobjState used for non-player mobj. Use P_SetMobjState instead! \n (Mobj type: %d, State: %d) " , mobj - > type , state ) ;
# endif
// Catch state changes for Super Sonic
2016-08-15 03:51:08 +00:00
/* // SRB2kart - don't need
2014-03-15 16:59:03 +00:00
if ( player - > powers [ pw_super ] & & ( player - > charflags & SF_SUPERANIMS ) )
{
switch ( state )
{
case S_PLAY_STND :
case S_PLAY_TAP1 :
case S_PLAY_TAP2 :
case S_PLAY_GASP :
P_SetPlayerMobjState ( mobj , S_PLAY_SUPERSTAND ) ;
return true ;
case S_PLAY_FALL1 :
case S_PLAY_SPRING :
case S_PLAY_RUN1 :
case S_PLAY_RUN2 :
case S_PLAY_RUN3 :
case S_PLAY_RUN4 :
P_SetPlayerMobjState ( mobj , S_PLAY_SUPERWALK1 ) ;
return true ;
case S_PLAY_FALL2 :
case S_PLAY_RUN5 :
case S_PLAY_RUN6 :
case S_PLAY_RUN7 :
case S_PLAY_RUN8 :
P_SetPlayerMobjState ( mobj , S_PLAY_SUPERWALK2 ) ;
return true ;
case S_PLAY_SPD1 :
case S_PLAY_SPD2 :
P_SetPlayerMobjState ( mobj , S_PLAY_SUPERFLY1 ) ;
return true ;
case S_PLAY_SPD3 :
case S_PLAY_SPD4 :
P_SetPlayerMobjState ( mobj , S_PLAY_SUPERFLY2 ) ;
return true ;
case S_PLAY_TEETER1 :
case S_PLAY_TEETER2 :
P_SetPlayerMobjState ( mobj , S_PLAY_SUPERTEETER ) ;
return true ;
case S_PLAY_ATK1 :
case S_PLAY_ATK2 :
case S_PLAY_ATK3 :
case S_PLAY_ATK4 :
if ( ! ( player - > charflags & SF_SUPERSPIN ) )
return true ;
break ;
default :
break ;
}
}
// You were in pain state after taking a hit, and you're moving out of pain state now?
2018-08-11 04:12:41 +00:00
else */ if ( mobj - > state = = & states [ mobj - > info - > painstate ] & & player - > powers [ pw_flashing ] = = K_GetKartFlashing ( player ) & & state ! = mobj - > info - > painstate )
2014-03-15 16:59:03 +00:00
{
// Start flashing, since you've landed.
2018-08-11 04:12:41 +00:00
player - > powers [ pw_flashing ] = K_GetKartFlashing ( player ) - 1 ;
2017-10-22 07:06:35 +00:00
//P_DoPityCheck(player);
2014-03-15 16:59:03 +00:00
}
// Set animation state
// The pflags version of this was just as convoluted.
2016-08-15 03:51:08 +00:00
// Rewriten for SRB2kart ... though I don't know what this is.
2017-11-04 17:32:47 +00:00
if ( ( state > = S_KART_STND1 & & state < = S_KART_STND2_R ) | | state = = S_KART_SQUISH | | state = = S_KART_SPIN )
2014-03-15 16:59:03 +00:00
player - > panim = PA_IDLE ;
2017-11-04 17:32:47 +00:00
else if ( state > = S_KART_WALK1 & & state < = S_KART_WALK2_R )
2014-03-15 16:59:03 +00:00
player - > panim = PA_WALK ;
2017-11-04 17:32:47 +00:00
else if ( state > = S_KART_RUN1 & & state < = S_KART_DRIFT2_R )
2014-03-15 16:59:03 +00:00
player - > panim = PA_RUN ;
2016-08-15 03:51:08 +00:00
//else if (state >= S_PLAY_ATK1 && state <= S_PLAY_ATK4)
// player->panim = PA_ROLL;
//else if (state >= S_PLAY_FALL1 && state <= S_PLAY_FALL2)
// player->panim = PA_FALL;
//else if (state >= S_PLAY_ABL1 && state <= S_PLAY_ABL2)
// player->panim = PA_ABILITY;
2014-03-15 16:59:03 +00:00
else
player - > panim = PA_ETC ;
if ( recursion + + ) // if recursion detected,
memset ( seenstate = tempstate , 0 , sizeof tempstate ) ; // clear state table
i = state ;
do
{
if ( state = = S_NULL )
{ // Bad SOC!
CONS_Alert ( CONS_ERROR , " Cannot remove player mobj by setting its state to S_NULL. \n " ) ;
//P_RemoveMobj(mobj);
return false ;
}
st = & states [ state ] ;
mobj - > state = st ;
mobj - > tics = st - > tics ;
// Adjust the player's animation speed to match their velocity.
if ( ! ( disableSpeedAdjust | | player - > charflags & SF_NOSPEEDADJUST ) )
{
2016-08-24 01:03:58 +00:00
fixed_t speed = FixedDiv ( player - > speed , FixedMul ( mobj - > scale , player - > mo - > movefactor ) ) ; // fixed_t speed = FixedDiv(player->speed, mobj->scale);
2014-03-15 16:59:03 +00:00
if ( player - > panim = = PA_ROLL )
{
if ( speed > 16 < < FRACBITS )
mobj - > tics = 1 ;
else
mobj - > tics = 2 ;
}
else if ( player - > panim = = PA_FALL )
{
speed = FixedDiv ( abs ( mobj - > momz ) , mobj - > scale ) ;
if ( speed < 10 < < FRACBITS )
mobj - > tics = 4 ;
else if ( speed < 20 < < FRACBITS )
mobj - > tics = 3 ;
else if ( speed < 30 < < FRACBITS )
mobj - > tics = 2 ;
else
mobj - > tics = 1 ;
}
else if ( P_IsObjectOnGround ( mobj ) | | player - > powers [ pw_super ] ) // Only if on the ground or superflying.
{
if ( player - > panim = = PA_WALK )
{
if ( speed > 12 < < FRACBITS )
mobj - > tics = 2 ;
else if ( speed > 6 < < FRACBITS )
mobj - > tics = 3 ;
else
mobj - > tics = 4 ;
}
else if ( player - > panim = = PA_RUN )
{
if ( speed > 52 < < FRACBITS )
mobj - > tics = 1 ;
else
mobj - > tics = 2 ;
}
}
}
mobj - > sprite = st - > sprite ;
mobj - > frame = st - > frame ;
2016-07-06 04:09:17 +00:00
mobj - > anim_duration = ( UINT16 ) st - > var2 ; // only used if FF_ANIMATE is set
2014-03-15 16:59:03 +00:00
// Modified handling.
// Call action functions when the state is set
if ( st - > action . acp1 )
{
var1 = st - > var1 ;
var2 = st - > var2 ;
# ifdef HAVE_BLUA
astate = st ;
# endif
st - > action . acp1 ( mobj ) ;
2014-03-18 17:56:54 +00:00
// woah. a player was removed by an action.
// this sounds like a VERY BAD THING, but there's nothing we can do now...
if ( P_MobjWasRemoved ( mobj ) )
return false ;
2014-03-15 16:59:03 +00:00
}
seenstate [ state ] = 1 + st - > nextstate ;
state = st - > nextstate ;
} while ( ! mobj - > tics & & ! seenstate [ state ] ) ;
if ( ! mobj - > tics )
CONS_Alert ( CONS_WARNING , M_GetText ( " State cycle detected, exiting. \n " ) ) ;
if ( ! - - recursion )
for ( ; ( state = seenstate [ i ] ) > S_NULL ; i = state - 1 )
seenstate [ i ] = S_NULL ; // erase memory of states
return true ;
}
boolean P_SetMobjState ( mobj_t * mobj , statenum_t state )
{
state_t * st ;
// remember states seen, to detect cycles:
static statenum_t seenstate_tab [ NUMSTATES ] ; // fast transition table
statenum_t * seenstate = seenstate_tab ; // pointer to table
static INT32 recursion ; // detects recursion
statenum_t i = state ; // initial state
statenum_t tempstate [ NUMSTATES ] ; // for use with recursion
# ifdef PARANOIA
if ( mobj - > player ! = NULL )
I_Error ( " P_SetMobjState used for player mobj. Use P_SetPlayerMobjState instead! \n (State called: %d) " , state ) ;
# endif
if ( recursion + + ) // if recursion detected,
memset ( seenstate = tempstate , 0 , sizeof tempstate ) ; // clear state table
do
{
if ( state = = S_NULL )
{
P_RemoveMobj ( mobj ) ;
return false ;
}
st = & states [ state ] ;
mobj - > state = st ;
mobj - > tics = st - > tics ;
mobj - > sprite = st - > sprite ;
mobj - > frame = st - > frame ;
2016-07-06 04:09:17 +00:00
mobj - > anim_duration = ( UINT16 ) st - > var2 ; // only used if FF_ANIMATE is set
2014-03-15 16:59:03 +00:00
// Modified handling.
// Call action functions when the state is set
if ( st - > action . acp1 )
{
var1 = st - > var1 ;
var2 = st - > var2 ;
# ifdef HAVE_BLUA
astate = st ;
# endif
st - > action . acp1 ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) )
return false ;
}
seenstate [ state ] = 1 + st - > nextstate ;
state = st - > nextstate ;
} while ( ! mobj - > tics & & ! seenstate [ state ] ) ;
if ( ! mobj - > tics )
CONS_Alert ( CONS_WARNING , M_GetText ( " State cycle detected, exiting. \n " ) ) ;
if ( ! - - recursion )
for ( ; ( state = seenstate [ i ] ) > S_NULL ; i = state - 1 )
seenstate [ i ] = S_NULL ; // erase memory of states
return true ;
}
//----------------------------------------------------------------------------
//
// FUNC P_SetMobjStateNF
//
// Same as P_SetMobjState, but does not call the state function.
//
//----------------------------------------------------------------------------
boolean P_SetMobjStateNF ( mobj_t * mobj , statenum_t state )
{
state_t * st ;
if ( state = = S_NULL )
{ // Remove mobj
P_RemoveMobj ( mobj ) ;
return false ;
}
st = & states [ state ] ;
mobj - > state = st ;
mobj - > tics = st - > tics ;
mobj - > sprite = st - > sprite ;
mobj - > frame = st - > frame ;
2016-07-06 04:09:17 +00:00
mobj - > anim_duration = ( UINT16 ) st - > var2 ; // only used if FF_ANIMATE is set
2014-03-15 16:59:03 +00:00
return true ;
}
static boolean P_SetPrecipMobjState ( precipmobj_t * mobj , statenum_t state )
{
state_t * st ;
if ( state = = S_NULL )
{ // Remove mobj
P_RemovePrecipMobj ( mobj ) ;
return false ;
}
st = & states [ state ] ;
mobj - > state = st ;
mobj - > tics = st - > tics ;
mobj - > sprite = st - > sprite ;
mobj - > frame = st - > frame ;
2016-07-06 04:09:17 +00:00
mobj - > anim_duration = ( UINT16 ) st - > var2 ; // only used if FF_ANIMATE is set
2014-03-15 16:59:03 +00:00
return true ;
}
//
// P_MobjFlip
//
// Special utility to return +1 or -1 depending on mobj's gravity
//
SINT8 P_MobjFlip ( mobj_t * mobj )
{
if ( mobj & & mobj - > eflags & MFE_VERTICALFLIP )
return - 1 ;
return 1 ;
}
//
// P_WeaponOrPanel
//
// Returns true if weapon ring/panel; otherwise returns false
//
boolean P_WeaponOrPanel ( mobjtype_t type )
{
if ( type = = MT_BOUNCERING
| | type = = MT_AUTOMATICRING
| | type = = MT_INFINITYRING
| | type = = MT_RAILRING
| | type = = MT_EXPLOSIONRING
| | type = = MT_SCATTERRING
| | type = = MT_GRENADERING
| | type = = MT_BOUNCEPICKUP
| | type = = MT_RAILPICKUP
| | type = = MT_AUTOPICKUP
| | type = = MT_EXPLODEPICKUP
| | type = = MT_SCATTERPICKUP
| | type = = MT_GRENADEPICKUP )
return true ;
return false ;
}
//
// P_EmeraldManager
//
// Power Stone emerald management
//
Nuke a bunch of iteration things that have no purpose in SRB2Kart. A full explanation of my reasoning and what it affects is as follows.
p_inter.c -
Everything to do with setting states for starposts
In SRB2Kart, starposts are invisble. We don't need to loop through all thinkers just to set their states when there's no visible effect of the state-setting. In addition, it has no consequences for gameplay - starposts have long been silent here, and all checking is done regarding their health, not their state.
Remove extremely low-traffic conditionals (MT_FLINGEMERALD collision height extension, for example)
These objects serve no functional purpose during regular SRB2Kart gameplay. Why should every other object have to pay an admittedly minor performance hit just for them?
Disable all mechanisms of damaging bosses or enemies with the player's physical contact
With the exception of Sapphire Coast, no MF_ENEMY objects exist in the entirety of the standard roster. In addition, the conditions for damaging the enemies were impossible to achieve, because they required vanilla SRB2 mechanics such as "jumping", "spindashing", or "super". Therefore, they can be safely commented out.
Disable NiGHTS-related material (excepting bumper, hoop, and wing-emblem objects)
NiGHTS is fundamentally incompatible with regular kart gameplay and I believe was already broken. Therefore, any mechanism which enters, aids, or abets it can be safely disabled.
Comment out Tag mechanisms
Tag is the only vanilla multiplayer gametype which has sufficient gameplay depth and complexity (HEYOOOOOOOOO) to require dedicated thinking in and of itself in order to manage. This thinking is irrelevant to Kart's functioning, and can be neutered easily.
d_clisrv.c
Comment out Tag mechanisms
See p_inter.c
d_netcmd.c
Disable several devmode commands which are irrelevant to SRB2Kart gameplay
When investigating for references to NiGHTS material, I discovered that these remained untouched. In order to present a more coherent game, I have hidden the ones that serve no purpose for us.
Comment out Tag mechanisms
See p_inter.c
g_game.c
Disable NiGHTS-related material
See p_inter.c
Disable some team-related material
Teams are not present in SRB2Kart at present. Obviously we'd want to reconsider for future, but it doesn't need to be run right now.
Everything to do with setting states for starposts
See p_inter.c
m_cheat.c
Disable several devmode commands which are irrelevant to SRB2Kart gameplay
See d_netcmd.c
p_map.c
Remove extremely low-traffic conditionals (MT_EGGSHIELD collision, for example)
See p_inter.c
Disable NiGHTS-related material
See p_inter.c
p_mobj.c
Disable P_EmeraldManager
Power stones, despite their relevance in vanilla Match, are not in SRB2Kart's Battle. No management of nonexistent emeralds is required.
p_setup.c
Everything to do with setting states for starposts
See p_inter.c
p_spec.c
Disable NiGHTS-related material
See p_inter.c
Everything to do with setting states for starposts
See p_inter.c
p_telept.c
Everything to do with setting states for starposts
See p_inter.c
p_tick.c
Disable some team-related material
See g_game.c
Disable P_EmeraldManager
See p_mobj.c
Do not run shields
Shield objects are not run under the vanilla system; the Thunder Shield is a domain-specific recreation using a standard mobjthinker.
Do not run special stages
SRB2Kart does not have special stages.
Comment out Tag mechanisms
See p_inter.c
y_inter.c
Disable some team-related material
See g_game.c
p_user.c
Disable NiGHTS-related material
See p_inter.c
Disable 2d movement for players
2D mode? In a kart racer? :nick:
2018-10-03 16:04:41 +00:00
/*void P_EmeraldManager(void)
2014-03-15 16:59:03 +00:00
{
thinker_t * think ;
mobj_t * mo ;
INT32 i , j ;
INT32 numtospawn ;
INT32 emeraldsspawned = 0 ;
boolean hasemerald [ MAXHUNTEMERALDS ] ;
INT32 numwithemerald = 0 ;
// record empty spawn points
mobj_t * spawnpoints [ MAXHUNTEMERALDS ] ;
INT32 numspawnpoints = 0 ;
for ( i = 0 ; i < MAXHUNTEMERALDS ; i + + )
{
hasemerald [ i ] = false ;
spawnpoints [ i ] = NULL ;
}
for ( think = thinkercap . next ; think ! = & thinkercap ; think = think - > next )
{
if ( think - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ; // not a mobj thinker
mo = ( mobj_t * ) think ;
if ( mo - > type = = MT_EMERALDSPAWN )
{
if ( mo - > threshold | | mo - > target ) // Either has the emerald spawned or is spawning
{
numwithemerald + + ;
emeraldsspawned | = mobjinfo [ mo - > reactiontime ] . speed ;
}
else if ( numspawnpoints < MAXHUNTEMERALDS )
spawnpoints [ numspawnpoints + + ] = mo ; // empty spawn points
}
else if ( mo - > type = = MT_FLINGEMERALD )
{
numwithemerald + + ;
emeraldsspawned | = mo - > threshold ;
}
}
if ( numspawnpoints = = 0 )
return ;
// But wait! We need to check all the players too, to see if anyone has some of the emeralds.
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo )
continue ;
if ( players [ i ] . powers [ pw_emeralds ] & EMERALD1 )
{
numwithemerald + + ;
emeraldsspawned | = EMERALD1 ;
}
if ( players [ i ] . powers [ pw_emeralds ] & EMERALD2 )
{
numwithemerald + + ;
emeraldsspawned | = EMERALD2 ;
}
if ( players [ i ] . powers [ pw_emeralds ] & EMERALD3 )
{
numwithemerald + + ;
emeraldsspawned | = EMERALD3 ;
}
if ( players [ i ] . powers [ pw_emeralds ] & EMERALD4 )
{
numwithemerald + + ;
emeraldsspawned | = EMERALD4 ;
}
if ( players [ i ] . powers [ pw_emeralds ] & EMERALD5 )
{
numwithemerald + + ;
emeraldsspawned | = EMERALD5 ;
}
if ( players [ i ] . powers [ pw_emeralds ] & EMERALD6 )
{
numwithemerald + + ;
emeraldsspawned | = EMERALD6 ;
}
if ( players [ i ] . powers [ pw_emeralds ] & EMERALD7 )
{
numwithemerald + + ;
emeraldsspawned | = EMERALD7 ;
}
}
// All emeralds spawned, no worries
if ( numwithemerald > = 7 )
return ;
// Set up spawning for the emeralds
numtospawn = 7 - numwithemerald ;
# ifdef PARANOIA
if ( numtospawn < = 0 ) // ???
I_Error ( " P_EmeraldManager: numtospawn is %d! \n " , numtospawn ) ;
# endif
for ( i = 0 , j = 0 ; i < numtospawn ; i + + )
{
INT32 tries = 0 ;
while ( true )
{
tries + + ;
if ( tries > 50 )
break ;
j = P_RandomKey ( numspawnpoints ) ;
if ( hasemerald [ j ] )
continue ;
hasemerald [ j ] = true ;
if ( ! ( emeraldsspawned & EMERALD1 ) )
{
spawnpoints [ j ] - > reactiontime = MT_EMERALD1 ;
emeraldsspawned | = EMERALD1 ;
}
else if ( ! ( emeraldsspawned & EMERALD2 ) )
{
spawnpoints [ j ] - > reactiontime = MT_EMERALD2 ;
emeraldsspawned | = EMERALD2 ;
}
else if ( ! ( emeraldsspawned & EMERALD3 ) )
{
spawnpoints [ j ] - > reactiontime = MT_EMERALD3 ;
emeraldsspawned | = EMERALD3 ;
}
else if ( ! ( emeraldsspawned & EMERALD4 ) )
{
spawnpoints [ j ] - > reactiontime = MT_EMERALD4 ;
emeraldsspawned | = EMERALD4 ;
}
else if ( ! ( emeraldsspawned & EMERALD5 ) )
{
spawnpoints [ j ] - > reactiontime = MT_EMERALD5 ;
emeraldsspawned | = EMERALD5 ;
}
else if ( ! ( emeraldsspawned & EMERALD6 ) )
{
spawnpoints [ j ] - > reactiontime = MT_EMERALD6 ;
emeraldsspawned | = EMERALD6 ;
}
else if ( ! ( emeraldsspawned & EMERALD7 ) )
{
spawnpoints [ j ] - > reactiontime = MT_EMERALD7 ;
emeraldsspawned | = EMERALD7 ;
}
else
break ;
if ( leveltime < TICRATE ) // Start of map
2016-07-06 04:09:17 +00:00
spawnpoints [ j ] - > threshold = 60 * TICRATE + P_RandomByte ( ) * ( TICRATE / 5 ) ;
2014-03-15 16:59:03 +00:00
else
2016-07-06 04:09:17 +00:00
spawnpoints [ j ] - > threshold = P_RandomByte ( ) * ( TICRATE / 5 ) ;
2014-03-15 16:59:03 +00:00
break ;
}
}
Nuke a bunch of iteration things that have no purpose in SRB2Kart. A full explanation of my reasoning and what it affects is as follows.
p_inter.c -
Everything to do with setting states for starposts
In SRB2Kart, starposts are invisble. We don't need to loop through all thinkers just to set their states when there's no visible effect of the state-setting. In addition, it has no consequences for gameplay - starposts have long been silent here, and all checking is done regarding their health, not their state.
Remove extremely low-traffic conditionals (MT_FLINGEMERALD collision height extension, for example)
These objects serve no functional purpose during regular SRB2Kart gameplay. Why should every other object have to pay an admittedly minor performance hit just for them?
Disable all mechanisms of damaging bosses or enemies with the player's physical contact
With the exception of Sapphire Coast, no MF_ENEMY objects exist in the entirety of the standard roster. In addition, the conditions for damaging the enemies were impossible to achieve, because they required vanilla SRB2 mechanics such as "jumping", "spindashing", or "super". Therefore, they can be safely commented out.
Disable NiGHTS-related material (excepting bumper, hoop, and wing-emblem objects)
NiGHTS is fundamentally incompatible with regular kart gameplay and I believe was already broken. Therefore, any mechanism which enters, aids, or abets it can be safely disabled.
Comment out Tag mechanisms
Tag is the only vanilla multiplayer gametype which has sufficient gameplay depth and complexity (HEYOOOOOOOOO) to require dedicated thinking in and of itself in order to manage. This thinking is irrelevant to Kart's functioning, and can be neutered easily.
d_clisrv.c
Comment out Tag mechanisms
See p_inter.c
d_netcmd.c
Disable several devmode commands which are irrelevant to SRB2Kart gameplay
When investigating for references to NiGHTS material, I discovered that these remained untouched. In order to present a more coherent game, I have hidden the ones that serve no purpose for us.
Comment out Tag mechanisms
See p_inter.c
g_game.c
Disable NiGHTS-related material
See p_inter.c
Disable some team-related material
Teams are not present in SRB2Kart at present. Obviously we'd want to reconsider for future, but it doesn't need to be run right now.
Everything to do with setting states for starposts
See p_inter.c
m_cheat.c
Disable several devmode commands which are irrelevant to SRB2Kart gameplay
See d_netcmd.c
p_map.c
Remove extremely low-traffic conditionals (MT_EGGSHIELD collision, for example)
See p_inter.c
Disable NiGHTS-related material
See p_inter.c
p_mobj.c
Disable P_EmeraldManager
Power stones, despite their relevance in vanilla Match, are not in SRB2Kart's Battle. No management of nonexistent emeralds is required.
p_setup.c
Everything to do with setting states for starposts
See p_inter.c
p_spec.c
Disable NiGHTS-related material
See p_inter.c
Everything to do with setting states for starposts
See p_inter.c
p_telept.c
Everything to do with setting states for starposts
See p_inter.c
p_tick.c
Disable some team-related material
See g_game.c
Disable P_EmeraldManager
See p_mobj.c
Do not run shields
Shield objects are not run under the vanilla system; the Thunder Shield is a domain-specific recreation using a standard mobjthinker.
Do not run special stages
SRB2Kart does not have special stages.
Comment out Tag mechanisms
See p_inter.c
y_inter.c
Disable some team-related material
See g_game.c
p_user.c
Disable NiGHTS-related material
See p_inter.c
Disable 2d movement for players
2D mode? In a kart racer? :nick:
2018-10-03 16:04:41 +00:00
} */
2014-03-15 16:59:03 +00:00
//
// P_ExplodeMissile
//
void P_ExplodeMissile ( mobj_t * mo )
{
mobj_t * explodemo ;
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
mo - > momx = mo - > momy = mo - > momz = 0 ;
if ( mo - > flags & MF_NOCLIPTHING )
return ;
if ( mo - > type = = MT_DETON )
{
P_RadiusAttack ( mo , mo , 96 * FRACUNIT ) ;
explodemo = P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_EXPLODE ) ;
P_SetScale ( explodemo , mo - > scale ) ;
explodemo - > destscale = mo - > destscale ;
2016-07-06 04:09:17 +00:00
explodemo - > momx + = ( P_RandomByte ( ) % 32 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
explodemo - > momy + = ( P_RandomByte ( ) % 32 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
2014-03-15 16:59:03 +00:00
S_StartSound ( explodemo , sfx_pop ) ;
explodemo = P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_EXPLODE ) ;
P_SetScale ( explodemo , mo - > scale ) ;
explodemo - > destscale = mo - > destscale ;
2016-07-06 04:09:17 +00:00
explodemo - > momx + = ( P_RandomByte ( ) % 64 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
explodemo - > momy - = ( P_RandomByte ( ) % 64 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
2014-03-15 16:59:03 +00:00
S_StartSound ( explodemo , sfx_dmpain ) ;
explodemo = P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_EXPLODE ) ;
P_SetScale ( explodemo , mo - > scale ) ;
explodemo - > destscale = mo - > destscale ;
2016-07-06 04:09:17 +00:00
explodemo - > momx - = ( P_RandomByte ( ) % 128 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
explodemo - > momy + = ( P_RandomByte ( ) % 128 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
2014-03-15 16:59:03 +00:00
S_StartSound ( explodemo , sfx_pop ) ;
explodemo = P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_EXPLODE ) ;
P_SetScale ( explodemo , mo - > scale ) ;
explodemo - > destscale = mo - > destscale ;
2016-07-06 04:09:17 +00:00
explodemo - > momx - = ( P_RandomByte ( ) % 96 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
explodemo - > momy - = ( P_RandomByte ( ) % 96 ) * FixedMul ( FRACUNIT / 8 , explodemo - > scale ) ;
2014-03-15 16:59:03 +00:00
S_StartSound ( explodemo , sfx_cybdth ) ;
2014-08-27 03:56:30 +00:00
// Hack: Release an animal.
P_DamageMobj ( mo , NULL , NULL , 10000 ) ;
2014-03-15 16:59:03 +00:00
}
mo - > flags & = ~ MF_MISSILE ;
mo - > flags | = MF_NOGRAVITY ; // Dead missiles don't need to sink anymore.
mo - > flags | = MF_NOCLIPTHING ; // Dummy flag to indicate that this was already called.
if ( mo - > info - > deathsound & & ! ( mo - > flags2 & MF2_DEBRIS ) )
S_StartSound ( mo , mo - > info - > deathsound ) ;
P_SetMobjState ( mo , mo - > info - > deathstate ) ;
}
// P_InsideANonSolidFFloor
//
// Returns TRUE if mobj is inside a non-solid 3d floor.
boolean P_InsideANonSolidFFloor ( mobj_t * mobj , ffloor_t * rover )
{
2016-07-06 04:09:17 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) )
return false ;
if ( ( ( ( rover - > flags & FF_BLOCKPLAYER ) & & mobj - > player )
| | ( ( rover - > flags & FF_BLOCKOTHERS ) & & ! mobj - > player ) ) )
return false ;
2016-07-06 04:09:17 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# ifdef ESLOPE
if ( * rover - > t_slope )
topheight = P_GetZAt ( * rover - > t_slope , mobj - > x , mobj - > y ) ;
if ( * rover - > b_slope )
bottomheight = P_GetZAt ( * rover - > b_slope , mobj - > x , mobj - > y ) ;
# endif
if ( mobj - > z > topheight )
2014-03-15 16:59:03 +00:00
return false ;
2016-07-06 04:09:17 +00:00
if ( mobj - > z + mobj - > height < bottomheight )
2014-03-15 16:59:03 +00:00
return false ;
return true ;
}
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
// P_GetFloorZ (and its ceiling counterpart)
// Gets the floor height (or ceiling height) of the mobj's contact point in sector, assuming object's center if moved to [x, y]
// If line is supplied, it's a divider line on the sector. Set it to NULL if you're not checking for collision with a line
// Supply boundsec ONLY when checking for specials! It should be the "in-level" sector, and sector the control sector (if separate).
// If set, then this function will iterate through boundsec's linedefs to find the highest contact point on the slope. Non-special-checking
// usage will handle that later.
static fixed_t HighestOnLine ( fixed_t radius , fixed_t x , fixed_t y , line_t * line , pslope_t * slope , boolean actuallylowest )
{
// Alright, so we're sitting on a line that contains our slope sector, and need to figure out the highest point we're touching...
// The solution is simple! Get the line's vertices, and pull each one in along its line until it touches the object's bounding box
// (assuming it isn't already inside), then test each point's slope Z and return the higher of the two.
vertex_t v1 , v2 ;
v1 . x = line - > v1 - > x ;
v1 . y = line - > v1 - > y ;
v2 . x = line - > v2 - > x ;
v2 . y = line - > v2 - > y ;
/*CONS_Printf("BEFORE: v1 = %f %f %f\n",
FIXED_TO_FLOAT ( v1 . x ) ,
FIXED_TO_FLOAT ( v1 . y ) ,
FIXED_TO_FLOAT ( P_GetZAt ( slope , v1 . x , v1 . y ) )
) ;
CONS_Printf ( " v2 = %f %f %f \n " ,
FIXED_TO_FLOAT ( v2 . x ) ,
FIXED_TO_FLOAT ( v2 . y ) ,
FIXED_TO_FLOAT ( P_GetZAt ( slope , v2 . x , v2 . y ) )
) ; */
if ( abs ( v1 . x - x ) > radius ) {
// v1's x is out of range, so rein it in
fixed_t diff = abs ( v1 . x - x ) - radius ;
if ( v1 . x < x ) { // Moving right
v1 . x + = diff ;
v1 . y + = FixedMul ( diff , FixedDiv ( line - > dy , line - > dx ) ) ;
} else { // Moving left
v1 . x - = diff ;
v1 . y - = FixedMul ( diff , FixedDiv ( line - > dy , line - > dx ) ) ;
}
}
if ( abs ( v1 . y - y ) > radius ) {
// v1's y is out of range, so rein it in
fixed_t diff = abs ( v1 . y - y ) - radius ;
if ( v1 . y < y ) { // Moving up
v1 . y + = diff ;
v1 . x + = FixedMul ( diff , FixedDiv ( line - > dx , line - > dy ) ) ;
} else { // Moving down
v1 . y - = diff ;
v1 . x - = FixedMul ( diff , FixedDiv ( line - > dx , line - > dy ) ) ;
}
}
if ( abs ( v2 . x - x ) > radius ) {
// v1's x is out of range, so rein it in
fixed_t diff = abs ( v2 . x - x ) - radius ;
if ( v2 . x < x ) { // Moving right
v2 . x + = diff ;
v2 . y + = FixedMul ( diff , FixedDiv ( line - > dy , line - > dx ) ) ;
} else { // Moving left
v2 . x - = diff ;
v2 . y - = FixedMul ( diff , FixedDiv ( line - > dy , line - > dx ) ) ;
}
}
if ( abs ( v2 . y - y ) > radius ) {
// v2's y is out of range, so rein it in
fixed_t diff = abs ( v2 . y - y ) - radius ;
if ( v2 . y < y ) { // Moving up
v2 . y + = diff ;
v2 . x + = FixedMul ( diff , FixedDiv ( line - > dx , line - > dy ) ) ;
} else { // Moving down
v2 . y - = diff ;
v2 . x - = FixedMul ( diff , FixedDiv ( line - > dx , line - > dy ) ) ;
}
}
/*CONS_Printf("AFTER: v1 = %f %f %f\n",
FIXED_TO_FLOAT ( v1 . x ) ,
FIXED_TO_FLOAT ( v1 . y ) ,
FIXED_TO_FLOAT ( P_GetZAt ( slope , v1 . x , v1 . y ) )
) ;
CONS_Printf ( " v2 = %f %f %f \n " ,
FIXED_TO_FLOAT ( v2 . x ) ,
FIXED_TO_FLOAT ( v2 . y ) ,
FIXED_TO_FLOAT ( P_GetZAt ( slope , v2 . x , v2 . y ) )
) ; */
// Return the higher of the two points
if ( actuallylowest )
return min (
P_GetZAt ( slope , v1 . x , v1 . y ) ,
P_GetZAt ( slope , v2 . x , v2 . y )
) ;
else
return max (
P_GetZAt ( slope , v1 . x , v1 . y ) ,
P_GetZAt ( slope , v2 . x , v2 . y )
) ;
}
# endif
fixed_t P_MobjFloorZ ( mobj_t * mobj , sector_t * sector , sector_t * boundsec , fixed_t x , fixed_t y , line_t * line , boolean lowest , boolean perfect )
{
# ifdef ESLOPE
I_Assert ( mobj ! = NULL ) ;
# endif
I_Assert ( sector ! = NULL ) ;
# ifdef ESLOPE
if ( sector - > f_slope ) {
fixed_t testx , testy ;
pslope_t * slope = sector - > f_slope ;
// Get the corner of the object that should be the highest on the slope
if ( slope - > d . x < 0 )
testx = mobj - > radius ;
else
testx = - mobj - > radius ;
if ( slope - > d . y < 0 )
testy = mobj - > radius ;
else
testy = - mobj - > radius ;
if ( ( slope - > zdelta > 0 ) ^ ! ! ( lowest ) ) {
testx = - testx ;
testy = - testy ;
}
testx + = x ;
testy + = y ;
// If the highest point is in the sector, then we have it easy! Just get the Z at that point
2016-05-22 03:53:04 +00:00
if ( R_PointInSubsector ( testx , testy ) - > sector = = ( boundsec ? boundsec : sector ) )
2016-07-06 04:09:17 +00:00
return P_GetZAt ( slope , testx , testy ) ;
// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
if ( perfect ) {
size_t i ;
line_t * ld ;
fixed_t bbox [ 4 ] ;
fixed_t finalheight ;
if ( lowest )
finalheight = INT32_MAX ;
else
finalheight = INT32_MIN ;
bbox [ BOXLEFT ] = x - mobj - > radius ;
bbox [ BOXRIGHT ] = x + mobj - > radius ;
bbox [ BOXTOP ] = y + mobj - > radius ;
bbox [ BOXBOTTOM ] = y - mobj - > radius ;
for ( i = 0 ; i < boundsec - > linecount ; i + + ) {
ld = boundsec - > lines [ i ] ;
if ( bbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | | bbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ]
| | bbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | | bbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
continue ;
if ( P_BoxOnLineSide ( bbox , ld ) ! = - 1 )
continue ;
if ( lowest )
finalheight = min ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , true ) ) ;
else
finalheight = max ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , false ) ) ;
}
return finalheight ;
}
// If we're just testing for base sector location (no collision line), just go for the center's spot...
// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
if ( line = = NULL )
return P_GetZAt ( slope , x , y ) ;
return HighestOnLine ( mobj - > radius , x , y , line , slope , lowest ) ;
} else // Well, that makes it easy. Just get the floor height
# else
( void ) mobj ;
( void ) boundsec ;
( void ) x ;
( void ) y ;
( void ) line ;
( void ) lowest ;
( void ) perfect ;
# endif
return sector - > floorheight ;
}
fixed_t P_MobjCeilingZ ( mobj_t * mobj , sector_t * sector , sector_t * boundsec , fixed_t x , fixed_t y , line_t * line , boolean lowest , boolean perfect )
{
# ifdef ESLOPE
I_Assert ( mobj ! = NULL ) ;
# endif
I_Assert ( sector ! = NULL ) ;
# ifdef ESLOPE
if ( sector - > c_slope ) {
fixed_t testx , testy ;
pslope_t * slope = sector - > c_slope ;
// Get the corner of the object that should be the highest on the slope
if ( slope - > d . x < 0 )
testx = mobj - > radius ;
else
testx = - mobj - > radius ;
if ( slope - > d . y < 0 )
testy = mobj - > radius ;
else
testy = - mobj - > radius ;
if ( ( slope - > zdelta > 0 ) ^ ! ! ( lowest ) ) {
testx = - testx ;
testy = - testy ;
}
testx + = x ;
testy + = y ;
// If the highest point is in the sector, then we have it easy! Just get the Z at that point
2016-05-22 03:53:04 +00:00
if ( R_PointInSubsector ( testx , testy ) - > sector = = ( boundsec ? boundsec : sector ) )
2016-07-06 04:09:17 +00:00
return P_GetZAt ( slope , testx , testy ) ;
// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
if ( perfect ) {
size_t i ;
line_t * ld ;
fixed_t bbox [ 4 ] ;
fixed_t finalheight ;
if ( lowest )
finalheight = INT32_MAX ;
else
finalheight = INT32_MIN ;
bbox [ BOXLEFT ] = x - mobj - > radius ;
bbox [ BOXRIGHT ] = x + mobj - > radius ;
bbox [ BOXTOP ] = y + mobj - > radius ;
bbox [ BOXBOTTOM ] = y - mobj - > radius ;
for ( i = 0 ; i < boundsec - > linecount ; i + + ) {
ld = boundsec - > lines [ i ] ;
if ( bbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | | bbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ]
| | bbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | | bbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
continue ;
if ( P_BoxOnLineSide ( bbox , ld ) ! = - 1 )
continue ;
if ( lowest )
finalheight = min ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , true ) ) ;
else
finalheight = max ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , false ) ) ;
}
return finalheight ;
}
// If we're just testing for base sector location (no collision line), just go for the center's spot...
// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
if ( line = = NULL )
return P_GetZAt ( slope , x , y ) ;
return HighestOnLine ( mobj - > radius , x , y , line , slope , lowest ) ;
} else // Well, that makes it easy. Just get the ceiling height
# else
( void ) mobj ;
( void ) boundsec ;
( void ) x ;
( void ) y ;
( void ) line ;
( void ) lowest ;
( void ) perfect ;
# endif
return sector - > ceilingheight ;
}
// Now do the same as all above, but for cameras because apparently cameras are special?
fixed_t P_CameraFloorZ ( camera_t * mobj , sector_t * sector , sector_t * boundsec , fixed_t x , fixed_t y , line_t * line , boolean lowest , boolean perfect )
{
# ifdef ESLOPE
I_Assert ( mobj ! = NULL ) ;
# endif
I_Assert ( sector ! = NULL ) ;
# ifdef ESLOPE
if ( sector - > f_slope ) {
fixed_t testx , testy ;
pslope_t * slope = sector - > f_slope ;
// Get the corner of the object that should be the highest on the slope
if ( slope - > d . x < 0 )
testx = mobj - > radius ;
else
testx = - mobj - > radius ;
if ( slope - > d . y < 0 )
testy = mobj - > radius ;
else
testy = - mobj - > radius ;
if ( ( slope - > zdelta > 0 ) ^ ! ! ( lowest ) ) {
testx = - testx ;
testy = - testy ;
}
testx + = x ;
testy + = y ;
// If the highest point is in the sector, then we have it easy! Just get the Z at that point
2016-05-22 03:53:04 +00:00
if ( R_PointInSubsector ( testx , testy ) - > sector = = ( boundsec ? boundsec : sector ) )
2016-07-06 04:09:17 +00:00
return P_GetZAt ( slope , testx , testy ) ;
// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
if ( perfect ) {
size_t i ;
line_t * ld ;
fixed_t bbox [ 4 ] ;
fixed_t finalheight ;
if ( lowest )
finalheight = INT32_MAX ;
else
finalheight = INT32_MIN ;
bbox [ BOXLEFT ] = x - mobj - > radius ;
bbox [ BOXRIGHT ] = x + mobj - > radius ;
bbox [ BOXTOP ] = y + mobj - > radius ;
bbox [ BOXBOTTOM ] = y - mobj - > radius ;
for ( i = 0 ; i < boundsec - > linecount ; i + + ) {
ld = boundsec - > lines [ i ] ;
if ( bbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | | bbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ]
| | bbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | | bbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
continue ;
if ( P_BoxOnLineSide ( bbox , ld ) ! = - 1 )
continue ;
if ( lowest )
finalheight = min ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , true ) ) ;
else
finalheight = max ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , false ) ) ;
}
return finalheight ;
}
// If we're just testing for base sector location (no collision line), just go for the center's spot...
// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
if ( line = = NULL )
return P_GetZAt ( slope , x , y ) ;
return HighestOnLine ( mobj - > radius , x , y , line , slope , lowest ) ;
} else // Well, that makes it easy. Just get the floor height
# else
( void ) mobj ;
( void ) boundsec ;
( void ) x ;
( void ) y ;
( void ) line ;
( void ) lowest ;
( void ) perfect ;
# endif
return sector - > floorheight ;
}
fixed_t P_CameraCeilingZ ( camera_t * mobj , sector_t * sector , sector_t * boundsec , fixed_t x , fixed_t y , line_t * line , boolean lowest , boolean perfect )
{
# ifdef ESLOPE
I_Assert ( mobj ! = NULL ) ;
# endif
I_Assert ( sector ! = NULL ) ;
# ifdef ESLOPE
if ( sector - > c_slope ) {
fixed_t testx , testy ;
pslope_t * slope = sector - > c_slope ;
// Get the corner of the object that should be the highest on the slope
if ( slope - > d . x < 0 )
testx = mobj - > radius ;
else
testx = - mobj - > radius ;
if ( slope - > d . y < 0 )
testy = mobj - > radius ;
else
testy = - mobj - > radius ;
if ( ( slope - > zdelta > 0 ) ^ ! ! ( lowest ) ) {
testx = - testx ;
testy = - testy ;
}
testx + = x ;
testy + = y ;
// If the highest point is in the sector, then we have it easy! Just get the Z at that point
2016-05-22 03:53:04 +00:00
if ( R_PointInSubsector ( testx , testy ) - > sector = = ( boundsec ? boundsec : sector ) )
2016-07-06 04:09:17 +00:00
return P_GetZAt ( slope , testx , testy ) ;
// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
if ( perfect ) {
size_t i ;
line_t * ld ;
fixed_t bbox [ 4 ] ;
fixed_t finalheight ;
if ( lowest )
finalheight = INT32_MAX ;
else
finalheight = INT32_MIN ;
bbox [ BOXLEFT ] = x - mobj - > radius ;
bbox [ BOXRIGHT ] = x + mobj - > radius ;
bbox [ BOXTOP ] = y + mobj - > radius ;
bbox [ BOXBOTTOM ] = y - mobj - > radius ;
for ( i = 0 ; i < boundsec - > linecount ; i + + ) {
ld = boundsec - > lines [ i ] ;
if ( bbox [ BOXRIGHT ] < = ld - > bbox [ BOXLEFT ] | | bbox [ BOXLEFT ] > = ld - > bbox [ BOXRIGHT ]
| | bbox [ BOXTOP ] < = ld - > bbox [ BOXBOTTOM ] | | bbox [ BOXBOTTOM ] > = ld - > bbox [ BOXTOP ] )
continue ;
if ( P_BoxOnLineSide ( bbox , ld ) ! = - 1 )
continue ;
if ( lowest )
finalheight = min ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , true ) ) ;
else
finalheight = max ( finalheight , HighestOnLine ( mobj - > radius , x , y , ld , slope , false ) ) ;
}
return finalheight ;
}
// If we're just testing for base sector location (no collision line), just go for the center's spot...
// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
if ( line = = NULL )
return P_GetZAt ( slope , x , y ) ;
return HighestOnLine ( mobj - > radius , x , y , line , slope , lowest ) ;
} else // Well, that makes it easy. Just get the ceiling height
# else
( void ) mobj ;
( void ) boundsec ;
( void ) x ;
( void ) y ;
( void ) line ;
( void ) lowest ;
( void ) perfect ;
# endif
return sector - > ceilingheight ;
}
2014-08-04 03:49:33 +00:00
static void P_PlayerFlip ( mobj_t * mo )
{
if ( ! mo - > player )
return ;
G_GhostAddFlip ( ) ;
// Flip aiming to match!
if ( mo - > player - > pflags & PF_NIGHTSMODE ) // NiGHTS doesn't use flipcam
{
if ( mo - > tracer )
mo - > tracer - > eflags ^ = MFE_VERTICALFLIP ;
}
else if ( mo - > player - > pflags & PF_FLIPCAM )
{
mo - > player - > aiming = InvAngle ( mo - > player - > aiming ) ;
if ( mo - > player - players = = displayplayer )
{
localaiming = mo - > player - > aiming ;
if ( camera . chase ) {
camera . aiming = InvAngle ( camera . aiming ) ;
camera . z = mo - > z - camera . z + mo - > z ;
if ( mo - > eflags & MFE_VERTICALFLIP )
camera . z + = FixedMul ( 20 * FRACUNIT , mo - > scale ) ;
}
}
else if ( mo - > player - players = = secondarydisplayplayer )
{
localaiming2 = mo - > player - > aiming ;
if ( camera2 . chase ) {
camera2 . aiming = InvAngle ( camera2 . aiming ) ;
camera2 . z = mo - > z - camera2 . z + mo - > z ;
if ( mo - > eflags & MFE_VERTICALFLIP )
camera2 . z + = FixedMul ( 20 * FRACUNIT , mo - > scale ) ;
}
}
2017-12-17 03:32:43 +00:00
else if ( mo - > player - players = = thirddisplayplayer )
{
localaiming3 = mo - > player - > aiming ;
if ( camera3 . chase ) {
camera3 . aiming = InvAngle ( camera3 . aiming ) ;
camera3 . z = mo - > z - camera3 . z + mo - > z ;
if ( mo - > eflags & MFE_VERTICALFLIP )
camera3 . z + = FixedMul ( 20 * FRACUNIT , mo - > scale ) ;
}
}
else if ( mo - > player - players = = fourthdisplayplayer )
{
localaiming4 = mo - > player - > aiming ;
if ( camera4 . chase ) {
camera4 . aiming = InvAngle ( camera4 . aiming ) ;
camera4 . z = mo - > z - camera4 . z + mo - > z ;
if ( mo - > eflags & MFE_VERTICALFLIP )
camera4 . z + = FixedMul ( 20 * FRACUNIT , mo - > scale ) ;
}
}
2014-08-04 03:49:33 +00:00
}
}
2014-03-15 16:59:03 +00:00
//
2016-05-31 14:01:19 +00:00
// P_GetMobjGravity
2014-03-15 16:59:03 +00:00
//
2016-05-31 14:01:19 +00:00
// Returns the current gravity
// value of the object.
2014-03-15 16:59:03 +00:00
//
2016-05-31 14:01:19 +00:00
fixed_t P_GetMobjGravity ( mobj_t * mo )
2014-03-15 16:59:03 +00:00
{
fixed_t gravityadd = 0 ;
boolean no3dfloorgrav = true ; // Custom gravity
boolean goopgravity = false ;
2014-08-04 03:49:33 +00:00
boolean wasflip ;
2014-03-15 16:59:03 +00:00
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
2014-08-04 03:49:33 +00:00
wasflip = ( mo - > eflags & MFE_VERTICALFLIP ) ! = 0 ;
2014-03-15 16:59:03 +00:00
if ( mo - > type ! = MT_SPINFIRE )
mo - > eflags & = ~ MFE_VERTICALFLIP ;
if ( mo - > subsector - > sector - > ffloors ) // Check for 3D floor gravity too.
{
ffloor_t * rover ;
for ( rover = mo - > subsector - > sector - > ffloors ; rover ; rover = rover - > next )
{
2016-08-28 19:46:56 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) | | ! P_InsideANonSolidFFloor ( mo , rover ) ) // P_InsideANonSolidFFloor checks for FF_EXISTS itself, but let's not always call this function
2014-03-15 16:59:03 +00:00
continue ;
2016-08-28 12:19:17 +00:00
if ( ( rover - > flags & ( FF_SWIMMABLE | FF_GOOWATER ) ) = = ( FF_SWIMMABLE | FF_GOOWATER ) )
goopgravity = true ;
2014-03-15 16:59:03 +00:00
2016-08-28 12:19:17 +00:00
if ( ! ( rover - > master - > frontsector - > gravity ) )
continue ;
2014-03-15 16:59:03 +00:00
2016-08-28 12:19:17 +00:00
gravityadd = - FixedMul ( gravity ,
( FixedDiv ( * rover - > master - > frontsector - > gravity > > FRACBITS , 1000 ) ) ) ;
if ( rover - > master - > frontsector - > verticalflip & & gravityadd > 0 )
mo - > eflags | = MFE_VERTICALFLIP ;
no3dfloorgrav = false ;
break ;
2014-03-15 16:59:03 +00:00
}
}
if ( no3dfloorgrav )
{
if ( mo - > subsector - > sector - > gravity )
gravityadd = - FixedMul ( gravity ,
( FixedDiv ( * mo - > subsector - > sector - > gravity > > FRACBITS , 1000 ) ) ) ;
else
gravityadd = - gravity ;
if ( mo - > subsector - > sector - > verticalflip & & gravityadd > 0 )
mo - > eflags | = MFE_VERTICALFLIP ;
}
// Less gravity underwater.
if ( mo - > eflags & MFE_UNDERWATER & & ! goopgravity )
gravityadd = gravityadd / 3 ;
if ( mo - > player )
{
2017-02-17 20:14:55 +00:00
//if ((mo->player->pflags & PF_GLIDING)
//|| (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
// || (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4]))))
// gravityadd = gravityadd/3; // less gravity while flying/gliding
2016-08-28 12:19:17 +00:00
if ( mo - > player - > climbing | | ( mo - > player - > pflags & PF_NIGHTSMODE ) )
Mammoth commit!
* Deaths in record attack no longer put you into a glitchy singleplayer game-over state that we somehow both kept around and also broke since we branched Kart off of Vanilla..
* Fix non-standard mapscales making the Death Egg respawn octagons dissasemble themselves.
* Allow for MULTIPLE TIME EMBLEMS PER MAP, at least in the emblem UI on the timer. It shows all completed emblems plus the uncompleted emblem up to a total of three.
* Major tweaks to the First Person HUD.
* I know this was your baby, Sal, and some of the changes may prove controversial - so I've put the ones that are likely to cause the most fuss inside an ifndef block, so that you can toggle it as you please with minimal code changes.
* Dontdraw-ness, transparency, and colorization match the player's object!
* Moves around on the screen with respect to the direction of the player object's motion, to make drifting look nicer!
* Flashes the colour of your drift sparks.
* Did a WHOLE bunch of things with respect to music. I'm not sure how to describe this, so I'll go through step-by-step.
* Countdowns now play the drowning music again.
* Removed/disabled extraenous P_RestoreMusics.
* Made map-ending music called by its own function, P_EndingMusic(player_t *player).
* Made the ending music play on the LAST player crossing the finishing line in splitscreen, rather than first.
* Make dead players spinout and clip through the floor, at least until we add the new death anims.
* Fix prior pogo spring usage making dead players fall faster.
* Make the time over countdown use the kart font when not splitscreen with 3 or 4 players.
* Removed a weird bonus HWR_DrawCroppedPatch function signature in the hardware header.
2018-07-16 19:19:30 +00:00
return 0 ;
2014-03-15 16:59:03 +00:00
2016-09-03 20:37:52 +00:00
if ( ! ( mo - > flags2 & MF2_OBJECTFLIP ) ! = ! ( mo - > player - > powers [ pw_gravityboots ] ) ) // negated to turn numeric into bool - would be double negated, but not needed if both would be
2014-03-15 16:59:03 +00:00
{
2016-08-28 13:09:15 +00:00
gravityadd = - gravityadd ;
mo - > eflags ^ = MFE_VERTICALFLIP ;
2014-03-15 16:59:03 +00:00
}
2016-09-03 21:05:45 +00:00
if ( wasflip = = ! ( mo - > eflags & MFE_VERTICALFLIP ) ) // note!! == ! is not equivalent to != here - turns numeric into bool this way
2016-08-28 12:19:17 +00:00
P_PlayerFlip ( mo ) ;
2018-02-05 23:55:52 +00:00
if ( mo - > player - > kartstuff [ k_pogospring ] )
2017-11-11 02:10:01 +00:00
gravityadd = FixedMul ( gravityadd , 5 * FRACUNIT / 2 ) ;
2014-03-15 16:59:03 +00:00
}
else
{
// Objects with permanent reverse gravity (MF2_OBJECTFLIP)
if ( mo - > flags2 & MF2_OBJECTFLIP )
{
mo - > eflags | = MFE_VERTICALFLIP ;
if ( mo - > z + mo - > height > = mo - > ceilingz )
gravityadd = 0 ;
2016-08-28 12:19:17 +00:00
else if ( gravityadd < 0 ) // Don't sink, only rise up
gravityadd * = - 1 ;
2014-03-15 16:59:03 +00:00
}
else //Otherwise, sort through the other exceptions.
{
switch ( mo - > type )
{
case MT_FLINGRING :
case MT_FLINGCOIN :
case MT_FLINGEMERALD :
case MT_BOUNCERING :
case MT_RAILRING :
case MT_INFINITYRING :
case MT_AUTOMATICRING :
case MT_EXPLOSIONRING :
case MT_SCATTERRING :
case MT_GRENADERING :
case MT_BOUNCEPICKUP :
case MT_RAILPICKUP :
case MT_AUTOPICKUP :
case MT_EXPLODEPICKUP :
case MT_SCATTERPICKUP :
case MT_GRENADEPICKUP :
case MT_REDFLAG :
case MT_BLUEFLAG :
if ( mo - > target )
{
// Flung items copy the gravity of their tosser.
if ( ( mo - > target - > eflags & MFE_VERTICALFLIP ) & & ! ( mo - > eflags & MFE_VERTICALFLIP ) )
{
gravityadd = - gravityadd ;
mo - > eflags | = MFE_VERTICALFLIP ;
}
}
break ;
case MT_WATERDROP :
gravityadd > > = 1 ;
2018-02-09 00:58:10 +00:00
break ;
2018-06-01 00:51:05 +00:00
case MT_BANANA :
2017-11-03 01:40:06 +00:00
case MT_FAKEITEM :
2018-06-01 00:51:05 +00:00
case MT_SSMINE :
2017-11-03 01:40:06 +00:00
gravityadd = FixedMul ( gravityadd , 5 * FRACUNIT / 2 ) ;
2018-09-04 23:58:20 +00:00
break ;
case MT_SINK :
gravityadd = FixedMul ( gravityadd , 5 * FRACUNIT ) ; // Double gravity
break ;
2018-09-13 21:42:34 +00:00
case MT_SIGN :
2018-09-21 23:44:14 +00:00
gravityadd / = 8 ;
2018-09-13 21:42:34 +00:00
break ;
2014-03-15 16:59:03 +00:00
default :
break ;
}
}
}
// Goop has slower, reversed gravity
if ( goopgravity )
gravityadd = - gravityadd / 5 ;
2016-06-02 15:42:07 +00:00
gravityadd = FixedMul ( gravityadd , mo - > scale ) ;
2016-05-31 14:01:19 +00:00
return gravityadd ;
}
//
// P_CheckGravity
//
// Checks the current gravity state
// of the object. If affect is true,
// a gravity force will be applied.
//
void P_CheckGravity ( mobj_t * mo , boolean affect )
{
fixed_t gravityadd = P_GetMobjGravity ( mo ) ;
2014-03-15 16:59:03 +00:00
2016-06-02 15:42:07 +00:00
if ( ! mo - > momz ) // mobj at stop, no floor, so feel the push of gravity!
gravityadd < < = 1 ;
2016-05-31 14:01:19 +00:00
if ( affect )
2016-06-02 15:42:07 +00:00
mo - > momz + = gravityadd ;
2014-08-04 03:49:33 +00:00
2014-03-15 16:59:03 +00:00
if ( mo - > type = = MT_SKIM & & mo - > z + mo - > momz < = mo - > watertop & & mo - > z > = mo - > watertop )
{
mo - > momz = 0 ;
mo - > flags | = MF_NOGRAVITY ;
}
}
# define STOPSPEED (FRACUNIT)
2016-08-24 01:03:58 +00:00
//#define FRICTION (ORIG_FRICTION) // 0.90625
2014-03-15 16:59:03 +00:00
//
// P_SceneryXYFriction
//
static void P_SceneryXYFriction ( mobj_t * mo , fixed_t oldx , fixed_t oldy )
{
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
if ( abs ( mo - > momx ) < FixedMul ( STOPSPEED / 32 , mo - > scale )
& & abs ( mo - > momy ) < FixedMul ( STOPSPEED / 32 , mo - > scale ) )
{
mo - > momx = 0 ;
mo - > momy = 0 ;
}
else
{
if ( ( oldx = = mo - > x ) & & ( oldy = = mo - > y ) ) // didn't go anywhere
{
mo - > momx = FixedMul ( mo - > momx , ORIG_FRICTION ) ;
mo - > momy = FixedMul ( mo - > momy , ORIG_FRICTION ) ;
}
else
{
mo - > momx = FixedMul ( mo - > momx , mo - > friction ) ;
mo - > momy = FixedMul ( mo - > momy , mo - > friction ) ;
}
if ( mo - > type = = MT_CANNONBALLDECOR )
{
// Stolen from P_SpawnFriction
mo - > friction = FRACUNIT - 0x100 ;
2016-08-24 01:03:58 +00:00
//mo->movefactor = ((0x10092 - mo->friction)*(0x70))/0x158;
2014-03-15 16:59:03 +00:00
}
else
mo - > friction = ORIG_FRICTION ;
}
}
//
// P_XYFriction
//
// adds friction on the xy plane
//
static void P_XYFriction ( mobj_t * mo , fixed_t oldx , fixed_t oldy )
{
player_t * player ;
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
player = mo - > player ;
if ( player ) // valid only if player avatar
{
2014-08-04 03:49:33 +00:00
// spinning friction
if ( player - > pflags & PF_SPINNING & & ( player - > rmomx | | player - > rmomy ) & & ! ( player - > pflags & PF_STARTDASH ) )
{
2016-08-24 01:03:58 +00:00
const fixed_t ns = FixedDiv ( 549 * ORIG_FRICTION , 500 * FRACUNIT ) ; //const fixed_t ns = FixedDiv(549*FRICTION,500*FRACUNIT);
2014-08-04 03:49:33 +00:00
mo - > momx = FixedMul ( mo - > momx , ns ) ;
mo - > momy = FixedMul ( mo - > momy , ns ) ;
}
else if ( abs ( player - > rmomx ) < FixedMul ( STOPSPEED , mo - > scale )
& & abs ( player - > rmomy ) < FixedMul ( STOPSPEED , mo - > scale )
2016-07-06 04:09:17 +00:00
& & ( ! ( player - > cmd . forwardmove & & ! ( twodlevel | | mo - > flags2 & MF2_TWOD ) ) & & ! player - > cmd . sidemove & & ! ( player - > pflags & PF_SPINNING ) )
# ifdef ESLOPE
2016-05-31 14:01:19 +00:00
& & ! ( player - > mo - > standingslope & & ( ! ( player - > mo - > standingslope - > flags & SL_NOPHYSICS ) ) & & ( abs ( player - > mo - > standingslope - > zdelta ) > = FRACUNIT / 2 ) )
2016-07-06 04:09:17 +00:00
# endif
)
2014-03-15 16:59:03 +00:00
{
// if in a walking frame, stop moving
2016-08-21 02:15:06 +00:00
if ( player - > panim = = PA_WALK & & player - > kartstuff [ k_spinouttimer ] = = 0 )
2017-11-04 17:32:47 +00:00
P_SetPlayerMobjState ( mo , S_KART_STND1 ) ; // SRB2kart - was S_PLAY_STND
2014-03-15 16:59:03 +00:00
mo - > momx = player - > cmomx ;
mo - > momy = player - > cmomy ;
}
else
{
2014-08-04 03:49:33 +00:00
if ( oldx = = mo - > x & & oldy = = mo - > y ) // didn't go anywhere
2014-03-15 16:59:03 +00:00
{
mo - > momx = FixedMul ( mo - > momx , ORIG_FRICTION ) ;
mo - > momy = FixedMul ( mo - > momy , ORIG_FRICTION ) ;
}
else
{
mo - > momx = FixedMul ( mo - > momx , mo - > friction ) ;
mo - > momy = FixedMul ( mo - > momy , mo - > friction ) ;
}
mo - > friction = ORIG_FRICTION ;
}
}
else
P_SceneryXYFriction ( mo , oldx , oldy ) ;
}
static void P_PushableCheckBustables ( mobj_t * mo )
{
msecnode_t * node ;
fixed_t oldx ;
fixed_t oldy ;
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
if ( netgame & & mo - > player & & mo - > player - > spectator )
return ;
oldx = mo - > x ;
oldy = mo - > y ;
P_UnsetThingPosition ( mo ) ;
mo - > x + = mo - > momx ;
mo - > y + = mo - > momy ;
P_SetThingPosition ( mo ) ;
2016-06-09 13:16:02 +00:00
for ( node = 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 ) ) continue ;
// Needs ML_EFFECT4 flag for pushables to break it
if ( ! ( rover - > master - > flags & ML_EFFECT4 ) ) continue ;
if ( ! rover - > master - > frontsector - > crumblestate )
{
2016-09-02 20:41:45 +00:00
topheight = P_GetFOFTopZ ( mo , node - > m_sector , rover , mo - > x , mo - > y , NULL ) ;
bottomheight = P_GetFOFBottomZ ( mo , node - > m_sector , rover , mo - > x , mo - > y , NULL ) ;
2014-03-15 16:59:03 +00:00
// Height checks
if ( rover - > flags & FF_SHATTERBOTTOM )
{
2016-09-02 20:41:45 +00:00
if ( mo - > z + mo - > momz + mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( mo - > z + 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 ( mo - > z + mo - > momz > topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( mo - > z + 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 ( mo - > z + mo - > momz > topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( mo - > z + mo - > momz + mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
}
else
{
2016-09-02 20:41:45 +00:00
if ( mo - > z > = topheight )
2014-03-15 16:59:03 +00:00
continue ;
2016-09-02 20:41:45 +00:00
if ( mo - > z + mo - > height < bottomheight )
2014-03-15 16:59:03 +00:00
continue ;
}
EV_CrumbleChain ( node - > m_sector , rover ) ;
// Run a linedef executor??
if ( rover - > master - > flags & ML_EFFECT5 )
P_LinedefExecute ( ( INT16 ) ( P_AproxDistance ( rover - > master - > dx , rover - > master - > dy ) > > FRACBITS ) , mo , node - > m_sector ) ;
goto bustupdone ;
}
}
}
}
bustupdone :
P_UnsetThingPosition ( mo ) ;
mo - > x = oldx ;
mo - > y = oldy ;
P_SetThingPosition ( mo ) ;
}
//
// P_CheckSkyHit
//
static boolean P_CheckSkyHit ( mobj_t * mo )
{
if ( ceilingline & & ceilingline - > backsector
& & ceilingline - > backsector - > ceilingpic = = skyflatnum
& & ceilingline - > frontsector
& & ceilingline - > frontsector - > ceilingpic = = skyflatnum
& & ( mo - > z > = ceilingline - > frontsector - > ceilingheight
| | mo - > z > = ceilingline - > backsector - > ceilingheight ) )
return true ;
return false ;
}
//
// P_XYMovement
//
void P_XYMovement ( mobj_t * mo )
{
player_t * player ;
fixed_t xmove , ymove ;
fixed_t oldx , oldy ; // reducing bobbing/momentum on ice when up against walls
boolean moved ;
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
pslope_t * oldslope = NULL ;
vector3_t slopemom ;
fixed_t predictedz = 0 ;
# endif
2014-03-15 16:59:03 +00:00
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
// if it's stopped
if ( ! mo - > momx & & ! mo - > momy )
{
if ( mo - > flags2 & MF2_SKULLFLY )
{
// the skull slammed into something
mo - > flags2 & = ~ MF2_SKULLFLY ;
mo - > momx = mo - > momy = mo - > momz = 0 ;
// set in 'search new direction' state?
if ( mo - > type ! = MT_EGGMOBILE )
P_SetMobjState ( mo , mo - > info - > spawnstate ) ;
return ;
}
}
player = mo - > player ; //valid only if player avatar
xmove = mo - > momx ;
ymove = mo - > momy ;
oldx = mo - > x ;
oldy = mo - > y ;
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
// adjust various things based on slope
if ( mo - > standingslope & & abs ( mo - > standingslope - > zdelta ) > FRACUNIT > > 8 ) {
if ( ! P_IsObjectOnGround ( mo ) ) { // We fell off at some point? Do the twisty thing!
P_SlopeLaunch ( mo ) ;
xmove = mo - > momx ;
ymove = mo - > momy ;
} else { // Still on the ground.
slopemom . x = xmove ;
slopemom . y = ymove ;
slopemom . z = 0 ;
P_QuantizeMomentumToSlope ( & slopemom , mo - > standingslope ) ;
xmove = slopemom . x ;
ymove = slopemom . y ;
predictedz = mo - > z + slopemom . z ; // We'll use this later...
oldslope = mo - > standingslope ;
}
} else if ( P_IsObjectOnGround ( mo ) & & ! mo - > momz )
predictedz = mo - > z ;
# endif
2014-03-15 16:59:03 +00:00
// Pushables can break some blocks
2014-08-04 03:49:33 +00:00
if ( CheckForBustableBlocks & & mo - > flags & MF_PUSHABLE )
2014-03-15 16:59:03 +00:00
P_PushableCheckBustables ( mo ) ;
2018-07-25 02:47:09 +00:00
//{ SRB2kart - Ballhogs
2018-06-25 21:12:01 +00:00
if ( mo - > type = = MT_BALLHOG )
2017-05-13 15:14:26 +00:00
{
2018-07-25 02:47:09 +00:00
if ( mo - > health )
2017-05-13 15:14:26 +00:00
{
2018-07-25 02:47:09 +00:00
mo - > health - - ;
if ( mo - > health = = 0 )
mo - > destscale = 1 ;
}
else
{
if ( mo - > scale < mapheaderinfo [ gamemap - 1 ] - > mobj_scale / 16 )
{
P_RemoveMobj ( mo ) ;
return ;
}
2017-05-13 15:14:26 +00:00
}
}
//}
2016-07-06 04:09:17 +00:00
if ( ! P_TryMove ( mo , mo - > x + xmove , mo - > y + ymove , true ) & & ! ( mo - > eflags & MFE_SPRUNG ) )
2014-03-15 16:59:03 +00:00
{
// blocked move
2016-08-13 22:43:22 +00:00
moved = false ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( player ) {
if ( player - > bot )
B_MoveBlocked ( player ) ;
2014-03-15 16:59:03 +00:00
}
2018-02-05 23:55:52 +00:00
//{ SRB2kart - Jawz
2018-06-01 00:51:05 +00:00
if ( mo - > type = = MT_JAWZ | | mo - > type = = MT_JAWZ_DUD )
2017-02-26 22:37:52 +00:00
{
if ( mo - > health = = 1 )
{
// This Item Damage
S_StartSound ( mo , mo - > info - > deathsound ) ;
P_KillMobj ( mo , NULL , NULL ) ;
2014-03-15 16:59:03 +00:00
2017-02-26 22:37:52 +00:00
P_SetObjectMomZ ( mo , 8 * FRACUNIT , false ) ;
P_InstaThrust ( mo , R_PointToAngle2 ( mo - > x , mo - > y , mo - > x + xmove , mo - > y + ymove ) + ANGLE_90 , 16 * FRACUNIT ) ;
}
}
//}
else if ( mo - > flags & MF_BOUNCE )
2014-03-15 16:59:03 +00:00
{
P_BounceMove ( mo ) ;
xmove = ymove = 0 ;
2018-06-27 14:10:53 +00:00
S_StartSound ( mo , mo - > info - > activesound ) ;
//{ SRB2kart - Orbinaut, Ballhog
// Bump sparks
2018-07-23 00:55:18 +00:00
if ( mo - > type = = MT_ORBINAUT | | mo - > type = = MT_BALLHOG )
2017-02-26 22:37:52 +00:00
{
2017-10-24 04:42:06 +00:00
mobj_t * fx ;
fx = P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_BUMP ) ;
if ( mo - > eflags & MFE_VERTICALFLIP )
fx - > eflags | = MFE_VERTICALFLIP ;
else
fx - > eflags & = ~ MFE_VERTICALFLIP ;
fx - > scale = mo - > scale ;
2018-06-27 14:10:53 +00:00
}
2018-07-23 00:55:18 +00:00
if ( mo - > type = = MT_ORBINAUT ) // Orbinaut speed decreasing
2018-06-27 14:10:53 +00:00
{
2017-02-26 22:37:52 +00:00
if ( mo - > health > 1 )
{
2017-10-24 04:42:06 +00:00
S_StartSound ( mo , mo - > info - > attacksound ) ;
mo - > health - - ;
mo - > threshold = 0 ;
2017-02-26 22:37:52 +00:00
}
else if ( mo - > health = = 1 )
{
// This Item Damage
S_StartSound ( mo , mo - > info - > deathsound ) ;
P_KillMobj ( mo , NULL , NULL ) ;
P_SetObjectMomZ ( mo , 8 * FRACUNIT , false ) ;
P_InstaThrust ( mo , R_PointToAngle2 ( mo - > x , mo - > y , mo - > x + xmove , mo - > y + ymove ) + ANGLE_90 , 16 * FRACUNIT ) ;
}
}
//}
2014-03-15 16:59:03 +00:00
// Bounce ring algorithm
if ( mo - > type = = MT_THROWNBOUNCE )
{
mo - > threshold + + ;
// Gain lower amounts of time on each bounce.
2016-07-06 04:09:17 +00:00
if ( mo - > fuse & & mo - > threshold < 5 )
2014-03-15 16:59:03 +00:00
mo - > fuse + = ( ( 5 - mo - > threshold ) * TICRATE ) ;
// Check for hit against sky here
if ( P_CheckSkyHit ( mo ) )
{
// Hack to prevent missiles exploding
// against the sky.
// Does not handle sky floors.
// Check frontsector as well.
P_RemoveMobj ( mo ) ;
return ;
}
}
}
else if ( mo - > flags & MF_STICKY )
{
S_StartSound ( mo , mo - > info - > activesound ) ;
mo - > momx = mo - > momy = mo - > momz = 0 ; //Full stop!
mo - > flags | = MF_NOGRAVITY ; //Stay there!
mo - > flags & = ~ MF_STICKY ; //Don't check again!
// Check for hit against sky here
if ( P_CheckSkyHit ( mo ) )
{
// Hack to prevent missiles exploding
// against the sky.
// Does not handle sky floors.
// Check frontsector as well.
P_RemoveMobj ( mo ) ;
return ;
}
}
2014-08-04 03:49:33 +00:00
else if ( player | | mo - > flags & ( MF_SLIDEME | MF_PUSHABLE ) )
2014-03-15 16:59:03 +00:00
{ // try to slide along it
2017-11-05 07:16:39 +00:00
P_SlideMove ( mo , false ) ;
2014-03-15 16:59:03 +00:00
xmove = ymove = 0 ;
}
2014-08-04 03:49:33 +00:00
else if ( mo - > type = = MT_SPINFIRE )
{
P_RemoveMobj ( mo ) ;
return ;
}
2014-03-15 16:59:03 +00:00
else if ( mo - > flags & MF_MISSILE )
{
// explode a missile
if ( P_CheckSkyHit ( mo ) )
{
// Hack to prevent missiles exploding
// against the sky.
// Does not handle sky floors.
// Check frontsector as well.
P_RemoveMobj ( mo ) ;
return ;
}
// draw damage on wall
//SPLAT TEST ----------------------------------------------------------
# ifdef WALLSPLATS
2018-06-25 21:12:01 +00:00
if ( blockingline & & mo - > type ! = MT_REDRING & & mo - > type ! = MT_FIREBALL
2014-08-04 03:49:33 +00:00
& & ! ( mo - > flags2 & ( MF2_AUTOMATIC | MF2_RAILRING | MF2_BOUNCERING | MF2_EXPLOSION | MF2_SCATTER ) ) )
2014-03-15 16:59:03 +00:00
// set by last P_TryMove() that failed
{
divline_t divl ;
divline_t misl ;
fixed_t frac ;
P_MakeDivline ( blockingline , & divl ) ;
misl . x = mo - > x ;
misl . y = mo - > y ;
misl . dx = mo - > momx ;
misl . dy = mo - > momy ;
frac = P_InterceptVector ( & divl , & misl ) ;
R_AddWallSplat ( blockingline , P_PointOnLineSide ( mo - > x , mo - > y , blockingline ) ,
" A_DMG3 " , mo - > z , frac , SPLATDRAWMODE_SHADE ) ;
}
# endif
// --------------------------------------------------------- SPLAT TEST
P_ExplodeMissile ( mo ) ;
return ;
}
else
mo - > momx = mo - > momy = 0 ;
}
2016-08-13 22:43:22 +00:00
else
2014-03-15 16:59:03 +00:00
moved = true ;
2014-03-15 22:55:07 +00:00
if ( P_MobjWasRemoved ( mo ) ) // MF_SPECIAL touched a player! O_o;;
return ;
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
if ( moved & & oldslope ) { // Check to see if we ran off
if ( oldslope ! = mo - > standingslope ) { // First, compare different slopes
angle_t oldangle , newangle ;
angle_t moveangle = R_PointToAngle2 ( 0 , 0 , mo - > momx , mo - > momy ) ;
oldangle = FixedMul ( ( signed ) oldslope - > zangle , FINECOSINE ( ( moveangle - oldslope - > xydirection ) > > ANGLETOFINESHIFT ) ) ;
if ( mo - > standingslope )
newangle = FixedMul ( ( signed ) mo - > standingslope - > zangle , FINECOSINE ( ( moveangle - mo - > standingslope - > xydirection ) > > ANGLETOFINESHIFT ) ) ;
else
newangle = 0 ;
// Now compare the Zs of the different quantizations
if ( oldangle - newangle > ANG30 & & oldangle - newangle < ANGLE_180 ) { // Allow for a bit of sticking - this value can be adjusted later
mo - > standingslope = oldslope ;
P_SlopeLaunch ( mo ) ;
//CONS_Printf("launched off of slope - ");
}
/*CONS_Printf("old angle %f - new angle %f = %f\n",
FIXED_TO_FLOAT ( AngleFixed ( oldangle ) ) ,
FIXED_TO_FLOAT ( AngleFixed ( newangle ) ) ,
FIXED_TO_FLOAT ( AngleFixed ( oldangle - newangle ) )
) ; */
} else if ( predictedz - mo - > z > abs ( slopemom . z / 2 ) ) { // Now check if we were supposed to stick to this slope
//CONS_Printf("%d-%d > %d\n", (predictedz), (mo->z), (slopemom.z/2));
P_SlopeLaunch ( mo ) ;
}
} else if ( moved & & mo - > standingslope & & predictedz ) {
angle_t moveangle = R_PointToAngle2 ( 0 , 0 , mo - > momx , mo - > momy ) ;
angle_t newangle = FixedMul ( ( signed ) mo - > standingslope - > zangle , FINECOSINE ( ( moveangle - mo - > standingslope - > xydirection ) > > ANGLETOFINESHIFT ) ) ;
/*CONS_Printf("flat to angle %f - predicted z of %f\n",
FIXED_TO_FLOAT ( AngleFixed ( ANGLE_MAX - newangle ) ) ,
FIXED_TO_FLOAT ( predictedz )
) ; */
if ( ANGLE_MAX - newangle > ANG30 & & newangle > ANGLE_180 ) {
mo - > momz = P_MobjFlip ( mo ) * FRACUNIT / 2 ;
mo - > z = predictedz + P_MobjFlip ( mo ) ;
mo - > standingslope = NULL ;
//CONS_Printf("Launched off of flat surface running into downward slope\n");
}
}
# endif
2014-03-15 16:59:03 +00:00
// Check the gravity status.
P_CheckGravity ( mo , false ) ;
2014-08-04 03:49:33 +00:00
if ( player & & ! moved & & player - > pflags & PF_NIGHTSMODE & & mo - > target )
2014-03-15 16:59:03 +00:00
{
angle_t fa ;
P_UnsetThingPosition ( mo ) ;
2014-08-04 03:49:33 +00:00
player - > angle_pos = player - > old_angle_pos ;
player - > speed = FixedMul ( player - > speed , 4 * FRACUNIT / 5 ) ;
2014-03-15 16:59:03 +00:00
if ( player - > flyangle > = 0 & & player - > flyangle < 90 )
player - > flyangle = 135 ;
else if ( player - > flyangle > = 90 & & player - > flyangle < 180 )
player - > flyangle = 45 ;
else if ( player - > flyangle > = 180 & & player - > flyangle < 270 )
player - > flyangle = 315 ;
else
player - > flyangle = 225 ;
player - > flyangle % = 360 ;
if ( player - > pflags & PF_TRANSFERTOCLOSEST )
{
mo - > x - = mo - > momx ;
mo - > y - = mo - > momy ;
}
else
{
fa = player - > old_angle_pos > > ANGLETOFINESHIFT ;
mo - > x = mo - > target - > x + FixedMul ( FINECOSINE ( fa ) , mo - > target - > radius ) ;
mo - > y = mo - > target - > y + FixedMul ( FINESINE ( fa ) , mo - > target - > radius ) ;
}
mo - > momx = mo - > momy = 0 ;
P_SetThingPosition ( mo ) ;
}
2014-08-04 03:49:33 +00:00
if ( mo - > flags & MF_NOCLIPHEIGHT )
return ; // no frictions for objects that can pass through floors
if ( mo - > flags & MF_MISSILE | | mo - > flags2 & MF2_SKULLFLY | | mo - > type = = MT_SHELL | | mo - > type = = MT_VULTURE )
2014-03-15 16:59:03 +00:00
return ; // no friction for missiles ever
2014-08-04 03:49:33 +00:00
if ( player & & player - > homing ) // no friction for homing
2014-03-15 16:59:03 +00:00
return ;
2016-07-06 04:09:17 +00:00
if ( player & & player - > pflags & PF_NIGHTSMODE )
return ; // no friction for NiGHTS players
# ifdef ESLOPE
if ( ( mo - > type = = MT_BIGTUMBLEWEED | | mo - > type = = MT_LITTLETUMBLEWEED )
& & ( mo - > standingslope & & abs ( mo - > standingslope - > zdelta ) > FRACUNIT > > 8 ) ) // Special exception for tumbleweeds on slopes
return ;
# endif
2016-08-21 02:15:06 +00:00
//{ SRB2kart stuff
2018-07-23 00:55:18 +00:00
if ( mo - > type = = MT_ORBINAUT | | mo - > type = = MT_JAWZ_DUD | | mo - > type = = MT_JAWZ | | mo - > type = = MT_BALLHOG ) //(mo->type == MT_JAWZ && !mo->tracer))
2017-02-26 22:37:52 +00:00
return ;
2016-08-21 02:15:06 +00:00
2018-07-20 20:13:02 +00:00
if ( mo - > player & & ( mo - > player - > kartstuff [ k_spinouttimer ] & & ! mo - > player - > kartstuff [ k_wipeoutslow ] ) & & mo - > player - > speed < = mo - > player - > normalspeed / 2 )
2016-08-21 02:15:06 +00:00
return ;
//}
2014-03-15 16:59:03 +00:00
if ( ( ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > z > mo - > floorz ) | | ( mo - > eflags & MFE_VERTICALFLIP & & mo - > z + mo - > height < mo - > ceilingz ) )
2014-08-04 03:49:33 +00:00
& & ! ( player & & player - > pflags & PF_SLIDING ) )
2014-03-15 16:59:03 +00:00
return ; // no friction when airborne
P_XYFriction ( mo , oldx , oldy ) ;
}
static void P_RingXYMovement ( mobj_t * mo )
{
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
if ( ! P_SceneryTryMove ( mo , mo - > x + mo - > momx , mo - > y + mo - > momy ) )
2017-11-05 07:16:39 +00:00
P_SlideMove ( mo , false ) ;
2014-03-15 16:59:03 +00:00
}
static void P_SceneryXYMovement ( mobj_t * mo )
{
fixed_t oldx , oldy ; // reducing bobbing/momentum on ice when up against walls
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
oldx = mo - > x ;
oldy = mo - > y ;
if ( ! P_SceneryTryMove ( mo , mo - > x + mo - > momx , mo - > y + mo - > momy ) )
2017-11-05 07:16:39 +00:00
P_SlideMove ( mo , false ) ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > z > mo - > floorz ) | | ( mo - > eflags & MFE_VERTICALFLIP & & mo - > z + mo - > height < mo - > ceilingz ) )
2014-03-15 16:59:03 +00:00
return ; // no friction when airborne
2014-08-04 03:49:33 +00:00
if ( mo - > flags & MF_NOCLIPHEIGHT )
return ; // no frictions for objects that can pass through floors
2014-03-15 16:59:03 +00:00
P_SceneryXYFriction ( mo , oldx , oldy ) ;
}
2015-01-01 19:50:31 +00:00
//
// P_AdjustMobjFloorZ_FFloors
//
// Utility function for P_ZMovement and related
// Adjusts mo->floorz/mo->ceiling accordingly for FFloors
//
// "motype" determines what behaviour to use exactly
// This is to keep things consistent in case these various object types NEED to be different
//
// motype options:
// 0 - normal
// 1 - forces false check for water (rings)
// 2 - forces false check for water + different quicksand behaviour (scenery)
//
static void P_AdjustMobjFloorZ_FFloors ( mobj_t * mo , sector_t * sector , UINT8 motype )
2014-03-15 16:59:03 +00:00
{
2015-01-01 19:50:31 +00:00
ffloor_t * rover ;
fixed_t delta1 , delta2 , thingtop ;
2016-07-06 04:09:17 +00:00
fixed_t topheight , bottomheight ;
2015-01-01 19:50:31 +00:00
2014-03-15 16:59:03 +00:00
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
2015-01-01 19:50:31 +00:00
thingtop = mo - > z + mo - > height ;
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
2014-03-15 16:59:03 +00:00
{
2015-01-01 19:50:31 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
topheight = P_GetFOFTopZ ( mo , sector , rover , mo - > x , mo - > y , NULL ) ;
bottomheight = P_GetFOFBottomZ ( mo , sector , rover , mo - > x , mo - > y , NULL ) ;
2015-01-01 19:50:31 +00:00
if ( mo - > player & & ( P_CheckSolidLava ( mo , rover ) | | P_CanRunOnWater ( mo - > player , rover ) ) ) // only the player should be affected
;
else if ( motype ! = 0 & & rover - > flags & FF_SWIMMABLE ) // "scenery" only
continue ;
else if ( rover - > flags & FF_QUICKSAND ) // quicksand
;
else if ( ! ( ( rover - > flags & FF_BLOCKPLAYER & & mo - > player ) // solid to players?
| | ( rover - > flags & FF_BLOCKOTHERS & & ! mo - > player ) ) ) // solid to others?
continue ;
if ( rover - > flags & FF_QUICKSAND )
2014-03-15 16:59:03 +00:00
{
2015-01-01 19:50:31 +00:00
switch ( motype )
2014-03-15 16:59:03 +00:00
{
2015-01-01 19:50:31 +00:00
case 2 : // scenery does things differently for some reason
2016-07-06 04:09:17 +00:00
if ( mo - > z < topheight & & bottomheight < thingtop )
2015-01-01 19:50:31 +00:00
{
2014-03-15 16:59:03 +00:00
mo - > floorz = mo - > z ;
2015-01-01 19:50:31 +00:00
continue ;
}
break ;
default :
2016-07-06 04:09:17 +00:00
if ( mo - > z < topheight & & bottomheight < thingtop )
2015-01-01 19:50:31 +00:00
{
if ( mo - > floorz < mo - > z )
mo - > floorz = mo - > z ;
}
continue ; // This is so you can jump/spring up through quicksand from below.
2014-03-15 16:59:03 +00:00
}
2015-01-01 19:50:31 +00:00
}
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
delta1 = mo - > z - ( bottomheight + ( ( topheight - bottomheight ) / 2 ) ) ;
delta2 = thingtop - ( bottomheight + ( ( topheight - bottomheight ) / 2 ) ) ;
if ( topheight > mo - > floorz & & abs ( delta1 ) < abs ( delta2 )
2016-06-06 19:53:29 +00:00
& & ! ( rover - > flags & FF_REVERSEPLATFORM )
2016-09-22 20:08:36 +00:00
& & ( ( P_MobjFlip ( mo ) * mo - > momz > = 0 ) | | ( ! ( rover - > flags & FF_PLATFORM ) ) ) ) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
2015-01-01 19:50:31 +00:00
{
2016-07-06 04:09:17 +00:00
mo - > floorz = topheight ;
2015-01-01 19:50:31 +00:00
}
2016-07-06 04:09:17 +00:00
if ( bottomheight < mo - > ceilingz & & abs ( delta1 ) > = abs ( delta2 )
2016-06-06 17:11:23 +00:00
& & ! ( rover - > flags & FF_PLATFORM )
2016-09-22 20:08:36 +00:00
& & ( ( P_MobjFlip ( mo ) * mo - > momz > = 0 ) | | ( ! ( rover - > flags & FF_REVERSEPLATFORM ) ) ) ) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
2015-01-01 19:50:31 +00:00
{
2016-07-06 04:09:17 +00:00
mo - > ceilingz = bottomheight ;
2015-01-01 19:50:31 +00:00
}
}
}
//
// P_AdjustMobjFloorZ_PolyObjs
//
// Utility function for P_ZMovement and related
// Adjusts mo->floorz/mo->ceiling accordingly for PolyObjs
//
static void P_AdjustMobjFloorZ_PolyObjs ( mobj_t * mo , subsector_t * subsec )
{
polyobj_t * po = subsec - > polyList ;
sector_t * polysec ;
fixed_t delta1 , delta2 , thingtop ;
fixed_t polytop , polybottom ;
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
thingtop = mo - > z + mo - > height ;
while ( po )
{
if ( ! P_MobjInsidePolyobj ( po , mo ) | | ! ( po - > flags & POF_SOLID ) )
{
po = ( polyobj_t * ) ( po - > 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 ;
2014-03-15 16:59:03 +00:00
}
2015-01-01 19:50:31 +00:00
delta1 = mo - > z - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
delta2 = thingtop - ( polybottom + ( ( polytop - polybottom ) / 2 ) ) ;
if ( polytop > mo - > floorz & & abs ( delta1 ) < abs ( delta2 ) )
mo - > floorz = polytop ;
if ( polybottom < mo - > ceilingz & & abs ( delta1 ) > = abs ( delta2 ) )
mo - > ceilingz = polybottom ;
po = ( polyobj_t * ) ( po - > link . next ) ;
2014-03-15 16:59:03 +00:00
}
2015-01-01 19:50:31 +00:00
}
static void P_RingZMovement ( mobj_t * mo )
{
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
// Intercept the stupid 'fall through 3dfloors' bug
if ( mo - > subsector - > sector - > ffloors )
P_AdjustMobjFloorZ_FFloors ( mo , mo - > subsector - > sector , 1 ) ;
if ( mo - > subsector - > polyList )
P_AdjustMobjFloorZ_PolyObjs ( mo , mo - > subsector ) ;
2014-03-15 16:59:03 +00:00
// adjust height
2016-07-06 04:09:17 +00:00
if ( mo - > eflags & MFE_APPLYPMOMZ & & ! P_IsObjectOnGround ( mo ) )
2014-03-15 16:59:03 +00:00
{
mo - > momz + = mo - > pmomz ;
2016-07-06 04:09:17 +00:00
mo - > eflags & = ~ MFE_APPLYPMOMZ ;
2014-03-15 16:59:03 +00:00
}
mo - > z + = mo - > momz ;
// clip movement
if ( mo - > z < = mo - > floorz & & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
{
mo - > z = mo - > floorz ;
mo - > momz = 0 ;
}
else if ( mo - > z + mo - > height > mo - > ceilingz & & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
{
mo - > z = mo - > ceilingz - mo - > height ;
2014-08-04 03:49:33 +00:00
mo - > momz = 0 ;
2014-03-15 16:59:03 +00:00
}
}
boolean P_CheckDeathPitCollide ( mobj_t * mo )
{
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
if ( ( ( mo - > z < = mo - > subsector - > sector - > floorheight
& & ! ( mo - > eflags & MFE_VERTICALFLIP ) & & ( mo - > subsector - > sector - > flags & SF_FLIPSPECIAL_FLOOR ) )
| | ( mo - > z + mo - > height > = mo - > subsector - > sector - > ceilingheight
& & ( mo - > eflags & MFE_VERTICALFLIP ) & & ( mo - > subsector - > sector - > flags & SF_FLIPSPECIAL_CEILING ) ) )
& & ( GETSECSPECIAL ( mo - > subsector - > sector - > special , 1 ) = = 6
| | GETSECSPECIAL ( mo - > subsector - > sector - > special , 1 ) = = 7 ) )
return true ;
return false ;
}
boolean P_CheckSolidLava ( mobj_t * mo , ffloor_t * rover )
{
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
2016-11-02 20:32:36 +00:00
{
fixed_t topheight =
# ifdef ESLOPE
* rover - > t_slope ? P_GetZAt ( * rover - > t_slope , mo - > x , mo - > y ) :
# endif
* rover - > topheight ;
if ( rover - > flags & FF_SWIMMABLE & & GETSECSPECIAL ( rover - > master - > frontsector - > special , 1 ) = = 3
& & ! ( rover - > master - > flags & ML_BLOCKMONSTERS )
& & ( ( rover - > master - > flags & ML_EFFECT3 ) | | mo - > z - mo - > momz > topheight - FixedMul ( 16 * FRACUNIT , mo - > scale ) ) )
return true ;
}
2014-03-15 16:59:03 +00:00
return false ;
}
//
// P_ZMovement
// Returns false if the mobj was killed/exploded/removed, true otherwise.
//
static boolean P_ZMovement ( mobj_t * mo )
{
fixed_t dist , delta ;
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
// Intercept the stupid 'fall through 3dfloors' bug
if ( mo - > subsector - > sector - > ffloors )
2015-01-01 19:50:31 +00:00
P_AdjustMobjFloorZ_FFloors ( mo , mo - > subsector - > sector , 0 ) ;
if ( mo - > subsector - > polyList )
P_AdjustMobjFloorZ_PolyObjs ( mo , mo - > subsector ) ;
2014-03-15 16:59:03 +00:00
// adjust height
2016-07-06 04:09:17 +00:00
if ( mo - > eflags & MFE_APPLYPMOMZ & & ! P_IsObjectOnGround ( mo ) )
2014-03-15 16:59:03 +00:00
{
mo - > momz + = mo - > pmomz ;
2016-07-06 04:09:17 +00:00
mo - > eflags & = ~ MFE_APPLYPMOMZ ;
2014-03-15 16:59:03 +00:00
}
mo - > z + = mo - > momz ;
2016-06-02 13:39:41 +00:00
# ifdef ESLOPE
if ( mo - > standingslope )
{
if ( mo - > flags & MF_NOCLIPHEIGHT )
mo - > standingslope = NULL ;
else if ( ! P_IsObjectOnGround ( mo ) )
P_SlopeLaunch ( mo ) ;
}
# endif
2014-03-15 16:59:03 +00:00
switch ( mo - > type )
{
case MT_THROWNBOUNCE :
if ( ( mo - > flags & MF_BOUNCE ) & & ( mo - > z < = mo - > floorz | | mo - > z + mo - > height > = mo - > ceilingz ) )
{
mo - > momz = - mo - > momz ;
mo - > z + = mo - > momz ;
S_StartSound ( mo , mo - > info - > activesound ) ;
mo - > threshold + + ;
// Be sure to change the XY one too if you change this.
// Gain lower amounts of time on each bounce.
2016-07-06 04:09:17 +00:00
if ( mo - > fuse & & mo - > threshold < 5 )
2014-03-15 16:59:03 +00:00
mo - > fuse + = ( ( 5 - mo - > threshold ) * TICRATE ) ;
}
break ;
case MT_SKIM :
// skims don't bounce
if ( mo - > z > mo - > watertop & & mo - > z - mo - > momz < = mo - > watertop )
{
mo - > z = mo - > watertop ;
mo - > momz = 0 ;
mo - > flags | = MF_NOGRAVITY ;
}
break ;
case MT_GOOP :
if ( P_CheckDeathPitCollide ( mo ) )
{
P_RemoveMobj ( mo ) ;
return false ;
}
if ( mo - > z < = mo - > floorz & & mo - > momz )
{
P_SetMobjState ( mo , mo - > info - > meleestate ) ;
mo - > momx = mo - > momy = mo - > momz = 0 ;
mo - > z = mo - > floorz ;
if ( mo - > info - > painsound )
S_StartSound ( mo , mo - > info - > painsound ) ;
}
break ;
case MT_FALLINGROCK :
case MT_BIGTUMBLEWEED :
case MT_LITTLETUMBLEWEED :
case MT_SHELL :
2017-11-11 00:25:57 +00:00
// SRB2kart stuff that should die in pits
// Shouldn't stop moving along the Z if there's no speed though!
case MT_FAKEITEM :
2018-06-01 00:51:05 +00:00
case MT_BANANA :
2018-07-23 00:55:18 +00:00
case MT_ORBINAUT :
2018-06-01 00:51:05 +00:00
case MT_JAWZ :
case MT_JAWZ_DUD :
2018-06-25 21:12:01 +00:00
case MT_BALLHOG :
2018-07-25 02:47:09 +00:00
case MT_SSMINE :
2014-03-15 16:59:03 +00:00
// Remove stuff from death pits.
if ( P_CheckDeathPitCollide ( mo ) )
{
P_RemoveMobj ( mo ) ;
return false ;
}
break ;
case MT_REDFLAG :
case MT_BLUEFLAG :
// Remove from death pits. DON'T FUCKING DESPAWN IT DAMMIT
if ( P_CheckDeathPitCollide ( mo ) )
{
mo - > fuse = 1 ;
return false ;
}
break ;
case MT_RING : // Ignore still rings
case MT_COIN :
case MT_BLUEBALL :
case MT_REDTEAMRING :
case MT_BLUETEAMRING :
case MT_FLINGRING :
case MT_FLINGCOIN :
2016-05-29 15:47:38 +00:00
case MT_FLINGEMERALD :
2014-03-15 16:59:03 +00:00
// Remove flinged stuff from death pits.
if ( P_CheckDeathPitCollide ( mo ) )
{
P_RemoveMobj ( mo ) ;
return false ;
}
if ( ! ( mo - > momx | | mo - > momy | | mo - > momz ) )
return true ;
break ;
case MT_BOUNCERING :
case MT_INFINITYRING :
case MT_AUTOMATICRING :
case MT_RAILRING :
case MT_EXPLOSIONRING :
case MT_SCATTERRING :
case MT_GRENADERING :
case MT_BOUNCEPICKUP :
case MT_RAILPICKUP :
case MT_AUTOPICKUP :
case MT_EXPLODEPICKUP :
case MT_SCATTERPICKUP :
case MT_GRENADEPICKUP :
// Remove flinged stuff from death pits.
if ( P_CheckDeathPitCollide ( mo ) & & ( mo - > flags2 & MF2_DONTRESPAWN ) )
{
P_RemoveMobj ( mo ) ;
return false ;
}
if ( ! ( mo - > momx | | mo - > momy | | mo - > momz ) )
return true ;
break ;
case MT_NIGHTSWING :
if ( ! ( mo - > momx | | mo - > momy | | mo - > momz ) )
return true ;
break ;
case MT_FLAMEJET :
case MT_VERTICALFLAMEJET :
if ( ! ( mo - > flags & MF_BOUNCE ) )
return true ;
break ;
case MT_SPIKE :
// Dead spike particles disappear upon ground contact
if ( ( mo - > z < = mo - > floorz | | mo - > z + mo - > height > = mo - > ceilingz ) & & mo - > health < = 0 )
{
P_RemoveMobj ( mo ) ;
return false ;
}
break ;
default :
break ;
}
if ( P_CheckDeathPitCollide ( mo ) )
{
if ( mo - > flags & MF_PUSHABLE )
{
// Remove other pushable items from death pits.
P_RemoveMobj ( mo ) ;
return false ;
}
else if ( mo - > flags & MF_ENEMY | | mo - > flags & MF_BOSS )
{
// Kill enemies and bosses that fall into death pits.
if ( mo - > health )
{
P_KillMobj ( mo , NULL , NULL ) ;
return false ;
}
}
}
if ( P_MobjFlip ( mo ) * mo - > momz < 0
& & ( mo - > flags2 & MF2_CLASSICPUSH ) )
mo - > momx = mo - > momy = 0 ;
if ( mo - > flags & MF_FLOAT & & mo - > target & & mo - > health
& & ! ( mo - > type = = MT_EGGMOBILE ) & & mo - > target - > health > 0 )
{
// float down towards target if too close
if ( ! ( mo - > flags2 & MF2_SKULLFLY ) & & ! ( mo - > flags2 & MF2_INFLOAT ) )
{
dist = P_AproxDistance ( mo - > x - mo - > target - > x , mo - > y - mo - > target - > y ) ;
delta = ( mo - > target - > z + ( mo - > height > > 1 ) ) - mo - > z ;
if ( delta < 0 & & dist < - ( delta * 3 ) )
mo - > z - = FixedMul ( FLOATSPEED , mo - > scale ) ;
else if ( delta > 0 & & dist < ( delta * 3 ) )
mo - > z + = FixedMul ( FLOATSPEED , mo - > scale ) ;
if ( mo - > type = = MT_JETJAW & & mo - > z + mo - > height > mo - > watertop )
mo - > z = mo - > watertop - mo - > height ;
}
}
// clip movement
2014-08-04 03:49:33 +00:00
if ( ( ( mo - > z < = mo - > floorz & & ! ( mo - > eflags & MFE_VERTICALFLIP ) )
| | ( mo - > z + mo - > height > = mo - > ceilingz & & mo - > eflags & MFE_VERTICALFLIP ) )
& & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
vector3_t mom ;
mom . x = mo - > momx ;
mom . y = mo - > momy ;
mom . z = mo - > momz ;
2014-08-04 03:49:33 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > z = mo - > ceilingz - mo - > height ;
else
mo - > z = mo - > floorz ;
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
2017-05-14 13:47:09 +00:00
if ( ! ( mo - > flags & MF_MISSILE ) & & mo - > standingslope ) // You're still on the ground; why are we here?
2016-08-14 05:03:00 +00:00
{
mo - > momz = 0 ;
2016-08-14 14:43:44 +00:00
return true ;
2016-08-14 05:03:00 +00:00
}
2016-07-06 04:09:17 +00:00
P_CheckPosition ( mo , mo - > x , mo - > y ) ; // Sets mo->standingslope correctly
2016-06-30 22:23:50 +00:00
if ( ( ( mo - > eflags & MFE_VERTICALFLIP ) ? tmceilingslope : tmfloorslope ) & & ( mo - > type ! = MT_STEAM ) )
{
2016-07-06 04:09:17 +00:00
mo - > standingslope = ( mo - > eflags & MFE_VERTICALFLIP ) ? tmceilingslope : tmfloorslope ;
2016-06-12 18:27:34 +00:00
P_ReverseQuantizeMomentumToSlope ( & mom , mo - > standingslope ) ;
2016-07-06 04:09:17 +00:00
}
# endif
2014-03-15 16:59:03 +00:00
// hit the floor
if ( mo - > type = = MT_FIREBALL ) // special case for the fireball
2016-07-06 04:09:17 +00:00
mom . z = P_MobjFlip ( mo ) * FixedMul ( 5 * FRACUNIT , mo - > scale ) ;
2014-08-04 03:49:33 +00:00
else if ( mo - > type = = MT_SPINFIRE ) // elemental shield fire is another exception here
;
2014-03-15 16:59:03 +00:00
else if ( mo - > flags & MF_MISSILE )
{
if ( ! ( mo - > flags & MF_NOCLIP ) )
{
// This is a really ugly hard-coded hack to prevent grenades
// from exploding the instant they hit the ground, and then
// another to prevent them from turning into hockey pucks.
// I'm sorry in advance. -SH
// PS: Oh, and Brak's napalm bombs too, now.
2014-03-23 16:00:29 +00:00
if ( mo - > flags & MF_GRENADEBOUNCE )
2014-03-15 16:59:03 +00:00
{
2014-03-23 16:00:29 +00:00
// Going down? (Or up in reverse gravity?)
2016-07-06 04:09:17 +00:00
if ( P_MobjFlip ( mo ) * mom . z < 0 )
2014-03-15 16:59:03 +00:00
{
2014-03-23 16:00:29 +00:00
// If going slower than a fracunit, just stop.
2016-07-06 04:09:17 +00:00
if ( abs ( mom . z ) < FixedMul ( FRACUNIT , mo - > scale ) )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
mom . x = mom . y = mom . z = 0 ;
2014-03-23 16:00:29 +00:00
// Napalm hack
if ( mo - > type = = MT_CYBRAKDEMON_NAPALM_BOMB_LARGE & & mo - > fuse )
mo - > fuse = 1 ;
2014-03-15 16:59:03 +00:00
}
2014-03-23 16:00:29 +00:00
// Otherwise bounce up at half speed.
2014-03-15 16:59:03 +00:00
else
2016-07-06 04:09:17 +00:00
mom . z = - mom . z / 2 ;
2014-03-15 16:59:03 +00:00
S_StartSound ( mo , mo - > info - > activesound ) ;
}
}
// Hack over. Back to your regularly scheduled detonation. -SH
else
{
// Don't explode on the sky!
2014-08-04 03:49:33 +00:00
if ( ! ( mo - > eflags & MFE_VERTICALFLIP )
& & mo - > subsector - > sector - > floorpic = = skyflatnum
2014-03-15 16:59:03 +00:00
& & mo - > subsector - > sector - > floorheight = = mo - > floorz )
P_RemoveMobj ( mo ) ;
2014-08-04 03:49:33 +00:00
else if ( mo - > eflags & MFE_VERTICALFLIP
& & mo - > subsector - > sector - > ceilingpic = = skyflatnum
& & mo - > subsector - > sector - > ceilingheight = = mo - > ceilingz )
P_RemoveMobj ( mo ) ;
2014-03-15 16:59:03 +00:00
else
P_ExplodeMissile ( mo ) ;
return false ;
}
}
}
2016-07-06 04:09:17 +00:00
if ( P_MobjFlip ( mo ) * mom . z < 0 ) // falling
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( ! tmfloorthing | | tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER )
mo - > eflags | = MFE_JUSTHITFLOOR ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( mo - > flags2 & MF2_SKULLFLY ) // the skull slammed into something
2016-07-06 04:09:17 +00:00
mom . z = - mom . z ;
2014-08-04 03:49:33 +00:00
else
2014-03-15 16:59:03 +00:00
// Flingrings bounce
if ( mo - > type = = MT_FLINGRING
| | mo - > type = = MT_FLINGCOIN
| | P_WeaponOrPanel ( mo - > type )
| | mo - > type = = MT_FLINGEMERALD
| | mo - > type = = MT_BIGTUMBLEWEED
| | mo - > type = = MT_LITTLETUMBLEWEED
| | mo - > type = = MT_CANNONBALLDECOR
2014-08-04 03:49:33 +00:00
| | mo - > type = = MT_FALLINGROCK )
2014-03-15 16:59:03 +00:00
{
if ( maptol & TOL_NIGHTS )
2016-07-06 04:09:17 +00:00
mom . z = - FixedDiv ( mom . z , 10 * FRACUNIT ) ;
2014-03-15 16:59:03 +00:00
else
2016-07-06 04:09:17 +00:00
mom . z = - FixedMul ( mom . z , FixedDiv ( 17 * FRACUNIT , 20 * FRACUNIT ) ) ;
2014-03-15 16:59:03 +00:00
if ( mo - > type = = MT_BIGTUMBLEWEED | | mo - > type = = MT_LITTLETUMBLEWEED )
{
2016-07-06 04:09:17 +00:00
if ( abs ( mom . x ) < FixedMul ( STOPSPEED , mo - > scale )
& & abs ( mom . y ) < FixedMul ( STOPSPEED , mo - > scale )
& & abs ( mom . z ) < FixedMul ( STOPSPEED * 3 , mo - > scale ) )
2014-03-15 16:59:03 +00:00
{
2016-08-22 21:54:30 +00:00
if ( mo - > flags2 & MF2_AMBUSH )
2014-03-15 16:59:03 +00:00
{
// If deafed, give the tumbleweed another random kick if it runs out of steam.
2016-07-06 04:09:17 +00:00
mom . z + = P_MobjFlip ( mo ) * FixedMul ( 6 * FRACUNIT , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 2 ) )
mom . x + = FixedMul ( 6 * FRACUNIT , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
else
2016-07-06 04:09:17 +00:00
mom . x - = FixedMul ( 6 * FRACUNIT , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 2 ) )
mom . y + = FixedMul ( 6 * FRACUNIT , mo - > scale ) ;
2014-03-15 16:59:03 +00:00
else
2016-07-06 04:09:17 +00:00
mom . y - = FixedMul ( 6 * FRACUNIT , mo - > scale ) ;
}
# ifdef ESLOPE
else if ( mo - > standingslope & & abs ( mo - > standingslope - > zdelta ) > FRACUNIT > > 8 )
{
// Pop the object up a bit to encourage bounciness
//mom.z = P_MobjFlip(mo)*mo->scale;
}
# endif
else
{
mom . x = mom . y = mom . z = 0 ;
P_SetMobjState ( mo , mo - > info - > spawnstate ) ;
2014-03-15 16:59:03 +00:00
}
}
// Stolen from P_SpawnFriction
mo - > friction = FRACUNIT - 0x100 ;
2016-08-24 01:03:58 +00:00
//mo->movefactor = ((0x10092 - mo->friction)*(0x70))/0x158;
2014-03-15 16:59:03 +00:00
}
else if ( mo - > type = = MT_FALLINGROCK )
{
2016-07-06 04:09:17 +00:00
if ( P_MobjFlip ( mo ) * mom . z > FixedMul ( 2 * FRACUNIT , mo - > scale ) )
2014-03-15 16:59:03 +00:00
S_StartSound ( mo , mo - > info - > activesound + P_RandomKey ( mo - > info - > mass ) ) ;
2016-07-06 04:09:17 +00:00
mom . z / = 2 ; // Rocks not so bouncy
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
if ( abs ( mom . x ) < FixedMul ( STOPSPEED , mo - > scale )
& & abs ( mom . y ) < FixedMul ( STOPSPEED , mo - > scale )
& & abs ( mom . z ) < FixedMul ( STOPSPEED * 3 , mo - > scale ) )
2014-03-15 16:59:03 +00:00
{
P_RemoveMobj ( mo ) ;
return false ;
}
}
else if ( mo - > type = = MT_CANNONBALLDECOR )
{
2016-07-06 04:09:17 +00:00
mom . z / = 2 ;
if ( abs ( mom . z ) < FixedMul ( STOPSPEED * 3 , mo - > scale ) )
mom . z = 0 ;
2014-03-15 16:59:03 +00:00
}
}
2014-08-04 03:49:33 +00:00
else if ( tmfloorthing & & ( tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
2014-03-15 16:59:03 +00:00
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER ) )
2016-07-06 04:09:17 +00:00
mom . z = tmfloorthing - > momz ;
2014-03-15 16:59:03 +00:00
else if ( ! tmfloorthing )
2016-07-06 04:09:17 +00:00
mom . z = 0 ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
else if ( tmfloorthing & & ( tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER ) )
2016-07-06 04:09:17 +00:00
mom . z = tmfloorthing - > momz ;
# ifdef ESLOPE
2016-06-30 22:23:50 +00:00
if ( mo - > standingslope ) { // MT_STEAM will never have a standingslope, see above.
2016-07-06 04:09:17 +00:00
P_QuantizeMomentumToSlope ( & mom , mo - > standingslope ) ;
}
# endif
mo - > momx = mom . x ;
mo - > momy = mom . y ;
mo - > momz = mom . z ;
2014-03-15 16:59:03 +00:00
if ( mo - > type = = MT_STEAM )
return true ;
}
else if ( ! ( mo - > flags & MF_NOGRAVITY ) ) // Gravity here!
{
/// \todo may not be needed (done in P_MobjThinker normally)
mo - > eflags & = ~ MFE_JUSTHITFLOOR ;
P_CheckGravity ( mo , true ) ;
}
2014-08-04 03:49:33 +00:00
if ( ( ( mo - > z + mo - > height > mo - > ceilingz & & ! ( mo - > eflags & MFE_VERTICALFLIP ) )
| | ( mo - > z < mo - > floorz & & mo - > eflags & MFE_VERTICALFLIP ) )
& & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > z = mo - > floorz ;
else
mo - > z = mo - > ceilingz - mo - > height ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( mo - > type = = MT_SPINFIRE )
;
else if ( ( mo - > flags & MF_MISSILE ) & & ! ( mo - > flags & MF_NOCLIP ) )
2014-03-15 16:59:03 +00:00
{
// Hack 2: Electric Boogaloo -SH
2014-08-04 03:49:33 +00:00
if ( mo - > flags & MF_GRENADEBOUNCE )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( P_MobjFlip ( mo ) * mo - > momz > = 0 )
2014-03-15 16:59:03 +00:00
{
mo - > momz = - mo - > momz ;
S_StartSound ( mo , mo - > info - > activesound ) ;
}
}
else
{
// Don't explode on the sky!
2014-08-04 03:49:33 +00:00
if ( ! ( mo - > eflags & MFE_VERTICALFLIP )
& & mo - > subsector - > sector - > ceilingpic = = skyflatnum
2014-03-15 16:59:03 +00:00
& & mo - > subsector - > sector - > ceilingheight = = mo - > ceilingz )
P_RemoveMobj ( mo ) ;
2014-08-04 03:49:33 +00:00
else if ( mo - > eflags & MFE_VERTICALFLIP
& & mo - > subsector - > sector - > floorpic = = skyflatnum
& & mo - > subsector - > sector - > floorheight = = mo - > floorz )
P_RemoveMobj ( mo ) ;
2014-03-15 16:59:03 +00:00
else
P_ExplodeMissile ( mo ) ;
return false ;
}
}
2014-08-04 03:49:33 +00:00
if ( P_MobjFlip ( mo ) * mo - > momz > 0 ) // hit the ceiling
{
if ( mo - > flags2 & MF2_SKULLFLY ) // the skull slammed into something
mo - > momz = - mo - > momz ;
else
// Flags bounce
if ( mo - > type = = MT_REDFLAG | | mo - > type = = MT_BLUEFLAG )
{
if ( maptol & TOL_NIGHTS )
mo - > momz = - FixedDiv ( mo - > momz , 10 * FRACUNIT ) ;
else
mo - > momz = - FixedMul ( mo - > momz , FixedDiv ( 17 * FRACUNIT , 20 * FRACUNIT ) ) ;
}
else
mo - > momz = 0 ;
}
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
2014-03-15 16:59:03 +00:00
return true ;
}
static void P_PlayerZMovement ( mobj_t * mo )
{
I_Assert ( mo ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
if ( ! mo - > player )
return ;
// Intercept the stupid 'fall through 3dfloors' bug
if ( mo - > subsector - > sector - > ffloors )
2015-01-01 19:50:31 +00:00
P_AdjustMobjFloorZ_FFloors ( mo , mo - > subsector - > sector , 0 ) ;
if ( mo - > subsector - > polyList )
P_AdjustMobjFloorZ_PolyObjs ( mo , mo - > subsector ) ;
2014-03-15 16:59:03 +00:00
// check for smooth step up
if ( ( mo - > eflags & MFE_VERTICALFLIP & & mo - > z + mo - > height > mo - > ceilingz )
| | ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > z < mo - > floorz ) )
{
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > player - > viewheight - = ( mo - > z + mo - > height ) - mo - > ceilingz ;
else
mo - > player - > viewheight - = mo - > floorz - mo - > z ;
2018-01-22 22:08:31 +00:00
/*mo->player->deltaviewheight =
( FixedMul ( cv_viewheight . value < < FRACBITS , mo - > scale ) - mo - > player - > viewheight ) > > 3 ; */
2014-03-15 16:59:03 +00:00
}
// adjust height
2016-07-06 04:09:17 +00:00
if ( mo - > eflags & MFE_APPLYPMOMZ & & ! P_IsObjectOnGround ( mo ) )
2014-03-15 16:59:03 +00:00
{
mo - > momz + = mo - > pmomz ;
2016-07-06 04:09:17 +00:00
mo - > eflags & = ~ MFE_APPLYPMOMZ ;
}
2014-03-15 16:59:03 +00:00
mo - > z + = mo - > momz ;
// Have player fall through floor?
if ( mo - > player - > playerstate = = PST_DEAD
| | mo - > player - > playerstate = = PST_REBORN )
return ;
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
if ( mo - > standingslope )
{
if ( mo - > flags & MF_NOCLIPHEIGHT )
mo - > standingslope = NULL ;
else if ( ! P_IsObjectOnGround ( mo ) )
P_SlopeLaunch ( mo ) ;
}
# endif
2014-03-15 16:59:03 +00:00
// clip movement
2014-08-04 03:49:33 +00:00
if ( P_IsObjectOnGround ( mo ) & & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > z = mo - > ceilingz - mo - > height ;
else
mo - > z = mo - > floorz ;
2016-07-06 04:09:17 +00:00
if ( mo - > player - > pflags & PF_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
// bounce off floor if you were flying towards it
if ( ( mo - > eflags & MFE_VERTICALFLIP & & mo - > player - > flyangle > 0 & & mo - > player - > flyangle < 180 )
| | ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > player - > flyangle > 180 & & mo - > player - > flyangle < = 359 ) )
{
if ( mo - > player - > flyangle < 90 | | mo - > player - > flyangle > = 270 )
mo - > player - > flyangle + = P_MobjFlip ( mo ) * 90 ;
else
mo - > player - > flyangle - = P_MobjFlip ( mo ) * 90 ;
mo - > player - > speed = FixedMul ( mo - > player - > speed , 4 * FRACUNIT / 5 ) ;
}
2014-03-15 16:59:03 +00:00
goto nightsdone ;
}
// Get up if you fell.
2017-11-04 14:07:53 +00:00
if ( ( mo - > state = = & states [ mo - > info - > painstate ] | | mo - > state = = & states [ S_KART_SPIN ] )
2016-08-21 02:15:06 +00:00
& & mo - > player - > kartstuff [ k_spinouttimer ] = = 0 & & mo - > player - > kartstuff [ k_squishedtimer ] = = 0 ) // SRB2kart
2017-11-04 17:32:47 +00:00
P_SetPlayerMobjState ( mo , S_KART_STND1 ) ;
2014-03-15 16:59:03 +00:00
2017-02-17 20:03:10 +00:00
# ifdef ESLOPE
if ( ! mo - > standingslope & & ( mo - > eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope ) ) {
// Handle landing on slope during Z movement
P_HandleSlopeLanding ( mo , ( mo - > eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope ) ) ;
}
# endif
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
if ( ! mo - > standingslope & & ( mo - > eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope ) ) {
// Handle landing on slope during Z movement
P_HandleSlopeLanding ( mo , ( mo - > eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope ) ) ;
}
# endif
2014-03-15 16:59:03 +00:00
if ( P_MobjFlip ( mo ) * mo - > momz < 0 ) // falling
{
2016-07-06 04:09:17 +00:00
mo - > pmomz = 0 ; // We're on a new floor, don't keep doing platform movement.
2014-03-15 16:59:03 +00:00
// Squat down. Decrease viewheight for a moment after hitting the ground (hard),
2018-01-22 22:08:31 +00:00
/*if (P_MobjFlip(mo)*mo->momz < -FixedMul(8*FRACUNIT, mo->scale))
2016-07-06 04:09:17 +00:00
mo - > player - > deltaviewheight = ( P_MobjFlip ( mo ) * mo - > momz ) > > 3 ; // make sure momz is negative
2018-01-22 22:08:31 +00:00
*/
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( ! tmfloorthing | | tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER ) // Spin Attack
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
mo - > eflags | = MFE_JUSTHITFLOOR ; // Spin Attack
2014-03-15 16:59:03 +00:00
if ( mo - > eflags & MFE_JUSTHITFLOOR )
{
# ifdef POLYOBJECTS
// Check if we're on a polyobject
// that triggers a linedef executor.
msecnode_t * node ;
2014-11-12 00:55:07 +00:00
boolean stopmovecut = false ;
2014-03-15 16:59:03 +00:00
2016-06-09 13:56:24 +00:00
for ( node = mo - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
sector_t * sec = node - > m_sector ;
subsector_t * newsubsec ;
size_t i ;
for ( i = 0 ; i < numsubsectors ; i + + )
{
newsubsec = & subsectors [ i ] ;
if ( newsubsec - > sector ! = sec )
continue ;
if ( newsubsec - > polyList )
{
polyobj_t * po = newsubsec - > polyList ;
sector_t * polysec ;
while ( po )
{
2015-01-01 19:50:31 +00:00
if ( ! P_MobjInsidePolyobj ( po , mo ) | | ! ( po - > flags & POF_SOLID ) )
2014-03-15 16:59:03 +00:00
{
po = ( polyobj_t * ) ( po - > link . next ) ;
continue ;
}
2015-01-01 19:50:31 +00:00
// We're inside it! Yess...
2014-11-12 00:55:07 +00:00
polysec = po - > lines [ 0 ] - > backsector ;
// Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red
2015-01-01 19:50:31 +00:00
if ( ( mo - > z = = polysec - > ceilingheight | | mo - > z + mo - > height = = polysec - > floorheight ) & & po - > thinker )
2014-11-12 00:55:07 +00:00
stopmovecut = true ;
2015-01-01 19:50:31 +00:00
if ( ! ( po - > flags & POF_LDEXEC ) )
2014-03-15 16:59:03 +00:00
{
po = ( polyobj_t * ) ( po - > link . next ) ;
continue ;
}
if ( mo - > z = = polysec - > ceilingheight )
{
// We're landing on a PO, so check for
// a linedef executor.
// Trigger tags are 32000 + the PO's ID number.
P_LinedefExecute ( ( INT16 ) ( 32000 + po - > id ) , mo , NULL ) ;
}
po = ( polyobj_t * ) ( po - > link . next ) ;
}
}
}
}
2014-11-12 00:55:07 +00:00
if ( ! stopmovecut )
2014-03-15 16:59:03 +00:00
# endif
// Cut momentum in half when you hit the ground and
// aren't pressing any controls.
2017-02-17 20:03:10 +00:00
if ( ! ( mo - > player - > cmd . forwardmove | | mo - > player - > cmd . sidemove ) & & ! mo - > player - > cmomx & & ! mo - > player - > cmomy
2018-07-20 02:37:32 +00:00
& & ! ( mo - > player - > kartstuff [ k_spinouttimer ] ) )
2014-03-15 16:59:03 +00:00
{
mo - > momx = mo - > momx / 2 ;
mo - > momy = mo - > momy / 2 ;
2018-06-05 21:12:42 +00:00
2018-07-20 02:37:32 +00:00
if ( mo - > player - > cmd . buttons & BT_BRAKE & & ! ( mo - > player - > cmd . forwardmove ) ) // FURTHER slowdown if you're braking.
{
mo - > momx = mo - > momx / 2 ;
mo - > momy = mo - > momy / 2 ;
}
2018-06-05 21:12:42 +00:00
}
2014-03-15 16:59:03 +00:00
}
2016-07-06 04:09:17 +00:00
if ( mo - > health )
2014-03-15 16:59:03 +00:00
{
if ( mo - > player - > pflags & PF_GLIDING ) // ground gliding
{
mo - > player - > skidtime = TICRATE ;
mo - > tics = - 1 ;
}
2016-08-21 02:15:06 +00:00
else if ( ( mo - > player - > pflags & PF_JUMPED | | ( mo - > player - > pflags & ( PF_SPINNING | PF_USEDOWN ) ) ! = ( PF_SPINNING | PF_USEDOWN )
2018-06-20 00:20:06 +00:00
| | mo - > player - > powers [ pw_tailsfly ] ) & & ( mo - > player - > kartstuff [ k_spinouttimer ] = = 0 ) ) // SRB2kart
2014-03-15 16:59:03 +00:00
{
2017-11-04 17:32:47 +00:00
K_KartMoveAnimation ( mo - > player ) ;
2014-03-15 16:59:03 +00:00
}
if ( mo - > player - > pflags & PF_JUMPED )
mo - > player - > pflags & = ~ PF_SPINNING ;
else if ( ! ( mo - > player - > pflags & PF_USEDOWN ) )
mo - > player - > pflags & = ~ PF_SPINNING ;
if ( ! ( mo - > player - > pflags & PF_GLIDING ) )
mo - > player - > pflags & = ~ PF_JUMPED ;
mo - > player - > pflags & = ~ PF_THOKKED ;
//mo->player->pflags &= ~PF_GLIDING;
mo - > player - > jumping = 0 ;
mo - > player - > secondjump = 0 ;
mo - > player - > glidetime = 0 ;
mo - > player - > climbing = 0 ;
2014-08-04 03:49:33 +00:00
mo - > player - > powers [ pw_tailsfly ] = 0 ;
2014-03-15 16:59:03 +00:00
}
}
2016-07-06 04:09:17 +00:00
if ( ! ( mo - > player - > pflags & PF_SPINNING ) )
2014-03-15 16:59:03 +00:00
mo - > player - > pflags & = ~ PF_STARTDASH ;
2014-08-04 03:49:33 +00:00
if ( tmfloorthing & & ( tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER ) )
mo - > momz = tmfloorthing - > momz ;
else if ( ! tmfloorthing )
2014-03-15 16:59:03 +00:00
mo - > momz = 0 ;
}
2014-08-04 03:49:33 +00:00
else if ( tmfloorthing & & ( tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER ) )
mo - > momz = tmfloorthing - > momz ;
2014-03-15 16:59:03 +00:00
}
else if ( ! ( mo - > flags & MF_NOGRAVITY ) ) // Gravity here!
{
2014-08-04 03:49:33 +00:00
if ( P_IsObjectInGoop ( mo ) & & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( mo - > z < mo - > floorz )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
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-03-15 16:59:03 +00:00
}
}
2014-08-04 03:49:33 +00:00
/// \todo may not be needed (done in P_MobjThinker normally)
mo - > eflags & = ~ MFE_JUSTHITFLOOR ;
P_CheckGravity ( mo , true ) ;
2014-03-15 16:59:03 +00:00
}
nightsdone :
2014-08-04 03:49:33 +00:00
if ( ( ( mo - > eflags & MFE_VERTICALFLIP & & mo - > z < mo - > floorz ) | | ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > z + mo - > height > mo - > ceilingz ) )
& & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > z = mo - > floorz ;
else
mo - > z = mo - > ceilingz - mo - > height ;
2016-07-06 04:09:17 +00:00
if ( mo - > player - > pflags & PF_NIGHTSMODE )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
// bounce off ceiling if you were flying towards it
if ( ( mo - > eflags & MFE_VERTICALFLIP & & mo - > player - > flyangle > 180 & & mo - > player - > flyangle < = 359 )
| | ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > player - > flyangle > 0 & & mo - > player - > flyangle < 180 ) )
{
if ( mo - > player - > flyangle < 90 | | mo - > player - > flyangle > = 270 )
mo - > player - > flyangle - = P_MobjFlip ( mo ) * 90 ;
else
mo - > player - > flyangle + = P_MobjFlip ( mo ) * 90 ;
mo - > player - > flyangle % = 360 ;
mo - > player - > speed = FixedMul ( mo - > player - > speed , 4 * FRACUNIT / 5 ) ;
}
2014-03-15 16:59:03 +00:00
}
// Check for "Mario" blocks to hit and bounce them
if ( P_MobjFlip ( mo ) * mo - > momz > 0 )
{
msecnode_t * node ;
2016-07-06 04:09:17 +00:00
if ( CheckForMarioBlocks & & ! ( netgame & & mo - > player - > spectator ) ) // Only let the player punch
2014-03-15 16:59:03 +00:00
{
// Search the touching sectors, from side-to-side...
2016-06-09 13:16:02 +00:00
for ( node = mo - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
ffloor_t * rover ;
if ( ! node - > m_sector - > ffloors )
continue ;
for ( rover = node - > m_sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
// Come on, it's time to go...
if ( rover - > flags & FF_MARIO
& & ! ( mo - > eflags & MFE_VERTICALFLIP ) // if you were flipped, your head isn't actually hitting your ceilingz is it?
& & * rover - > bottomheight = = mo - > ceilingz ) // The player's head hit the bottom!
// DO THE MARIO!
EV_MarioBlock ( rover - > master - > frontsector , node - > m_sector , * rover - > topheight , mo ) ;
}
} // Ugly ugly billions of braces! Argh!
}
// hit the ceiling
if ( mariomode )
S_StartSound ( mo , sfx_mario1 ) ;
2016-07-06 04:09:17 +00:00
if ( ! mo - > player - > climbing )
2014-03-15 16:59:03 +00:00
mo - > momz = 0 ;
}
}
}
static boolean P_SceneryZMovement ( mobj_t * mo )
{
// Intercept the stupid 'fall through 3dfloors' bug
if ( mo - > subsector - > sector - > ffloors )
2015-01-01 19:50:31 +00:00
P_AdjustMobjFloorZ_FFloors ( mo , mo - > subsector - > sector , 2 ) ;
if ( mo - > subsector - > polyList )
P_AdjustMobjFloorZ_PolyObjs ( mo , mo - > subsector ) ;
2014-03-15 16:59:03 +00:00
// adjust height
2016-07-06 04:09:17 +00:00
if ( mo - > eflags & MFE_APPLYPMOMZ & & ! P_IsObjectOnGround ( mo ) )
2014-03-15 16:59:03 +00:00
{
mo - > momz + = mo - > pmomz ;
2016-07-06 04:09:17 +00:00
mo - > eflags & = ~ MFE_APPLYPMOMZ ;
2014-03-15 16:59:03 +00:00
}
mo - > z + = mo - > momz ;
switch ( mo - > type )
{
2018-02-08 15:46:07 +00:00
case MT_BOOMEXPLODE :
2018-02-05 22:53:31 +00:00
case MT_BOOMPARTICLE :
if ( ( mo - > flags & MF_BOUNCE ) & & ( mo - > z < = mo - > floorz | | mo - > z + mo - > height > = mo - > ceilingz ) )
{
2018-02-08 15:46:07 +00:00
// set standingslope
P_TryMove ( mo , mo - > x , mo - > y , true ) ;
2018-02-05 22:53:31 +00:00
mo - > momz = - mo - > momz ;
2018-02-08 15:46:07 +00:00
# ifdef ESLOPE
if ( mo - > standingslope )
{
if ( mo - > flags & MF_NOCLIPHEIGHT )
mo - > standingslope = NULL ;
else if ( ! P_IsObjectOnGround ( mo ) )
P_SlopeLaunch ( mo ) ;
}
# endif
2018-02-05 22:53:31 +00:00
S_StartSound ( mo , mo - > info - > activesound ) ;
}
break ;
2014-03-15 16:59:03 +00:00
case MT_SMALLBUBBLE :
if ( mo - > z < = mo - > floorz | | mo - > z + mo - > height > = mo - > ceilingz ) // Hit the floor, so POP!
{
// don't sounds stop when you kill the mobj..?
// yes, they do, making this entirely redundant
P_RemoveMobj ( mo ) ;
return false ;
}
break ;
case MT_MEDIUMBUBBLE :
if ( P_CheckDeathPitCollide ( mo ) ) // Don't split if you fell in a pit
{
P_RemoveMobj ( mo ) ;
return false ;
}
if ( ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > z < = mo - > floorz )
| | ( mo - > eflags & MFE_VERTICALFLIP & & mo - > z + mo - > height > = mo - > ceilingz ) ) // Hit the floor, so split!
{
// split
2016-07-06 04:09:17 +00:00
mobj_t * explodemo = NULL ;
2014-03-15 16:59:03 +00:00
UINT8 prandom , i ;
for ( i = 0 ; i < 4 ; + + i ) // split into four
{
2016-07-06 04:09:17 +00:00
prandom = P_RandomByte ( ) ;
2014-03-15 16:59:03 +00:00
explodemo = P_SpawnMobj ( mo - > x , mo - > y , mo - > z , MT_SMALLBUBBLE ) ;
explodemo - > momx + = ( ( prandom & 0x0F ) < < ( FRACBITS - 2 ) ) * ( i & 2 ? - 1 : 1 ) ;
explodemo - > momy + = ( ( prandom & 0xF0 ) < < ( FRACBITS - 6 ) ) * ( i & 1 ? - 1 : 1 ) ;
explodemo - > destscale = mo - > scale ;
P_SetScale ( explodemo , mo - > scale ) ;
}
if ( mo - > threshold ! = 42 ) // Don't make pop sound if threshold is 42.
S_StartSound ( explodemo , sfx_bubbl1 + P_RandomKey ( 5 ) ) ;
//note that we assign the bubble sound to one of the new bubbles.
// in other words, IT ACTUALLY GETS USED YAAAAAAAY
P_RemoveMobj ( mo ) ;
return false ;
}
else if ( mo - > z < = mo - > floorz | | mo - > z + mo - > height > = mo - > ceilingz ) // Hit the ceiling instead? Just disappear anyway
{
P_RemoveMobj ( mo ) ;
return false ;
}
break ;
case MT_SEED : // now scenery
if ( P_CheckDeathPitCollide ( mo ) ) // No flowers for death pits
{
P_RemoveMobj ( mo ) ;
return false ;
}
// Soniccd seed turns into a flower!
if ( ( ! ( mo - > eflags & MFE_VERTICALFLIP ) & & mo - > z < = mo - > floorz )
| | ( mo - > eflags & MFE_VERTICALFLIP & & mo - > z + mo - > height > = mo - > ceilingz ) )
{
// DO NOT use random numbers here.
// SonicCD mode is console togglable and
// affects demos.
UINT8 rltime = ( leveltime & 4 ) ;
if ( ! rltime )
P_SpawnMobj ( mo - > x , mo - > y , mo - > floorz , MT_GFZFLOWER3 ) ;
else if ( rltime = = 2 )
P_SpawnMobj ( mo - > x , mo - > y , mo - > floorz , MT_GFZFLOWER2 ) ;
else
P_SpawnMobj ( mo - > x , mo - > y , mo - > floorz , MT_GFZFLOWER1 ) ;
P_RemoveMobj ( mo ) ;
return false ;
}
default :
break ;
}
// Fix for any silly pushables like the egg statues that are also scenery for some reason -- Monster Iestyn
if ( P_CheckDeathPitCollide ( mo ) )
{
if ( mo - > flags & MF_PUSHABLE )
{
P_RemoveMobj ( mo ) ;
return false ;
}
}
// clip movement
2014-08-04 03:49:33 +00:00
if ( ( ( mo - > z < = mo - > floorz & & ! ( mo - > eflags & MFE_VERTICALFLIP ) )
| | ( mo - > z + mo - > height > = mo - > ceilingz & & mo - > eflags & MFE_VERTICALFLIP ) )
& & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > z = mo - > ceilingz - mo - > height ;
else
mo - > z = mo - > floorz ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( P_MobjFlip ( mo ) * mo - > momz < 0 ) // falling
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( ! tmfloorthing | | tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
2014-03-15 16:59:03 +00:00
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER )
mo - > eflags | = MFE_JUSTHITFLOOR ; // Spin Attack
2014-08-04 03:49:33 +00:00
if ( tmfloorthing & & ( tmfloorthing - > flags & ( MF_PUSHABLE | MF_MONITOR )
| | tmfloorthing - > flags2 & MF2_STANDONME | | tmfloorthing - > type = = MT_PLAYER ) )
mo - > momz = tmfloorthing - > momz ;
else if ( ! tmfloorthing )
2014-03-15 16:59:03 +00:00
mo - > momz = 0 ;
}
}
else if ( ! ( mo - > flags & MF_NOGRAVITY ) ) // Gravity here!
{
/// \todo may not be needed (done in P_MobjThinker normally)
mo - > eflags & = ~ MFE_JUSTHITFLOOR ;
P_CheckGravity ( mo , true ) ;
}
2014-08-04 03:49:33 +00:00
if ( ( ( mo - > z + mo - > height > mo - > ceilingz & & ! ( mo - > eflags & MFE_VERTICALFLIP ) )
| | ( mo - > z < mo - > floorz & & mo - > eflags & MFE_VERTICALFLIP ) )
& & ! ( mo - > flags & MF_NOCLIPHEIGHT ) )
2014-03-15 16:59:03 +00:00
{
2014-08-04 03:49:33 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > z = mo - > floorz ;
else
mo - > z = mo - > ceilingz - mo - > height ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
if ( P_MobjFlip ( mo ) * mo - > momz > 0 ) // hit the ceiling
mo - > momz = 0 ;
2014-03-15 16:59:03 +00:00
}
return true ;
}
// P_CanRunOnWater
//
// Returns true if player can waterrun on the 3D floor
//
boolean P_CanRunOnWater ( player_t * player , ffloor_t * rover )
{
2016-11-02 20:32:36 +00:00
fixed_t topheight =
# ifdef ESLOPE
* rover - > t_slope ? P_GetZAt ( * rover - > t_slope , player - > mo - > x , player - > mo - > y ) :
# endif
* rover - > topheight ;
2014-03-15 16:59:03 +00:00
if ( ! ( player - > pflags & PF_NIGHTSMODE ) & & ! player - > homing
2016-11-02 20:32:36 +00:00
& & ( ( ( player - > charability = = CA_SWIM ) | | player - > powers [ pw_super ] | | player - > charflags & SF_RUNONWATER ) & & player - > mo - > ceilingz - topheight > = player - > mo - > height )
2014-03-15 16:59:03 +00:00
& & ( rover - > flags & FF_SWIMMABLE ) & & ! ( player - > pflags & PF_SPINNING ) & & player - > speed > FixedMul ( player - > runspeed , player - > mo - > scale )
& & ! ( player - > pflags & PF_SLIDING )
2016-11-02 20:32:36 +00:00
& & abs ( player - > mo - > z - topheight ) < FixedMul ( 30 * FRACUNIT , player - > mo - > scale ) )
2014-03-15 16:59:03 +00:00
return true ;
return false ;
}
//
// P_MobjCheckWater
//
// Check for water, set stuff in mobj_t struct for movement code later.
// This is called either by P_MobjThinker() or P_PlayerThink()
void P_MobjCheckWater ( mobj_t * mobj )
{
boolean waterwasnotset = ( mobj - > watertop = = INT32_MAX ) ;
boolean wasinwater = ( mobj - > eflags & MFE_UNDERWATER ) = = MFE_UNDERWATER ;
boolean wasingoo = ( mobj - > eflags & MFE_GOOWATER ) = = MFE_GOOWATER ;
fixed_t thingtop = mobj - > z + mobj - > height ; // especially for players, infotable height does not neccessarily match actual height
sector_t * sector = mobj - > subsector - > sector ;
ffloor_t * rover ;
player_t * p = mobj - > player ; // Will just be null if not a player.
// Default if no water exists.
2016-07-06 04:09:17 +00:00
mobj - > watertop = mobj - > waterbottom = mobj - > z - 1000 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
// Reset water state.
mobj - > eflags & = ~ ( MFE_UNDERWATER | MFE_TOUCHWATER | MFE_GOOWATER ) ;
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
2016-07-06 04:09:17 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_SWIMMABLE )
| | ( ( ( rover - > flags & FF_BLOCKPLAYER ) & & mobj - > player )
| | ( ( rover - > flags & FF_BLOCKOTHERS ) & & ! mobj - > player ) ) )
continue ;
2016-07-06 04:09:17 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# ifdef ESLOPE
if ( * rover - > t_slope )
topheight = P_GetZAt ( * rover - > t_slope , mobj - > x , mobj - > y ) ;
if ( * rover - > b_slope )
bottomheight = P_GetZAt ( * rover - > b_slope , mobj - > x , mobj - > y ) ;
# endif
2014-03-15 16:59:03 +00:00
if ( mobj - > eflags & MFE_VERTICALFLIP )
{
2016-07-06 04:09:17 +00:00
if ( topheight < ( thingtop - FixedMul ( mobj - > info - > height / 2 , mobj - > scale ) )
| | bottomheight > thingtop )
2014-03-15 16:59:03 +00:00
continue ;
}
else
{
2016-07-06 04:09:17 +00:00
if ( topheight < mobj - > z
| | bottomheight > ( mobj - > z + FixedMul ( mobj - > info - > height / 2 , mobj - > scale ) ) )
2014-03-15 16:59:03 +00:00
continue ;
}
// Set the watertop and waterbottom
2016-07-06 04:09:17 +00:00
mobj - > watertop = topheight ;
mobj - > waterbottom = bottomheight ;
2014-03-15 16:59:03 +00:00
// Just touching the water?
2016-07-06 04:09:17 +00:00
if ( ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & thingtop - FixedMul ( mobj - > info - > height , mobj - > scale ) < bottomheight )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + FixedMul ( mobj - > info - > height , mobj - > scale ) > topheight ) )
2014-03-15 16:59:03 +00:00
{
mobj - > eflags | = MFE_TOUCHWATER ;
if ( rover - > flags & FF_GOOWATER & & ! ( mobj - > flags & MF_NOGRAVITY ) )
mobj - > eflags | = MFE_GOOWATER ;
}
// Actually in the water?
2016-07-06 04:09:17 +00:00
if ( ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & thingtop - FixedMul ( mobj - > info - > height / 2 , mobj - > scale ) > bottomheight )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + FixedMul ( mobj - > info - > height / 2 , mobj - > scale ) < topheight ) )
2014-03-15 16:59:03 +00:00
{
mobj - > eflags | = MFE_UNDERWATER ;
if ( rover - > flags & FF_GOOWATER & & ! ( mobj - > flags & MF_NOGRAVITY ) )
mobj - > eflags | = MFE_GOOWATER ;
}
}
// Specific things for underwater players
if ( p & & ( mobj - > eflags & MFE_UNDERWATER ) = = MFE_UNDERWATER )
{
if ( ! ( ( p - > powers [ pw_super ] ) | | ( p - > powers [ pw_invulnerability ] ) ) )
{
if ( ( p - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ATTRACT )
{ // Water removes attract shield.
p - > powers [ pw_shield ] = p - > powers [ pw_shield ] & SH_STACK ;
P_FlashPal ( p , PAL_WHITE , 1 ) ;
}
}
// Drown timer setting
2016-08-21 21:55:35 +00:00
/* // SRB2kart - Can't drown.
2014-03-15 16:59:03 +00:00
if ( ( p - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_ELEMENTAL // Has elemental
| | ( p - > exiting ) // Or exiting
| | ( maptol & TOL_NIGHTS ) // Or in NiGHTS mode
| | ( mariomode ) ) // Or in Mario mode...
2016-08-21 21:55:35 +00:00
*/
2014-03-15 16:59:03 +00:00
{
// Can't drown.
p - > powers [ pw_underwater ] = 0 ;
}
2016-08-21 21:55:35 +00:00
/*
2014-03-15 16:59:03 +00:00
else if ( p - > powers [ pw_underwater ] < = 0 ) // No underwater timer set
{
// Then we'll set it!
p - > powers [ pw_underwater ] = underwatertics + 1 ;
}
2016-08-21 21:55:35 +00:00
*/
2014-03-15 16:59:03 +00:00
}
// The rest of this code only executes on a water state change.
if ( waterwasnotset | | ! ! ( mobj - > eflags & MFE_UNDERWATER ) = = wasinwater )
return ;
// Spectators and dead players also don't count.
if ( p & & ( p - > spectator | | p - > playerstate ! = PST_LIVE ) )
return ;
if ( ( p ) // Players
| | ( mobj - > flags & MF_PUSHABLE ) // Pushables
| | ( ( mobj - > info - > flags & MF_PUSHABLE ) & & mobj - > fuse ) // Previously pushable, might be moving still
)
{
// Check to make sure you didn't just cross into a sector to jump out of
// that has shallower water than the block you were originally in.
if ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > watertop - mobj - > floorz < = FixedMul ( mobj - > info - > height , mobj - > scale ) > > 1 )
return ;
if ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > ceilingz - mobj - > waterbottom < = FixedMul ( mobj - > info - > height , mobj - > scale ) > > 1 )
return ;
if ( ( mobj - > eflags & MFE_GOOWATER | | wasingoo ) ) { // Decide what happens to your momentum when you enter/leave goopy water.
2016-07-06 04:09:17 +00:00
if ( P_MobjFlip ( mobj ) * mobj - > momz < 0 ) // You are entering the goo?
mobj - > momz = FixedMul ( mobj - > momz , FixedDiv ( 2 * FRACUNIT , 5 * FRACUNIT ) ) ; // kill momentum significantly, to make the goo feel thick.
2014-03-15 16:59:03 +00:00
}
else if ( wasinwater & & P_MobjFlip ( mobj ) * mobj - > momz > 0 )
mobj - > momz = FixedMul ( mobj - > momz , FixedDiv ( 780 * FRACUNIT , 457 * FRACUNIT ) ) ; // Give the mobj a little out-of-water boost.
if ( P_MobjFlip ( mobj ) * mobj - > momz < 0 )
{
if ( ( mobj - > eflags & MFE_VERTICALFLIP & & thingtop - ( FixedMul ( mobj - > info - > height , mobj - > scale ) > > 1 ) - mobj - > momz < = mobj - > waterbottom )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + ( FixedMul ( mobj - > info - > height , mobj - > scale ) > > 1 ) - mobj - > momz > = mobj - > watertop ) )
{
// Spawn a splash
mobj_t * splish ;
if ( mobj - > eflags & MFE_VERTICALFLIP )
{
splish = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > waterbottom - FixedMul ( mobjinfo [ MT_SPLISH ] . height , mobj - > scale ) , MT_SPLISH ) ;
splish - > flags2 | = MF2_OBJECTFLIP ;
splish - > eflags | = MFE_VERTICALFLIP ;
}
else
splish = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > watertop , MT_SPLISH ) ;
splish - > destscale = mobj - > scale ;
P_SetScale ( splish , mobj - > scale ) ;
}
// skipping stone!
2018-07-17 02:51:31 +00:00
if ( p & & p - > kartstuff [ k_waterskip ] < 2
& & ( ( p - > speed / 2 > abs ( mobj - > momz ) ) // Going more forward than horizontal, so you can skip across the water.
| | ( p - > speed > K_GetKartSpeed ( p , false ) / 4 & & p - > kartstuff [ k_waterskip ] ) ) // Already skipped once, so you can skip once more!
2014-03-15 16:59:03 +00:00
& & ( ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & thingtop - mobj - > momz > mobj - > watertop )
| | ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z - mobj - > momz < mobj - > waterbottom ) ) )
{
2018-07-17 02:51:31 +00:00
const fixed_t min = 6 < < FRACBITS ;
//const fixed_t max = 8<<FRACBITS;
mobj - > momx = mobj - > momx / 2 ;
mobj - > momy = mobj - > momy / 2 ;
2014-03-15 16:59:03 +00:00
mobj - > momz = - mobj - > momz / 2 ;
2018-07-17 02:51:31 +00:00
if ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > momz < FixedMul ( min , mobj - > scale ) )
mobj - > momz = FixedMul ( min , mobj - > scale ) ;
else if ( mobj - > eflags & MFE_VERTICALFLIP & & mobj - > momz > FixedMul ( - min , mobj - > scale ) )
mobj - > momz = FixedMul ( - min , mobj - > scale ) ;
/*if (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->momz > FixedMul(max, mobj->scale))
mobj - > momz = FixedMul ( max , mobj - > scale ) ;
else if ( mobj - > eflags & MFE_VERTICALFLIP & & mobj - > momz < FixedMul ( - max , mobj - > scale ) )
mobj - > momz = FixedMul ( - max , mobj - > scale ) ; */
p - > kartstuff [ k_waterskip ] + + ;
2014-03-15 16:59:03 +00:00
}
}
else if ( P_MobjFlip ( mobj ) * mobj - > momz > 0 )
{
if ( ( ( mobj - > eflags & MFE_VERTICALFLIP & & thingtop - ( FixedMul ( mobj - > info - > height , mobj - > scale ) > > 1 ) - mobj - > momz > mobj - > waterbottom )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + ( FixedMul ( mobj - > info - > height , mobj - > scale ) > > 1 ) - mobj - > momz < mobj - > watertop ) )
& & ! ( mobj - > eflags & MFE_UNDERWATER ) ) // underwater check to prevent splashes on opposite side
{
// Spawn a splash
mobj_t * splish ;
if ( mobj - > eflags & MFE_VERTICALFLIP )
{
splish = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > waterbottom - FixedMul ( mobjinfo [ MT_SPLISH ] . height , mobj - > scale ) , MT_SPLISH ) ;
splish - > flags2 | = MF2_OBJECTFLIP ;
splish - > eflags | = MFE_VERTICALFLIP ;
}
else
splish = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > watertop , MT_SPLISH ) ;
splish - > destscale = mobj - > scale ;
P_SetScale ( splish , mobj - > scale ) ;
}
}
// Time to spawn the bubbles!
{
INT32 i ;
INT32 bubblecount ;
UINT8 prandom [ 4 ] ;
mobj_t * bubble ;
mobjtype_t bubbletype ;
if ( mobj - > eflags & MFE_GOOWATER | | wasingoo )
S_StartSound ( mobj , sfx_ghit ) ;
else
S_StartSound ( mobj , sfx_splish ) ; // And make a sound!
bubblecount = FixedDiv ( abs ( mobj - > momz ) , mobj - > scale ) > > ( FRACBITS - 1 ) ;
// Max bubble count
if ( bubblecount > 128 )
bubblecount = 128 ;
// Create tons of bubbles
for ( i = 0 ; i < bubblecount ; i + + )
{
2016-07-06 04:09:17 +00:00
// P_RandomByte()s are called individually to allow consistency
2014-03-15 16:59:03 +00:00
// across various compilers, since the order of function calls
// in C is not part of the ANSI specification.
2016-07-06 04:09:17 +00:00
prandom [ 0 ] = P_RandomByte ( ) ;
prandom [ 1 ] = P_RandomByte ( ) ;
prandom [ 2 ] = P_RandomByte ( ) ;
prandom [ 3 ] = P_RandomByte ( ) ;
2014-03-15 16:59:03 +00:00
bubbletype = MT_SMALLBUBBLE ;
if ( ! ( prandom [ 0 ] & 0x3 ) ) // medium bubble chance up to 64 from 32
bubbletype = MT_MEDIUMBUBBLE ;
bubble = P_SpawnMobj (
mobj - > x + FixedMul ( ( prandom [ 1 ] < < ( FRACBITS - 3 ) ) * ( prandom [ 0 ] & 0x80 ? 1 : - 1 ) , mobj - > scale ) ,
mobj - > y + FixedMul ( ( prandom [ 2 ] < < ( FRACBITS - 3 ) ) * ( prandom [ 0 ] & 0x40 ? 1 : - 1 ) , mobj - > scale ) ,
mobj - > z + FixedMul ( ( prandom [ 3 ] < < ( FRACBITS - 2 ) ) , mobj - > scale ) , bubbletype ) ;
if ( bubble )
{
if ( P_MobjFlip ( mobj ) * mobj - > momz < 0 )
bubble - > momz = mobj - > momz > > 4 ;
else
bubble - > momz = 0 ;
bubble - > destscale = mobj - > scale ;
P_SetScale ( bubble , mobj - > scale ) ;
}
}
}
}
}
static void P_SceneryCheckWater ( mobj_t * mobj )
{
sector_t * sector ;
// Default if no water exists.
2016-07-06 04:09:17 +00:00
mobj - > watertop = mobj - > waterbottom = mobj - > z - 1000 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
// see if we are in water, and set some flags for later
sector = mobj - > subsector - > sector ;
if ( sector - > ffloors )
{
ffloor_t * rover ;
2016-07-06 04:09:17 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
mobj - > eflags & = ~ ( MFE_UNDERWATER | MFE_TOUCHWATER ) ;
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_SWIMMABLE ) | | rover - > flags & FF_BLOCKOTHERS )
continue ;
2016-07-06 04:09:17 +00:00
topheight = * rover - > topheight ;
bottomheight = * rover - > bottomheight ;
# ifdef ESLOPE
if ( * rover - > t_slope )
topheight = P_GetZAt ( * rover - > t_slope , mobj - > x , mobj - > y ) ;
if ( * rover - > b_slope )
bottomheight = P_GetZAt ( * rover - > b_slope , mobj - > x , mobj - > y ) ;
# endif
if ( topheight < = mobj - > z
| | bottomheight > ( mobj - > z + FixedMul ( mobj - > info - > height > > 1 , mobj - > scale ) ) )
2014-03-15 16:59:03 +00:00
continue ;
2016-07-06 04:09:17 +00:00
if ( mobj - > z + FixedMul ( mobj - > info - > height , mobj - > scale ) > topheight )
2014-03-15 16:59:03 +00:00
mobj - > eflags | = MFE_TOUCHWATER ;
else
mobj - > eflags & = ~ MFE_TOUCHWATER ;
// Set the watertop and waterbottom
2016-07-06 04:09:17 +00:00
mobj - > watertop = topheight ;
mobj - > waterbottom = bottomheight ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
if ( mobj - > z + FixedMul ( mobj - > info - > height > > 1 , mobj - > scale ) < topheight )
2014-03-15 16:59:03 +00:00
mobj - > eflags | = MFE_UNDERWATER ;
else
mobj - > eflags & = ~ MFE_UNDERWATER ;
}
}
else
mobj - > eflags & = ~ ( MFE_UNDERWATER | MFE_TOUCHWATER ) ;
}
static boolean P_CameraCheckHeat ( camera_t * thiscam )
{
sector_t * sector ;
2014-08-04 03:49:33 +00:00
fixed_t halfheight = thiscam - > z + ( thiscam - > height > > 1 ) ;
2014-03-15 16:59:03 +00:00
// see if we are in water
sector = thiscam - > subsector - > sector ;
if ( P_FindSpecialLineFromTag ( 13 , sector - > tag , - 1 ) ! = - 1 )
return true ;
if ( sector - > ffloors )
{
ffloor_t * rover ;
for ( rover = sector - > ffloors ; rover ; rover = rover - > next )
{
2014-08-04 03:49:33 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) )
2014-03-15 16:59:03 +00:00
continue ;
2014-08-04 03:49:33 +00:00
2016-07-06 04:09:17 +00:00
if ( halfheight > = (
# ifdef ESLOPE
* rover - > t_slope ? P_GetZAt ( * rover - > t_slope , thiscam - > x , thiscam - > y ) :
# endif
* rover - > topheight ) | | halfheight < = (
# ifdef ESLOPE
* rover - > b_slope ? P_GetZAt ( * rover - > b_slope , thiscam - > x , thiscam - > y ) :
# endif
* rover - > bottomheight ) )
2014-03-15 16:59:03 +00:00
continue ;
2014-08-04 03:49:33 +00:00
if ( P_FindSpecialLineFromTag ( 13 , rover - > master - > frontsector - > tag , - 1 ) ! = - 1 )
return true ;
2014-03-15 16:59:03 +00:00
}
}
return false ;
}
static boolean P_CameraCheckWater ( camera_t * thiscam )
{
sector_t * sector ;
2014-08-04 03:49:33 +00:00
fixed_t halfheight = thiscam - > z + ( thiscam - > height > > 1 ) ;
2014-03-15 16:59:03 +00:00
// see if we are in water
sector = thiscam - > 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 ) | | rover - > flags & FF_BLOCKOTHERS )
continue ;
2014-08-04 03:49:33 +00:00
2016-07-06 04:09:17 +00:00
if ( halfheight > = (
# ifdef ESLOPE
* rover - > t_slope ? P_GetZAt ( * rover - > t_slope , thiscam - > x , thiscam - > y ) :
# endif
* rover - > topheight ) | | halfheight < = (
# ifdef ESLOPE
* rover - > b_slope ? P_GetZAt ( * rover - > b_slope , thiscam - > x , thiscam - > y ) :
# endif
* rover - > bottomheight ) )
2014-03-15 16:59:03 +00:00
continue ;
2014-08-04 03:49:33 +00:00
return true ;
2014-03-15 16:59:03 +00:00
}
}
return false ;
}
void P_DestroyRobots ( void )
{
// Search through all the thinkers for enemies.
mobj_t * mo ;
thinker_t * think ;
for ( think = thinkercap . next ; think ! = & thinkercap ; think = think - > next )
{
if ( think - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ; // not a mobj thinker
mo = ( mobj_t * ) think ;
if ( mo - > health < = 0 | | ! ( mo - > flags & MF_ENEMY | | mo - > flags & MF_BOSS ) )
continue ; // not a valid enemy
if ( mo - > type = = MT_PLAYER ) // Don't chase after other players!
continue ;
// Found a target enemy
P_KillMobj ( mo , players [ consoleplayer ] . mo , players [ consoleplayer ] . mo ) ;
}
}
// P_CameraThinker
//
// Process the mobj-ish required functions of the camera
boolean P_CameraThinker ( player_t * player , camera_t * thiscam , boolean resetcalled )
{
boolean itsatwodlevel = false ;
postimg_t postimg = postimg_none ;
if ( twodlevel
| | ( thiscam = = & camera & & players [ displayplayer ] . mo & & ( players [ displayplayer ] . mo - > flags2 & MF2_TWOD ) )
2017-12-17 03:32:43 +00:00
| | ( thiscam = = & camera2 & & players [ secondarydisplayplayer ] . mo & & ( players [ secondarydisplayplayer ] . mo - > flags2 & MF2_TWOD ) )
| | ( thiscam = = & camera3 & & players [ thirddisplayplayer ] . mo & & ( players [ thirddisplayplayer ] . mo - > flags2 & MF2_TWOD ) )
| | ( thiscam = = & camera4 & & players [ fourthdisplayplayer ] . mo & & ( players [ fourthdisplayplayer ] . mo - > flags2 & MF2_TWOD ) ) )
2014-03-15 16:59:03 +00:00
itsatwodlevel = true ;
2018-07-23 22:50:41 +00:00
if ( encoremode )
2017-12-12 05:07:14 +00:00
postimg = postimg_mirror ;
else if ( player - > pflags & PF_FLIPCAM & & ! ( player - > pflags & PF_NIGHTSMODE ) & & player - > mo - > eflags & MFE_VERTICALFLIP )
2014-03-15 16:59:03 +00:00
postimg = postimg_flip ;
2014-08-04 03:49:33 +00:00
else if ( player - > awayviewtics )
{
camera_t dummycam ;
dummycam . subsector = player - > awayviewmobj - > subsector ;
dummycam . x = player - > awayviewmobj - > x ;
dummycam . y = player - > awayviewmobj - > y ;
dummycam . z = player - > awayviewmobj - > z ;
dummycam . height = 40 * FRACUNIT ; // alt view height is 20*FRACUNIT
// Are we in water?
if ( P_CameraCheckWater ( & dummycam ) )
postimg = postimg_water ;
else if ( P_CameraCheckHeat ( & dummycam ) )
postimg = postimg_heat ;
}
else
{
// Are we in water?
if ( P_CameraCheckWater ( thiscam ) )
postimg = postimg_water ;
else if ( P_CameraCheckHeat ( thiscam ) )
postimg = postimg_heat ;
}
2014-03-15 16:59:03 +00:00
if ( postimg ! = postimg_none )
{
2017-12-19 01:59:04 +00:00
if ( splitscreen & & player = = & players [ secondarydisplayplayer ] )
2014-03-15 16:59:03 +00:00
postimgtype2 = postimg ;
2017-12-19 01:59:04 +00:00
else if ( splitscreen > 1 & & player = = & players [ thirddisplayplayer ] )
2017-12-17 06:21:24 +00:00
postimgtype3 = postimg ;
2017-12-19 01:59:04 +00:00
else if ( splitscreen > 2 & & player = = & players [ fourthdisplayplayer ] )
2017-12-17 06:21:24 +00:00
postimgtype4 = postimg ;
2014-03-15 16:59:03 +00:00
else
postimgtype = postimg ;
}
if ( thiscam - > momx | | thiscam - > momy )
{
if ( ! P_TryCameraMove ( thiscam - > x + thiscam - > momx , thiscam - > y + thiscam - > momy , thiscam ) )
{ // Never fails for 2D mode.
mobj_t dummy ;
dummy . thinker . function . acp1 = ( actionf_p1 ) P_MobjThinker ;
dummy . subsector = thiscam - > subsector ;
dummy . x = thiscam - > x ;
dummy . y = thiscam - > y ;
dummy . z = thiscam - > z ;
dummy . height = thiscam - > height ;
2018-06-25 13:18:30 +00:00
if ( ! resetcalled & & ! ( player - > pflags & PF_NOCLIP | | leveltime < introtime ) & & ! P_CheckSight ( & dummy , player - > mo ) ) // TODO: "P_CheckCameraSight" instead.
2014-03-15 16:59:03 +00:00
P_ResetCamera ( player , thiscam ) ;
else
P_SlideCameraMove ( thiscam ) ;
if ( resetcalled ) // Okay this means the camera is fully reset.
return true ;
}
}
if ( ! itsatwodlevel )
P_CheckCameraPosition ( thiscam - > x , thiscam - > y , thiscam ) ;
thiscam - > subsector = R_PointInSubsector ( thiscam - > x , thiscam - > y ) ;
thiscam - > floorz = tmfloorz ;
thiscam - > ceilingz = tmceilingz ;
2016-07-06 04:09:17 +00:00
if ( thiscam - > momz | | player - > mo - > pmomz )
2014-03-15 16:59:03 +00:00
{
// adjust height
2016-07-06 04:09:17 +00:00
thiscam - > z + = thiscam - > momz + player - > mo - > pmomz ;
2014-03-15 16:59:03 +00:00
2018-06-25 13:18:30 +00:00
# ifndef NOCLIPCAM
if ( ! itsatwodlevel & & ! ( player - > pflags & PF_NOCLIP | | leveltime < introtime ) )
2014-03-15 16:59:03 +00:00
{
// clip movement
if ( thiscam - > z < = thiscam - > floorz ) // hit the floor
{
fixed_t cam_height = cv_cam_height . value ;
thiscam - > z = thiscam - > floorz ;
if ( player = = & players [ secondarydisplayplayer ] )
cam_height = cv_cam2_height . value ;
2017-12-17 06:21:24 +00:00
if ( player = = & players [ thirddisplayplayer ] )
cam_height = cv_cam3_height . value ;
if ( player = = & players [ fourthdisplayplayer ] )
cam_height = cv_cam4_height . value ;
2014-03-15 16:59:03 +00:00
if ( thiscam - > z > player - > mo - > z + player - > mo - > height + FixedMul ( cam_height * FRACUNIT + 16 * FRACUNIT , player - > mo - > scale ) )
{
if ( ! resetcalled )
P_ResetCamera ( player , thiscam ) ;
return true ;
}
}
if ( thiscam - > z + thiscam - > height > thiscam - > ceilingz )
{
if ( thiscam - > momz > 0 )
{
// hit the ceiling
thiscam - > momz = 0 ;
}
thiscam - > z = thiscam - > ceilingz - thiscam - > height ;
if ( thiscam - > z + thiscam - > height < player - > mo - > z - player - > mo - > height )
{
if ( ! resetcalled )
P_ResetCamera ( player , thiscam ) ;
return true ;
}
}
}
2018-06-25 13:18:30 +00:00
# endif
2014-03-15 16:59:03 +00:00
}
if ( itsatwodlevel
| | ( thiscam - > ceilingz - thiscam - > z < thiscam - > height
& & thiscam - > ceilingz > = thiscam - > z ) )
{
thiscam - > ceilingz = thiscam - > z + thiscam - > height ;
thiscam - > floorz = thiscam - > z ;
}
return false ;
}
//
// P_PlayerMobjThinker
//
static void P_PlayerMobjThinker ( mobj_t * mobj )
{
msecnode_t * node ;
I_Assert ( mobj ! = NULL ) ;
2016-07-06 04:09:17 +00:00
I_Assert ( mobj - > player ! = NULL ) ;
2014-03-15 16:59:03 +00:00
I_Assert ( ! P_MobjWasRemoved ( mobj ) ) ;
P_MobjCheckWater ( mobj ) ;
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
P_ButteredSlope ( mobj ) ;
# endif
2014-03-15 16:59:03 +00:00
// momentum movement
mobj - > eflags & = ~ MFE_JUSTSTEPPEDDOWN ;
// Zoom tube
if ( mobj - > tracer & & mobj - > tracer - > type = = MT_TUBEWAYPOINT )
{
P_UnsetThingPosition ( mobj ) ;
mobj - > x + = mobj - > momx ;
mobj - > y + = mobj - > momy ;
mobj - > z + = mobj - > momz ;
P_SetThingPosition ( mobj ) ;
P_CheckPosition ( mobj , mobj - > x , mobj - > y ) ;
goto animonly ;
}
2016-07-06 04:09:17 +00:00
else if ( mobj - > player - > pflags & PF_MACESPIN & & mobj - > tracer )
2014-03-15 16:59:03 +00:00
{
P_CheckPosition ( mobj , mobj - > x , mobj - > y ) ;
goto animonly ;
}
// Needed for gravity boots
P_CheckGravity ( mobj , false ) ;
if ( mobj - > momx | | mobj - > momy )
{
P_XYMovement ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
else
P_TryMove ( mobj , mobj - > x , mobj - > y , true ) ;
2016-07-06 04:09:17 +00:00
if ( ! ( netgame & & mobj - > player - > spectator ) )
2014-03-15 16:59:03 +00:00
{
// Crumbling platforms
2016-06-09 13:56:24 +00:00
for ( node = mobj - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
fixed_t topheight , bottomheight ;
2014-03-15 16:59:03 +00:00
ffloor_t * rover ;
for ( rover = node - > m_sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_CRUMBLE ) )
continue ;
2016-07-06 04:09:17 +00:00
topheight = P_GetSpecialTopZ ( mobj , sectors + rover - > secnum , node - > m_sector ) ;
bottomheight = P_GetSpecialBottomZ ( mobj , sectors + rover - > secnum , node - > m_sector ) ;
if ( ( topheight = = mobj - > z & & ! ( mobj - > eflags & MFE_VERTICALFLIP ) )
| | ( bottomheight = = mobj - > z + mobj - > height & & mobj - > eflags & MFE_VERTICALFLIP ) ) // You nut.
2014-03-15 16:59:03 +00:00
EV_StartCrumble ( rover - > master - > frontsector , rover , ( rover - > flags & FF_FLOATBOB ) , mobj - > player , rover - > alpha , ! ( rover - > flags & FF_NORETURN ) ) ;
}
}
}
// Check for floating water platforms and bounce them
if ( CheckForFloatBob & & P_MobjFlip ( mobj ) * mobj - > momz < 0 )
{
boolean thereiswater = false ;
2016-06-09 13:56:24 +00:00
for ( node = mobj - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
if ( node - > m_sector - > ffloors )
{
ffloor_t * rover ;
// Get water boundaries first
for ( rover = node - > m_sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
if ( rover - > flags & FF_SWIMMABLE ) // Is there water?
{
thereiswater = true ;
break ;
}
}
}
}
if ( thereiswater )
{
2016-06-09 13:56:24 +00:00
for ( node = mobj - > touching_sectorlist ; node ; node = node - > m_sectorlist_next )
2014-03-15 16:59:03 +00:00
{
if ( node - > m_sector - > ffloors )
{
ffloor_t * rover ;
for ( rover = node - > m_sector - > ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) | | ! ( rover - > flags & FF_FLOATBOB ) )
continue ;
if ( ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & abs ( * rover - > topheight - mobj - > z ) < = abs ( mobj - > momz ) ) // The player is landing on the cheese!
| | ( mobj - > eflags & MFE_VERTICALFLIP & & abs ( * rover - > bottomheight - ( mobj - > z + mobj - > height ) ) < = abs ( mobj - > momz ) ) )
{
// Initiate a 'bouncy' elevator function
// which slowly diminishes.
EV_BounceSector ( rover - > master - > frontsector , - mobj - > momz , rover - > master ) ;
}
}
}
}
} // Ugly ugly billions of braces! Argh!
}
// always do the gravity bit now, that's simpler
// BUT CheckPosition only if wasn't done before.
if ( ! ( mobj - > eflags & MFE_ONGROUND ) | | mobj - > momz
| | ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + mobj - > height ! = mobj - > ceilingz )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z ! = mobj - > floorz )
2014-08-04 03:49:33 +00:00
| | P_IsObjectInGoop ( mobj ) )
2014-03-15 16:59:03 +00:00
{
P_PlayerZMovement ( mobj ) ;
P_CheckPosition ( mobj , mobj - > x , mobj - > y ) ; // Need this to pick up objects!
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
else
{
2016-07-06 04:09:17 +00:00
if ( ! ( mobj - > player - > pflags & PF_NIGHTSMODE ) ) // "jumping" is used for drilling
2014-08-04 03:49:33 +00:00
mobj - > player - > jumping = 0 ;
2016-07-06 04:09:17 +00:00
mobj - > player - > pflags & = ~ PF_JUMPED ;
if ( mobj - > player - > secondjump | | mobj - > player - > powers [ pw_tailsfly ] )
{
mobj - > player - > secondjump = 0 ;
mobj - > player - > powers [ pw_tailsfly ] = 0 ;
2016-08-15 03:51:08 +00:00
P_SetPlayerMobjState ( mobj , S_KART_WALK1 ) ; // SRB2kart - was S_PLAY_RUN1
2014-08-04 03:49:33 +00:00
}
2014-03-15 16:59:03 +00:00
mobj - > eflags & = ~ MFE_JUSTHITFLOOR ;
}
animonly :
// cycle through states,
// calling action functions at transitions
if ( mobj - > tics ! = - 1 )
{
mobj - > tics - - ;
// you can cycle through multiple states in a tic
if ( ! mobj - > tics )
if ( ! P_SetPlayerMobjState ( mobj , mobj - > state - > nextstate ) )
return ; // freed itself
}
}
static void CalculatePrecipFloor ( precipmobj_t * mobj )
{
// recalculate floorz each time
const sector_t * mobjsecsubsec ;
if ( mobj & & mobj - > subsector & & mobj - > subsector - > sector )
mobjsecsubsec = mobj - > subsector - > sector ;
else
return ;
2016-07-06 04:09:17 +00:00
mobj - > floorz =
# ifdef ESLOPE
mobjsecsubsec - > f_slope ? P_GetZAt ( mobjsecsubsec - > f_slope , mobj - > x , mobj - > y ) :
# endif
mobjsecsubsec - > floorheight ;
2014-03-15 16:59:03 +00:00
if ( mobjsecsubsec - > ffloors )
{
ffloor_t * rover ;
2016-07-06 04:09:17 +00:00
fixed_t topheight ;
2014-03-15 16:59:03 +00:00
for ( rover = mobjsecsubsec - > ffloors ; rover ; rover = rover - > next )
{
// If it exists, it'll get rained on.
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
if ( ! ( rover - > flags & FF_BLOCKOTHERS ) & & ! ( rover - > flags & FF_SWIMMABLE ) )
continue ;
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE
if ( * rover - > t_slope )
topheight = P_GetZAt ( * rover - > t_slope , mobj - > x , mobj - > y ) ;
else
# endif
topheight = * rover - > topheight ;
if ( topheight > mobj - > floorz )
mobj - > floorz = topheight ;
2014-03-15 16:59:03 +00:00
}
}
}
void P_RecalcPrecipInSector ( sector_t * sector )
{
mprecipsecnode_t * psecnode ;
if ( ! sector )
return ;
sector - > moved = true ; // Recalc lighting and things too, maybe
2016-06-09 13:16:02 +00:00
for ( psecnode = sector - > touching_preciplist ; psecnode ; psecnode = psecnode - > m_thinglist_next )
2014-03-15 16:59:03 +00:00
CalculatePrecipFloor ( psecnode - > m_thing ) ;
}
//
// P_NullPrecipThinker
//
// For "Blank" precipitation
//
void P_NullPrecipThinker ( precipmobj_t * mobj )
{
2018-10-07 14:00:58 +00:00
//(void)mobj;
mobj - > precipflags & = ~ PCF_THUNK ;
2014-03-15 16:59:03 +00:00
}
void P_SnowThinker ( precipmobj_t * mobj )
{
2016-07-06 04:09:17 +00:00
P_CycleStateAnimation ( ( mobj_t * ) mobj ) ;
2014-03-15 16:59:03 +00:00
// adjust height
if ( ( mobj - > z + = mobj - > momz ) < = mobj - > floorz )
mobj - > z = mobj - > ceilingz ;
}
void P_RainThinker ( precipmobj_t * mobj )
{
2016-07-06 04:09:17 +00:00
P_CycleStateAnimation ( ( mobj_t * ) mobj ) ;
2014-03-15 16:59:03 +00:00
if ( mobj - > state ! = & states [ S_RAIN1 ] )
{
// cycle through states,
// calling action functions at transitions
2018-10-07 14:00:58 +00:00
if ( mobj - > tics < = 0 )
return ;
if ( - - mobj - > tics )
return ;
if ( ! P_SetPrecipMobjState ( mobj , mobj - > state - > nextstate ) )
return ;
if ( mobj - > state ! = & states [ S_RAINRETURN ] )
return ;
mobj - > z = mobj - > ceilingz ;
P_SetPrecipMobjState ( mobj , S_RAIN1 ) ;
2014-03-15 16:59:03 +00:00
return ;
}
// adjust height
2018-10-07 14:00:58 +00:00
if ( ( mobj - > z + = mobj - > momz ) < = mobj - > floorz )
2014-03-15 16:59:03 +00:00
{
// no splashes on sky or bottomless pits
if ( mobj - > precipflags & PCF_PIT )
mobj - > z = mobj - > ceilingz ;
else
{
mobj - > z = mobj - > floorz ;
P_SetPrecipMobjState ( mobj , S_SPLASH1 ) ;
}
}
}
static void P_RingThinker ( mobj_t * mobj )
{
if ( mobj - > momx | | mobj - > momy )
{
P_RingXYMovement ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
// always do the gravity bit now, that's simpler
// BUT CheckPosition only if wasn't done before.
if ( mobj - > momz )
{
P_RingZMovement ( mobj ) ;
P_CheckPosition ( mobj , mobj - > x , mobj - > y ) ; // Need this to pick up objects!
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
P_CycleMobjState ( mobj ) ;
}
//
// P_BossTargetPlayer
// If closest is true, find the closest player.
// Returns true if a player is targeted.
//
boolean P_BossTargetPlayer ( mobj_t * actor , boolean closest )
{
INT32 stop = - 1 , c = 0 ;
player_t * player ;
fixed_t dist , lastdist = 0 ;
// first time init, this allow minimum lastlook changes
if ( actor - > lastlook < 0 )
2016-07-06 04:09:17 +00:00
actor - > lastlook = P_RandomByte ( ) ;
2014-03-15 16:59:03 +00:00
actor - > lastlook & = PLAYERSMASK ;
for ( ; ; actor - > lastlook = ( actor - > lastlook + 1 ) & PLAYERSMASK )
{
// save the first look so we stop next time.
if ( stop < 0 )
stop = actor - > lastlook ;
// reached the beginning again, done looking.
else if ( actor - > lastlook = = stop )
return ( closest & & lastdist > 0 ) ;
if ( ! playeringame [ actor - > lastlook ] )
continue ;
if ( ! closest & & c + + = = 2 )
return false ;
player = & players [ actor - > lastlook ] ;
if ( player - > health < = 0 )
continue ; // dead
if ( player - > pflags & PF_INVIS | | player - > bot | | player - > spectator )
continue ; // ignore notarget
if ( ! player - > mo | | P_MobjWasRemoved ( player - > mo ) )
continue ;
if ( ! P_CheckSight ( actor , player - > mo ) )
continue ; // out of sight
if ( closest )
{
dist = P_AproxDistance ( actor - > x - player - > mo - > x , actor - > y - player - > mo - > y ) ;
if ( ! lastdist | | dist < lastdist )
{
lastdist = dist + 1 ;
P_SetTarget ( & actor - > target , player - > mo ) ;
}
continue ;
}
P_SetTarget ( & actor - > target , player - > mo ) ;
return true ;
}
}
// Finds the player no matter what they're hiding behind (even lead!)
boolean P_SupermanLook4Players ( mobj_t * actor )
{
INT32 c , stop = 0 ;
player_t * playersinthegame [ MAXPLAYERS ] ;
for ( c = 0 ; c < MAXPLAYERS ; c + + )
{
if ( playeringame [ c ] )
{
if ( players [ c ] . health < = 0 )
continue ; // dead
if ( players [ c ] . pflags & PF_INVIS )
continue ; // ignore notarget
if ( ! players [ c ] . mo | | players [ c ] . bot )
continue ;
playersinthegame [ stop ] = & players [ c ] ;
stop + + ;
}
}
if ( ! stop )
return false ;
P_SetTarget ( & actor - > target , playersinthegame [ P_RandomKey ( stop ) ] - > mo ) ;
return true ;
}
// AI for a generic boss.
static void P_GenericBossThinker ( mobj_t * mobj )
{
if ( mobj - > state - > nextstate = = mobj - > info - > spawnstate & & mobj - > tics = = 1 )
mobj - > flags2 & = ~ MF2_FRET ;
if ( ! mobj - > target | | ! ( mobj - > target - > flags & MF_SHOOTABLE ) )
{
if ( mobj - > health < = 0 )
{
// look for a new target
if ( P_BossTargetPlayer ( mobj , false ) & & mobj - > info - > mass ) // Bid farewell!
S_StartSound ( mobj , mobj - > info - > mass ) ;
return ;
}
// look for a new target
if ( P_BossTargetPlayer ( mobj , false ) & & mobj - > info - > seesound )
S_StartSound ( mobj , mobj - > info - > seesound ) ;
return ;
}
// Don't call A_ functions here, let the SOC do the AI!
if ( mobj - > state = = & states [ mobj - > info - > meleestate ]
| | ( mobj - > state = = & states [ mobj - > info - > missilestate ]
& & mobj - > health > mobj - > info - > damage ) )
{
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x , mobj - > target - > y ) ;
}
}
// AI for the first boss.
static void P_Boss1Thinker ( mobj_t * mobj )
{
if ( mobj - > flags2 & MF2_FRET & & ( statenum_t ) ( mobj - > state - states ) = = mobj - > info - > spawnstate ) {
mobj - > flags2 & = ~ ( MF2_FRET | MF2_SKULLFLY ) ;
mobj - > momx = mobj - > momy = mobj - > momz = 0 ;
}
if ( ! mobj - > tracer )
{
var1 = 0 ;
A_BossJetFume ( mobj ) ;
}
if ( ! mobj - > target | | ! ( mobj - > target - > flags & MF_SHOOTABLE ) )
{
if ( mobj - > target & & mobj - > target - > health
& & mobj - > target - > type = = MT_EGGMOBILE_TARGET ) // Oh, we're just firing our laser.
return ; // It's okay, then.
if ( mobj - > health < = 0 )
{
if ( P_BossTargetPlayer ( mobj , false ) & & mobj - > info - > mass ) // Bid farewell!
S_StartSound ( mobj , mobj - > info - > mass ) ;
return ;
}
// look for a new target
if ( P_BossTargetPlayer ( mobj , false ) & & mobj - > info - > seesound )
S_StartSound ( mobj , mobj - > info - > seesound ) ;
return ;
}
if ( mobj - > state ! = & states [ mobj - > info - > spawnstate ] & & mobj - > health > 0 & & mobj - > flags & MF_FLOAT & & ! ( mobj - > flags2 & MF2_SKULLFLY ) )
mobj - > momz = FixedMul ( mobj - > momz , 7 * FRACUNIT / 8 ) ;
if ( mobj - > state = = & states [ mobj - > info - > meleestate ]
| | ( mobj - > state = = & states [ mobj - > info - > missilestate ]
& & mobj - > health > mobj - > info - > damage ) )
{
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x , mobj - > target - > y ) ;
}
}
// AI for the second boss.
// No, it does NOT convert "Boss" to a "Thinker". =P
static void P_Boss2Thinker ( mobj_t * mobj )
{
if ( mobj - > movecount )
mobj - > movecount - - ;
if ( ! mobj - > movecount )
mobj - > flags2 & = ~ MF2_FRET ;
2015-01-01 19:50:31 +00:00
if ( ! mobj - > tracer )
2014-03-15 16:59:03 +00:00
{
var1 = 0 ;
A_BossJetFume ( mobj ) ;
}
if ( mobj - > health < = mobj - > info - > damage & & ( ! mobj - > target | | ! ( mobj - > target - > flags & MF_SHOOTABLE ) ) )
{
if ( mobj - > health < = 0 )
{
// look for a new target
if ( P_BossTargetPlayer ( mobj , false ) & & mobj - > info - > mass ) // Bid farewell!
S_StartSound ( mobj , mobj - > info - > mass ) ;
return ;
}
// look for a new target
if ( P_BossTargetPlayer ( mobj , false ) & & mobj - > info - > seesound )
S_StartSound ( mobj , mobj - > info - > seesound ) ;
return ;
}
2015-01-01 19:50:31 +00:00
if ( mobj - > state = = & states [ mobj - > info - > spawnstate ] & & mobj - > health > mobj - > info - > damage )
2014-03-15 16:59:03 +00:00
A_Boss2Chase ( mobj ) ;
else if ( mobj - > health > 0 & & mobj - > state ! = & states [ mobj - > info - > painstate ] & & mobj - > state ! = & states [ mobjinfo [ mobj - > info - > missilestate ] . raisestate ] )
{
mobj - > flags & = ~ MF_NOGRAVITY ;
A_Boss2Pogo ( mobj ) ;
P_LinedefExecute ( LE_PINCHPHASE , mobj , NULL ) ;
}
}
// AI for the third boss.
//
// Notes for reminders:
// movedir = move 2x fast?
// movecount = fire missiles?
// reactiontime = shock the water?
// threshold = next waypoint #
// extravalue1 = previous time shock sound was used
//
static void P_Boss3Thinker ( mobj_t * mobj )
{
if ( mobj - > state = = & states [ mobj - > info - > spawnstate ] )
mobj - > flags2 & = ~ MF2_FRET ;
if ( mobj - > flags2 & MF2_FRET )
mobj - > movedir = 1 ;
if ( ! mobj - > tracer )
{
var1 = 1 ;
A_BossJetFume ( mobj ) ;
}
if ( mobj - > health < = 0 )
{
mobj - > movecount = 0 ;
mobj - > reactiontime = 0 ;
if ( mobj - > state < & states [ mobj - > info - > xdeathstate ] )
return ;
if ( mobj - > threshold = = - 1 )
{
mobj - > momz = mobj - > info - > speed ;
return ;
}
}
if ( mobj - > reactiontime ) // Shock mode
{
UINT32 i ;
if ( mobj - > state ! = & states [ mobj - > info - > spawnstate ] )
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
mobj - > reactiontime - - ;
if ( ! mobj - > reactiontime )
{
ffloor_t * rover ;
// Shock the water
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo )
continue ;
if ( players [ i ] . mo - > health < = 0 )
continue ;
if ( players [ i ] . mo - > eflags & MFE_UNDERWATER )
P_DamageMobj ( players [ i ] . mo , mobj , mobj , 1 ) ;
}
// Make the water flash
for ( i = 0 ; i < numsectors ; i + + )
{
if ( ! sectors [ i ] . ffloors )
continue ;
for ( rover = sectors [ i ] . ffloors ; rover ; rover = rover - > next )
{
if ( ! ( rover - > flags & FF_EXISTS ) )
continue ;
if ( ! ( rover - > flags & FF_SWIMMABLE ) )
continue ;
P_SpawnLightningFlash ( rover - > master - > frontsector ) ;
break ;
}
}
if ( ( UINT32 ) mobj - > extravalue1 + TICRATE * 2 < leveltime )
{
mobj - > extravalue1 = ( INT32 ) leveltime ;
S_StartSound ( 0 , sfx_buzz1 ) ;
}
// If in the center, check to make sure
// none of the players are in the water
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo | | players [ i ] . bot )
continue ;
if ( players [ i ] . mo - > health < = 0 )
continue ;
if ( players [ i ] . mo - > eflags & MFE_UNDERWATER )
{ // Stay put
mobj - > reactiontime = 2 * TICRATE ;
return ;
}
}
}
if ( ! mobj - > reactiontime & & mobj - > health < = mobj - > info - > damage )
{ // Spawn pinch dummies from the center when we're leaving it.
2014-08-04 03:49:33 +00:00
thinker_t * th ;
mobj_t * mo2 ;
2014-03-15 16:59:03 +00:00
mobj_t * dummy ;
SINT8 way = mobj - > threshold - 1 ; // 0 through 4.
SINT8 way2 ;
2014-08-05 23:59:40 +00:00
2014-08-04 03:49:33 +00:00
i = 0 ; // reset i to 0 so we can check how many clones we've removed
// scan the thinkers to make sure all the old pinch dummies are gone before making new ones
// this can happen if the boss was hurt earlier than expected
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = ( mobjtype_t ) mobj - > info - > mass & & mo2 - > tracer = = mobj )
{
P_RemoveMobj ( mo2 ) ;
i + + ;
}
if ( i = = 2 ) // we've already removed 2 of these, let's stop now
break ;
}
2014-03-15 16:59:03 +00:00
way = ( way + P_RandomRange ( 1 , 3 ) ) % 5 ; // dummy 1 at one of the first three options after eggmobile
dummy = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , mobj - > info - > mass ) ;
dummy - > angle = mobj - > angle ;
dummy - > threshold = way + 1 ;
dummy - > tracer = mobj ;
do
way2 = ( way + P_RandomRange ( 1 , 3 ) ) % 5 ; // dummy 2 has to be careful,
while ( way2 = = mobj - > threshold - 1 ) ; // to make sure it doesn't try to go the Eggman Way if dummy 1 rolled high.
dummy = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , mobj - > info - > mass ) ;
dummy - > angle = mobj - > angle ;
dummy - > threshold = way2 + 1 ;
dummy - > tracer = mobj ;
CONS_Debug ( DBG_GAMELOGIC , " Eggman path %d - Dummy selected paths %d and %d \n " , mobj - > threshold , way + 1 , dummy - > threshold ) ;
P_LinedefExecute ( LE_PINCHPHASE , mobj , NULL ) ;
}
}
else if ( mobj - > movecount ) // Firing mode
{
UINT32 i ;
// look for a new target
P_BossTargetPlayer ( mobj , false ) ;
if ( ! mobj - > target | | ! mobj - > target - > player )
return ;
// Are there any players underwater? If so, shock them!
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo | | players [ i ] . bot )
continue ;
if ( players [ i ] . mo - > health < = 0 )
continue ;
if ( players [ i ] . mo - > eflags & MFE_UNDERWATER )
{
mobj - > movecount = 0 ;
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
return ;
}
}
// Always face your target.
A_FaceTarget ( mobj ) ;
// Check if the attack animation is running. If not, play it.
if ( mobj - > state < & states [ mobj - > info - > missilestate ] | | mobj - > state > & states [ mobj - > info - > raisestate ] )
{
if ( mobj - > health < = mobj - > info - > damage ) // pinch phase
mobj - > movecount - - ; // limited number of shots before diving again
if ( mobj - > movecount )
P_SetMobjState ( mobj , mobj - > info - > missilestate ) ;
}
}
else if ( mobj - > threshold > = 0 ) // Traveling mode
{
thinker_t * th ;
mobj_t * mo2 ;
fixed_t dist , dist2 ;
fixed_t speed ;
P_SetTarget ( & mobj - > target , NULL ) ;
if ( mobj - > state ! = & states [ mobj - > info - > spawnstate ] & & mobj - > health > 0
& & ! ( mobj - > flags2 & MF2_FRET ) )
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
// scan the thinkers
// to find a point that matches
// the number
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = MT_BOSS3WAYPOINT & & mo2 - > spawnpoint & & mo2 - > spawnpoint - > angle = = mobj - > threshold )
{
P_SetTarget ( & mobj - > target , mo2 ) ;
break ;
}
}
if ( ! mobj - > target ) // Should NEVER happen
{
CONS_Debug ( DBG_GAMELOGIC , " Error: Boss 3 was unable to find specified waypoint: %d \n " , mobj - > threshold ) ;
return ;
}
dist = P_AproxDistance ( P_AproxDistance ( mobj - > target - > x - mobj - > x , mobj - > target - > y - mobj - > y ) , mobj - > target - > z - mobj - > z ) ;
if ( dist < 1 )
dist = 1 ;
if ( ( mobj - > movedir ) | | ( mobj - > health < = mobj - > info - > damage ) )
speed = mobj - > info - > speed * 2 ;
else
speed = mobj - > info - > speed ;
mobj - > momx = FixedMul ( FixedDiv ( mobj - > target - > x - mobj - > x , dist ) , speed ) ;
mobj - > momy = FixedMul ( FixedDiv ( mobj - > target - > y - mobj - > y , dist ) , speed ) ;
mobj - > momz = FixedMul ( FixedDiv ( mobj - > target - > z - mobj - > z , dist ) , speed ) ;
if ( mobj - > momx ! = 0 | | mobj - > momy ! = 0 )
mobj - > angle = R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) ;
dist2 = P_AproxDistance ( P_AproxDistance ( mobj - > target - > x - ( mobj - > x + mobj - > momx ) , mobj - > target - > y - ( mobj - > y + mobj - > momy ) ) , mobj - > target - > z - ( mobj - > z + mobj - > momz ) ) ;
if ( dist2 < 1 )
dist2 = 1 ;
if ( ( dist > > FRACBITS ) < = ( dist2 > > FRACBITS ) )
{
// If further away, set XYZ of mobj to waypoint location
P_UnsetThingPosition ( mobj ) ;
mobj - > x = mobj - > target - > x ;
mobj - > y = mobj - > target - > y ;
mobj - > z = mobj - > target - > z ;
mobj - > momx = mobj - > momy = mobj - > momz = 0 ;
P_SetThingPosition ( mobj ) ;
if ( mobj - > threshold = = 0 )
{
mobj - > reactiontime = 1 ; // Bzzt! Shock the water!
mobj - > movedir = 0 ;
if ( mobj - > health < = 0 )
{
mobj - > flags | = MF_NOGRAVITY | MF_NOCLIP ;
mobj - > flags | = MF_NOCLIPHEIGHT ;
mobj - > threshold = - 1 ;
return ;
}
}
// Set to next waypoint in sequence
if ( mobj - > target - > spawnpoint )
{
// From the center point, choose one of the five paths
if ( mobj - > target - > spawnpoint - > angle = = 0 )
mobj - > threshold = P_RandomRange ( 1 , 5 ) ;
else
mobj - > threshold = mobj - > target - > spawnpoint - > extrainfo ;
// If the deaf flag is set, go into firing mode
if ( mobj - > target - > spawnpoint - > options & MTF_AMBUSH )
mobj - > movecount = mobj - > health + 1 ;
}
else // This should never happen, as well
CONS_Debug ( DBG_GAMELOGIC , " Error: Boss 3 waypoint has no spawnpoint associated with it. \n " ) ;
}
}
}
// Move Boss4's sectors by delta.
static boolean P_Boss4MoveCage ( fixed_t delta )
{
2014-05-02 21:24:20 +00:00
const UINT16 tag = 65534 ;
2014-03-15 16:59:03 +00:00
INT32 snum ;
sector_t * sector ;
for ( snum = sectors [ tag % numsectors ] . firsttag ; snum ! = - 1 ; snum = sector - > nexttag )
{
sector = & sectors [ snum ] ;
if ( sector - > tag ! = tag )
continue ;
sector - > floorheight + = delta ;
sector - > ceilingheight + = delta ;
P_CheckSector ( sector , true ) ;
}
return sectors [ tag % numsectors ] . firsttag ! = - 1 ;
}
// Move Boss4's arms to angle
static void P_Boss4MoveSpikeballs ( mobj_t * mobj , angle_t angle , fixed_t fz )
{
INT32 s ;
mobj_t * base = mobj , * seg ;
2017-01-02 19:04:33 +00:00
fixed_t dist , bz = mobj - > watertop + ( 16 < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
while ( ( base = base - > tracer ) )
{
for ( seg = base , dist = 172 * FRACUNIT , s = 9 ; seg ; seg = seg - > hnext , dist + = 124 * FRACUNIT , - - s )
P_TeleportMove ( seg , mobj - > x + P_ReturnThrustX ( mobj , angle , dist ) , mobj - > y + P_ReturnThrustY ( mobj , angle , dist ) , bz + FixedMul ( fz , FixedDiv ( s < < FRACBITS , 9 < < FRACBITS ) ) ) ;
angle + = ANGLE_MAX / 3 ;
}
}
// Pull them closer.
static void P_Boss4PinchSpikeballs ( mobj_t * mobj , angle_t angle , fixed_t fz )
{
INT32 s ;
mobj_t * base = mobj , * seg ;
2017-01-02 19:04:33 +00:00
fixed_t dist , bz = mobj - > watertop + ( 16 < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
while ( ( base = base - > tracer ) )
{
for ( seg = base , dist = 112 * FRACUNIT , s = 9 ; seg ; seg = seg - > hnext , dist + = 132 * FRACUNIT , - - s )
{
seg - > z = bz + FixedMul ( fz , FixedDiv ( s < < FRACBITS , 9 < < FRACBITS ) ) ;
P_TryMove ( seg , mobj - > x + P_ReturnThrustX ( mobj , angle , dist ) , mobj - > y + P_ReturnThrustY ( mobj , angle , dist ) , true ) ;
}
angle + = ANGLE_MAX / 3 ;
}
}
// Destroy cage FOFs.
static void P_Boss4DestroyCage ( void )
{
2014-05-02 21:24:20 +00:00
const UINT16 tag = 65534 ;
2014-03-15 16:59:03 +00:00
INT32 snum , next ;
size_t a ;
sector_t * sector , * rsec ;
ffloor_t * rover ;
// This will be the final iteration of sector tag.
// We'll destroy the tag list as we go.
next = sectors [ tag % numsectors ] . firsttag ;
sectors [ tag % numsectors ] . firsttag = - 1 ;
for ( snum = next ; snum ! = - 1 ; snum = next )
{
sector = & sectors [ snum ] ;
next = sector - > nexttag ;
sector - > nexttag = - 1 ;
if ( sector - > tag ! = tag )
continue ;
sector - > tag = 0 ;
// Destroy the FOFs.
for ( a = 0 ; a < sector - > numattached ; a + + )
{
rsec = & sectors [ sector - > attached [ a ] ] ;
for ( rover = rsec - > ffloors ; rover ; rover = rover - > next )
if ( rover - > flags & FF_EXISTS & & rover - > secnum = = ( size_t ) snum )
{
if ( rover - > flags & FF_RENDERALL ) // checking for FF_RENDERANY.
EV_CrumbleChain ( rsec , rover ) ; // This FOF is visible to some extent? Crumble it.
else // Completely invisible FOF
{
// no longer exists (can't collide with again)
rover - > flags & = ~ FF_EXISTS ;
sector - > moved = true ;
rsec - > moved = true ;
}
}
}
}
}
// Destroy Boss4's arms
static void P_Boss4PopSpikeballs ( mobj_t * mobj )
{
mobj_t * base = mobj - > tracer , * seg , * next ;
P_SetTarget ( & mobj - > tracer , NULL ) ;
while ( base )
{
next = base - > tracer ;
P_SetTarget ( & base - > tracer , NULL ) ;
for ( seg = base ; seg ; seg = seg - > hnext )
if ( seg - > health )
P_KillMobj ( seg , NULL , NULL ) ;
base = next ;
}
}
//
// AI for the fourth boss.
//
static void P_Boss4Thinker ( mobj_t * mobj )
{
if ( ( statenum_t ) ( mobj - > state - states ) = = mobj - > info - > spawnstate )
{
if ( mobj - > health > mobj - > info - > damage | | mobj - > movedir = = 4 )
mobj - > flags2 & = ~ MF2_FRET ;
mobj - > reactiontime = 0 ; // Drop the cage immediately.
}
// Oh no, we dead? D:
if ( ! mobj - > health )
{
if ( mobj - > tracer ) // need to clean up!
{
P_Boss4DestroyCage ( ) ; // Just in case pinch phase was skipped.
P_Boss4PopSpikeballs ( mobj ) ;
}
return ;
}
// movedir == battle stage:
// 0: initialization
// 1: phase 1 forward
// 2: phase 1 reverse
// 3: pinch rise
// 4: pinch phase
switch ( mobj - > movedir )
{
// WELCOME to your DOOM!
case 0 :
{
// For this stage only:
// movecount == cage height
// threshold == cage momz
if ( mobj - > movecount = = 0 ) // Initialize stage!
{
fixed_t z ;
INT32 i , arm ;
mobj_t * seg , * base = mobj ;
// First frame init, spawn all the things.
2017-01-02 19:04:33 +00:00
mobj - > watertop = mobj - > z ;
2014-03-15 16:59:03 +00:00
z = mobj - > z + mobj - > height / 2 - mobjinfo [ MT_EGGMOBILE4_MACE ] . height / 2 ;
for ( arm = 0 ; arm < 3 ; arm + + )
{
seg = P_SpawnMobj ( mobj - > x , mobj - > y , z , MT_EGGMOBILE4_MACE ) ;
P_SetTarget ( & base - > tracer , seg ) ;
base = seg ;
P_SetTarget ( & seg - > target , mobj ) ;
for ( i = 0 ; i < 9 ; i + + )
{
seg - > hnext = P_SpawnMobj ( mobj - > x , mobj - > y , z , MT_EGGMOBILE4_MACE ) ;
seg - > hnext - > hprev = seg ;
seg = seg - > hnext ;
}
}
// Move the cage up to the sky.
mobj - > movecount = 800 * FRACUNIT ;
if ( ! P_Boss4MoveCage ( mobj - > movecount ) )
{
mobj - > movecount = 0 ;
mobj - > threshold = 3 * TICRATE ;
mobj - > extravalue1 = 1 ;
mobj - > movedir + + ; // We don't have a cage, just continue.
}
else
P_Boss4MoveSpikeballs ( mobj , 0 , mobj - > movecount ) ;
}
else // Cage slams down over Eggman's head!
{
fixed_t oldz = mobj - > movecount ;
mobj - > threshold - = 5 * FRACUNIT ;
mobj - > movecount + = mobj - > threshold ;
if ( mobj - > movecount < 0 )
mobj - > movecount = 0 ;
P_Boss4MoveCage ( mobj - > movecount - oldz ) ;
P_Boss4MoveSpikeballs ( mobj , 0 , mobj - > movecount ) ;
if ( mobj - > movecount = = 0 )
{
mobj - > threshold = 3 * TICRATE ;
mobj - > extravalue1 = 1 ;
P_LinedefExecute ( LE_BOSS4DROP , mobj , NULL ) ;
mobj - > movedir + + ; // Initialization complete, next phase!
}
}
return ;
}
// Normal operation
case 1 :
case 2 :
break ;
// Pinch phase init!
case 3 :
{
fixed_t z ;
2017-01-02 19:04:33 +00:00
if ( mobj - > z < mobj - > watertop + ( 512 < < FRACBITS ) )
2014-03-15 16:59:03 +00:00
mobj - > momz = 8 * FRACUNIT ;
else
{
mobj - > momz = 0 ;
mobj - > movedir + + ;
}
mobj - > movecount + = 400 < < ( FRACBITS > > 1 ) ;
mobj - > movecount % = 360 * FRACUNIT ;
2017-01-02 19:04:33 +00:00
z = mobj - > z - mobj - > watertop - mobjinfo [ MT_EGGMOBILE4_MACE ] . height - mobj - > height / 2 ;
2014-03-15 16:59:03 +00:00
if ( z < 0 ) // We haven't risen high enough to pull the spikeballs along yet
P_Boss4MoveSpikeballs ( mobj , FixedAngle ( mobj - > movecount ) , 0 ) ; // So don't pull the spikeballs along yet.
else
P_Boss4PinchSpikeballs ( mobj , FixedAngle ( mobj - > movecount ) , z ) ;
return ;
}
// Pinch phase!
case 4 :
{
2017-01-02 19:07:20 +00:00
if ( mobj - > z < ( mobj - > watertop + ( ( 512 + 128 * ( mobj - > info - > damage - mobj - > health ) ) < < FRACBITS ) ) )
2014-03-15 16:59:03 +00:00
mobj - > momz = 8 * FRACUNIT ;
else
mobj - > momz = 0 ;
mobj - > movecount + = ( 800 + 800 * ( mobj - > info - > damage - mobj - > health ) ) < < ( FRACBITS > > 1 ) ;
mobj - > movecount % = 360 * FRACUNIT ;
2017-01-02 19:04:33 +00:00
P_Boss4PinchSpikeballs ( mobj , FixedAngle ( mobj - > movecount ) , mobj - > z - mobj - > watertop - mobjinfo [ MT_EGGMOBILE4_MACE ] . height - mobj - > height / 2 ) ;
2014-03-15 16:59:03 +00:00
if ( ! mobj - > target | | ! mobj - > target - > health )
P_SupermanLook4Players ( mobj ) ;
A_FaceTarget ( mobj ) ;
return ;
}
default : // ?????
return ;
}
// Haahahahahaaa, and let the FUN.. BEGIN!
// movedir == arms direction
// movecount == arms angle
// threshold == countdown to next attack
// reactiontime == cage raise, speed burst
// movefactor == cage z
// friction == turns until helm lift
// Raise the cage!
if ( mobj - > reactiontime = = 1 )
{
fixed_t oldz = mobj - > movefactor ;
mobj - > movefactor + = 8 * FRACUNIT ;
if ( mobj - > movefactor > 128 * FRACUNIT )
mobj - > movefactor = 128 * FRACUNIT ;
P_Boss4MoveCage ( mobj - > movefactor - oldz ) ;
}
// Drop the cage!
else if ( mobj - > movefactor )
{
fixed_t oldz = mobj - > movefactor ;
mobj - > movefactor - = 4 * FRACUNIT ;
if ( mobj - > movefactor < 0 )
mobj - > movefactor = 0 ;
P_Boss4MoveCage ( mobj - > movefactor - oldz ) ;
if ( ! mobj - > movefactor )
{
if ( mobj - > health < = mobj - > info - > damage )
{ // Proceed to pinch phase!
P_Boss4DestroyCage ( ) ;
mobj - > movedir = 3 ;
P_LinedefExecute ( LE_PINCHPHASE , mobj , NULL ) ;
return ;
}
P_LinedefExecute ( LE_BOSS4DROP , mobj , NULL ) ;
}
}
{
fixed_t movespeed = 170 < < ( FRACBITS > > 1 ) ;
if ( mobj - > reactiontime = = 2 )
movespeed * = 3 ;
if ( mobj - > movedir = = 2 )
mobj - > movecount - = movespeed ;
else
mobj - > movecount + = movespeed ;
}
mobj - > movecount % = 360 * FRACUNIT ;
P_Boss4MoveSpikeballs ( mobj , FixedAngle ( mobj - > movecount ) , mobj - > movefactor ) ;
// Check for attacks, always tick the timer even while animating!!
if ( ! ( mobj - > flags2 & MF2_FRET ) // but pause for pain so we don't interrupt pinch phase, eep!
& & mobj - > threshold - - = = 0 )
{
// 5 -> 2.5 second timer
mobj - > threshold = 5 * TICRATE - ( TICRATE / 2 ) * ( mobj - > info - > spawnhealth - mobj - > health ) ;
if ( mobj - > threshold < 1 )
mobj - > threshold = 1 ;
if ( mobj - > extravalue1 - - = = 0 )
{
P_SetMobjState ( mobj , mobj - > info - > raisestate ) ;
mobj - > extravalue1 = 3 ;
}
else
{
if ( mobj - > reactiontime = = 1 ) // Cage is raised?
mobj - > reactiontime = 0 ; // Drop it!
switch ( P_RandomKey ( 10 ) )
{
// Telegraph Right (Speed Up!!)
case 1 :
case 3 :
case 4 :
case 5 :
case 6 :
P_SetMobjState ( mobj , mobj - > info - > missilestate ) ;
break ;
// Telegraph Left (Reverse Direction)
default :
P_SetMobjState ( mobj , mobj - > info - > meleestate ) ;
break ;
}
}
}
// Leave if animating.
if ( ( statenum_t ) ( mobj - > state - states ) ! = mobj - > info - > spawnstate )
return ;
// Map allows us to get killed despite cage being down?
if ( mobj - > health < = mobj - > info - > damage )
{ // Proceed to pinch phase!
P_Boss4DestroyCage ( ) ;
// spawn jet's flame now you're flying upwards
// tracer is already used, so if this ever gets reached again we've got problems
var1 = 3 ;
A_BossJetFume ( mobj ) ;
mobj - > movedir = 3 ;
P_LinedefExecute ( LE_PINCHPHASE , mobj , NULL ) ;
return ;
}
mobj - > reactiontime = 0 ; // Drop the cage if it hasn't been dropped already.
if ( ! mobj - > target | | ! mobj - > target - > health )
P_SupermanLook4Players ( mobj ) ;
A_FaceTarget ( mobj ) ;
}
//
// AI for Black Eggman
// Note: You CANNOT have more than ONE Black Eggman
// in a level! Just don't try it!
//
static void P_Boss7Thinker ( mobj_t * mobj )
{
if ( ! mobj - > target | | ! ( mobj - > target - > flags & MF_SHOOTABLE ) )
{
// look for a new target
if ( P_BossTargetPlayer ( mobj , false ) )
return ; // got a new target
P_SetMobjStateNF ( mobj , mobj - > info - > spawnstate ) ;
return ;
}
if ( mobj - > health > = mobj - > info - > spawnhealth & & ( leveltime & 14 ) = = 0 )
{
mobj_t * smoke = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z + mobj - > height , MT_SMOKE ) ;
smoke - > destscale = mobj - > destscale ;
P_SetScale ( smoke , smoke - > destscale ) ;
smoke - > momz = FixedMul ( FRACUNIT , smoke - > scale ) ;
}
if ( mobj - > state = = & states [ S_BLACKEGG_STND ] & & mobj - > tics = = mobj - > state - > tics )
{
2016-07-06 04:09:17 +00:00
mobj - > reactiontime + = P_RandomByte ( ) ;
2014-03-15 16:59:03 +00:00
if ( mobj - > health < = mobj - > info - > damage )
mobj - > reactiontime / = 4 ;
}
else if ( mobj - > state = = & states [ S_BLACKEGG_DIE4 ] & & mobj - > tics = = mobj - > state - > tics )
A_BossDeath ( mobj ) ;
else if ( mobj - > state > = & states [ S_BLACKEGG_WALK1 ]
& & mobj - > state < = & states [ S_BLACKEGG_WALK6 ] )
A_Boss7Chase ( mobj ) ;
else if ( mobj - > state = = & states [ S_BLACKEGG_PAIN1 ] & & mobj - > tics = = mobj - > state - > tics )
{
if ( mobj - > health > 0 )
mobj - > health - - ;
S_StartSound ( 0 , ( mobj - > health ) ? sfx_behurt : sfx_bedie2 ) ;
mobj - > reactiontime / = 3 ;
if ( mobj - > health < = 0 )
{
INT32 i ;
P_KillMobj ( mobj , NULL , NULL ) ;
// It was a team effort
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
P_AddPlayerScore ( & players [ i ] , 1000 ) ;
}
}
}
else if ( mobj - > state = = & states [ S_BLACKEGG_PAIN35 ] & & mobj - > tics = = 1 )
{
if ( mobj - > health = = mobj - > info - > damage )
{
// Begin platform destruction
mobj - > flags2 | = MF2_FRET ;
P_SetMobjState ( mobj , mobj - > info - > raisestate ) ;
P_LinedefExecute ( LE_PINCHPHASE , mobj , NULL ) ;
}
}
else if ( mobj - > state = = & states [ S_BLACKEGG_HITFACE4 ] & & mobj - > tics = = mobj - > state - > tics )
{
// This is where Black Eggman hits his face.
// If a player is on top of him, the player gets hurt.
// But, if the player has managed to escape,
// Black Eggman gets hurt!
INT32 i ;
mobj - > state - > nextstate = mobj - > info - > painstate ; // Reset
S_StartSound ( 0 , sfx_bedeen ) ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo )
continue ;
if ( players [ i ] . mo - > health < = 0 )
continue ;
if ( P_AproxDistance ( players [ i ] . mo - > x - mobj - > x , players [ i ] . mo - > y - mobj - > y ) > ( mobj - > radius + players [ i ] . mo - > radius ) )
continue ;
if ( players [ i ] . mo - > z > mobj - > z + mobj - > height - FRACUNIT
& & players [ i ] . mo - > z < mobj - > z + mobj - > height + 128 * FRACUNIT ) // You can't be in the vicinity, either...
{
// Punch him!
P_DamageMobj ( players [ i ] . mo , mobj , mobj , 1 ) ;
mobj - > state - > nextstate = mobj - > info - > spawnstate ;
// Laugh
S_StartSound ( 0 , sfx_bewar1 + P_RandomKey ( 4 ) ) ;
}
}
}
else if ( mobj - > state = = & states [ S_BLACKEGG_GOOP ] )
{
// Lob cannon balls
if ( mobj - > movecount - - < = 0 | | ! mobj - > target )
{
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
return ;
}
if ( ( leveltime & 15 ) = = 0 )
{
var1 = MT_CANNONBALL ;
var2 = 2 * TICRATE + ( 80 < < 16 ) ;
A_LobShot ( mobj ) ;
S_StartSound ( 0 , sfx_begoop ) ;
}
}
else if ( mobj - > state = = & states [ S_BLACKEGG_SHOOT2 ] )
{
// Chaingun goop
mobj_t * missile ;
if ( mobj - > movecount - - < = 0 | | ! mobj - > target )
{
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
return ;
}
A_FaceTarget ( mobj ) ;
missile = P_SpawnXYZMissile ( mobj , mobj - > target , MT_BLACKEGGMAN_GOOPFIRE ,
mobj - > x + P_ReturnThrustX ( mobj , mobj - > angle - ANGLE_90 , FixedDiv ( mobj - > radius , 3 * FRACUNIT / 2 ) + ( 4 * FRACUNIT ) ) ,
mobj - > y + P_ReturnThrustY ( mobj , mobj - > angle - ANGLE_90 , FixedDiv ( mobj - > radius , 3 * FRACUNIT / 2 ) + ( 4 * FRACUNIT ) ) ,
mobj - > z + FixedDiv ( mobj - > height , 3 * FRACUNIT / 2 ) ) ;
S_StopSound ( missile ) ;
if ( leveltime & 1 )
S_StartSound ( 0 , sfx_beshot ) ;
}
else if ( mobj - > state = = & states [ S_BLACKEGG_JUMP1 ] & & mobj - > tics = = 1 )
{
mobj_t * hitspot = NULL , * mo2 ;
angle_t an ;
fixed_t dist , closestdist ;
fixed_t vertical , horizontal ;
fixed_t airtime = 5 * TICRATE ;
INT32 waypointNum = 0 ;
thinker_t * th ;
INT32 i ;
boolean foundgoop = false ;
INT32 closestNum ;
// Looks for players in goop. If you find one, try to jump on him.
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo )
continue ;
if ( players [ i ] . mo - > health < = 0 )
continue ;
if ( players [ i ] . powers [ pw_ingoop ] )
{
closestNum = - 1 ;
closestdist = 16384 * FRACUNIT ; // Just in case...
// Find waypoint he is closest to
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = MT_BOSS3WAYPOINT & & mo2 - > spawnpoint )
{
dist = P_AproxDistance ( players [ i ] . mo - > x - mo2 - > x , players [ i ] . mo - > y - mo2 - > y ) ;
if ( closestNum = = - 1 | | dist < closestdist )
{
closestNum = ( mo2 - > spawnpoint - > options & 7 ) ;
closestdist = dist ;
foundgoop = true ;
}
}
}
waypointNum = closestNum ;
break ;
}
}
if ( ! foundgoop )
{
if ( mobj - > z > 1056 * FRACUNIT )
waypointNum = 0 ;
else
waypointNum = 1 + P_RandomKey ( 4 ) ;
}
// Don't jump to the center when health is low.
// Force the player to beat you with missiles.
if ( mobj - > health < = mobj - > info - > damage & & waypointNum = = 0 )
waypointNum = 1 + P_RandomKey ( 4 ) ;
if ( mobj - > tracer & & mobj - > tracer - > type = = MT_BOSS3WAYPOINT
& & mobj - > tracer - > spawnpoint & & ( mobj - > tracer - > spawnpoint - > options & 7 ) = = waypointNum )
{
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 2 ) )
2014-03-15 16:59:03 +00:00
waypointNum + + ;
else
waypointNum - - ;
waypointNum % = 5 ;
if ( waypointNum < 0 )
waypointNum = 0 ;
}
if ( waypointNum = = 0 & & mobj - > health < = mobj - > info - > damage )
2016-07-06 04:09:17 +00:00
waypointNum = 1 + ( P_RandomFixed ( ) & 1 ) ;
2014-03-15 16:59:03 +00:00
// scan the thinkers to find
// the waypoint to use
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = MT_BOSS3WAYPOINT & & mo2 - > spawnpoint & & ( mo2 - > spawnpoint - > options & 7 ) = = waypointNum )
{
hitspot = mo2 ;
break ;
}
}
if ( hitspot = = NULL )
{
CONS_Debug ( DBG_GAMELOGIC , " BlackEggman unable to find waypoint #%d! \n " , waypointNum ) ;
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
return ;
}
P_SetTarget ( & mobj - > tracer , hitspot ) ;
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , hitspot - > x , hitspot - > y ) ;
an = mobj - > angle ;
an > > = ANGLETOFINESHIFT ;
dist = P_AproxDistance ( hitspot - > x - mobj - > x , hitspot - > y - mobj - > y ) ;
horizontal = dist / airtime ;
vertical = ( gravity * airtime ) / 2 ;
mobj - > momx = FixedMul ( horizontal , FINECOSINE ( an ) ) ;
mobj - > momy = FixedMul ( horizontal , FINESINE ( an ) ) ;
mobj - > momz = vertical ;
// mobj->momz = 10*FRACUNIT;
}
else if ( mobj - > state = = & states [ S_BLACKEGG_JUMP2 ] & & mobj - > z < = mobj - > floorz )
{
// BANG! onto the ground
INT32 i , j ;
fixed_t ns ;
fixed_t x , y , z ;
mobj_t * mo2 ;
S_StartSound ( 0 , sfx_befall ) ;
z = mobj - > floorz ;
for ( j = 0 ; j < 2 ; j + + )
{
for ( i = 0 ; i < 32 ; i + + )
{
const angle_t fa = ( i * FINEANGLES / 16 ) & FINEMASK ;
ns = 64 * FRACUNIT ;
x = mobj - > x + FixedMul ( FINESINE ( fa ) , ns ) ;
y = mobj - > y + FixedMul ( FINECOSINE ( fa ) , ns ) ;
mo2 = P_SpawnMobj ( x , y , z , MT_EXPLODE ) ;
ns = 16 * FRACUNIT ;
mo2 - > momx = FixedMul ( FINESINE ( fa ) , ns ) ;
mo2 - > momy = FixedMul ( FINECOSINE ( fa ) , ns ) ;
}
z - = 32 * FRACUNIT ;
}
// Hurt player??
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
if ( ! players [ i ] . mo )
continue ;
if ( players [ i ] . mo - > health < = 0 )
continue ;
if ( P_AproxDistance ( players [ i ] . mo - > x - mobj - > x , players [ i ] . mo - > y - mobj - > y ) > mobj - > radius * 4 )
continue ;
if ( players [ i ] . mo - > z > mobj - > z + 128 * FRACUNIT )
continue ;
if ( players [ i ] . mo - > z < mobj - > z - 64 * FRACUNIT )
continue ;
P_DamageMobj ( players [ i ] . mo , mobj , mobj , 1 ) ;
// Laugh
S_StartSound ( 0 , sfx_bewar1 + P_RandomKey ( 4 ) ) ;
}
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
}
else if ( mobj - > state = = & states [ mobj - > info - > deathstate ] & & mobj - > tics = = mobj - > state - > tics )
2016-07-06 04:09:17 +00:00
S_StartSound ( 0 , sfx_bedie1 + ( P_RandomFixed ( ) & 1 ) ) ;
2014-03-15 16:59:03 +00:00
}
// Metal Sonic battle boss
// You CAN put multiple Metal Sonics in a single map
// because I am a totally competent programmer who can do shit right.
static void P_Boss9Thinker ( mobj_t * mobj )
{
if ( ( statenum_t ) ( mobj - > state - states ) = = mobj - > info - > spawnstate )
mobj - > flags2 & = ~ MF2_FRET ;
if ( ! mobj - > tracer )
{
thinker_t * th ;
mobj_t * mo2 ;
mobj_t * last = NULL ;
// Initialize the boss, spawn jet fumes, etc.
mobj - > threshold = 0 ;
mobj - > reactiontime = 0 ;
mobj - > watertop = mobj - > floorz + 32 * FRACUNIT ;
var1 = 2 ;
A_BossJetFume ( mobj ) ;
// Run through the thinkers ONCE and find all of the MT_BOSS9GATHERPOINT in the map.
// Build a hoop linked list of 'em!
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = MT_BOSS9GATHERPOINT )
{
if ( last )
last - > hnext = mo2 ;
else
mobj - > hnext = mo2 ;
mo2 - > hprev = last ;
last = mo2 ;
}
}
}
if ( mobj - > health < = 0 )
return ;
if ( ( ! mobj - > target | | ! ( mobj - > target - > flags & MF_SHOOTABLE ) ) )
{
P_BossTargetPlayer ( mobj , false ) ;
if ( mobj - > target & & ( ! P_IsObjectOnGround ( mobj - > target ) | | mobj - > target - > player - > pflags & PF_SPINNING ) )
P_SetTarget ( & mobj - > target , NULL ) ; // Wait for them to hit the ground first
if ( ! mobj - > target ) // Still no target, aww.
{
// Reset the boss.
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
mobj - > fuse = 0 ;
mobj - > momx = FixedDiv ( mobj - > momx , FRACUNIT + ( FRACUNIT > > 2 ) ) ;
mobj - > momy = FixedDiv ( mobj - > momy , FRACUNIT + ( FRACUNIT > > 2 ) ) ;
mobj - > momz = FixedDiv ( mobj - > momz , FRACUNIT + ( FRACUNIT > > 2 ) ) ;
return ;
}
else if ( ! mobj - > fuse )
mobj - > fuse = 10 * TICRATE ;
}
// AI goes here.
{
boolean danger = true ;
angle_t angle ;
if ( mobj - > threshold )
mobj - > momz = ( mobj - > watertop - mobj - > z ) / 16 ; // Float to your desired position FASTER
else
mobj - > momz = ( mobj - > watertop - mobj - > z ) / 40 ; // Float to your desired position
if ( mobj - > movecount = = 2 ) {
mobj_t * spawner ;
fixed_t dist = 0 ;
angle = 0x06000000 * leveltime ;
// Alter your energy bubble's size/position
if ( mobj - > health > 3 ) {
mobj - > tracer - > destscale = FRACUNIT + ( 4 * TICRATE - mobj - > fuse ) * ( FRACUNIT / 2 ) / TICRATE + FixedMul ( FINECOSINE ( angle > > ANGLETOFINESHIFT ) , FRACUNIT / 2 ) ;
P_SetScale ( mobj - > tracer , mobj - > tracer - > destscale ) ;
P_TeleportMove ( mobj - > tracer , mobj - > x , mobj - > y , mobj - > z + mobj - > height / 2 - mobj - > tracer - > height / 2 ) ;
mobj - > tracer - > momx = mobj - > momx ;
mobj - > tracer - > momy = mobj - > momy ;
mobj - > tracer - > momz = mobj - > momz ;
}
// Face your target
P_BossTargetPlayer ( mobj , true ) ;
angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x , mobj - > target - > y ) ; // absolute angle
angle = ( angle - mobj - > angle ) ; // relative angle
if ( angle < ANGLE_180 )
mobj - > angle + = angle / 8 ;
else
mobj - > angle - = InvAngle ( angle ) / 8 ;
// Spawn energy particles
for ( spawner = mobj - > hnext ; spawner ; spawner = spawner - > hnext ) {
dist = P_AproxDistance ( spawner - > x - mobj - > x , spawner - > y - mobj - > y ) ;
if ( P_RandomRange ( 1 , ( dist > > FRACBITS ) / 16 ) = = 1 )
break ;
}
if ( spawner ) {
mobj_t * missile = P_SpawnMissile ( spawner , mobj , MT_MSGATHER ) ;
missile - > momz = FixedDiv ( missile - > momz , 7 * FRACUNIT / 4 ) ;
if ( dist = = 0 )
missile - > fuse = 0 ;
else
missile - > fuse = ( dist / P_AproxDistance ( missile - > momx , missile - > momy ) ) ;
if ( missile - > fuse > mobj - > fuse )
P_RemoveMobj ( missile ) ;
}
}
// Pre-threshold reactiontime stuff for attack phases
if ( mobj - > reactiontime & & mobj - > movecount = = 3 ) {
if ( mobj - > movedir = = 0 | | mobj - > movedir = = 2 ) { // Pausing between bounces in the pinball phase
if ( mobj - > target - > player - > powers [ pw_tailsfly ] ) // Trying to escape, eh?
mobj - > watertop = mobj - > target - > z + mobj - > target - > momz * 6 ; // Readjust your aim. >:3
else
mobj - > watertop = mobj - > target - > floorz + 16 * FRACUNIT ;
if ( ! ( mobj - > threshold % 4 ) )
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x + mobj - > target - > momx * 4 , mobj - > target - > y + mobj - > target - > momy * 4 ) ;
}
// Pausing between energy ball shots
mobj - > reactiontime - - ;
return ;
}
// threshold is used for attacks/maneuvers.
if ( mobj - > threshold ) {
fixed_t speed = 20 * FRACUNIT + FixedMul ( 40 * FRACUNIT , FixedDiv ( ( mobj - > info - > spawnhealth - mobj - > health ) < < FRACBITS , mobj - > info - > spawnhealth < < FRACBITS ) ) ;
int tries = 0 ;
// Firin' mah lazors
if ( mobj - > movecount = = 3 & & mobj - > movedir = = 1 ) {
if ( ! ( mobj - > threshold & 1 ) ) {
mobj_t * missile ;
if ( mobj - > info - > seesound )
S_StartSound ( mobj , mobj - > info - > seesound ) ;
P_SetMobjState ( mobj , mobj - > info - > missilestate ) ;
if ( mobj - > extravalue1 = = 3 )
mobj - > reactiontime = TICRATE / 16 ;
else
mobj - > reactiontime = TICRATE / 8 ;
A_FaceTarget ( mobj ) ;
missile = P_SpawnMissile ( mobj , mobj - > target , mobj - > info - > speed ) ;
if ( mobj - > extravalue1 = = 2 | | mobj - > extravalue1 = = 3 ) {
missile - > destscale = FRACUNIT > > 1 ;
P_SetScale ( missile , missile - > destscale ) ;
}
missile - > fuse = 3 * TICRATE ;
missile - > z - = missile - > height / 2 ;
if ( mobj - > extravalue1 = = 2 ) {
int i ;
mobj_t * spread ;
missile - > flags | = MF_MISSILE ;
for ( i = 0 ; i < 5 ; i + + ) {
if ( i = = 2 )
continue ;
spread = P_SpawnMobj ( missile - > x , missile - > y , missile - > z , missile - > type ) ;
spread - > angle = missile - > angle + ( ANGLE_11hh / 2 ) * ( i - 2 ) ;
P_InstaThrust ( spread , spread - > angle , spread - > info - > speed ) ;
spread - > momz = missile - > momz ;
spread - > destscale = FRACUNIT > > 1 ;
P_SetScale ( spread , spread - > destscale ) ;
spread - > fuse = 3 * TICRATE ;
}
missile - > flags & = ~ MF_MISSILE ;
}
} else {
P_SetMobjState ( mobj , mobj - > state - > nextstate ) ;
if ( mobj - > extravalue1 = = 3 )
mobj - > reactiontime = TICRATE / 8 ;
else
mobj - > reactiontime = TICRATE / 4 ;
}
mobj - > threshold - - ;
return ;
}
P_SpawnGhostMobj ( mobj ) ;
// Pinball attack!
if ( mobj - > movecount = = 3 & & ( mobj - > movedir = = 0 | | mobj - > movedir = = 2 ) ) {
if ( ( statenum_t ) ( mobj - > state - states ) ! = mobj - > info - > seestate )
P_SetMobjState ( mobj , mobj - > info - > seestate ) ;
if ( mobj - > movedir = = 0 ) // mobj health == 1
P_InstaThrust ( mobj , mobj - > angle , 38 * FRACUNIT ) ;
else if ( mobj - > health = = 3 )
P_InstaThrust ( mobj , mobj - > angle , 22 * FRACUNIT ) ;
else // mobj health == 2
P_InstaThrust ( mobj , mobj - > angle , 30 * FRACUNIT ) ;
if ( ! P_TryMove ( mobj , mobj - > x + mobj - > momx , mobj - > y + mobj - > momy , true ) ) { // Hit a wall? Find a direction to bounce
mobj - > threshold - - ;
if ( mobj - > threshold ) {
P_SetMobjState ( mobj , mobj - > state - > nextstate ) ;
if ( mobj - > info - > mass )
S_StartSound ( mobj , mobj - > info - > mass ) ;
if ( ! ( mobj - > threshold % 4 ) ) { // We've decided to lock onto the player this bounce.
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x + mobj - > target - > momx * 4 , mobj - > target - > y + mobj - > target - > momy * 4 ) ;
mobj - > reactiontime = TICRATE ; // targetting time
} else { // No homing, just use P_BounceMove
P_BounceMove ( mobj ) ;
mobj - > angle = R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) ;
mobj - > reactiontime = TICRATE / 4 ; // just a pause before you bounce away
}
mobj - > momx = mobj - > momy = 0 ;
}
}
return ;
}
// Vector form dodge!
mobj - > angle + = mobj - > movedir ;
P_InstaThrust ( mobj , mobj - > angle , - speed ) ;
while ( ! P_TryMove ( mobj , mobj - > x + mobj - > momx , mobj - > y + mobj - > momy , true ) & & tries + + < 16 ) {
mobj - > angle + = mobj - > movedir ;
P_InstaThrust ( mobj , mobj - > angle , - speed ) ;
}
mobj - > momx = mobj - > momy = 0 ;
mobj - > threshold - - ;
if ( ! mobj - > threshold )
{ // Go into stun after dodge.
// from 3*TICRATE down to 1.25*TICRATE
//mobj->reactiontime = 5*TICRATE/4 + (FixedMul((7*TICRATE/4)<<FRACBITS, FixedDiv((mobj->health-1)<<FRACBITS, (mobj->info->spawnhealth-1)<<FRACBITS))>>FRACBITS);
// from 3*TICRATE down to 2*TICRATE
mobj - > reactiontime = 2 * TICRATE + ( FixedMul ( ( 1 * TICRATE ) < < FRACBITS , FixedDiv ( ( mobj - > health - 1 ) < < FRACBITS , ( mobj - > info - > spawnhealth - 1 ) < < FRACBITS ) ) > > FRACBITS ) ;
mobj - > flags | = MF_SPECIAL | MF_SHOOTABLE ;
P_SetMobjState ( mobj , mobj - > state - > nextstate ) ;
}
return ;
}
angle = 0x06000000 * leveltime ;
mobj - > momz + = FixedMul ( FINECOSINE ( angle > > ANGLETOFINESHIFT ) , 2 * FRACUNIT ) ; // Use that "angle" to bob gently in the air
// This is below threshold because we don't want to bob while zipping around
// Ohh you're in for it now..
2014-03-23 16:00:29 +00:00
if ( mobj - > flags2 & MF2_FRET & & mobj - > health < = mobj - > info - > damage )
2014-03-15 16:59:03 +00:00
mobj - > fuse = 0 ;
// reactiontime is used for delays.
if ( mobj - > reactiontime )
{
// Stunned after vector form
if ( mobj - > movedir > ANGLE_180 )
mobj - > angle - = FixedAngle ( FixedMul ( AngleFixed ( InvAngle ( mobj - > movedir ) ) , FixedDiv ( mobj - > reactiontime < < FRACBITS , 24 < < FRACBITS ) ) ) ;
else
mobj - > angle + = FixedAngle ( FixedMul ( AngleFixed ( mobj - > movedir ) , FixedDiv ( mobj - > reactiontime < < FRACBITS , 24 < < FRACBITS ) ) ) ;
mobj - > reactiontime - - ;
if ( ! mobj - > reactiontime )
// Out of stun.
P_SetMobjState ( mobj , mobj - > state - > nextstate ) ;
return ;
}
// Not stunned? Can hit.
// Here because stun won't always get the chance to complete due to pinch phase activating, being hit, etc.
mobj - > flags & = ~ ( MF_SPECIAL | MF_SHOOTABLE ) ;
if ( mobj - > health < = mobj - > info - > damage & & mobj - > fuse & & ! ( mobj - > fuse % TICRATE ) )
{
var1 = 1 ;
var2 = 0 ;
A_BossScream ( mobj ) ;
}
// Don't move if we're still in pain!
if ( mobj - > flags2 & MF2_FRET )
return ;
if ( mobj - > state = = & states [ mobj - > info - > raisestate ] )
{ // Charging energy
if ( mobj - > momx ! = 0 | | mobj - > momy ! = 0 ) { // Apply the air breaks
if ( abs ( mobj - > momx ) + abs ( mobj - > momy ) < FRACUNIT )
mobj - > momx = mobj - > momy = 0 ;
else
P_Thrust ( mobj , R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) , - 6 * FRACUNIT / 8 ) ;
}
return ;
}
if ( mobj - > fuse = = 0 )
{
// It's time to attack! What are we gonna do?!
switch ( mobj - > movecount )
{
case 0 :
default :
// Fly up and prepare for an attack!
// We have to charge up first, so let's go up into the air
P_SetMobjState ( mobj , mobj - > info - > raisestate ) ;
if ( mobj - > floorz > = mobj - > target - > floorz )
mobj - > watertop = mobj - > floorz + 256 * FRACUNIT ;
else
mobj - > watertop = mobj - > target - > floorz + 256 * FRACUNIT ;
break ;
case 1 : {
// Okay, we're up? Good, time to gather energy...
2014-03-23 16:00:29 +00:00
if ( mobj - > health > mobj - > info - > damage )
{ // No more bubble if we're broken (pinch phase)
2014-03-15 16:59:03 +00:00
mobj_t * shield = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_MSSHIELD_FRONT ) ;
P_SetTarget ( & mobj - > tracer , shield ) ;
P_SetTarget ( & shield - > target , mobj ) ;
2014-03-23 16:00:29 +00:00
}
else
2014-03-15 16:59:03 +00:00
P_LinedefExecute ( LE_PINCHPHASE , mobj , NULL ) ;
mobj - > fuse = 4 * TICRATE ;
mobj - > flags | = MF_PAIN ;
if ( mobj - > info - > attacksound )
S_StartSound ( mobj , mobj - > info - > attacksound ) ;
A_FaceTarget ( mobj ) ;
break ;
}
case 2 :
// We're all charged and ready now! Unleash the fury!!
2014-03-23 16:00:29 +00:00
if ( mobj - > health > mobj - > info - > damage )
{
mobj_t * removemobj = mobj - > tracer ;
P_SetTarget ( & mobj - > tracer , mobj - > hnext ) ;
P_RemoveMobj ( removemobj ) ;
}
2014-03-15 16:59:03 +00:00
if ( mobj - > health < = mobj - > info - > damage ) {
// Attack 1: Pinball dash!
if ( mobj - > health = = 1 )
mobj - > movedir = 0 ;
else
mobj - > movedir = 2 ;
if ( mobj - > info - > seesound )
S_StartSound ( mobj , mobj - > info - > seesound ) ;
P_SetMobjState ( mobj , mobj - > info - > seestate ) ;
if ( mobj - > movedir = = 2 )
mobj - > threshold = 16 ; // bounce 16 times
else
mobj - > threshold = 32 ; // bounce 32 times
mobj - > watertop = mobj - > target - > floorz + 16 * FRACUNIT ;
P_LinedefExecute ( LE_PINCHPHASE , mobj , NULL ) ;
} else {
// Attack 2: Energy shot!
mobj - > movedir = 1 ;
if ( mobj - > health > = 8 )
mobj - > extravalue1 = 0 ;
else if ( mobj - > health > = 5 )
mobj - > extravalue1 = 2 ;
else if ( mobj - > health > = 4 )
mobj - > extravalue1 = 1 ;
else
mobj - > extravalue1 = 3 ;
switch ( mobj - > extravalue1 ) {
case 0 : // shoot once
case 2 : // spread-shot
default :
mobj - > threshold = 2 ;
break ;
case 1 : // shoot 3 times
mobj - > threshold = 3 * 2 ;
break ;
case 3 : // shoot like a goddamn machinegun
mobj - > threshold = 8 * 2 ;
break ;
}
}
break ;
case 3 :
// Return to idle.
mobj - > watertop = mobj - > target - > floorz + 32 * FRACUNIT ;
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
mobj - > flags & = ~ MF_PAIN ;
mobj - > fuse = 10 * TICRATE ;
break ;
}
mobj - > movecount + + ;
mobj - > movecount % = 4 ;
return ;
}
// Idle AI
if ( mobj - > state = = & states [ mobj - > info - > spawnstate ] )
{
fixed_t dist ;
// Target the closest player
P_BossTargetPlayer ( mobj , true ) ;
// Face your target
angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x , mobj - > target - > y ) ; // absolute angle
angle = ( angle - mobj - > angle ) ; // relative angle
if ( angle < ANGLE_180 )
mobj - > angle + = angle / 8 ;
else
mobj - > angle - = InvAngle ( angle ) / 8 ;
//A_FaceTarget(mobj);
// Check if we're being attacked
if ( ! ( mobj - > target - > player - > pflags & ( PF_JUMPED | PF_SPINNING )
| | mobj - > target - > player - > powers [ pw_tailsfly ]
| | mobj - > target - > player - > powers [ pw_invulnerability ]
| | mobj - > target - > player - > powers [ pw_super ] ) )
danger = false ;
if ( mobj - > target - > x + mobj - > target - > radius + abs ( mobj - > target - > momx * 2 ) < mobj - > x - mobj - > radius )
danger = false ;
if ( mobj - > target - > x - mobj - > target - > radius - abs ( mobj - > target - > momx * 2 ) > mobj - > x + mobj - > radius )
danger = false ;
if ( mobj - > target - > y + mobj - > target - > radius + abs ( mobj - > target - > momy * 2 ) < mobj - > y - mobj - > radius )
danger = false ;
if ( mobj - > target - > y - mobj - > target - > radius - abs ( mobj - > target - > momy * 2 ) > mobj - > y + mobj - > radius )
danger = false ;
if ( mobj - > target - > z + mobj - > target - > height + mobj - > target - > momz * 2 < mobj - > z )
danger = false ;
if ( mobj - > target - > z + mobj - > target - > momz * 2 > mobj - > z + mobj - > height )
danger = false ;
if ( danger ) {
// An incoming attack is detected! What should we do?!
// Go into vector form!
mobj - > movedir = ANGLE_11hh - FixedAngle ( FixedMul ( AngleFixed ( ANGLE_11hh ) , FixedDiv ( ( mobj - > info - > spawnhealth - mobj - > health ) < < FRACBITS , ( mobj - > info - > spawnhealth - 1 ) < < FRACBITS ) ) ) ;
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 2 ) )
2014-03-15 16:59:03 +00:00
mobj - > movedir = InvAngle ( mobj - > movedir ) ;
mobj - > threshold = 6 + ( FixedMul ( 24 < < FRACBITS , FixedDiv ( ( mobj - > info - > spawnhealth - mobj - > health ) < < FRACBITS , ( mobj - > info - > spawnhealth - 1 ) < < FRACBITS ) ) > > FRACBITS ) ;
if ( mobj - > info - > activesound )
S_StartSound ( mobj , mobj - > info - > activesound ) ;
if ( mobj - > info - > painchance )
P_SetMobjState ( mobj , mobj - > info - > painchance ) ;
return ;
}
// Move normally: Approach the player using normal thrust and simulated friction.
dist = P_AproxDistance ( mobj - > x - mobj - > target - > x , mobj - > y - mobj - > target - > y ) ;
P_Thrust ( mobj , R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) , - 3 * FRACUNIT / 8 ) ;
if ( dist < 64 * FRACUNIT )
P_Thrust ( mobj , mobj - > angle , - 4 * FRACUNIT ) ;
else if ( dist > 180 * FRACUNIT )
P_Thrust ( mobj , mobj - > angle , FRACUNIT ) ;
mobj - > momz + = P_AproxDistance ( mobj - > momx , mobj - > momy ) / 12 ; // Move up higher the faster you're going.
}
}
}
//
// P_GetClosestAxis
//
// Finds the CLOSEST axis to the source mobj
mobj_t * P_GetClosestAxis ( mobj_t * source )
{
thinker_t * th ;
mobj_t * mo2 ;
mobj_t * closestaxis = NULL ;
fixed_t dist1 , dist2 = 0 ;
// scan the thinkers to find the closest axis point
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 - > type = = MT_AXIS )
{
if ( closestaxis = = NULL )
{
closestaxis = mo2 ;
dist2 = R_PointToDist2 ( source - > x , source - > y , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
}
else
{
dist1 = R_PointToDist2 ( source - > x , source - > y , mo2 - > x , mo2 - > y ) - mo2 - > radius ;
if ( dist1 < dist2 )
{
closestaxis = mo2 ;
dist2 = dist1 ;
}
}
}
}
if ( closestaxis = = NULL )
CONS_Debug ( DBG_NIGHTS , " ERROR: No axis points found! \n " ) ;
return closestaxis ;
}
static void P_GimmeAxisXYPos ( mobj_t * closestaxis , degenmobj_t * mobj )
{
const angle_t fa = R_PointToAngle2 ( closestaxis - > x , closestaxis - > y , mobj - > x , mobj - > y ) > > ANGLETOFINESHIFT ;
mobj - > x = closestaxis - > x + FixedMul ( FINECOSINE ( fa ) , closestaxis - > radius ) ;
mobj - > y = closestaxis - > y + FixedMul ( FINESINE ( fa ) , closestaxis - > radius ) ;
}
static void P_MoveHoop ( mobj_t * mobj )
{
const fixed_t fuse = ( mobj - > fuse * mobj - > extravalue2 ) ;
const angle_t fa = mobj - > movedir * ( FINEANGLES / mobj - > extravalue1 ) ;
TVector v ;
TVector * res ;
fixed_t finalx , finaly , finalz ;
2014-08-04 03:49:33 +00:00
fixed_t x , y , z ;
2014-03-15 16:59:03 +00:00
//I_Assert(mobj->target != NULL);
if ( ! mobj - > target ) /// \todo DEBUG ME! Target was P_RemoveMobj'd at some point, and therefore no longer valid!
return ;
2014-08-04 03:49:33 +00:00
x = mobj - > target - > x ;
y = mobj - > target - > y ;
z = mobj - > target - > z + mobj - > target - > height / 2 ;
2014-03-15 16:59:03 +00:00
// Make the sprite travel towards the center of the hoop
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , fuse ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , fuse ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( FixedAngle ( mobj - > target - > movedir * FRACUNIT ) ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( FixedAngle ( mobj - > target - > movecount * FRACUNIT ) ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
2014-08-04 03:49:33 +00:00
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
2014-03-15 16:59:03 +00:00
P_UnsetThingPosition ( mobj ) ;
mobj - > x = finalx ;
mobj - > y = finaly ;
P_SetThingPosition ( mobj ) ;
mobj - > z = finalz - mobj - > height / 2 ;
}
void P_SpawnHoopOfSomething ( fixed_t x , fixed_t y , fixed_t z , fixed_t radius , INT32 number , mobjtype_t type , angle_t rotangle )
{
mobj_t * mobj ;
INT32 i ;
TVector v ;
TVector * res ;
fixed_t finalx , finaly , finalz ;
mobj_t hoopcenter ;
mobj_t * axis ;
degenmobj_t xypos ;
angle_t degrees , fa , closestangle ;
hoopcenter . x = x ;
hoopcenter . y = y ;
hoopcenter . z = z ;
axis = P_GetClosestAxis ( & hoopcenter ) ;
if ( ! axis )
{
CONS_Debug ( DBG_NIGHTS , " You forgot to put axis points in the map! \n " ) ;
return ;
}
xypos . x = x ;
xypos . y = y ;
P_GimmeAxisXYPos ( axis , & xypos ) ;
x = xypos . x ;
y = xypos . y ;
hoopcenter . z = z - mobjinfo [ type ] . height / 2 ;
hoopcenter . x = x ;
hoopcenter . y = y ;
closestangle = R_PointToAngle2 ( x , y , axis - > x , axis - > y ) ;
degrees = FINEANGLES / number ;
radius > > = FRACBITS ;
// Create the hoop!
for ( i = 0 ; i < number ; i + + )
{
fa = ( i * degrees ) ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , radius ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , radius ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( rotangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
mobj = P_SpawnMobj ( finalx , finaly , finalz , type ) ;
mobj - > z - = mobj - > height / 2 ;
}
}
void P_SpawnParaloop ( fixed_t x , fixed_t y , fixed_t z , fixed_t radius , INT32 number , mobjtype_t type , statenum_t nstate , angle_t rotangle , boolean spawncenter )
{
mobj_t * mobj ;
INT32 i ;
TVector v ;
TVector * res ;
fixed_t finalx , finaly , finalz , dist ;
angle_t degrees , fa , closestangle ;
fixed_t mobjx , mobjy , mobjz ;
degrees = FINEANGLES / number ;
radius = FixedDiv ( radius , 5 * ( FRACUNIT / 4 ) ) ;
closestangle = 0 ;
// Create the hoop!
for ( i = 0 ; i < number ; i + + )
{
fa = ( i * degrees ) ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , radius ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , radius ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( rotangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
mobj = P_SpawnMobj ( finalx , finaly , finalz , type ) ;
mobj - > z - = mobj - > height > > 1 ;
// change angle
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , x , y ) ;
// change slope
dist = P_AproxDistance ( P_AproxDistance ( x - mobj - > x , y - mobj - > y ) , z - mobj - > z ) ;
if ( dist < 1 )
dist = 1 ;
mobjx = mobj - > x ;
mobjy = mobj - > y ;
mobjz = mobj - > z ;
// set to special state
if ( nstate ! = S_NULL )
P_SetMobjState ( mobj , nstate ) ;
mobj - > momx = FixedMul ( FixedDiv ( x - mobjx , dist ) , 5 * FRACUNIT ) ;
mobj - > momy = FixedMul ( FixedDiv ( y - mobjy , dist ) , 5 * FRACUNIT ) ;
mobj - > momz = FixedMul ( FixedDiv ( z - mobjz , dist ) , 5 * FRACUNIT ) ;
mobj - > fuse = ( radius > > ( FRACBITS + 2 ) ) + 1 ;
if ( spawncenter )
{
mobj - > x = x ;
mobj - > y = y ;
mobj - > z = z ;
}
if ( mobj - > fuse < = 1 )
mobj - > fuse = 2 ;
mobj - > flags | = MF_NOCLIPTHING ;
mobj - > flags & = ~ MF_SPECIAL ;
if ( mobj - > fuse > 7 )
mobj - > tics = mobj - > fuse - 7 ;
else
mobj - > tics = 1 ;
}
}
//
// P_SetScale
//
// Sets the sprite scaling
//
void P_SetScale ( mobj_t * mobj , fixed_t newscale )
{
player_t * player ;
fixed_t oldscale ;
if ( ! mobj )
return ;
oldscale = mobj - > scale ; //keep for adjusting stuff below
mobj - > scale = newscale ;
mobj - > radius = FixedMul ( mobj - > info - > radius , newscale ) ;
mobj - > height = FixedMul ( mobj - > info - > height , newscale ) ;
player = mobj - > player ;
if ( player )
{
G_GhostAddScale ( newscale ) ;
player - > viewheight = FixedMul ( FixedDiv ( player - > viewheight , oldscale ) , newscale ) ; // Nonono don't calculate viewheight elsewhere, this is the best place for it!
2014-08-04 03:49:33 +00:00
player - > dashspeed = FixedMul ( FixedDiv ( player - > dashspeed , oldscale ) , newscale ) ; // Prevents the player from having to re-charge up spindash if the player grew in size
2014-03-15 16:59:03 +00:00
}
}
void P_Attract ( mobj_t * source , mobj_t * dest , boolean nightsgrab ) // Home in on your target
{
fixed_t dist , ndist , speedmul ;
fixed_t tx = dest - > x ;
fixed_t ty = dest - > y ;
fixed_t tz = dest - > z + ( dest - > height / 2 ) ; // Aim for center
2017-03-04 22:13:19 +00:00
2014-03-15 16:59:03 +00:00
if ( ! dest | | dest - > health < = 0 | | ! dest - > player | | ! source - > tracer )
return ;
// change angle
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
//source->angle = R_PointToAngle2(source->x, source->y, tx, ty);
2014-03-15 16:59:03 +00:00
// change slope
dist = P_AproxDistance ( P_AproxDistance ( tx - source - > x , ty - source - > y ) , tz - source - > z ) ;
if ( dist < 1 )
dist = 1 ;
if ( nightsgrab )
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
speedmul = P_AproxDistance ( dest - > momx , dest - > momy ) + source - > scale ;
2014-03-15 16:59:03 +00:00
else
speedmul = P_AproxDistance ( dest - > momx , dest - > momy ) + FixedMul ( source - > info - > speed , source - > scale ) ;
source - > momx = FixedMul ( FixedDiv ( tx - source - > x , dist ) , speedmul ) ;
source - > momy = FixedMul ( FixedDiv ( ty - source - > y , dist ) , speedmul ) ;
source - > momz = FixedMul ( FixedDiv ( tz - source - > z , dist ) , speedmul ) ;
// Instead of just unsetting NOCLIP like an idiot, let's check the distance to our target.
ndist = P_AproxDistance ( P_AproxDistance ( tx - ( source - > x + source - > momx ) ,
ty - ( source - > y + source - > momy ) ) ,
tz - ( source - > z + source - > momz ) ) ;
if ( ndist > dist ) // gone past our target
{
// place us on top of them then.
source - > momx = source - > momy = source - > momz = 0 ;
P_UnsetThingPosition ( source ) ;
source - > x = tx ;
source - > y = ty ;
source - > z = tz ;
P_SetThingPosition ( source ) ;
}
}
static void P_NightsItemChase ( mobj_t * thing )
{
if ( ! thing - > tracer )
{
P_SetTarget ( & thing - > tracer , NULL ) ;
thing - > flags2 & = ~ MF2_NIGHTSPULL ;
return ;
}
if ( ! thing - > tracer - > player )
return ;
P_Attract ( thing , thing - > tracer , true ) ;
}
2018-10-03 16:16:23 +00:00
/*static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
2014-03-15 16:59:03 +00:00
{
if ( ! thing - > target | | thing - > target - > health < = 0 | | ! thing - > target - > player
| | ( thing - > target - > player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_NONE | | thing - > target - > player - > powers [ pw_super ]
| | thing - > target - > player - > powers [ pw_invulnerability ] > 1 )
{
P_RemoveMobj ( thing ) ;
return false ;
}
// TODO: Make an MT_SHIELDORB which changes color/states to always match the appropriate shield,
// instead of having completely seperate mobjtypes.
if ( shield ! = SH_FORCE )
{ // Regular shields check for themselves only
if ( ( shieldtype_t ) ( thing - > target - > player - > powers [ pw_shield ] & SH_NOSTACK ) ! = shield )
{
P_RemoveMobj ( thing ) ;
return false ;
}
}
else if ( ! ( thing - > target - > player - > powers [ pw_shield ] & SH_FORCE ) )
{ // Force shields check for any force shield
P_RemoveMobj ( thing ) ;
return false ;
}
if ( shield = = SH_FORCE & & thing - > movecount ! = ( thing - > target - > player - > powers [ pw_shield ] & 0xFF ) )
{
thing - > movecount = ( thing - > target - > player - > powers [ pw_shield ] & 0xFF ) ;
if ( thing - > movecount < 1 )
{
if ( thing - > info - > painstate )
P_SetMobjState ( thing , thing - > info - > painstate ) ;
else
thing - > flags2 | = MF2_SHADOW ;
}
else
{
if ( thing - > info - > painstate )
P_SetMobjState ( thing , thing - > info - > spawnstate ) ;
else
thing - > flags2 & = ~ MF2_SHADOW ;
}
}
thing - > flags | = MF_NOCLIPHEIGHT ;
thing - > eflags = ( thing - > eflags & ~ MFE_VERTICALFLIP ) | ( thing - > target - > eflags & MFE_VERTICALFLIP ) ;
P_SetScale ( thing , thing - > target - > scale ) ;
P_UnsetThingPosition ( thing ) ;
2016-07-06 04:09:17 +00:00
thing - > x = thing - > target - > x ;
thing - > y = thing - > target - > y ;
2014-03-15 16:59:03 +00:00
if ( thing - > eflags & MFE_VERTICALFLIP )
thing - > z = thing - > target - > z + thing - > target - > height - thing - > height + FixedDiv ( P_GetPlayerHeight ( thing - > target - > player ) - thing - > target - > height , 3 * FRACUNIT ) - FixedMul ( 2 * FRACUNIT , thing - > target - > scale ) ;
else
thing - > z = thing - > target - > z - FixedDiv ( P_GetPlayerHeight ( thing - > target - > player ) - thing - > target - > height , 3 * FRACUNIT ) + FixedMul ( 2 * FRACUNIT , thing - > target - > scale ) ;
P_SetThingPosition ( thing ) ;
P_CheckPosition ( thing , thing - > x , thing - > y ) ;
if ( P_MobjWasRemoved ( thing ) )
return false ;
// if (thing->z < thing->floorz)
// thing->z = thing->floorz;
return true ;
}
mobj_t * shields [ MAXPLAYERS * 2 ] ;
INT32 numshields = 0 ;
void P_RunShields ( void )
{
INT32 i ;
2014-03-18 17:56:54 +00:00
// run shields
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < numshields ; i + + )
{
P_ShieldLook ( shields [ i ] , shields [ i ] - > info - > speed ) ;
P_SetTarget ( & shields [ i ] , NULL ) ;
}
numshields = 0 ;
2016-07-06 04:09:17 +00:00
}
static boolean P_AddShield ( mobj_t * thing )
{
shieldtype_t shield = thing - > info - > speed ;
if ( ! thing - > target | | thing - > target - > health < = 0 | | ! thing - > target - > player
| | ( thing - > target - > player - > powers [ pw_shield ] & SH_NOSTACK ) = = SH_NONE | | thing - > target - > player - > powers [ pw_super ]
| | thing - > target - > player - > powers [ pw_invulnerability ] > 1 )
{
P_RemoveMobj ( thing ) ;
return false ;
}
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
if ( shield ! = SH_FORCE )
{ // Regular shields check for themselves only
if ( ( shieldtype_t ) ( thing - > target - > player - > powers [ pw_shield ] & SH_NOSTACK ) ! = shield )
{
P_RemoveMobj ( thing ) ;
return false ;
}
}
else if ( ! ( thing - > target - > player - > powers [ pw_shield ] & SH_FORCE ) )
{ // Force shields check for any force shield
P_RemoveMobj ( thing ) ;
return false ;
}
// Queue has been hit... why?!?
if ( numshields > = MAXPLAYERS * 2 )
return P_ShieldLook ( thing , thing - > info - > speed ) ;
P_SetTarget ( & shields [ numshields + + ] , thing ) ;
return true ;
2018-10-03 16:14:25 +00:00
} */
2016-07-06 04:09:17 +00:00
void P_RunOverlays ( void )
{
2014-03-18 17:56:54 +00:00
// run overlays
2016-07-06 04:09:17 +00:00
mobj_t * mo , * next = NULL ;
fixed_t destx , desty , zoffs ;
2014-03-18 17:56:54 +00:00
for ( mo = overlaycap ; mo ; mo = next )
2014-03-15 16:59:03 +00:00
{
2014-03-18 17:56:54 +00:00
I_Assert ( ! P_MobjWasRemoved ( mo ) ) ;
// grab next in chain, then unset the chain target
next = mo - > hnext ;
P_SetTarget ( & mo - > hnext , NULL ) ;
2014-03-15 16:59:03 +00:00
if ( ! mo - > target )
continue ;
2017-12-19 01:59:04 +00:00
if ( ! splitscreen /*&& rendermode != render_soft*/ )
2014-03-15 16:59:03 +00:00
{
angle_t viewingangle ;
if ( players [ displayplayer ] . awayviewtics )
viewingangle = R_PointToAngle2 ( mo - > target - > x , mo - > target - > y , players [ displayplayer ] . awayviewmobj - > x , players [ displayplayer ] . awayviewmobj - > y ) ;
else if ( ! camera . chase & & players [ displayplayer ] . mo )
viewingangle = R_PointToAngle2 ( mo - > target - > x , mo - > target - > y , players [ displayplayer ] . mo - > x , players [ displayplayer ] . mo - > y ) ;
else
viewingangle = R_PointToAngle2 ( mo - > target - > x , mo - > target - > y , camera . x , camera . y ) ;
2016-07-06 04:09:17 +00:00
if ( ! ( mo - > state - > frame & FF_ANIMATE ) & & mo - > state - > var1 )
2014-03-15 16:59:03 +00:00
viewingangle + = ANGLE_180 ;
destx = mo - > target - > x + P_ReturnThrustX ( mo - > target , viewingangle , FixedMul ( FRACUNIT / 4 , mo - > scale ) ) ;
desty = mo - > target - > y + P_ReturnThrustY ( mo - > target , viewingangle , FixedMul ( FRACUNIT / 4 , mo - > scale ) ) ;
}
else
{
destx = mo - > target - > x ;
desty = mo - > target - > y ;
}
mo - > eflags = ( mo - > eflags & ~ MFE_VERTICALFLIP ) | ( mo - > target - > eflags & MFE_VERTICALFLIP ) ;
mo - > scale = mo - > destscale = mo - > target - > scale ;
mo - > angle = mo - > target - > angle ;
2018-08-30 12:13:25 +00:00
if ( ( mo - > flags & MF_DONTENCOREMAP ) ! = ( mo - > target - > flags & MF_DONTENCOREMAP ) )
mo - > flags ^ = MF_DONTENCOREMAP ;
2016-07-06 04:09:17 +00:00
if ( ! ( mo - > state - > frame & FF_ANIMATE ) )
zoffs = FixedMul ( ( ( signed ) mo - > state - > var2 ) * FRACUNIT , mo - > scale ) ;
// if you're using FF_ANIMATE on an overlay,
// then you're on your own.
else
zoffs = 0 ;
2014-03-15 16:59:03 +00:00
P_UnsetThingPosition ( mo ) ;
mo - > x = destx ;
mo - > y = desty ;
2016-09-27 16:17:23 +00:00
mo - > radius = mo - > target - > radius ;
mo - > height = mo - > target - > height ;
2014-03-15 16:59:03 +00:00
if ( mo - > eflags & MFE_VERTICALFLIP )
mo - > z = ( mo - > target - > z + mo - > target - > height - mo - > height ) - zoffs ;
else
mo - > z = mo - > target - > z + zoffs ;
if ( mo - > state - > var1 )
P_SetUnderlayPosition ( mo ) ;
else
P_SetThingPosition ( mo ) ;
P_CheckPosition ( mo , mo - > x , mo - > y ) ;
}
2014-03-18 17:56:54 +00:00
P_SetTarget ( & overlaycap , NULL ) ;
2014-03-15 16:59:03 +00:00
}
2014-03-18 17:56:54 +00:00
// Called only when MT_OVERLAY thinks.
2014-03-15 16:59:03 +00:00
static void P_AddOverlay ( mobj_t * thing )
{
2014-03-18 17:56:54 +00:00
I_Assert ( thing ! = NULL ) ;
if ( overlaycap = = NULL )
P_SetTarget ( & overlaycap , thing ) ;
2014-03-15 16:59:03 +00:00
else {
2014-03-18 17:56:54 +00:00
mobj_t * mo ;
2014-03-15 16:59:03 +00:00
for ( mo = overlaycap ; mo & & mo - > hnext ; mo = mo - > hnext )
;
2014-03-18 17:56:54 +00:00
I_Assert ( mo ! = NULL ) ;
I_Assert ( mo - > hnext = = NULL ) ;
P_SetTarget ( & mo - > hnext , thing ) ;
2014-03-15 16:59:03 +00:00
}
2014-03-18 17:56:54 +00:00
P_SetTarget ( & thing - > hnext , NULL ) ;
}
// Called only when MT_OVERLAY (or anything else in the overlaycap list) is removed.
// Keeps the hnext list from corrupting.
static void P_RemoveOverlay ( mobj_t * thing )
{
mobj_t * mo ;
for ( mo = overlaycap ; mo ; mo = mo - > hnext )
if ( mo - > hnext = = thing )
{
P_SetTarget ( & mo - > hnext , thing - > hnext ) ;
P_SetTarget ( & thing - > hnext , NULL ) ;
return ;
}
2014-03-15 16:59:03 +00:00
}
2017-10-12 02:14:14 +00:00
void P_RunShadows ( void )
{
2018-09-13 18:01:36 +00:00
mobj_t * mobj , * next , * dest ;
2017-10-12 02:14:14 +00:00
2018-03-13 05:58:57 +00:00
for ( mobj = shadowcap ; mobj ; mobj = next )
2017-10-12 02:14:14 +00:00
{
2018-03-13 05:58:57 +00:00
next = mobj - > hnext ;
P_SetTarget ( & mobj - > hnext , NULL ) ;
2017-10-12 02:14:14 +00:00
2018-09-13 19:41:12 +00:00
if ( ! mobj - > target | | P_MobjWasRemoved ( mobj - > target ) )
{
mobj - > flags2 | = MF2_DONTDRAW ;
2018-03-13 05:58:57 +00:00
continue ; // shouldn't you already be dead?
2018-09-13 19:41:12 +00:00
}
2017-10-12 02:14:14 +00:00
2018-03-13 05:58:57 +00:00
if ( ( mobj - > target - > flags2 & MF2_DONTDRAW )
| | ( ( ( mobj - > target - > eflags & MFE_VERTICALFLIP ) & & mobj - > target - > z + mobj - > target - > height > mobj - > target - > ceilingz )
| | ( ! ( mobj - > target - > eflags & MFE_VERTICALFLIP ) & & mobj - > target - > z < mobj - > target - > floorz ) ) )
mobj - > flags2 | = MF2_DONTDRAW ;
else
mobj - > flags2 & = ~ MF2_DONTDRAW ;
2017-10-12 02:14:14 +00:00
2018-07-28 06:37:00 +00:00
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
mobj - > eflags | = MFE_VERTICALFLIP ;
else
mobj - > eflags & = ~ MFE_VERTICALFLIP ;
2018-06-06 22:36:39 +00:00
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP1 ) // groooooaann...
mobj - > eflags | = MFE_DRAWONLYFORP1 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP1 ;
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP2 )
mobj - > eflags | = MFE_DRAWONLYFORP2 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP2 ;
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP3 )
mobj - > eflags | = MFE_DRAWONLYFORP3 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP3 ;
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP4 )
mobj - > eflags | = MFE_DRAWONLYFORP4 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP4 ;
2018-03-13 05:58:57 +00:00
// First scale to the same radius
P_SetScale ( mobj , FixedDiv ( mobj - > target - > radius , mobj - > info - > radius ) ) ;
2017-10-12 02:14:14 +00:00
2018-09-13 18:01:36 +00:00
dest = mobj - > target ;
if ( dest - > type = = MT_THUNDERSHIELD )
dest = dest - > target ;
P_TeleportMove ( mobj , dest - > x , dest - > y , mobj - > target - > z ) ;
2017-10-12 02:14:14 +00:00
2018-07-28 06:37:00 +00:00
if ( ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & ( mobj - > ceilingz > mobj - > z + mobj - > height ) )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & ( mobj - > floorz < mobj - > z ) ) )
2018-03-13 05:58:57 +00:00
{
INT32 i ;
fixed_t prevz ;
2017-10-12 02:14:14 +00:00
2018-07-28 06:37:00 +00:00
mobj - > z = ( mobj - > eflags & MFE_VERTICALFLIP ? mobj - > ceilingz : mobj - > floorz ) ;
2018-03-13 05:58:57 +00:00
for ( i = 0 ; i < MAXFFLOORS ; i + + )
2017-10-12 02:14:14 +00:00
{
2018-03-13 05:58:57 +00:00
prevz = mobj - > z ;
// Now scale again based on height difference
P_SetScale ( mobj , FixedDiv ( mobj - > scale , max ( FRACUNIT , ( ( mobj - > target - > z - mobj - > z ) / 200 ) + FRACUNIT ) ) ) ;
// Check new position to see if you should still be on that ledge
2018-09-13 18:01:36 +00:00
P_TeleportMove ( mobj , dest - > x , dest - > y , mobj - > z ) ;
2017-10-12 02:14:14 +00:00
2018-07-28 06:37:00 +00:00
mobj - > z = ( mobj - > eflags & MFE_VERTICALFLIP ? mobj - > ceilingz : mobj - > floorz ) ;
2017-10-12 02:14:14 +00:00
2018-03-13 05:58:57 +00:00
if ( mobj - > z = = prevz )
break ;
}
}
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( mobj - > target - > type = = MT_FLOATINGITEM )
P_SetScale ( mobj , mobj - > scale / 2 ) ;
2018-03-13 05:58:57 +00:00
}
P_SetTarget ( & shadowcap , NULL ) ;
}
2017-10-12 02:14:14 +00:00
2018-03-13 05:58:57 +00:00
// called whenever shadows think
// It must be done this way so that level changes don't break when the shadowcap can't be reset
static void P_AddShadow ( mobj_t * thing )
{
I_Assert ( thing ! = NULL ) ;
2017-10-12 02:14:14 +00:00
2018-03-13 05:58:57 +00:00
if ( shadowcap = = NULL )
P_SetTarget ( & shadowcap , thing ) ;
else {
mobj_t * mo ;
for ( mo = shadowcap ; mo & & mo - > hnext ; mo = mo - > hnext )
;
2017-10-12 02:14:14 +00:00
2018-03-13 05:58:57 +00:00
I_Assert ( mo ! = NULL ) ;
I_Assert ( mo - > hnext = = NULL ) ;
2017-10-12 02:14:14 +00:00
2018-03-13 05:58:57 +00:00
P_SetTarget ( & mo - > hnext , thing ) ;
}
P_SetTarget ( & thing - > hnext , NULL ) ;
}
// Called only when MT_SHADOW (or anything else in the shadowcap list) is removed.
// Keeps the hnext list from corrupting.
static void P_RemoveShadow ( mobj_t * thing )
{
mobj_t * mo ;
if ( shadowcap = = thing )
{
P_SetTarget ( & shadowcap , thing - > hnext ) ;
P_SetTarget ( & thing - > hnext , NULL ) ;
return ;
}
for ( mo = shadowcap ; mo ; mo = mo - > hnext )
if ( mo - > hnext = = thing )
2017-10-12 02:14:14 +00:00
{
2018-03-13 05:58:57 +00:00
P_SetTarget ( & mo - > hnext , thing - > hnext ) ;
P_SetTarget ( & thing - > hnext , NULL ) ;
return ;
2017-10-12 02:14:14 +00:00
}
}
2014-03-15 16:59:03 +00:00
void A_BossDeath ( mobj_t * mo ) ;
// AI for the Koopa boss.
static void P_KoopaThinker ( mobj_t * koopa )
{
P_MobjCheckWater ( koopa ) ;
if ( koopa - > watertop > koopa - > z + koopa - > height + FixedMul ( 128 * FRACUNIT , koopa - > scale ) & & koopa - > health > 0 )
{
A_BossDeath ( koopa ) ;
P_RemoveMobj ( koopa ) ;
return ;
}
// Koopa moves ONLY on the X axis!
if ( koopa - > threshold > 0 )
{
koopa - > threshold - - ;
koopa - > momx = FixedMul ( FRACUNIT , koopa - > scale ) ;
if ( ! koopa - > threshold )
koopa - > threshold = - TICRATE * 2 ;
}
else if ( koopa - > threshold < 0 )
{
koopa - > threshold + + ;
koopa - > momx = FixedMul ( - FRACUNIT , koopa - > scale ) ;
if ( ! koopa - > threshold )
koopa - > threshold = TICRATE * 2 ;
}
else
koopa - > threshold = TICRATE * 2 ;
P_XYMovement ( koopa ) ;
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 32 ) & & koopa - > z < = koopa - > floorz )
2014-03-15 16:59:03 +00:00
koopa - > momz = FixedMul ( 5 * FRACUNIT , koopa - > scale ) ;
if ( koopa - > z > koopa - > floorz )
koopa - > momz + = FixedMul ( FRACUNIT / 4 , koopa - > scale ) ;
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 64 ) )
2014-03-15 16:59:03 +00:00
{
mobj_t * flame ;
2016-07-06 04:09:17 +00:00
flame = P_SpawnMobj ( koopa - > x - koopa - > radius + FixedMul ( 5 * FRACUNIT , koopa - > scale ) , koopa - > y , koopa - > z + ( P_RandomByte ( ) < < ( FRACBITS - 2 ) ) , MT_KOOPAFLAME ) ;
2014-03-15 16:59:03 +00:00
flame - > momx = - FixedMul ( flame - > info - > speed , flame - > scale ) ;
S_StartSound ( flame , sfx_koopfr ) ;
}
2016-07-06 04:09:17 +00:00
else if ( P_RandomChance ( 5 * FRACUNIT / 256 ) )
2014-03-15 16:59:03 +00:00
{
mobj_t * hammer ;
hammer = P_SpawnMobj ( koopa - > x - koopa - > radius , koopa - > y , koopa - > z + koopa - > height , MT_HAMMER ) ;
hammer - > momx = FixedMul ( - 5 * FRACUNIT , hammer - > scale ) ;
hammer - > momz = FixedMul ( 7 * FRACUNIT , hammer - > scale ) ;
}
}
//
// P_MobjThinker
//
void P_MobjThinker ( mobj_t * mobj )
{
I_Assert ( mobj ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mobj ) ) ;
if ( mobj - > flags & MF_NOTHINK )
return ;
// Remove dead target/tracer.
if ( mobj - > target & & P_MobjWasRemoved ( mobj - > target ) )
P_SetTarget ( & mobj - > target , NULL ) ;
if ( mobj - > tracer & & P_MobjWasRemoved ( mobj - > tracer ) )
P_SetTarget ( & mobj - > tracer , NULL ) ;
2018-06-16 23:57:08 +00:00
// hnext/hprev changes suggested by toaster
if ( mobj - > hnext & & P_MobjWasRemoved ( mobj - > hnext ) )
P_SetTarget ( & mobj - > hnext , NULL ) ;
if ( mobj - > hprev & & P_MobjWasRemoved ( mobj - > hprev ) )
P_SetTarget ( & mobj - > hprev , NULL ) ;
2014-03-15 16:59:03 +00:00
mobj - > flags2 & = ~ MF2_PUSHED ;
2018-06-05 03:23:52 +00:00
mobj - > eflags & = ~ ( MFE_SPRUNG | MFE_JUSTBOUNCEDWALL ) ;
2016-07-06 04:09:17 +00:00
tmfloorthing = tmhitthing = NULL ;
2014-03-15 16:59:03 +00:00
// 970 allows ANY mobj to trigger a linedef exec
if ( mobj - > subsector & & GETSECSPECIAL ( mobj - > subsector - > sector - > special , 2 ) = = 8 )
{
sector_t * sec2 ;
sec2 = P_ThingOnSpecial3DFloor ( mobj ) ;
if ( sec2 & & GETSECSPECIAL ( sec2 - > special , 2 ) = = 1 )
P_LinedefExecute ( sec2 - > tag , mobj , sec2 ) ;
}
// Slowly scale up/down to reach your destscale.
if ( mobj - > scale ! = mobj - > destscale )
{
fixed_t oldheight = mobj - > height ;
UINT8 correctionType = 0 ; // Don't correct Z position, just gain height
if ( mobj - > z > mobj - > floorz & & mobj - > z + mobj - > height < mobj - > ceilingz
& & mobj - > type ! = MT_EGGMOBILE_FIRE )
correctionType = 1 ; // Correct Z position by centering
else if ( mobj - > eflags & MFE_VERTICALFLIP )
correctionType = 2 ; // Correct Z position by moving down
if ( abs ( mobj - > scale - mobj - > destscale ) < mobj - > scalespeed )
P_SetScale ( mobj , mobj - > destscale ) ;
else if ( mobj - > scale < mobj - > destscale )
P_SetScale ( mobj , mobj - > scale + mobj - > scalespeed ) ;
else if ( mobj - > scale > mobj - > destscale )
P_SetScale ( mobj , mobj - > scale - mobj - > scalespeed ) ;
if ( correctionType = = 1 )
mobj - > z - = ( mobj - > height - oldheight ) / 2 ;
else if ( correctionType = = 2 )
mobj - > z - = mobj - > height - oldheight ;
if ( mobj - > scale = = mobj - > destscale )
/// \todo Lua hook for "reached destscale"?
switch ( mobj - > type )
{
case MT_EGGMOBILE_FIRE :
mobj - > destscale = FRACUNIT ;
mobj - > scalespeed = FRACUNIT > > 4 ;
break ;
default :
break ;
}
}
if ( mobj - > type = = MT_GHOST & & mobj - > fuse > 0 // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
& & ( signed ) ( mobj - > frame > > FF_TRANSSHIFT ) < ( NUMTRANSMAPS - 1 ) - mobj - > fuse / 2 )
// fade out when nearing the end of fuse...
mobj - > frame = ( mobj - > frame & ~ FF_TRANSMASK ) | ( ( ( NUMTRANSMAPS - 1 ) - mobj - > fuse / 2 ) < < FF_TRANSSHIFT ) ;
// Special thinker for scenery objects
if ( mobj - > flags & MF_SCENERY )
{
# ifdef HAVE_BLUA
if ( LUAh_MobjThinker ( mobj ) )
return ;
if ( P_MobjWasRemoved ( mobj ) )
return ;
# endif
switch ( mobj - > type )
{
case MT_HOOP :
if ( mobj - > fuse > 1 )
P_MoveHoop ( mobj ) ;
else if ( mobj - > fuse = = 1 )
mobj - > movecount = 1 ;
if ( mobj - > movecount )
{
mobj - > fuse + + ;
if ( mobj - > fuse > 32 )
{
// Don't kill the hoop center. For the sake of respawning.
//if (mobj->target)
// P_RemoveMobj(mobj->target);
P_RemoveMobj ( mobj ) ;
}
}
else
mobj - > fuse - - ;
return ;
case MT_NIGHTSPARKLE :
if ( mobj - > tics ! = - 1 )
{
mobj - > tics - - ;
// you can cycle through multiple states in a tic
if ( ! mobj - > tics )
if ( ! P_SetMobjState ( mobj , mobj - > state - > nextstate ) )
return ; // freed itself
}
P_UnsetThingPosition ( mobj ) ;
mobj - > x + = mobj - > momx ;
mobj - > y + = mobj - > momy ;
mobj - > z + = mobj - > momz ;
P_SetThingPosition ( mobj ) ;
return ;
case MT_NIGHTSLOOPHELPER :
if ( - - mobj - > tics < = 0 )
P_RemoveMobj ( mobj ) ;
// Don't touch my fuse!
return ;
case MT_OVERLAY :
2014-03-18 17:56:54 +00:00
if ( ! mobj - > target )
2014-03-15 16:59:03 +00:00
{
P_RemoveMobj ( mobj ) ;
return ;
}
2018-10-03 16:14:25 +00:00
P_AddOverlay ( mobj ) ;
2014-03-15 16:59:03 +00:00
break ;
2018-03-13 05:58:57 +00:00
case MT_SHADOW :
if ( ! mobj - > target )
{
P_RemoveMobj ( mobj ) ;
return ;
}
2018-10-03 16:14:25 +00:00
P_AddShadow ( mobj ) ;
2018-03-13 05:58:57 +00:00
break ;
2018-10-03 16:14:25 +00:00
/*case MT_BLACKORB:
2014-03-15 16:59:03 +00:00
case MT_WHITEORB :
case MT_GREENORB :
case MT_YELLOWORB :
case MT_BLUEORB :
case MT_PITYORB :
if ( ! P_AddShield ( mobj ) )
return ;
2018-10-03 16:14:25 +00:00
break ; */
2016-08-21 21:55:35 +00:00
//{ SRB2kart mobs
2018-08-24 14:14:18 +00:00
case MT_ORBINAUT_SHIELD : // Kart orbit/trail items
2018-06-01 00:51:05 +00:00
case MT_JAWZ_SHIELD :
2018-08-24 14:14:18 +00:00
case MT_BANANA_SHIELD :
case MT_SSMINE_SHIELD :
case MT_FAKESHIELD :
2018-09-04 23:14:44 +00:00
case MT_SINK_SHIELD :
2018-08-24 14:14:18 +00:00
/*if (mobj->health > 0 && mobj->target && mobj->target->player
2017-02-26 15:19:12 +00:00
& & mobj - > target - > player - > health > 0 & & ! mobj - > target - > player - > spectator )
2016-08-21 21:55:35 +00:00
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
// Was this so hard? -- Handled this with K_UpdateHnextList instead of thinking it away...
2018-07-23 00:55:18 +00:00
if ( ( mobj - > type = = MT_ORBINAUT_SHIELD & & mobj - > target - > player - > kartstuff [ k_itemtype ] ! = KITEM_ORBINAUT )
2018-06-01 00:51:05 +00:00
| | ( mobj - > type = = MT_JAWZ_SHIELD & & mobj - > target - > player - > kartstuff [ k_itemtype ] ! = KITEM_JAWZ )
2018-07-08 22:05:22 +00:00
| | ( mobj - > movedir > 0 & & ( ( UINT16 ) mobj - > target - > player - > kartstuff [ k_itemamount ] < mobj - > movedir ) )
2018-06-16 21:54:12 +00:00
| | ( ! mobj - > target - > player - > kartstuff [ k_itemheld ] ) )
{
P_RemoveMobj ( mobj ) ;
return ;
}
}
2018-08-24 14:14:18 +00:00
else */ if ( ( mobj - > health > 0
2018-06-17 00:42:47 +00:00
& & ( ! mobj - > target | | ! mobj - > target - > player | | mobj - > target - > player - > health < = 0 | | mobj - > target - > player - > spectator ) )
2017-11-03 00:43:03 +00:00
| | ( mobj - > health < = 0 & & mobj - > z < = mobj - > floorz )
| | P_CheckDeathPitCollide ( mobj ) ) // When in death state
{
P_RemoveMobj ( mobj ) ;
return ;
}
break ;
2018-02-05 22:53:31 +00:00
case MT_SMOLDERING :
if ( leveltime % 2 = = 0 )
{
fixed_t x = P_RandomRange ( - 35 , 35 ) * mobj - > scale ;
fixed_t y = P_RandomRange ( - 35 , 35 ) * mobj - > scale ;
fixed_t z = P_RandomRange ( 0 , 70 ) * mobj - > scale ;
mobj_t * smoke = P_SpawnMobj ( mobj - > x + x , mobj - > y + y , mobj - > z + z , MT_SMOKE ) ;
smoke - > scale = mobj - > scale * 2 ;
smoke - > destscale = mobj - > scale * 6 ;
smoke - > momz = P_RandomRange ( 4 , 9 ) * FRACUNIT ;
}
break ;
case MT_BOOMPARTICLE :
{
fixed_t x = P_RandomRange ( - 16 , 16 ) * mobj - > scale ;
fixed_t y = P_RandomRange ( - 16 , 16 ) * mobj - > scale ;
fixed_t z = P_RandomRange ( 0 , 32 ) * mobj - > scale ;
if ( leveltime % 2 = = 0 )
{
mobj_t * smoke = P_SpawnMobj ( mobj - > x + x , mobj - > y + y , mobj - > z + z , MT_BOSSEXPLODE ) ;
P_SetMobjState ( smoke , S_QUICKBOOM1 ) ;
smoke - > scale = mobj - > scale / 2 ;
smoke - > destscale = mobj - > scale ;
2018-02-06 01:23:09 +00:00
smoke - > color = mobj - > color ;
2018-02-05 22:53:31 +00:00
}
else
{
mobj_t * smoke = P_SpawnMobj ( mobj - > x + x , mobj - > y + y , mobj - > z + z , MT_SMOKE ) ;
smoke - > scale = mobj - > scale ;
smoke - > destscale = mobj - > scale * 2 ;
}
if ( mobj - > tics < = TICRATE )
{
mobj - > destscale = FixedDiv ( mobj - > scale , 100 * FRACUNIT ) ;
}
}
break ;
2018-07-03 19:14:47 +00:00
case MT_BATTLEBUMPER :
2018-06-06 22:36:39 +00:00
if ( mobj - > health > 0 & & mobj - > target & & mobj - > target - > player
2017-11-03 00:43:03 +00:00
& & mobj - > target - > player - > health > 0 & & ! mobj - > target - > player - > spectator )
{
fixed_t rad = 32 * mobj - > target - > scale ;
fixed_t offz ;
angle_t ang , diff ;
if ( ! ( ( mobj - > target - > player - players ) & 1 ) )
ang = ( FixedAngle ( mobj - > info - > speed ) * - 1 ) ;
else
ang = FixedAngle ( mobj - > info - > speed ) ;
2018-07-03 19:14:47 +00:00
if ( mobj - > target - > player - > kartstuff [ k_bumper ] < = 1 )
2017-11-03 00:43:03 +00:00
diff = 0 ;
else
2018-07-03 19:14:47 +00:00
diff = FixedAngle ( 360 * FRACUNIT / mobj - > target - > player - > kartstuff [ k_bumper ] ) ;
2017-11-03 00:43:03 +00:00
ang = ( ang * leveltime ) + ( diff * ( mobj - > threshold - 1 ) ) ;
// If the player is on the ceiling, then flip your items as well.
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
{
mobj - > eflags | = MFE_VERTICALFLIP ;
offz = mobj - > target - > height / 2 ;
}
else
{
mobj - > eflags & = ~ MFE_VERTICALFLIP ;
offz = mobj - > target - > height / 5 ;
}
2018-06-06 22:36:39 +00:00
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP1 ) // groooooaann...
mobj - > eflags | = MFE_DRAWONLYFORP1 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP1 ;
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP2 )
mobj - > eflags | = MFE_DRAWONLYFORP2 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP2 ;
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP3 )
mobj - > eflags | = MFE_DRAWONLYFORP3 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP3 ;
if ( mobj - > target - > eflags & MFE_DRAWONLYFORP4 )
mobj - > eflags | = MFE_DRAWONLYFORP4 ;
else
mobj - > eflags & = ~ MFE_DRAWONLYFORP4 ;
2017-11-03 00:43:03 +00:00
if ( mobj - > target - > flags2 & MF2_DONTDRAW )
mobj - > flags2 | = MF2_DONTDRAW ;
else
mobj - > flags2 & = ~ MF2_DONTDRAW ;
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
offz + = 4 * FRACUNIT ;
else
offz - = 4 * FRACUNIT ;
if ( mobj - > tracer & & mobj - > tracer - > player & & mobj - > tracer - > player - > mo
& & mobj - > tracer - > player - > health > 0 & & ! mobj - > tracer - > player - > spectator ) // STOLEN
2018-07-03 19:14:47 +00:00
mobj - > color = mobj - > tracer - > player - > skincolor ; // don't do star flashing for stolen bumpers
2017-11-03 00:43:03 +00:00
else
mobj - > color = mobj - > target - > color ; // but do so if it belongs to you :B
2018-07-03 19:14:47 +00:00
if ( mobj - > target - > player - > kartstuff [ k_bumper ] < 2 )
P_SetMobjState ( mobj , S_BATTLEBUMPER3 ) ;
else if ( mobj - > target - > player - > kartstuff [ k_bumper ] < 3 )
P_SetMobjState ( mobj , S_BATTLEBUMPER2 ) ;
2017-11-03 00:43:03 +00:00
else
2018-07-03 19:14:47 +00:00
P_SetMobjState ( mobj , S_BATTLEBUMPER1 ) ;
2017-11-03 00:43:03 +00:00
// Shrink your items if the player shrunk too.
mobj - > scale = mobj - > target - > scale ;
P_UnsetThingPosition ( mobj ) ;
{
const angle_t fa = ang > > ANGLETOFINESHIFT ;
mobj - > x = mobj - > target - > x + FixedMul ( FINECOSINE ( fa ) , rad ) ;
mobj - > y = mobj - > target - > y + FixedMul ( FINESINE ( fa ) , rad ) ;
mobj - > z = mobj - > target - > z + offz ;
P_SetThingPosition ( mobj ) ;
}
// Was this so hard?
2018-07-03 19:14:47 +00:00
if ( mobj - > target - > player - > kartstuff [ k_bumper ] < = mobj - > threshold )
2016-08-21 21:55:35 +00:00
{
P_RemoveMobj ( mobj ) ;
return ;
}
}
else if ( ( mobj - > health > 0
& & ( ! mobj - > target | | ! mobj - > target - > player | | ! mobj - > target - > player - > mo | | mobj - > target - > player - > health < = 0 | | mobj - > target - > player - > spectator ) )
2017-05-13 15:14:26 +00:00
| | ( mobj - > health < = 0 & & mobj - > z < = mobj - > floorz )
| | P_CheckDeathPitCollide ( mobj ) ) // When in death state
2016-08-21 21:55:35 +00:00
{
P_RemoveMobj ( mobj ) ;
return ;
}
break ;
2017-10-26 06:31:01 +00:00
case MT_PLAYERARROW :
if ( mobj - > target & & mobj - > target - > health
2018-01-30 00:15:25 +00:00
& & mobj - > target - > player & & ! mobj - > target - > player - > spectator
& & mobj - > target - > player - > health & & mobj - > target - > player - > playerstate ! = PST_DEAD
& & players [ displayplayer ] . mo & & ! players [ displayplayer ] . spectator )
2017-10-26 06:31:01 +00:00
{
fixed_t scale = mobj - > target - > scale ;
mobj - > color = mobj - > target - > color ;
2018-07-01 18:11:48 +00:00
if ( G_RaceGametype ( )
2017-11-05 21:34:12 +00:00
| | mobj - > target - > player = = & players [ displayplayer ]
2018-07-03 19:14:47 +00:00
| | mobj - > target - > player - > kartstuff [ k_bumper ] < = 0
2018-07-01 18:11:48 +00:00
| | ( mobj - > target - > player - > mo - > flags2 & MF2_DONTDRAW )
# if 1 // Set to 0 to test without needing to host
| | ! netgame
# endif
)
2017-10-26 06:31:01 +00:00
mobj - > flags2 | = MF2_DONTDRAW ;
2018-06-11 05:56:41 +00:00
else
2017-10-26 06:31:01 +00:00
mobj - > flags2 & = ~ MF2_DONTDRAW ;
P_UnsetThingPosition ( mobj ) ;
mobj - > x = mobj - > target - > x ;
mobj - > y = mobj - > target - > y ;
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
mobj - > angle = R_PointToAngle ( mobj - > x , mobj - > y ) + ANGLE_90 ; // literally only happened because i wanted to ^L^R the SPR_ITEM's
2017-10-26 06:31:01 +00:00
if ( ! ( mobj - > target - > eflags & MFE_VERTICALFLIP ) )
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
mobj - > z = mobj - > target - > z + P_GetPlayerHeight ( mobj - > target - > player ) + ( 16 + 11 ) * mapheaderinfo [ gamemap - 1 ] - > mobj_scale ;
2017-10-26 06:31:01 +00:00
mobj - > eflags & = ~ MFE_VERTICALFLIP ;
}
else
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
mobj - > z = mobj - > target - > z - P_GetPlayerHeight ( mobj - > target - > player ) + ( 16 + 11 ) * mapheaderinfo [ gamemap - 1 ] - > mobj_scale ;
2017-10-26 06:31:01 +00:00
mobj - > eflags | = MFE_VERTICALFLIP ;
}
P_SetThingPosition ( mobj ) ;
2018-02-12 02:47:19 +00:00
scale + = FixedMul ( FixedDiv ( abs ( P_AproxDistance ( players [ displayplayer ] . mo - > x - mobj - > target - > x ,
players [ displayplayer ] . mo - > y - mobj - > target - > y ) ) , RING_DIST ) , mobj - > target - > scale ) ;
if ( scale > 16 * FRACUNIT )
scale = 16 * FRACUNIT ;
mobj - > destscale = scale ;
2018-06-14 01:33:55 +00:00
if ( ! mobj - > tracer )
2018-02-05 23:55:52 +00:00
{
2018-06-14 01:33:55 +00:00
mobj - > tracer = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_OVERLAY ) ;
P_SetTarget ( & mobj - > tracer - > target , mobj ) ;
P_SetMobjState ( mobj - > tracer , S_PLAYERARROW_ITEM ) ;
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
P_SetMobjState ( mobj - > tracer , S_ITEMICON ) ; // null sprite and frame to be overwritten later
P_SetScale ( mobj - > tracer , ( mobj - > tracer - > destscale = mobj - > scale ) ) ;
2018-06-14 01:33:55 +00:00
}
2018-02-05 23:55:52 +00:00
2018-06-14 01:33:55 +00:00
if ( ! ( mobj - > flags2 & MF2_DONTDRAW ) )
{
2018-08-14 21:16:33 +00:00
const INT32 numberdisplaymin = ( ( mobj - > target - > player - > kartstuff [ k_itemtype ] = = KITEM_ORBINAUT ) ? 5 : 2 ) ;
2018-02-12 02:47:19 +00:00
// Set it to use the correct states for its condition
if ( mobj - > target - > player - > kartstuff [ k_itemroulette ] )
{
P_SetMobjState ( mobj , S_PLAYERARROW_BOX ) ;
2018-07-01 18:11:48 +00:00
mobj - > tracer - > sprite = SPR_ITEM ;
2018-07-04 01:12:25 +00:00
mobj - > tracer - > frame = FF_FULLBRIGHT | ( ( ( mobj - > target - > player - > kartstuff [ k_itemroulette ] % ( 13 * 3 ) ) / 3 ) + 1 ) ;
2018-08-14 14:23:38 +00:00
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
}
else if ( mobj - > target - > player - > kartstuff [ k_stolentimer ] > 0 )
{
P_SetMobjState ( mobj , S_PLAYERARROW_BOX ) ;
mobj - > tracer - > sprite = SPR_ITEM ;
mobj - > tracer - > frame = FF_FULLBRIGHT | KITEM_HYUDORO ;
2018-08-24 14:14:18 +00:00
if ( leveltime & 2 )
2018-08-14 14:23:38 +00:00
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
2018-08-24 14:14:18 +00:00
else
mobj - > tracer - > flags2 | = MF2_DONTDRAW ;
2018-08-14 14:23:38 +00:00
}
else if ( ( mobj - > target - > player - > kartstuff [ k_stealingtimer ] > 0 ) & & ( leveltime & 2 ) )
{
P_SetMobjState ( mobj , S_PLAYERARROW_BOX ) ;
mobj - > tracer - > sprite = SPR_ITEM ;
mobj - > tracer - > frame = FF_FULLBRIGHT | KITEM_HYUDORO ;
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
}
else if ( mobj - > target - > player - > kartstuff [ k_eggmanexplode ] > 1 )
{
P_SetMobjState ( mobj , S_PLAYERARROW_BOX ) ;
mobj - > tracer - > sprite = SPR_ITEM ;
mobj - > tracer - > frame = FF_FULLBRIGHT | KITEM_EGGMAN ;
if ( leveltime & 1 )
2018-08-24 14:14:18 +00:00
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
2018-08-14 14:23:38 +00:00
else
2018-08-24 14:14:18 +00:00
mobj - > tracer - > flags2 | = MF2_DONTDRAW ;
}
2018-08-26 11:27:45 +00:00
else if ( mobj - > target - > player - > kartstuff [ k_rocketsneakertimer ] > 1 )
2018-08-24 14:14:18 +00:00
{
2018-08-26 11:27:45 +00:00
//itembar = mobj->target->player->kartstuff[k_rocketsneakertimer]; -- not today satan
2018-08-24 14:14:18 +00:00
P_SetMobjState ( mobj , S_PLAYERARROW_BOX ) ;
mobj - > tracer - > sprite = SPR_ITEM ;
mobj - > tracer - > frame = FF_FULLBRIGHT | KITEM_ROCKETSNEAKER ;
if ( leveltime & 1 )
2018-08-14 14:23:38 +00:00
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
2018-08-24 14:14:18 +00:00
else
mobj - > tracer - > flags2 | = MF2_DONTDRAW ;
2018-08-14 14:23:38 +00:00
}
else if ( mobj - > target - > player - > kartstuff [ k_growshrinktimer ] > 0 )
{
P_SetMobjState ( mobj , S_PLAYERARROW_BOX ) ;
mobj - > tracer - > sprite = SPR_ITEM ;
mobj - > tracer - > frame = FF_FULLBRIGHT | KITEM_GROW ;
if ( leveltime & 1 )
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
2018-08-24 14:14:18 +00:00
else
mobj - > tracer - > flags2 | = MF2_DONTDRAW ;
2018-02-12 02:47:19 +00:00
}
2018-08-24 12:36:03 +00:00
else if ( mobj - > target - > player - > kartstuff [ k_itemtype ] & & mobj - > target - > player - > kartstuff [ k_itemamount ] > 0 )
2018-02-12 02:47:19 +00:00
{
P_SetMobjState ( mobj , S_PLAYERARROW_BOX ) ;
switch ( mobj - > target - > player - > kartstuff [ k_itemtype ] )
{
2018-08-14 14:23:38 +00:00
case KITEM_ORBINAUT :
mobj - > tracer - > sprite = SPR_ITMO ;
mobj - > tracer - > frame = FF_FULLBRIGHT | ( min ( mobj - > target - > player - > kartstuff [ k_itemamount ] - 1 , 3 ) ) ;
break ;
2018-02-12 02:47:19 +00:00
case KITEM_INVINCIBILITY :
2018-06-11 04:59:20 +00:00
mobj - > tracer - > sprite = SPR_ITMI ;
mobj - > tracer - > frame = FF_FULLBRIGHT | ( ( leveltime % ( 7 * 3 ) ) / 3 ) ;
2018-02-12 02:47:19 +00:00
break ;
case KITEM_SAD :
2018-06-11 04:59:20 +00:00
mobj - > tracer - > sprite = SPR_ITEM ;
2018-02-12 02:47:19 +00:00
mobj - > tracer - > frame = FF_FULLBRIGHT ;
break ;
default :
2018-06-11 04:59:20 +00:00
mobj - > tracer - > sprite = SPR_ITEM ;
mobj - > tracer - > frame = FF_FULLBRIGHT | ( mobj - > target - > player - > kartstuff [ k_itemtype ] ) ;
2018-02-12 02:47:19 +00:00
break ;
}
2018-09-10 07:17:15 +00:00
if ( mobj - > target - > player - > kartstuff [ k_itemheld ] )
{
if ( leveltime & 1 )
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
else
mobj - > tracer - > flags2 | = MF2_DONTDRAW ;
}
else
mobj - > tracer - > flags2 & = ~ MF2_DONTDRAW ;
2018-02-12 02:47:19 +00:00
}
else
{
P_SetMobjState ( mobj , S_PLAYERARROW ) ;
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
P_SetMobjState ( mobj - > tracer , S_ITEMICON ) ; // null sprite and frame to be overwritten later
2018-02-12 02:47:19 +00:00
}
mobj - > tracer - > destscale = scale ;
2018-08-14 21:16:33 +00:00
if ( mobj - > target - > player - > kartstuff [ k_itemamount ] > = numberdisplaymin
2018-09-06 20:06:37 +00:00
& & mobj - > target - > player - > kartstuff [ k_itemamount ] < = 10 ) // Meh, too difficult to support greater than this; convert this to a decent HUD object and then maybe :V
2018-02-12 02:47:19 +00:00
{
mobj_t * number = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_OVERLAY ) ;
mobj_t * numx = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_OVERLAY ) ;
P_SetTarget ( & number - > target , mobj ) ;
P_SetMobjState ( number , S_PLAYERARROW_NUMBER ) ;
P_SetScale ( number , mobj - > scale ) ;
number - > destscale = scale ;
number - > frame = FF_FULLBRIGHT | ( mobj - > target - > player - > kartstuff [ k_itemamount ] ) ;
P_SetTarget ( & numx - > target , mobj ) ;
P_SetMobjState ( numx , S_PLAYERARROW_X ) ;
P_SetScale ( numx , mobj - > scale ) ;
numx - > destscale = scale ;
}
2018-07-01 18:11:48 +00:00
if ( K_IsPlayerWanted ( mobj - > target - > player ) & & mobj - > movecount ! = 1 )
{
mobj_t * wanted = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_PLAYERWANTED ) ;
P_SetTarget ( & wanted - > target , mobj - > target ) ;
P_SetTarget ( & wanted - > tracer , mobj ) ;
P_SetScale ( wanted , mobj - > scale ) ;
wanted - > destscale = scale ;
mobj - > movecount = 1 ;
}
else if ( ! K_IsPlayerWanted ( mobj - > target - > player ) )
mobj - > movecount = 0 ;
2017-10-26 06:31:01 +00:00
}
2018-06-12 22:01:17 +00:00
else
mobj - > tracer - > flags2 | = MF2_DONTDRAW ;
2017-10-26 06:31:01 +00:00
}
else if ( mobj - > health > 0 )
{
P_KillMobj ( mobj , NULL , NULL ) ;
return ;
}
break ;
2018-07-01 18:11:48 +00:00
case MT_PLAYERWANTED :
if ( mobj - > target & & mobj - > target - > health & & mobj - > tracer
& & mobj - > target - > player & & ! mobj - > target - > player - > spectator
& & mobj - > target - > player - > health & & mobj - > target - > player - > playerstate ! = PST_DEAD
& & players [ displayplayer ] . mo & & ! players [ displayplayer ] . spectator )
{
fixed_t scale = mobj - > target - > scale ;
if ( ! K_IsPlayerWanted ( mobj - > target - > player ) )
{
mobj - > tracer - > movecount = 0 ;
P_RemoveMobj ( mobj ) ;
return ;
}
if ( mobj - > tracer - > flags2 & MF2_DONTDRAW )
mobj - > flags2 | = MF2_DONTDRAW ;
else
mobj - > flags2 & = ~ MF2_DONTDRAW ;
P_UnsetThingPosition ( mobj ) ;
mobj - > x = mobj - > target - > x ;
mobj - > y = mobj - > target - > y ;
if ( ! ( mobj - > target - > eflags & MFE_VERTICALFLIP ) )
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
mobj - > z = mobj - > target - > z + ( P_GetPlayerHeight ( mobj - > target - > player ) + 16 * mapheaderinfo [ gamemap - 1 ] - > mobj_scale + ( 64 * mobj - > scale ) ) ;
2018-07-01 18:11:48 +00:00
mobj - > eflags & = ~ MFE_VERTICALFLIP ;
}
else
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
mobj - > z = mobj - > target - > z - ( P_GetPlayerHeight ( mobj - > target - > player ) + 16 * mapheaderinfo [ gamemap - 1 ] - > mobj_scale + ( 64 * mobj - > scale ) ) ;
2018-07-01 18:11:48 +00:00
mobj - > eflags | = MFE_VERTICALFLIP ;
}
P_SetThingPosition ( mobj ) ;
scale + = FixedMul ( FixedDiv ( abs ( P_AproxDistance ( players [ displayplayer ] . mo - > x - mobj - > target - > x ,
players [ displayplayer ] . mo - > y - mobj - > target - > y ) ) , RING_DIST ) , mobj - > target - > scale ) ;
if ( scale > 16 * FRACUNIT )
scale = 16 * FRACUNIT ;
mobj - > destscale = scale ;
}
else if ( mobj - > health > 0 )
{
P_KillMobj ( mobj , NULL , NULL ) ;
return ;
}
break ;
2016-08-21 21:55:35 +00:00
//}
2014-03-15 16:59:03 +00:00
case MT_WATERDROP :
P_SceneryCheckWater ( mobj ) ;
if ( ( mobj - > z < = mobj - > floorz | | mobj - > z < = mobj - > watertop )
& & mobj - > health > 0 )
{
mobj - > health = 0 ;
P_SetMobjState ( mobj , mobj - > info - > deathstate ) ;
S_StartSound ( mobj , mobj - > info - > deathsound + P_RandomKey ( mobj - > info - > mass ) ) ;
return ;
}
break ;
case MT_BUBBLES :
P_SceneryCheckWater ( mobj ) ;
break ;
case MT_SMALLBUBBLE :
case MT_MEDIUMBUBBLE :
case MT_EXTRALARGEBUBBLE : // start bubble dissipate
P_SceneryCheckWater ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) ) // bubble was removed by not being in water
return ;
if ( ! ( mobj - > eflags & MFE_UNDERWATER )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + mobj - > height > = mobj - > ceilingz )
| | ( mobj - > eflags & MFE_VERTICALFLIP & & mobj - > z < = mobj - > floorz )
| | ( P_CheckDeathPitCollide ( mobj ) )
| | - - mobj - > fuse < = 0 ) // Bubbles eventually dissipate if they can't reach the surface.
{
// no playing sound: no point; the object is being removed
P_RemoveMobj ( mobj ) ;
return ;
}
break ;
case MT_DROWNNUMBERS :
2014-03-18 17:56:54 +00:00
if ( ! mobj - > target )
2014-03-15 16:59:03 +00:00
{
P_RemoveMobj ( mobj ) ;
return ;
}
if ( ! mobj - > target - > player | | ! ( mobj - > target - > player - > powers [ pw_underwater ] | | mobj - > target - > player - > powers [ pw_spacetime ] ) )
{
P_RemoveMobj ( mobj ) ;
return ;
}
mobj - > x = mobj - > target - > x ;
mobj - > y = mobj - > target - > y ;
mobj - > destscale = mobj - > target - > destscale ;
P_SetScale ( mobj , mobj - > target - > scale ) ;
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
{
mobj - > z = mobj - > target - > z - FixedMul ( 16 * FRACUNIT , mobj - > target - > scale ) - mobj - > height ;
if ( mobj - > target - > player - > pflags & PF_FLIPCAM )
mobj - > eflags | = MFE_VERTICALFLIP ;
}
else
mobj - > z = mobj - > target - > z + ( mobj - > target - > height ) + FixedMul ( 8 * FRACUNIT , mobj - > target - > scale ) ; // Adjust height for height changes
if ( mobj - > threshold < = 35 )
mobj - > flags2 | = MF2_DONTDRAW ;
else
mobj - > flags2 & = ~ MF2_DONTDRAW ;
if ( mobj - > threshold < = 30 )
mobj - > threshold = 40 ;
mobj - > threshold - - ;
break ;
case MT_FLAMEJET :
if ( ( mobj - > flags2 & MF2_FIRING ) & & ( leveltime & 3 ) = = 0 )
{
mobj_t * flame ;
fixed_t strength ;
// Wave the flames back and forth. Reactiontime determines which direction it's going.
if ( mobj - > fuse < = - 16 )
mobj - > reactiontime = 1 ;
else if ( mobj - > fuse > = 16 )
mobj - > reactiontime = 0 ;
if ( mobj - > reactiontime )
mobj - > fuse + = 2 ;
else
mobj - > fuse - = 2 ;
flame = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_FLAMEJETFLAME ) ;
flame - > angle = mobj - > angle ;
2016-08-22 21:54:30 +00:00
if ( mobj - > flags2 & MF2_AMBUSH ) // Wave up and down instead of side-to-side
2014-03-15 16:59:03 +00:00
flame - > momz = mobj - > fuse < < ( FRACBITS - 2 ) ;
else
flame - > angle + = FixedAngle ( mobj - > fuse * FRACUNIT ) ;
strength = 20 * FRACUNIT ;
strength - = ( ( 20 * FRACUNIT ) / 16 ) * mobj - > movedir ;
P_InstaThrust ( flame , flame - > angle , strength ) ;
S_StartSound ( flame , sfx_fire ) ;
}
break ;
case MT_VERTICALFLAMEJET :
if ( ( mobj - > flags2 & MF2_FIRING ) & & ( leveltime & 3 ) = = 0 )
{
mobj_t * flame ;
fixed_t strength ;
// Wave the flames back and forth. Reactiontime determines which direction it's going.
if ( mobj - > fuse < = - 16 )
mobj - > reactiontime = 1 ;
else if ( mobj - > fuse > = 16 )
mobj - > reactiontime = 0 ;
if ( mobj - > reactiontime )
mobj - > fuse + + ;
else
mobj - > fuse - - ;
flame = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_FLAMEJETFLAME ) ;
strength = 20 * FRACUNIT ;
strength - = ( ( 20 * FRACUNIT ) / 16 ) * mobj - > movedir ;
// If deaf'd, the object spawns on the ceiling.
2016-08-22 21:54:30 +00:00
if ( mobj - > flags2 & MF2_AMBUSH )
2014-03-15 16:59:03 +00:00
{
mobj - > z = mobj - > ceilingz - mobj - > height ;
flame - > momz = - strength ;
}
else
flame - > momz = strength ;
P_InstaThrust ( flame , mobj - > angle , FixedDiv ( mobj - > fuse * FRACUNIT , 3 * FRACUNIT ) ) ;
S_StartSound ( flame , sfx_fire ) ;
}
break ;
case MT_SEED :
mobj - > momz = mobj - > info - > speed ;
break ;
2014-11-12 00:55:07 +00:00
case MT_ROCKCRUMBLE1 :
case MT_ROCKCRUMBLE2 :
case MT_ROCKCRUMBLE3 :
case MT_ROCKCRUMBLE4 :
case MT_ROCKCRUMBLE5 :
case MT_ROCKCRUMBLE6 :
case MT_ROCKCRUMBLE7 :
case MT_ROCKCRUMBLE8 :
case MT_ROCKCRUMBLE9 :
case MT_ROCKCRUMBLE10 :
case MT_ROCKCRUMBLE11 :
case MT_ROCKCRUMBLE12 :
case MT_ROCKCRUMBLE13 :
case MT_ROCKCRUMBLE14 :
case MT_ROCKCRUMBLE15 :
case MT_ROCKCRUMBLE16 :
if ( mobj - > z < = P_FloorzAtPos ( mobj - > x , mobj - > y , mobj - > z , mobj - > height )
& & mobj - > state ! = & states [ mobj - > info - > deathstate ] )
{
P_SetMobjState ( mobj , mobj - > info - > deathstate ) ;
return ;
}
break ;
2017-10-24 16:19:14 +00:00
case MT_FIREDITEM :
{
fixed_t x , y , z ;
if ( mobj - > movecount )
{
x = mobj - > target - > x + P_ReturnThrustX ( mobj - > target , mobj - > target - > angle + mobj - > movedir , mobj - > target - > radius + mobj - > radius ) ;
y = mobj - > target - > y + P_ReturnThrustY ( mobj - > target , mobj - > target - > angle + mobj - > movedir , mobj - > target - > radius + mobj - > radius ) ;
z = mobj - > target - > z + mobj - > target - > height / 3 ;
}
else
{
x = mobj - > target - > x ;
y = mobj - > target - > y ;
2018-03-04 20:59:51 +00:00
z = mobj - > target - > z + 80 * ( mapheaderinfo [ gamemap - 1 ] - > mobj_scale ) ;
2017-10-24 16:19:14 +00:00
}
P_TeleportMove ( mobj , x , y , z ) ;
break ;
}
2014-03-15 16:59:03 +00:00
default :
if ( mobj - > fuse )
{ // Scenery object fuse! Very basic!
mobj - > fuse - - ;
if ( ! mobj - > fuse )
{
# ifdef HAVE_BLUA
if ( ! LUAh_MobjFuse ( mobj ) )
# endif
P_RemoveMobj ( mobj ) ;
return ;
}
}
break ;
}
P_SceneryThinker ( mobj ) ;
return ;
}
# ifdef HAVE_BLUA
// Check for a Lua thinker first
2014-08-05 23:59:40 +00:00
if ( ! mobj - > player )
{
if ( LUAh_MobjThinker ( mobj ) | | P_MobjWasRemoved ( mobj ) )
return ;
}
else if ( ! mobj - > player - > spectator )
{
// You cannot short-circuit the player thinker like you can other thinkers.
2014-03-15 16:59:03 +00:00
LUAh_MobjThinker ( mobj ) ;
2014-08-05 23:59:40 +00:00
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
2014-03-15 16:59:03 +00:00
# endif
// if it's pushable, or if it would be pushable other than temporary disablement, use the
// separate thinker
if ( mobj - > flags & MF_PUSHABLE | | ( mobj - > info - > flags & MF_PUSHABLE & & mobj - > fuse ) )
{
P_MobjCheckWater ( mobj ) ;
P_PushableThinker ( mobj ) ;
// Extinguish fire objects in water. (Yes, it's extraordinarily rare to have a pushable flame object, but Brak uses such a case.)
2018-06-25 21:12:01 +00:00
if ( mobj - > flags & MF_FIRE & & mobj - > type ! = MT_PUMA & & mobj - > type ! = MT_FIREBALL
2014-03-15 16:59:03 +00:00
& & ( mobj - > eflags & ( MFE_UNDERWATER | MFE_TOUCHWATER ) ) )
{
P_KillMobj ( mobj , NULL , NULL ) ;
return ;
}
}
else if ( mobj - > flags & MF_BOSS )
{
# ifdef HAVE_BLUA
if ( LUAh_BossThinker ( mobj ) )
{
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
else if ( P_MobjWasRemoved ( mobj ) )
return ;
else
# endif
switch ( mobj - > type )
{
case MT_EGGMOBILE :
if ( mobj - > health < mobj - > info - > damage + 1 & & leveltime & 1 & & mobj - > health > 0 )
P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_SMOKE ) ;
if ( mobj - > flags2 & MF2_SKULLFLY )
# if 1
P_SpawnGhostMobj ( mobj ) ;
# else
{
mobj_t * spawnmobj ;
spawnmobj = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , mobj - > info - > painchance ) ;
P_SetTarget ( & spawnmobj - > target , mobj ) ;
spawnmobj - > color = SKINCOLOR_GREY ;
}
# endif
P_Boss1Thinker ( mobj ) ;
break ;
case MT_EGGMOBILE2 :
P_Boss2Thinker ( mobj ) ;
break ;
case MT_EGGMOBILE3 :
P_Boss3Thinker ( mobj ) ;
break ;
case MT_EGGMOBILE4 :
P_Boss4Thinker ( mobj ) ;
break ;
case MT_BLACKEGGMAN :
P_Boss7Thinker ( mobj ) ;
break ;
case MT_METALSONIC_BATTLE :
P_Boss9Thinker ( mobj ) ;
break ;
default : // Generic SOC-made boss
if ( mobj - > flags2 & MF2_SKULLFLY )
P_SpawnGhostMobj ( mobj ) ;
P_GenericBossThinker ( mobj ) ;
break ;
}
if ( mobj - > flags2 & MF2_BOSSFLEE )
P_InstaThrust ( mobj , mobj - > angle , FixedMul ( 12 * FRACUNIT , mobj - > scale ) ) ;
}
else if ( mobj - > health < = 0 ) // Dead things think differently than the living.
switch ( mobj - > type )
{
case MT_BLUEBALL :
if ( ( mobj - > tics > > 2 ) + 1 > 0 & & ( mobj - > tics > > 2 ) + 1 < = tr_trans60 ) // tr_trans50 through tr_trans90, shifting once every second frame
mobj - > frame = ( NUMTRANSMAPS - ( ( mobj - > tics > > 2 ) + 1 ) ) < < FF_TRANSSHIFT ;
else // tr_trans60 otherwise
mobj - > frame = tr_trans60 < < FF_TRANSSHIFT ;
break ;
case MT_EGGCAPSULE :
if ( mobj - > z < = mobj - > floorz )
{
P_RemoveMobj ( mobj ) ;
return ;
}
break ;
case MT_EGGTRAP : // Egg Capsule animal release
if ( mobj - > fuse > 0 & & mobj - > fuse < 2 * TICRATE - ( TICRATE / 7 )
& & ( mobj - > fuse & 3 ) )
{
INT32 i , j ;
fixed_t x , y , z ;
fixed_t ns ;
mobj_t * mo2 ;
2016-07-06 04:09:17 +00:00
i = P_RandomByte ( ) ;
z = mobj - > subsector - > sector - > floorheight + ( ( P_RandomByte ( ) & 63 ) * FRACUNIT ) ;
2014-03-15 16:59:03 +00:00
for ( j = 0 ; j < 2 ; j + + )
{
2016-07-06 04:09:17 +00:00
const angle_t fa = ( P_RandomByte ( ) * FINEANGLES / 16 ) & FINEMASK ;
2014-03-15 16:59:03 +00:00
ns = 64 * FRACUNIT ;
x = mobj - > x + FixedMul ( FINESINE ( fa ) , ns ) ;
y = mobj - > y + FixedMul ( FINECOSINE ( fa ) , ns ) ;
mo2 = P_SpawnMobj ( x , y , z , MT_EXPLODE ) ;
ns = 4 * FRACUNIT ;
mo2 - > momx = FixedMul ( FINESINE ( fa ) , ns ) ;
mo2 - > momy = FixedMul ( FINECOSINE ( fa ) , ns ) ;
2016-07-06 04:09:17 +00:00
i = P_RandomByte ( ) ;
2014-03-15 16:59:03 +00:00
if ( i % 5 = = 0 )
P_SpawnMobj ( x , y , z , MT_CHICKEN ) ;
else if ( i % 4 = = 0 )
P_SpawnMobj ( x , y , z , MT_COW ) ;
else if ( i % 3 = = 0 )
{
P_SpawnMobj ( x , y , z , MT_BIRD ) ;
S_StartSound ( mo2 , mobj - > info - > deathsound ) ;
}
else if ( ( i & 1 ) = = 0 )
P_SpawnMobj ( x , y , z , MT_BUNNY ) ;
else
P_SpawnMobj ( x , y , z , MT_MOUSE ) ;
}
mobj - > fuse - - ;
}
break ;
2014-04-19 17:41:29 +00:00
case MT_PLAYER :
/// \todo Have the player's dead body completely finish its animation even if they've already respawned.
if ( ! ( mobj - > flags2 & MF2_DONTDRAW ) )
{
2014-08-04 03:49:33 +00:00
if ( ! mobj - > fuse )
2014-04-19 17:41:29 +00:00
{ // Go away.
/// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it.
mobj - > momz = 0 ;
2014-08-04 03:49:33 +00:00
if ( mobj - > player )
mobj - > flags2 | = MF2_DONTDRAW ;
else // safe to remove, nobody's going to complain!
{
P_RemoveMobj ( mobj ) ;
return ;
}
2014-04-19 17:41:29 +00:00
}
else // Apply gravity to fall downwards.
Mammoth commit!
* Deaths in record attack no longer put you into a glitchy singleplayer game-over state that we somehow both kept around and also broke since we branched Kart off of Vanilla..
* Fix non-standard mapscales making the Death Egg respawn octagons dissasemble themselves.
* Allow for MULTIPLE TIME EMBLEMS PER MAP, at least in the emblem UI on the timer. It shows all completed emblems plus the uncompleted emblem up to a total of three.
* Major tweaks to the First Person HUD.
* I know this was your baby, Sal, and some of the changes may prove controversial - so I've put the ones that are likely to cause the most fuss inside an ifndef block, so that you can toggle it as you please with minimal code changes.
* Dontdraw-ness, transparency, and colorization match the player's object!
* Moves around on the screen with respect to the direction of the player object's motion, to make drifting look nicer!
* Flashes the colour of your drift sparks.
* Did a WHOLE bunch of things with respect to music. I'm not sure how to describe this, so I'll go through step-by-step.
* Countdowns now play the drowning music again.
* Removed/disabled extraenous P_RestoreMusics.
* Made map-ending music called by its own function, P_EndingMusic(player_t *player).
* Made the ending music play on the LAST player crossing the finishing line in splitscreen, rather than first.
* Make dead players spinout and clip through the floor, at least until we add the new death anims.
* Fix prior pogo spring usage making dead players fall faster.
* Make the time over countdown use the kart font when not splitscreen with 3 or 4 players.
* Removed a weird bonus HWR_DrawCroppedPatch function signature in the hardware header.
2018-07-16 19:19:30 +00:00
{
2014-04-19 17:41:29 +00:00
P_SetObjectMomZ ( mobj , - 2 * FRACUNIT / 3 , true ) ;
Mammoth commit!
* Deaths in record attack no longer put you into a glitchy singleplayer game-over state that we somehow both kept around and also broke since we branched Kart off of Vanilla..
* Fix non-standard mapscales making the Death Egg respawn octagons dissasemble themselves.
* Allow for MULTIPLE TIME EMBLEMS PER MAP, at least in the emblem UI on the timer. It shows all completed emblems plus the uncompleted emblem up to a total of three.
* Major tweaks to the First Person HUD.
* I know this was your baby, Sal, and some of the changes may prove controversial - so I've put the ones that are likely to cause the most fuss inside an ifndef block, so that you can toggle it as you please with minimal code changes.
* Dontdraw-ness, transparency, and colorization match the player's object!
* Moves around on the screen with respect to the direction of the player object's motion, to make drifting look nicer!
* Flashes the colour of your drift sparks.
* Did a WHOLE bunch of things with respect to music. I'm not sure how to describe this, so I'll go through step-by-step.
* Countdowns now play the drowning music again.
* Removed/disabled extraenous P_RestoreMusics.
* Made map-ending music called by its own function, P_EndingMusic(player_t *player).
* Made the ending music play on the LAST player crossing the finishing line in splitscreen, rather than first.
* Make dead players spinout and clip through the floor, at least until we add the new death anims.
* Fix prior pogo spring usage making dead players fall faster.
* Make the time over countdown use the kart font when not splitscreen with 3 or 4 players.
* Removed a weird bonus HWR_DrawCroppedPatch function signature in the hardware header.
2018-07-16 19:19:30 +00:00
if ( mobj - > player )
mobj - > player - > frameangle - = ANGLE_22h ;
}
2014-04-19 17:41:29 +00:00
}
break ;
2017-02-26 15:19:12 +00:00
//{ SRB2kart Items - Death States
2018-07-23 00:55:18 +00:00
case MT_ORBINAUT :
2018-06-01 00:51:05 +00:00
case MT_BANANA :
2017-02-26 15:19:12 +00:00
case MT_FAKEITEM :
2018-10-18 08:43:50 +00:00
case MT_SPB :
2017-02-26 15:19:12 +00:00
if ( mobj - > z < = mobj - > floorz )
2018-08-05 15:38:46 +00:00
{
2017-02-26 15:19:12 +00:00
P_RemoveMobj ( mobj ) ;
2018-08-05 15:38:46 +00:00
return ;
}
// fallthru
case MT_ORBINAUT_SHIELD :
case MT_BANANA_SHIELD :
case MT_FAKESHIELD :
mobj - > flags2 ^ = MF2_DONTDRAW ;
2017-02-26 15:19:12 +00:00
break ;
2018-06-19 01:52:26 +00:00
case MT_JAWZ :
case MT_JAWZ_DUD :
if ( mobj - > z < = mobj - > floorz )
P_SetMobjState ( mobj , mobj - > info - > xdeathstate ) ;
2018-08-05 15:38:46 +00:00
// fallthru
case MT_JAWZ_SHIELD :
mobj - > flags2 ^ = MF2_DONTDRAW ;
2018-06-19 01:52:26 +00:00
break ;
2018-06-01 00:51:05 +00:00
case MT_SSMINE :
2018-10-18 08:43:50 +00:00
case MT_SPBEXPLOSION :
2017-02-26 22:37:52 +00:00
if ( mobj - > health > - 100 )
{
P_SetMobjState ( mobj , mobj - > info - > deathstate ) ;
mobj - > health = - 100 ;
}
else
2018-08-05 15:38:46 +00:00
{
2017-02-26 22:37:52 +00:00
P_RemoveMobj ( mobj ) ;
2018-08-05 15:38:46 +00:00
return ;
}
2017-02-26 22:37:52 +00:00
break ;
2018-02-08 03:33:27 +00:00
case MT_MINEEXPLOSIONSOUND :
2017-02-26 22:37:52 +00:00
P_RemoveMobj ( mobj ) ;
2018-08-05 15:38:46 +00:00
return ;
2017-02-26 15:19:12 +00:00
//}
2014-03-15 16:59:03 +00:00
default :
break ;
}
else switch ( mobj - > type )
{
2017-04-25 02:31:55 +00:00
case MT_FALLINGROCK :
// Despawn rocks here in case zmovement code can't do so (blame slopes)
if ( ! mobj - > momx & & ! mobj - > momy & & ! mobj - > momz
& & ( ( mobj - > eflags & MFE_VERTICALFLIP ) ?
mobj - > z + mobj - > height > = mobj - > ceilingz
: mobj - > z < = mobj - > floorz ) )
{
P_RemoveMobj ( mobj ) ;
return ;
}
P_MobjCheckWater ( mobj ) ;
break ;
2014-03-15 16:59:03 +00:00
case MT_EMERALDSPAWN :
if ( mobj - > threshold )
{
mobj - > threshold - - ;
if ( ! mobj - > threshold & & ! mobj - > target & & mobj - > reactiontime )
{
mobj_t * emerald = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , mobj - > reactiontime ) ;
emerald - > threshold = 42 ;
P_SetTarget ( & mobj - > target , emerald ) ;
P_SetTarget ( & emerald - > target , mobj ) ;
}
}
break ;
case MT_AQUABUZZ :
case MT_BIGAIRMINE :
{
if ( mobj - > tracer & & mobj - > tracer - > player & & mobj - > tracer - > health > 0
& & P_AproxDistance ( P_AproxDistance ( mobj - > tracer - > x - mobj - > x , mobj - > tracer - > y - mobj - > y ) , mobj - > tracer - > z - mobj - > z ) < = mobj - > radius * 16 )
{
// Home in on the target.
P_HomingAttack ( mobj , mobj - > tracer ) ;
if ( mobj - > z < mobj - > floorz )
mobj - > z = mobj - > floorz ;
if ( leveltime % mobj - > info - > painchance = = 0 )
S_StartSound ( mobj , mobj - > info - > activesound ) ;
}
else
{
// Try to find a player
P_LookForPlayers ( mobj , true , true , mobj - > radius * 16 ) ;
mobj - > momx > > = 1 ;
mobj - > momy > > = 1 ;
mobj - > momz > > = 1 ;
}
}
break ;
case MT_BIGMINE :
{
if ( mobj - > tracer & & mobj - > tracer - > player & & mobj - > tracer - > health > 0
& & P_AproxDistance ( P_AproxDistance ( mobj - > tracer - > x - mobj - > x , mobj - > tracer - > y - mobj - > y ) , mobj - > tracer - > z - mobj - > z ) < = mobj - > radius * 16 )
{
P_MobjCheckWater ( mobj ) ;
// Home in on the target.
P_HomingAttack ( mobj , mobj - > tracer ) ;
// Don't let it go out of water
if ( mobj - > z + mobj - > height > mobj - > watertop )
mobj - > z = mobj - > watertop - mobj - > height ;
if ( mobj - > z < mobj - > floorz )
mobj - > z = mobj - > floorz ;
if ( leveltime % mobj - > info - > painchance = = 0 )
S_StartSound ( mobj , mobj - > info - > activesound ) ;
}
else
{
// Try to find a player
P_LookForPlayers ( mobj , true , true , mobj - > radius * 16 ) ;
mobj - > momx > > = 1 ;
mobj - > momy > > = 1 ;
mobj - > momz > > = 1 ;
}
}
break ;
case MT_SPINMACEPOINT :
if ( leveltime & 1 )
{
if ( mobj - > lastlook > mobj - > movecount )
mobj - > lastlook - - ;
/*
if ( mobj - > threshold > mobj - > movefactor )
mobj - > threshold - = FRACUNIT ;
else if ( mobj - > threshold < mobj - > movefactor )
mobj - > threshold + = FRACUNIT ; */
}
break ;
case MT_EGGCAPSULE :
if ( ! mobj - > reactiontime )
{
// Target nearest player on your mare.
// (You can make it float up/down by adding MF_FLOAT,
// but beware level design pitfalls.)
fixed_t shortest = 1024 * FRACUNIT ;
INT32 i ;
P_SetTarget ( & mobj - > target , NULL ) ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
if ( playeringame [ i ] & & players [ i ] . mo
& & players [ i ] . mare = = mobj - > threshold & & players [ i ] . health > 1 )
{
fixed_t dist = P_AproxDistance ( players [ i ] . mo - > x - mobj - > x , players [ i ] . mo - > y - mobj - > y ) ;
if ( dist < shortest )
{
P_SetTarget ( & mobj - > target , players [ i ] . mo ) ;
shortest = dist ;
}
}
}
break ;
case MT_EGGMOBILE2_POGO :
if ( ! mobj - > target
| | ! mobj - > target - > health
| | mobj - > target - > state = = & states [ mobj - > target - > info - > spawnstate ]
| | mobj - > target - > state = = & states [ mobj - > target - > info - > raisestate ] )
{
P_RemoveMobj ( mobj ) ;
return ;
}
P_TeleportMove ( mobj , mobj - > target - > x , mobj - > target - > y , mobj - > target - > z - mobj - > height ) ;
break ;
case MT_HAMMER :
if ( mobj - > z < = mobj - > floorz )
{
P_RemoveMobj ( mobj ) ;
return ;
}
break ;
case MT_KOOPA :
P_KoopaThinker ( mobj ) ;
break ;
case MT_REDRING :
if ( ( ( mobj - > z < mobj - > floorz ) | | ( mobj - > z + mobj - > height > mobj - > ceilingz ) )
& & mobj - > flags & MF_MISSILE )
{
P_ExplodeMissile ( mobj ) ;
return ;
}
break ;
case MT_BOSSFLYPOINT :
return ;
case MT_NIGHTSCORE :
mobj - > color = ( UINT8 ) ( leveltime % SKINCOLOR_WHITE ) ;
break ;
case MT_JETFUME1 :
{
fixed_t jetx , jety ;
if ( ! mobj - > target // if you have no target
| | ( ! ( mobj - > target - > flags & MF_BOSS ) & & mobj - > target - > health < = 0 ) ) // or your target isn't a boss and it's popped now
{ // then remove yourself as well!
P_RemoveMobj ( mobj ) ;
return ;
}
jetx = mobj - > target - > x + P_ReturnThrustX ( mobj - > target , mobj - > target - > angle , FixedMul ( - 64 * FRACUNIT , mobj - > target - > scale ) ) ;
jety = mobj - > target - > y + P_ReturnThrustY ( mobj - > target , mobj - > target - > angle , FixedMul ( - 64 * FRACUNIT , mobj - > target - > scale ) ) ;
if ( mobj - > fuse = = 56 ) // First one
{
P_UnsetThingPosition ( mobj ) ;
mobj - > x = jetx ;
mobj - > y = jety ;
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
mobj - > z = mobj - > target - > z + mobj - > target - > height - mobj - > height - FixedMul ( 38 * FRACUNIT , mobj - > target - > scale ) ;
else
mobj - > z = mobj - > target - > z + FixedMul ( 38 * FRACUNIT , mobj - > target - > scale ) ;
mobj - > floorz = mobj - > z ;
mobj - > ceilingz = mobj - > z + mobj - > height ;
P_SetThingPosition ( mobj ) ;
}
else if ( mobj - > fuse = = 57 )
{
P_UnsetThingPosition ( mobj ) ;
mobj - > x = jetx + P_ReturnThrustX ( mobj - > target , mobj - > target - > angle - ANGLE_90 , FixedMul ( 24 * FRACUNIT , mobj - > target - > scale ) ) ;
mobj - > y = jety + P_ReturnThrustY ( mobj - > target , mobj - > target - > angle - ANGLE_90 , FixedMul ( 24 * FRACUNIT , mobj - > target - > scale ) ) ;
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
mobj - > z = mobj - > target - > z + mobj - > target - > height - mobj - > height - FixedMul ( 12 * FRACUNIT , mobj - > target - > scale ) ;
else
mobj - > z = mobj - > target - > z + FixedMul ( 12 * FRACUNIT , mobj - > target - > scale ) ;
mobj - > floorz = mobj - > z ;
mobj - > ceilingz = mobj - > z + mobj - > height ;
P_SetThingPosition ( mobj ) ;
}
else if ( mobj - > fuse = = 58 )
{
P_UnsetThingPosition ( mobj ) ;
mobj - > x = jetx + P_ReturnThrustX ( mobj - > target , mobj - > target - > angle + ANGLE_90 , FixedMul ( 24 * FRACUNIT , mobj - > target - > scale ) ) ;
mobj - > y = jety + P_ReturnThrustY ( mobj - > target , mobj - > target - > angle + ANGLE_90 , FixedMul ( 24 * FRACUNIT , mobj - > target - > scale ) ) ;
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
mobj - > z = mobj - > target - > z + mobj - > target - > height - mobj - > height - FixedMul ( 12 * FRACUNIT , mobj - > target - > scale ) ;
else
mobj - > z = mobj - > target - > z + FixedMul ( 12 * FRACUNIT , mobj - > target - > scale ) ;
mobj - > floorz = mobj - > z ;
mobj - > ceilingz = mobj - > z + mobj - > height ;
P_SetThingPosition ( mobj ) ;
}
else if ( mobj - > fuse = = 59 )
{
jetx = mobj - > target - > x + P_ReturnThrustX ( mobj - > target , mobj - > target - > angle , - mobj - > target - > radius ) ;
jety = mobj - > target - > y + P_ReturnThrustY ( mobj - > target , mobj - > target - > angle , - mobj - > target - > radius ) ;
P_UnsetThingPosition ( mobj ) ;
mobj - > x = jetx ;
mobj - > y = jety ;
if ( mobj - > target - > eflags & MFE_VERTICALFLIP )
mobj - > z = mobj - > target - > z + mobj - > target - > height / 2 + mobj - > height / 2 ;
else
mobj - > z = mobj - > target - > z + mobj - > target - > height / 2 - mobj - > height / 2 ;
mobj - > floorz = mobj - > z ;
mobj - > ceilingz = mobj - > z + mobj - > height ;
P_SetThingPosition ( mobj ) ;
}
mobj - > fuse + + ;
}
break ;
case MT_PROPELLER :
{
fixed_t jetx , jety ;
if ( ! mobj - > target // if you have no target
| | ( ! ( mobj - > target - > flags & MF_BOSS ) & & mobj - > target - > health < = 0 ) ) // or your target isn't a boss and it's popped now
{ // then remove yourself as well!
P_RemoveMobj ( mobj ) ;
return ;
}
jetx = mobj - > target - > x + P_ReturnThrustX ( mobj - > target , mobj - > target - > angle , FixedMul ( - 60 * FRACUNIT , mobj - > target - > scale ) ) ;
jety = mobj - > target - > y + P_ReturnThrustY ( mobj - > target , mobj - > target - > angle , FixedMul ( - 60 * FRACUNIT , mobj - > target - > scale ) ) ;
P_UnsetThingPosition ( mobj ) ;
mobj - > x = jetx ;
mobj - > y = jety ;
mobj - > z = mobj - > target - > z + FixedMul ( 17 * FRACUNIT , mobj - > target - > scale ) ;
mobj - > angle = mobj - > target - > angle - ANGLE_180 ;
mobj - > floorz = mobj - > z ;
mobj - > ceilingz = mobj - > z + mobj - > height ;
P_SetThingPosition ( mobj ) ;
}
break ;
case MT_JETFLAME :
{
if ( ! mobj - > target // if you have no target
| | ( ! ( mobj - > target - > flags & MF_BOSS ) & & mobj - > target - > health < = 0 ) ) // or your target isn't a boss and it's popped now
{ // then remove yourself as well!
P_RemoveMobj ( mobj ) ;
return ;
}
P_UnsetThingPosition ( mobj ) ;
mobj - > x = mobj - > target - > x ;
mobj - > y = mobj - > target - > y ;
mobj - > z = mobj - > target - > z - FixedMul ( 50 * FRACUNIT , mobj - > target - > scale ) ;
mobj - > floorz = mobj - > z ;
mobj - > ceilingz = mobj - > z + mobj - > height ;
P_SetThingPosition ( mobj ) ;
}
break ;
case MT_NIGHTSDRONE :
if ( mobj - > state > = & states [ S_NIGHTSDRONE_SPARKLING1 ] & & mobj - > state < = & states [ S_NIGHTSDRONE_SPARKLING16 ] )
{
mobj - > flags2 & = ~ MF2_DONTDRAW ;
mobj - > z = mobj - > floorz + mobj - > height + ( mobj - > spawnpoint - > options > > ZSHIFT ) * FRACUNIT ;
mobj - > angle = 0 ;
2014-03-18 17:56:54 +00:00
if ( ! mobj - > target )
2014-03-15 16:59:03 +00:00
{
mobj_t * goalpost = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z + FRACUNIT , MT_NIGHTSGOAL ) ;
CONS_Debug ( DBG_NIGHTSBASIC , " Adding goal post \n " ) ;
goalpost - > angle = mobj - > angle ;
P_SetTarget ( & mobj - > target , goalpost ) ;
}
if ( G_IsSpecialStage ( gamemap ) )
{ // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime.
INT32 i ;
boolean bonustime = false ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
if ( playeringame [ i ] & & players [ i ] . bonustime )
{
bonustime = true ;
break ;
}
if ( ! bonustime )
{
mobj - > flags & = ~ MF_NOGRAVITY ;
P_SetMobjState ( mobj , S_NIGHTSDRONE1 ) ;
2016-08-12 14:56:07 +00:00
mobj - > flags2 | = MF2_DONTDRAW ;
2014-03-15 16:59:03 +00:00
}
}
else if ( mobj - > tracer & & mobj - > tracer - > player )
{
if ( ! ( mobj - > tracer - > player - > pflags & PF_NIGHTSMODE ) )
{
mobj - > flags & = ~ MF_NOGRAVITY ;
mobj - > flags2 & = ~ MF2_DONTDRAW ;
P_SetMobjState ( mobj , S_NIGHTSDRONE1 ) ;
}
else if ( ! mobj - > tracer - > player - > bonustime )
{
mobj - > flags & = ~ MF_NOGRAVITY ;
P_SetMobjState ( mobj , S_NIGHTSDRONE1 ) ;
}
}
}
else
{
if ( G_IsSpecialStage ( gamemap ) )
{ // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime.
INT32 i ;
boolean bonustime = false ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
if ( playeringame [ i ] & & players [ i ] . bonustime )
{
bonustime = true ;
break ;
}
if ( bonustime )
{
P_SetMobjState ( mobj , S_NIGHTSDRONE_SPARKLING1 ) ;
mobj - > flags | = MF_NOGRAVITY ;
}
else
{
if ( mobj - > target )
{
CONS_Debug ( DBG_NIGHTSBASIC , " Removing goal post \n " ) ;
P_RemoveMobj ( mobj - > target ) ;
P_SetTarget ( & mobj - > target , NULL ) ;
}
mobj - > flags2 | = MF2_DONTDRAW ;
}
}
else if ( mobj - > tracer & & mobj - > tracer - > player )
{
if ( mobj - > target )
{
CONS_Debug ( DBG_NIGHTSBASIC , " Removing goal post \n " ) ;
P_RemoveMobj ( mobj - > target ) ;
P_SetTarget ( & mobj - > target , NULL ) ;
}
if ( mobj - > tracer - > player - > pflags & PF_NIGHTSMODE )
{
if ( mobj - > tracer - > player - > bonustime )
{
P_SetMobjState ( mobj , S_NIGHTSDRONE_SPARKLING1 ) ;
mobj - > flags | = MF_NOGRAVITY ;
}
else
mobj - > flags2 | = MF2_DONTDRAW ;
}
else // Not NiGHTS
mobj - > flags2 & = ~ MF2_DONTDRAW ;
}
mobj - > angle + = ANG10 ;
if ( mobj - > z < = mobj - > floorz )
mobj - > momz = 5 * FRACUNIT ;
}
break ;
case MT_PLAYER :
if ( mobj - > player )
P_PlayerMobjThinker ( mobj ) ;
return ;
case MT_SKIM :
// check mobj against possible water content, before movement code
P_MobjCheckWater ( mobj ) ;
// Keep Skim at water surface
if ( mobj - > z < = mobj - > watertop )
{
mobj - > flags | = MF_NOGRAVITY ;
if ( mobj - > z < mobj - > watertop )
{
if ( mobj - > watertop - mobj - > z < = FixedMul ( mobj - > info - > speed * FRACUNIT , mobj - > scale ) )
mobj - > z = mobj - > watertop ;
else
mobj - > momz = FixedMul ( mobj - > info - > speed * FRACUNIT , mobj - > scale ) ;
}
}
else
{
mobj - > flags & = ~ MF_NOGRAVITY ;
2018-08-27 05:07:44 +00:00
if ( mobj - > z > mobj - > watertop & & mobj - > z - mobj - > watertop < FixedMul ( MAXSTEPMOVE , mapheaderinfo [ gamemap - 1 ] - > mobj_scale ) )
2014-03-15 16:59:03 +00:00
mobj - > z = mobj - > watertop ;
}
break ;
case MT_RING :
case MT_COIN :
case MT_BLUEBALL :
case MT_REDTEAMRING :
case MT_BLUETEAMRING :
// No need to check water. Who cares?
P_RingThinker ( mobj ) ;
if ( mobj - > flags2 & MF2_NIGHTSPULL )
P_NightsItemChase ( mobj ) ;
else
A_AttractChase ( mobj ) ;
return ;
// Flung items
case MT_FLINGRING :
case MT_FLINGCOIN :
if ( mobj - > flags2 & MF2_NIGHTSPULL )
P_NightsItemChase ( mobj ) ;
else
A_AttractChase ( mobj ) ;
break ;
case MT_NIGHTSWING :
if ( mobj - > flags2 & MF2_NIGHTSPULL )
P_NightsItemChase ( mobj ) ;
break ;
2017-10-24 22:33:25 +00:00
case MT_SMALLMACE :
case MT_BIGMACE :
{
mobj_t * ghostmo = P_SpawnGhostMobj ( mobj ) ;
ghostmo - > fuse = 4 ;
}
break ;
2014-03-15 16:59:03 +00:00
case MT_SHELL :
if ( mobj - > threshold > TICRATE )
mobj - > threshold - - ;
if ( mobj - > state ! = & states [ S_SHELL ] )
{
2014-08-04 03:49:33 +00:00
mobj - > angle = R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) ;
2014-03-15 16:59:03 +00:00
P_InstaThrust ( mobj , mobj - > angle , FixedMul ( mobj - > info - > speed , mobj - > scale ) ) ;
}
break ;
2017-02-26 15:19:12 +00:00
//{ SRB2kart Items
case MT_POKEY :
if ( mobj - > threshold )
{
if ( mobj - > state = = & states [ S_POKEY1 ] )
mobj - > health = 1 ;
else if ( mobj - > state = = & states [ S_POKEY2 ] )
mobj - > health = 2 ;
else if ( mobj - > state = = & states [ S_POKEY3 ] )
mobj - > health = 3 ;
else if ( mobj - > state = = & states [ S_POKEY4 ] )
mobj - > health = 4 ;
else if ( mobj - > state = = & states [ S_POKEY5 ] )
mobj - > health = 5 ;
else if ( mobj - > state = = & states [ S_POKEY6 ] )
mobj - > health = 6 ;
else if ( mobj - > state = = & states [ S_POKEY7 ] )
mobj - > health = 7 ;
else if ( mobj - > state = = & states [ S_POKEY8 ] )
mobj - > health = 8 ;
mobj - > threshold + + ;
P_SetMobjState ( mobj , S_POKEYIDLE ) ;
}
if ( mobj - > state = = & states [ S_POKEYIDLE ] & & mobj - > threshold > = 105 )
{
if ( mobj - > health = = 1 )
P_SetMobjState ( mobj , S_POKEY1 ) ;
else if ( mobj - > health = = 2 )
P_SetMobjState ( mobj , S_POKEY2 ) ;
else if ( mobj - > health = = 3 )
P_SetMobjState ( mobj , S_POKEY3 ) ;
else if ( mobj - > health = = 4 )
P_SetMobjState ( mobj , S_POKEY4 ) ;
else if ( mobj - > health = = 5 )
P_SetMobjState ( mobj , S_POKEY5 ) ;
else if ( mobj - > health = = 6 )
P_SetMobjState ( mobj , S_POKEY6 ) ;
else if ( mobj - > health = = 7 )
P_SetMobjState ( mobj , S_POKEY7 ) ;
else if ( mobj - > health = = 8 )
P_SetMobjState ( mobj , S_POKEY8 ) ;
mobj - > threshold = 0 ;
}
break ;
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
case MT_FLOATINGITEM :
2017-10-22 21:29:39 +00:00
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( mobj - > flags & MF_NOCLIPTHING )
{
if ( P_IsObjectOnGround ( mobj ) )
{
mobj - > momx = 1 ;
mobj - > momy = 0 ;
mobj - > flags & = ~ MF_NOCLIPTHING ;
mobj - > flags | = MF_NOGRAVITY ;
}
}
else
{
mobj - > angle + = 2 * ANG2 ;
if ( mobj - > flags2 & MF2_NIGHTSPULL )
{
if ( ! mobj - > tracer | | ! mobj - > tracer - > health
2018-09-07 13:26:00 +00:00
| | mobj - > scale < = mapheaderinfo [ gamemap - 1 ] - > mobj_scale > > 4 )
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
{
P_RemoveMobj ( mobj ) ;
return ;
}
P_Attract ( mobj , mobj - > tracer , true ) ;
}
else
{
fixed_t adj = FixedMul ( FRACUNIT - FINECOSINE ( ( mobj - > movedir > > ANGLETOFINESHIFT ) & FINEMASK ) , ( mapheaderinfo [ gamemap - 1 ] - > mobj_scale < < 3 ) ) ;
mobj - > movedir + = 2 * ANG2 ;
if ( mobj - > eflags & MFE_VERTICALFLIP )
mobj - > z = mobj - > ceilingz - mobj - > height - adj ;
else
mobj - > z = mobj - > floorz + adj ;
}
}
2017-10-22 21:29:39 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
switch ( mobj - > threshold )
2017-10-22 21:29:39 +00:00
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
case KITEM_ORBINAUT :
mobj - > sprite = SPR_ITMO ;
mobj - > frame = FF_FULLBRIGHT | FF_PAPERSPRITE | ( min ( mobj - > movecount - 1 , 3 ) ) ;
break ;
case KITEM_INVINCIBILITY :
mobj - > sprite = SPR_ITMI ;
mobj - > frame = FF_FULLBRIGHT | FF_PAPERSPRITE | ( ( leveltime % ( 7 * 3 ) ) / 3 ) ;
break ;
case KITEM_SAD :
mobj - > sprite = SPR_ITEM ;
mobj - > frame = FF_FULLBRIGHT | FF_PAPERSPRITE ;
break ;
default :
mobj - > sprite = SPR_ITEM ;
mobj - > frame = FF_FULLBRIGHT | FF_PAPERSPRITE | ( mobj - > threshold ) ;
break ;
}
break ;
}
case MT_ORBINAUT :
{
boolean grounded = P_IsObjectOnGround ( mobj ) ;
if ( mobj - > flags2 & MF2_AMBUSH )
{
if ( grounded & & ( mobj - > flags & MF_NOCLIPTHING ) )
2017-10-22 21:29:39 +00:00
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
mobj - > momx = 1 ;
mobj - > momy = 0 ;
mobj - > frame = 3 ;
S_StartSound ( mobj , mobj - > info - > activesound ) ;
mobj - > flags & = ~ MF_NOCLIPTHING ;
}
else if ( mobj - > movecount )
mobj - > movecount - - ;
else if ( mobj - > frame < 3 )
{
mobj - > movecount = 2 ;
mobj - > frame + + ;
2017-10-22 21:29:39 +00:00
}
}
else
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
fixed_t finalspeed = mobj - > info - > speed ;
P_SpawnGhostMobj ( mobj ) ;
if ( gamespeed = = 0 )
finalspeed = FixedMul ( finalspeed , FRACUNIT - FRACUNIT / 4 ) ;
else if ( gamespeed = = 2 )
finalspeed = FixedMul ( finalspeed , FRACUNIT + FRACUNIT / 4 ) ;
mobj - > angle = R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) ;
if ( mobj - > health < = 5 )
{
INT32 i ;
for ( i = 5 ; i > = mobj - > health ; i - - )
finalspeed = FixedMul ( finalspeed , FRACUNIT - FRACUNIT / 4 ) ;
}
2018-03-04 20:27:52 +00:00
finalspeed = FixedMul ( finalspeed , mapheaderinfo [ gamemap - 1 ] - > mobj_scale ) ;
2017-10-22 21:29:39 +00:00
P_InstaThrust ( mobj , mobj - > angle , finalspeed ) ;
2017-11-19 07:37:28 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( grounded )
{
sector_t * sec2 = P_ThingOnSpecial3DFloor ( mobj ) ;
if ( ( sec2 & & GETSECSPECIAL ( sec2 - > special , 3 ) = = 1 )
| | ( P_IsObjectOnRealGround ( mobj , mobj - > subsector - > sector )
& & GETSECSPECIAL ( mobj - > subsector - > sector - > special , 3 ) = = 1 ) )
2018-09-27 17:32:07 +00:00
K_DoPogoSpring ( mobj , 0 , 1 ) ;
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
}
2017-11-19 07:37:28 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( mobj - > threshold > 0 )
mobj - > threshold - - ;
2017-11-19 07:37:28 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( leveltime % 6 = = 0 )
S_StartSound ( mobj , mobj - > info - > activesound ) ;
}
2017-02-26 15:19:12 +00:00
break ;
2017-10-22 21:29:39 +00:00
}
2018-06-01 00:51:05 +00:00
case MT_JAWZ :
2017-03-07 23:47:06 +00:00
{
2017-11-19 07:37:28 +00:00
sector_t * sec2 ;
2017-10-22 21:08:07 +00:00
fixed_t topspeed = 64 * FRACUNIT ;
fixed_t distbarrier = 512 * FRACUNIT ;
fixed_t distaway ;
2017-10-24 14:25:08 +00:00
P_SpawnGhostMobj ( mobj ) ;
2017-02-26 15:19:12 +00:00
if ( mobj - > threshold > 0 )
mobj - > threshold - - ;
2018-07-25 02:47:09 +00:00
if ( leveltime % TICRATE = = 0 )
2017-02-26 15:19:12 +00:00
S_StartSound ( mobj , mobj - > info - > activesound ) ;
2017-03-07 23:47:06 +00:00
Lots of changes
- Menus now have all of the Kart cvars
- Removed any cvars that aren't useful for Kart from the menu (they
still exist in the console, though)
- Removed SP and NiGHTS Mode options from the main menu
- "kartcc" is renamed "kartspeed", uses values 0-2 instead of multiples
of 50, or the terms "Relaxed", "Standard", and "Turbo"
- Many gametype options (game speed, frantic, mirror, & karma comeback)
are now changed on map load instead of instantly
- New cvar, "kartminimap", for disabling the minimap
- The maxplayers cvar now actually matches up with our 16 player limit
- Game now keeps track of matches played. Has a condition type
associated with it, as well.
- Game checks for unlocks and saves gamedata when finishing a match,
even in MP
- Removed most of the normal emblems, added a single emblem for Green
Hills. Didn't know what to do with extra emblems and such so I just left
them (FOR NOW c:<)
2018-01-16 03:31:14 +00:00
if ( gamespeed = = 0 )
2017-10-22 21:08:07 +00:00
{
topspeed = FixedMul ( topspeed , FRACUNIT - FRACUNIT / 4 ) ;
distbarrier = FixedMul ( distbarrier , FRACUNIT - FRACUNIT / 4 ) ;
}
Lots of changes
- Menus now have all of the Kart cvars
- Removed any cvars that aren't useful for Kart from the menu (they
still exist in the console, though)
- Removed SP and NiGHTS Mode options from the main menu
- "kartcc" is renamed "kartspeed", uses values 0-2 instead of multiples
of 50, or the terms "Relaxed", "Standard", and "Turbo"
- Many gametype options (game speed, frantic, mirror, & karma comeback)
are now changed on map load instead of instantly
- New cvar, "kartminimap", for disabling the minimap
- The maxplayers cvar now actually matches up with our 16 player limit
- Game now keeps track of matches played. Has a condition type
associated with it, as well.
- Game checks for unlocks and saves gamedata when finishing a match,
even in MP
- Removed most of the normal emblems, added a single emblem for Green
Hills. Didn't know what to do with extra emblems and such so I just left
them (FOR NOW c:<)
2018-01-16 03:31:14 +00:00
else if ( gamespeed = = 2 )
2017-03-07 23:47:06 +00:00
{
2017-10-22 21:08:07 +00:00
topspeed = FixedMul ( topspeed , FRACUNIT + FRACUNIT / 4 ) ;
distbarrier = FixedMul ( distbarrier , FRACUNIT + FRACUNIT / 4 ) ;
2017-03-07 23:47:06 +00:00
}
2017-10-22 21:08:07 +00:00
2018-03-04 20:27:52 +00:00
distbarrier = FixedMul ( distbarrier , mapheaderinfo [ gamemap - 1 ] - > mobj_scale ) ;
topspeed = FixedMul ( topspeed , mapheaderinfo [ gamemap - 1 ] - > mobj_scale ) ;
if ( G_RaceGametype ( ) & & mobj - > tracer )
2017-03-07 23:47:06 +00:00
{
2017-10-22 21:08:07 +00:00
distaway = P_AproxDistance ( mobj - > tracer - > x - mobj - > x , mobj - > tracer - > y - mobj - > y ) ;
if ( distaway < distbarrier )
{
if ( mobj - > tracer - > player )
{
fixed_t speeddifference = abs ( topspeed - min ( mobj - > tracer - > player - > speed , K_GetKartSpeed ( mobj - > tracer - > player , false ) ) ) ;
topspeed = topspeed - FixedMul ( speeddifference , FRACUNIT - FixedDiv ( distaway , distbarrier ) ) ;
}
}
2017-03-07 23:47:06 +00:00
}
2017-10-22 21:08:07 +00:00
2018-03-04 20:27:52 +00:00
if ( G_BattleGametype ( ) )
2017-11-29 23:31:17 +00:00
{
mobj - > friction - = 1228 ;
if ( mobj - > friction > FRACUNIT )
mobj - > friction = FRACUNIT ;
if ( mobj - > friction < 0 )
mobj - > friction = 0 ;
}
2018-06-01 00:51:05 +00:00
mobj - > angle = R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) ;
P_InstaThrust ( mobj , mobj - > angle , topspeed ) ;
2017-11-19 07:37:28 +00:00
2018-06-08 20:05:45 +00:00
if ( mobj - > tracer )
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > tracer - > x , mobj - > tracer - > y ) ;
else
mobj - > angle = R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) ;
K_DriftDustHandling ( mobj ) ;
2017-11-19 07:37:28 +00:00
sec2 = P_ThingOnSpecial3DFloor ( mobj ) ;
2017-11-28 06:13:23 +00:00
if ( ( sec2 & & GETSECSPECIAL ( sec2 - > special , 3 ) = = 1 )
| | ( P_IsObjectOnRealGround ( mobj , mobj - > subsector - > sector )
& & GETSECSPECIAL ( mobj - > subsector - > sector - > special , 3 ) = = 1 ) )
2018-09-27 17:32:07 +00:00
K_DoPogoSpring ( mobj , 0 , 1 ) ;
2017-11-19 07:37:28 +00:00
2017-02-26 15:19:12 +00:00
break ;
2017-03-07 23:47:06 +00:00
}
2018-06-01 00:51:05 +00:00
case MT_JAWZ_DUD :
2017-11-19 07:37:28 +00:00
{
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
boolean grounded = P_IsObjectOnGround ( mobj ) ;
if ( mobj - > flags2 & MF2_AMBUSH )
{
if ( grounded & & ( mobj - > flags & MF_NOCLIPTHING ) )
{
mobj - > momx = 1 ;
mobj - > momy = 0 ;
S_StartSound ( mobj , mobj - > info - > deathsound ) ;
mobj - > flags & = ~ MF_NOCLIPTHING ;
}
}
else
{
P_SpawnGhostMobj ( mobj ) ;
mobj - > angle = R_PointToAngle2 ( 0 , 0 , mobj - > momx , mobj - > momy ) ;
P_InstaThrust ( mobj , mobj - > angle , mobj - > info - > speed ) ;
2017-11-19 07:37:28 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( grounded )
{
sector_t * sec2 = P_ThingOnSpecial3DFloor ( mobj ) ;
if ( ( sec2 & & GETSECSPECIAL ( sec2 - > special , 3 ) = = 1 )
| | ( P_IsObjectOnRealGround ( mobj , mobj - > subsector - > sector )
& & GETSECSPECIAL ( mobj - > subsector - > sector - > special , 3 ) = = 1 ) )
2018-09-27 17:32:07 +00:00
K_DoPogoSpring ( mobj , 0 , 1 ) ;
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
}
2017-11-19 07:37:28 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( mobj - > threshold > 0 )
mobj - > threshold - - ;
2017-11-19 07:37:28 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
if ( leveltime % TICRATE = = 0 )
S_StartSound ( mobj , mobj - > info - > activesound ) ;
}
2017-11-19 07:37:28 +00:00
2017-02-26 15:19:12 +00:00
break ;
2017-11-19 07:37:28 +00:00
}
2018-06-01 00:51:05 +00:00
case MT_BANANA :
2017-02-26 15:19:12 +00:00
case MT_FAKEITEM :
2017-10-24 14:25:08 +00:00
if ( mobj - > momx | | mobj - > momy )
P_SpawnGhostMobj ( mobj ) ;
2017-02-26 15:19:12 +00:00
if ( mobj - > z < = mobj - > floorz & & mobj - > health > 1 )
{
S_StartSound ( mobj , mobj - > info - > activesound ) ;
mobj - > momx = mobj - > momy = 0 ;
mobj - > health = 1 ;
}
if ( mobj - > threshold > 0 )
mobj - > threshold - - ;
break ;
2018-06-25 21:12:01 +00:00
case MT_BALLHOG :
2018-10-18 08:43:50 +00:00
case MT_SPB :
2018-06-27 14:37:19 +00:00
P_SpawnGhostMobj ( mobj ) - > fuse = 3 ;
2017-05-13 15:14:26 +00:00
if ( mobj - > threshold > 0 )
mobj - > threshold - - ;
break ;
2017-02-26 15:19:12 +00:00
case MT_SINK :
2018-06-25 11:28:27 +00:00
if ( mobj - > momx | | mobj - > momy )
P_SpawnGhostMobj ( mobj ) ;
2017-02-26 15:19:12 +00:00
if ( mobj - > z < = mobj - > floorz )
{
S_StartSound ( mobj , mobj - > info - > deathsound ) ;
P_SetMobjState ( mobj , S_NULL ) ;
}
if ( mobj - > threshold > 0 )
mobj - > threshold - - ;
break ;
2018-06-01 00:51:05 +00:00
case MT_SSMINE :
2018-02-05 23:55:52 +00:00
if ( mobj - > target & & mobj - > target - > player )
mobj - > color = mobj - > target - > player - > skincolor ;
else
2018-10-18 08:43:50 +00:00
mobj - > color = SKINCOLOR_KETCHUP ;
2017-10-24 14:25:08 +00:00
if ( mobj - > momx | | mobj - > momy )
P_SpawnGhostMobj ( mobj ) ;
2018-03-13 10:40:02 +00:00
if ( P_IsObjectOnGround ( mobj ) )
2017-02-26 15:19:12 +00:00
{
2018-06-01 00:51:05 +00:00
if ( mobj - > state = = & states [ S_SSMINE_AIR1 ] | | mobj - > state = = & states [ S_SSMINE_AIR2 ] )
P_SetMobjState ( mobj , S_SSMINE_DEPLOY1 ) ;
2018-03-13 10:40:02 +00:00
if ( mobj - > reactiontime > = mobj - > info - > reactiontime )
2017-02-26 15:19:12 +00:00
{
mobj - > momx = mobj - > momy = 0 ;
S_StartSound ( mobj , mobj - > info - > activesound ) ;
2018-03-13 10:40:02 +00:00
mobj - > reactiontime - - ;
2017-02-26 15:19:12 +00:00
}
}
2018-03-13 10:40:02 +00:00
if ( mobj - > reactiontime & & mobj - > reactiontime < mobj - > info - > reactiontime )
{
mobj - > reactiontime - - ;
if ( ! mobj - > reactiontime )
P_KillMobj ( mobj , NULL , NULL ) ;
2017-02-26 15:19:12 +00:00
}
2018-06-15 00:23:04 +00:00
if ( ( mobj - > state > = & states [ S_SSMINE1 ] & & mobj - > state < = & states [ S_SSMINE4 ] )
| | ( mobj - > state > = & states [ S_SSMINE_DEPLOY8 ] & & mobj - > state < = & states [ S_SSMINE_DEPLOY13 ] ) )
2018-02-08 03:33:27 +00:00
A_GrenadeRing ( mobj ) ;
2017-02-26 15:19:12 +00:00
if ( mobj - > threshold > 0 )
mobj - > threshold - - ;
break ;
2018-10-18 08:43:50 +00:00
case MT_SPBEXPLOSION :
2017-02-26 22:37:52 +00:00
mobj - > health - - ;
break ;
2018-02-08 03:33:27 +00:00
case MT_MINEEXPLOSION :
2017-02-26 15:19:12 +00:00
if ( ( mobj - > z < mobj - > floorz - mobj - > height ) | | ( mobj - > z > mobj - > ceilingz + mobj - > height ) )
{
P_KillMobj ( mobj , NULL , NULL ) ;
break ;
}
if ( mobj - > tics ! = - 1 )
{
mobj - > tics - - ;
// you can cycle through multiple states in a tic
if ( ! mobj - > tics )
if ( ! P_SetMobjState ( mobj , mobj - > state - > nextstate ) )
return ; // freed itself
}
P_UnsetThingPosition ( mobj ) ;
mobj - > x + = mobj - > momx ;
mobj - > y + = mobj - > momy ;
mobj - > z + = mobj - > momz ;
P_SetThingPosition ( mobj ) ;
return ;
2018-02-08 03:33:27 +00:00
case MT_MINEEXPLOSIONSOUND :
2017-02-26 22:37:52 +00:00
if ( mobj - > health = = 100 )
2018-10-07 10:40:06 +00:00
S_StartSound ( mobj , sfx_s3k4e ) ;
2017-02-26 22:37:52 +00:00
mobj - > health - - ;
break ;
2018-09-07 03:49:51 +00:00
case MT_BOOSTFLAME :
if ( ! mobj - > target | | ! mobj - > target - > health )
{
P_RemoveMobj ( mobj ) ;
return ;
}
P_TeleportMove ( mobj , mobj - > target - > x + P_ReturnThrustX ( mobj , mobj - > target - > angle + ANGLE_180 , mobj - > target - > radius ) ,
mobj - > target - > y + P_ReturnThrustY ( mobj , mobj - > target - > angle + ANGLE_180 , mobj - > target - > radius ) , mobj - > target - > z ) ;
mobj - > angle = mobj - > target - > angle ;
P_SetScale ( mobj , mobj - > target - > scale ) ;
if ( mobj - > target - > player )
{
if ( mobj - > target - > player - > kartstuff [ k_sneakertimer ] > mobj - > movecount )
P_SetMobjState ( mobj , S_BOOSTFLAME ) ;
mobj - > movecount = mobj - > target - > player - > kartstuff [ k_sneakertimer ] ;
}
if ( mobj - > state = = & states [ S_BOOSTSMOKESPAWNER ] )
{
mobj_t * smoke = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z + ( 8 < < FRACBITS ) , MT_BOOSTSMOKE ) ;
P_SetScale ( smoke , mobj - > target - > scale / 2 ) ;
smoke - > destscale = 3 * mobj - > target - > scale / 2 ;
2018-09-27 21:17:04 +00:00
smoke - > scalespeed = FixedMul ( smoke - > scalespeed , mobj - > target - > scale ) ;
2018-09-07 03:49:51 +00:00
smoke - > momx = mobj - > target - > momx / 2 ;
smoke - > momy = mobj - > target - > momy / 2 ;
smoke - > momz = mobj - > target - > momz / 2 ;
2018-09-27 21:21:06 +00:00
P_Thrust ( smoke , mobj - > target - > angle + FixedAngle ( P_RandomRange ( 135 , 225 ) < < FRACBITS ) , P_RandomRange ( 0 , 8 ) * mobj - > target - > scale ) ;
2018-09-07 03:49:51 +00:00
}
break ;
2018-06-10 20:10:24 +00:00
case MT_SPARKLETRAIL :
if ( ! mobj - > target )
{
P_RemoveMobj ( mobj ) ;
return ;
}
mobj - > color = mobj - > target - > color ;
mobj - > colorized = mobj - > target - > colorized ;
break ;
case MT_INVULNFLASH :
2018-06-14 02:24:31 +00:00
if ( ! mobj - > target | | ! mobj - > target - > health | | ( mobj - > target - > player & & ! mobj - > target - > player - > kartstuff [ k_invincibilitytimer ] ) )
2018-06-10 20:10:24 +00:00
{
P_RemoveMobj ( mobj ) ;
return ;
}
2018-06-14 02:24:31 +00:00
P_TeleportMove ( mobj , mobj - > target - > x , mobj - > target - > y , mobj - > target - > z ) ;
2018-06-10 20:10:24 +00:00
break ;
2018-08-30 23:24:22 +00:00
case MT_PLAYERRETICULE :
if ( ! mobj - > target | | ! mobj - > target - > health )
{
P_RemoveMobj ( mobj ) ;
return ;
}
P_TeleportMove ( mobj , mobj - > target - > x , mobj - > target - > y , mobj - > target - > z ) ;
break ;
2018-07-27 00:12:42 +00:00
case MT_INSTASHIELDB :
if ( leveltime & 1 )
mobj - > flags2 | = MF2_DONTDRAW ;
else
mobj - > flags2 & = ~ MF2_DONTDRAW ;
/* FALLTHRU */
case MT_INSTASHIELDA :
if ( ! mobj - > target | | ! mobj - > target - > health | | ( mobj - > target - > player & & ! mobj - > target - > player - > kartstuff [ k_instashield ] ) )
{
P_RemoveMobj ( mobj ) ;
return ;
}
P_TeleportMove ( mobj , mobj - > target - > x , mobj - > target - > y , mobj - > target - > z ) ;
break ;
2018-08-04 19:48:31 +00:00
case MT_THUNDERSHIELD :
2018-09-13 18:01:36 +00:00
{
fixed_t destx , desty ;
2018-08-04 19:48:31 +00:00
if ( ! mobj - > target | | ! mobj - > target - > health | | ( mobj - > target - > player & & mobj - > target - > player - > kartstuff [ k_curshield ] ! = 1 ) )
{
P_RemoveMobj ( mobj ) ;
return ;
}
2018-09-13 18:01:36 +00:00
P_SetScale ( mobj , ( mobj - > destscale = ( 5 * mobj - > target - > destscale ) > > 2 ) ) ;
if ( ! splitscreen /*&& rendermode != render_soft*/ )
{
angle_t viewingangle ;
statenum_t curstate = ( ( mobj - > tics = = 1 ) ? ( mobj - > state - > nextstate ) : ( ( statenum_t ) ( mobj - > state - states ) ) ) ;
if ( players [ displayplayer ] . awayviewtics )
viewingangle = R_PointToAngle2 ( mobj - > target - > x , mobj - > target - > y , players [ displayplayer ] . awayviewmobj - > x , players [ displayplayer ] . awayviewmobj - > y ) ;
else if ( ! camera . chase & & players [ displayplayer ] . mo )
viewingangle = R_PointToAngle2 ( mobj - > target - > x , mobj - > target - > y , players [ displayplayer ] . mo - > x , players [ displayplayer ] . mo - > y ) ;
else
viewingangle = R_PointToAngle2 ( mobj - > target - > x , mobj - > target - > y , camera . x , camera . y ) ;
if ( curstate > S_THUNDERSHIELD15 )
viewingangle + = ANGLE_180 ;
destx = mobj - > target - > x + P_ReturnThrustX ( mobj - > target , viewingangle , mobj - > scale > > 4 ) ;
desty = mobj - > target - > y + P_ReturnThrustY ( mobj - > target , viewingangle , mobj - > scale > > 4 ) ;
}
else
{
destx = mobj - > target - > x ;
desty = mobj - > target - > y ;
}
P_TeleportMove ( mobj , destx , desty , mobj - > target - > z ) ;
2018-08-04 19:48:31 +00:00
break ;
2018-09-13 18:01:36 +00:00
}
2018-06-16 04:00:46 +00:00
case MT_KARMAHITBOX :
2018-07-04 01:12:25 +00:00
if ( ! mobj - > target | | ! mobj - > target - > health | | ! mobj - > target - > player | | mobj - > target - > player - > spectator
2018-07-03 19:14:47 +00:00
| | ( G_RaceGametype ( ) | | mobj - > target - > player - > kartstuff [ k_bumper ] ) )
2018-06-16 04:00:46 +00:00
{
P_RemoveMobj ( mobj ) ;
return ;
}
P_TeleportMove ( mobj , mobj - > target - > x , mobj - > target - > y , mobj - > target - > z ) ;
2018-07-01 03:49:37 +00:00
mobj - > scalespeed = mobj - > target - > scalespeed ;
mobj - > destscale = mobj - > target - > destscale ;
P_SetScale ( mobj , mobj - > target - > scale ) ;
2018-06-16 04:00:46 +00:00
mobj - > color = mobj - > target - > color ;
2018-10-07 10:40:06 +00:00
mobj - > colorized = ( mobj - > target - > player - > kartstuff [ k_comebackmode ] ) ;
2018-06-16 04:00:46 +00:00
if ( mobj - > target - > player - > kartstuff [ k_comebacktimer ] > 0 )
{
if ( mobj - > state ! = & states [ mobj - > info - > spawnstate ] )
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
if ( mobj - > target - > player - > kartstuff [ k_comebacktimer ] < TICRATE & & ( leveltime & 1 ) )
mobj - > flags2 & = ~ MF2_DONTDRAW ;
else
mobj - > flags2 | = MF2_DONTDRAW ;
}
else
{
2018-10-07 10:40:06 +00:00
if ( ! mobj - > target - > player - > kartstuff [ k_comebackmode ]
2018-06-16 04:00:46 +00:00
& & mobj - > state ! = & states [ mobj - > info - > spawnstate ] )
P_SetMobjState ( mobj , mobj - > info - > spawnstate ) ;
else if ( mobj - > target - > player - > kartstuff [ k_comebackmode ] = = 1
& & mobj - > state ! = & states [ mobj - > info - > seestate ] )
P_SetMobjState ( mobj , mobj - > info - > seestate ) ;
2018-10-07 10:40:06 +00:00
else if ( mobj - > target - > player - > kartstuff [ k_comebackmode ] = = 2
& & mobj - > state ! = & states [ mobj - > info - > painstate ] )
P_SetMobjState ( mobj , mobj - > info - > painstate ) ;
2018-06-16 04:00:46 +00:00
if ( mobj - > target - > player - > powers [ pw_flashing ] & & ( leveltime & 1 ) )
mobj - > flags2 | = MF2_DONTDRAW ;
else
mobj - > flags2 & = ~ MF2_DONTDRAW ;
}
2018-06-18 04:42:53 +00:00
// Now for the wheels
{
2018-07-01 08:36:09 +00:00
const fixed_t rad = FixedMul ( mobjinfo [ MT_PLAYER ] . radius , mobj - > target - > scale ) ;
2018-06-18 04:42:53 +00:00
mobj_t * cur = mobj - > hnext ;
while ( cur & & ! P_MobjWasRemoved ( cur ) )
{
fixed_t offx = rad ;
fixed_t offy = rad ;
if ( cur - > lastlook = = 1 | | cur - > lastlook = = 3 )
offx * = - 1 ;
if ( cur - > lastlook = = 2 | | cur - > lastlook = = 3 )
offy * = - 1 ;
P_TeleportMove ( cur , mobj - > x + offx , mobj - > y + offy , mobj - > z ) ;
2018-07-01 03:49:37 +00:00
cur - > scalespeed = mobj - > target - > scalespeed ;
cur - > destscale = mobj - > target - > destscale ;
P_SetScale ( cur , mobj - > target - > scale ) ;
2018-06-18 04:42:53 +00:00
if ( mobj - > flags2 & MF2_DONTDRAW )
cur - > flags2 | = MF2_DONTDRAW ;
else
cur - > flags2 & = ~ MF2_DONTDRAW ;
cur = cur - > hnext ;
}
}
2018-06-16 04:00:46 +00:00
break ;
2018-09-13 21:42:34 +00:00
case MT_SIGN : // Kart's unique sign behavior
if ( mobj - > movecount )
{
if ( mobj - > z < = mobj - > movefactor )
{
2018-09-21 22:40:18 +00:00
P_SetMobjState ( mobj , S_SIGN_END ) ;
2018-09-21 23:44:14 +00:00
if ( mobj - > info - > attacksound )
S_StartSound ( mobj , mobj - > info - > attacksound ) ;
2018-09-22 23:03:38 +00:00
mobj - > flags | = MF_NOGRAVITY ; // ?
2018-09-13 21:42:34 +00:00
mobj - > flags & = ~ MF_NOCLIPHEIGHT ;
2018-09-22 23:03:38 +00:00
mobj - > z = mobj - > movefactor ;
2018-09-13 21:42:34 +00:00
mobj - > movecount = 0 ;
}
else
{
2018-09-22 23:00:30 +00:00
P_SpawnMobj ( mobj - > x + ( P_RandomRange ( - 48 , 48 ) < < FRACBITS ) ,
mobj - > y + ( P_RandomRange ( - 48 , 48 ) < < FRACBITS ) ,
mobj - > z + ( 24 < < FRACBITS ) + ( P_RandomRange ( - 8 , 8 ) < < FRACBITS ) ,
2018-09-22 23:55:26 +00:00
MT_SIGNSPARKLE ) ;
2018-09-13 21:42:34 +00:00
mobj - > flags & = ~ MF_NOGRAVITY ;
2018-09-21 23:44:14 +00:00
if ( abs ( mobj - > z - mobj - > movefactor ) < = 512 < < FRACBITS & & ! mobj - > cvmem )
{
if ( mobj - > info - > seesound )
S_StartSound ( mobj , mobj - > info - > seesound ) ;
mobj - > cvmem = 1 ;
}
2018-09-13 21:42:34 +00:00
}
}
break ;
2017-02-26 15:19:12 +00:00
//}
2014-03-15 16:59:03 +00:00
case MT_TURRET :
P_MobjCheckWater ( mobj ) ;
P_CheckPosition ( mobj , mobj - > x , mobj - > y ) ;
if ( P_MobjWasRemoved ( mobj ) )
return ;
mobj - > floorz = tmfloorz ;
mobj - > ceilingz = tmceilingz ;
if ( ( mobj - > eflags & MFE_UNDERWATER ) & & mobj - > health > 0 )
{
P_SetMobjState ( mobj , mobj - > info - > deathstate ) ;
mobj - > health = 0 ;
mobj - > flags2 & = ~ MF2_FIRING ;
}
else if ( mobj - > health > 0 & & mobj - > z + mobj - > height > mobj - > ceilingz ) // Crushed
{
INT32 i , j ;
fixed_t ns ;
fixed_t x , y , z ;
mobj_t * mo2 ;
z = mobj - > subsector - > sector - > floorheight + FixedMul ( 64 * FRACUNIT , mobj - > scale ) ;
for ( j = 0 ; j < 2 ; j + + )
{
for ( i = 0 ; i < 32 ; i + + )
{
const angle_t fa = ( i * FINEANGLES / 16 ) & FINEMASK ;
ns = FixedMul ( 64 * FRACUNIT , mobj - > scale ) ;
x = mobj - > x + FixedMul ( FINESINE ( fa ) , ns ) ;
y = mobj - > y + FixedMul ( FINECOSINE ( fa ) , ns ) ;
mo2 = P_SpawnMobj ( x , y , z , MT_EXPLODE ) ;
ns = FixedMul ( 16 * FRACUNIT , mobj - > scale ) ;
mo2 - > momx = FixedMul ( FINESINE ( fa ) , ns ) ;
mo2 - > momy = FixedMul ( FINECOSINE ( fa ) , ns ) ;
}
z - = FixedMul ( 32 * FRACUNIT , mobj - > scale ) ;
}
P_SetMobjState ( mobj , mobj - > info - > deathstate ) ;
mobj - > health = 0 ;
mobj - > flags2 & = ~ MF2_FIRING ;
}
break ;
case MT_BLUEFLAG :
case MT_REDFLAG :
{
sector_t * sec2 ;
sec2 = P_ThingOnSpecial3DFloor ( mobj ) ;
if ( ( sec2 & & GETSECSPECIAL ( sec2 - > special , 4 ) = = 2 ) | | ( GETSECSPECIAL ( mobj - > subsector - > sector - > special , 4 ) = = 2 ) )
mobj - > fuse = 1 ; // Return to base.
break ;
}
case MT_CANNONBALL :
# ifdef FLOORSPLATS
R_AddFloorSplat ( mobj - > tracer - > subsector , mobj - > tracer , " TARGET " , mobj - > tracer - > x ,
mobj - > tracer - > y , mobj - > tracer - > floorz , SPLATDRAWMODE_SHADE ) ;
# endif
break ;
case MT_SPINFIRE :
2018-02-05 23:55:52 +00:00
case MT_SNEAKERTRAIL :
2014-03-15 16:59:03 +00:00
if ( mobj - > eflags & MFE_VERTICALFLIP )
mobj - > z = mobj - > ceilingz - mobj - > height ;
else
2014-08-04 03:49:33 +00:00
mobj - > z = mobj - > floorz ;
2017-09-28 13:39:47 +00:00
/* FALLTHRU */
2014-03-15 16:59:03 +00:00
default :
// check mobj against possible water content, before movement code
P_MobjCheckWater ( mobj ) ;
// Extinguish fire objects in water
2018-06-25 21:12:01 +00:00
if ( mobj - > flags & MF_FIRE & & mobj - > type ! = MT_PUMA & & mobj - > type ! = MT_FIREBALL
2014-03-15 16:59:03 +00:00
& & ( mobj - > eflags & ( MFE_UNDERWATER | MFE_TOUCHWATER ) ) )
{
P_KillMobj ( mobj , NULL , NULL ) ;
return ;
}
break ;
}
if ( P_MobjWasRemoved ( mobj ) )
return ;
if ( mobj - > flags2 & MF2_FIRING & & mobj - > target & & mobj - > health > 0 )
{
2016-07-06 04:09:17 +00:00
if ( mobj - > state - > action . acp1 = = ( actionf_p1 ) A_Boss1Laser )
2014-03-15 16:59:03 +00:00
{
var1 = mobj - > state - > var1 ;
var2 = mobj - > state - > var2 ;
mobj - > state - > action . acp1 ( mobj ) ;
}
else if ( leveltime & 1 ) // Fire mode
{
mobj_t * missile ;
if ( mobj - > target - > player & & mobj - > target - > player - > nightstime )
{
fixed_t oldval = mobjinfo [ mobj - > extravalue1 ] . speed ;
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x + mobj - > target - > momx , mobj - > target - > y + mobj - > target - > momy ) ;
mobjinfo [ mobj - > extravalue1 ] . speed = FixedMul ( 60 * FRACUNIT , mobj - > scale ) ;
missile = P_SpawnMissile ( mobj , mobj - > target , mobj - > extravalue1 ) ;
mobjinfo [ mobj - > extravalue1 ] . speed = oldval ;
}
else
{
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x , mobj - > target - > y ) ;
missile = P_SpawnMissile ( mobj , mobj - > target , mobj - > extravalue1 ) ;
}
if ( missile )
{
if ( mobj - > flags2 & MF2_SUPERFIRE )
missile - > flags2 | = MF2_SUPERFIRE ;
if ( mobj - > info - > attacksound )
S_StartSound ( missile , mobj - > info - > attacksound ) ;
}
}
else
mobj - > angle = R_PointToAngle2 ( mobj - > x , mobj - > y , mobj - > target - > x , mobj - > target - > y ) ;
}
if ( mobj - > flags & MF_AMBIENT )
{
if ( ! ( leveltime % mobj - > health ) & & mobj - > info - > seesound )
S_StartSound ( mobj , mobj - > info - > seesound ) ;
return ;
}
// Check fuse
if ( mobj - > fuse )
{
mobj - > fuse - - ;
if ( ! mobj - > fuse )
{
subsector_t * ss ;
fixed_t x , y , z ;
mobj_t * flagmo , * newmobj ;
# ifdef HAVE_BLUA
if ( ! LUAh_MobjFuse ( mobj ) & & ! P_MobjWasRemoved ( mobj ) )
# endif
switch ( mobj - > type )
{
// gargoyle and snowman handled in P_PushableThinker, not here
case MT_THROWNGRENADE :
2014-03-23 16:00:29 +00:00
case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE :
2014-03-15 16:59:03 +00:00
P_SetMobjState ( mobj , mobj - > info - > deathstate ) ;
break ;
case MT_BLUEFLAG :
case MT_REDFLAG :
if ( mobj - > spawnpoint )
{
x = mobj - > spawnpoint - > x < < FRACBITS ;
y = mobj - > spawnpoint - > y < < FRACBITS ;
ss = R_PointInSubsector ( x , y ) ;
if ( mobj - > spawnpoint - > options & MTF_OBJECTFLIP )
{
z = ss - > sector - > ceilingheight - mobjinfo [ mobj - > type ] . height ;
2016-07-06 04:09:17 +00:00
if ( mobj - > spawnpoint - > options > > ZSHIFT )
z - = ( mobj - > spawnpoint - > options > > ZSHIFT ) < < FRACBITS ;
2014-03-15 16:59:03 +00:00
}
else
{
z = ss - > sector - > floorheight ;
2016-07-06 04:09:17 +00:00
if ( mobj - > spawnpoint - > options > > ZSHIFT )
z + = ( mobj - > spawnpoint - > options > > ZSHIFT ) < < FRACBITS ;
2014-03-15 16:59:03 +00:00
}
flagmo = P_SpawnMobj ( x , y , z , mobj - > type ) ;
flagmo - > spawnpoint = mobj - > spawnpoint ;
if ( mobj - > spawnpoint - > options & MTF_OBJECTFLIP )
2016-07-06 04:09:17 +00:00
{
flagmo - > eflags | = MFE_VERTICALFLIP ;
flagmo - > flags2 | = MF2_OBJECTFLIP ;
}
2014-03-15 16:59:03 +00:00
if ( mobj - > type = = MT_REDFLAG )
{
if ( ! ( mobj - > flags2 & MF2_JUSTATTACKED ) )
2016-07-06 04:09:17 +00:00
CONS_Printf ( M_GetText ( " The %c%s%c has returned to base. \n " ) , 0x85 , M_GetText ( " Red flag " ) , 0x80 ) ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
// Assumedly in splitscreen players will be on opposing teams
2017-12-19 01:59:04 +00:00
if ( players [ consoleplayer ] . ctfteam = = 1 | | splitscreen )
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_hoop1 ) ;
2014-03-25 02:17:59 +00:00
redflag = flagmo ;
2014-03-15 16:59:03 +00:00
}
else // MT_BLUEFLAG
{
if ( ! ( mobj - > flags2 & MF2_JUSTATTACKED ) )
2016-07-06 04:09:17 +00:00
CONS_Printf ( M_GetText ( " The %c%s%c has returned to base. \n " ) , 0x84 , M_GetText ( " Blue flag " ) , 0x80 ) ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
// Assumedly in splitscreen players will be on opposing teams
2017-12-19 01:59:04 +00:00
if ( players [ consoleplayer ] . ctfteam = = 2 | | splitscreen )
2014-03-15 16:59:03 +00:00
S_StartSound ( NULL , sfx_hoop1 ) ;
2014-03-25 02:17:59 +00:00
blueflag = flagmo ;
2014-03-15 16:59:03 +00:00
}
}
P_RemoveMobj ( mobj ) ;
return ;
case MT_YELLOWTV : // Ring shield box
case MT_BLUETV : // Force shield box
case MT_GREENTV : // Water shield box
case MT_BLACKTV : // Bomb shield box
case MT_WHITETV : // Jump shield box
case MT_SNEAKERTV : // Super Sneaker box
case MT_SUPERRINGBOX : // 10-Ring box
case MT_REDRINGBOX : // Red Team 10-Ring box
case MT_BLUERINGBOX : // Blue Team 10-Ring box
case MT_INV : // Invincibility box
case MT_MIXUPBOX : // Teleporter Mixup box
case MT_RECYCLETV : // Recycler box
case MT_SCORETVSMALL :
case MT_SCORETVLARGE :
case MT_PRUP : // 1up!
case MT_EGGMANBOX : // Eggman box
case MT_GRAVITYBOX : // Gravity box
case MT_QUESTIONBOX :
2016-08-22 21:54:30 +00:00
if ( ( mobj - > flags2 & MF2_AMBUSH | | mobj - > flags2 & MF2_STRONGBOX ) & & mobj - > type ! = MT_QUESTIONBOX )
2014-03-15 16:59:03 +00:00
{
mobjtype_t spawnchance [ 64 ] ;
2014-04-14 05:14:58 +00:00
INT32 numchoices = 0 , i = 0 ;
// This define should make it a lot easier to organize and change monitor weights
# define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \
for ( i = ( ( mobj - > flags2 & MF2_STRONGBOX ) ? strongboxamt : weakboxamt ) ; i ; - - i ) spawnchance [ numchoices + + ] = type
// Type SRM WRM
SETMONITORCHANCES ( MT_SNEAKERTV , 0 , 10 ) ; // Super Sneakers
SETMONITORCHANCES ( MT_INV , 2 , 0 ) ; // Invincibility
SETMONITORCHANCES ( MT_WHITETV , 3 , 8 ) ; // Whirlwind Shield
SETMONITORCHANCES ( MT_GREENTV , 3 , 8 ) ; // Elemental Shield
SETMONITORCHANCES ( MT_YELLOWTV , 2 , 0 ) ; // Attraction Shield
SETMONITORCHANCES ( MT_BLUETV , 3 , 3 ) ; // Force Shield
SETMONITORCHANCES ( MT_BLACKTV , 2 , 0 ) ; // Armageddon Shield
SETMONITORCHANCES ( MT_MIXUPBOX , 0 , 1 ) ; // Teleporters
SETMONITORCHANCES ( MT_RECYCLETV , 0 , 1 ) ; // Recycler
SETMONITORCHANCES ( MT_PRUP , 1 , 1 ) ; // 1-Up
// ======================================
// Total 16 32
# undef SETMONITORCHANCES
2014-03-15 16:59:03 +00:00
i = P_RandomKey ( numchoices ) ; // Gotta love those random numbers!
newmobj = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , spawnchance [ i ] ) ;
2016-08-22 21:54:30 +00:00
// Transfer flags2 (strongbox, objectflip, ambush)
2014-03-15 16:59:03 +00:00
newmobj - > flags2 = mobj - > flags2 ;
}
else
{
newmobj = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , mobj - > type ) ;
// Transfer flags2 (strongbox, objectflip)
newmobj - > flags2 = mobj - > flags2 ;
}
P_RemoveMobj ( mobj ) ; // make sure they disappear
return ;
2018-03-13 05:20:47 +00:00
case MT_RANDOMITEM :
2018-03-27 21:53:47 +00:00
if ( G_BattleGametype ( ) )
2018-03-13 05:20:47 +00:00
{
2018-08-06 17:37:03 +00:00
if ( mobj - > threshold ! = 69 )
break ;
2018-03-13 05:20:47 +00:00
}
else
2018-08-06 17:37:03 +00:00
{
// Respawn from mapthing if you have one!
if ( mobj - > spawnpoint )
{
P_SpawnMapThing ( mobj - > spawnpoint ) ;
newmobj = mobj - > spawnpoint - > mobj ; // this is set to the new mobj in P_SpawnMapThing
}
else
newmobj = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , mobj - > type ) ;
2018-03-13 05:20:47 +00:00
2018-08-06 17:37:03 +00:00
// Transfer flags2 (strongbox, objectflip)
2018-08-10 14:38:32 +00:00
newmobj - > flags2 = mobj - > flags2 & ~ MF2_DONTDRAW ;
2018-08-06 17:37:03 +00:00
}
2018-03-13 05:20:47 +00:00
P_RemoveMobj ( mobj ) ; // make sure they disappear
return ;
2014-03-15 16:59:03 +00:00
case MT_METALSONIC_BATTLE :
break ; // don't remove
case MT_SPIKE :
P_SetMobjState ( mobj , mobj - > state - > nextstate ) ;
mobj - > fuse = mobj - > info - > speed ;
if ( mobj - > spawnpoint )
mobj - > fuse + = mobj - > spawnpoint - > angle ;
break ;
case MT_NIGHTSCORE :
P_RemoveMobj ( mobj ) ;
return ;
2014-08-04 03:49:33 +00:00
case MT_PLAYER :
break ; // don't remove
2014-03-15 16:59:03 +00:00
default :
P_SetMobjState ( mobj , mobj - > info - > xdeathstate ) ; // will remove the mobj if S_NULL.
break ;
}
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
2018-10-07 10:40:06 +00:00
else if ( ( ( mobj - > type = = MT_RANDOMITEM & & mobj - > threshold = = 69 ) | | mobj - > type = = MT_FAKEITEM ) & & mobj - > fuse < = TICRATE )
2018-08-06 17:37:03 +00:00
mobj - > flags2 ^ = MF2_DONTDRAW ;
2014-03-15 16:59:03 +00:00
}
I_Assert ( mobj ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mobj ) ) ;
if ( mobj - > momx | | mobj - > momy | | ( mobj - > flags2 & MF2_SKULLFLY ) )
{
P_XYMovement ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
// always do the gravity bit now, that's simpler
// BUT CheckPosition only if wasn't done before.
if ( ! ( mobj - > eflags & MFE_ONGROUND ) | | mobj - > momz
| | ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + mobj - > height ! = mobj - > ceilingz )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z ! = mobj - > floorz )
2014-08-04 03:49:33 +00:00
| | P_IsObjectInGoop ( mobj ) )
2014-03-15 16:59:03 +00:00
{
if ( ! P_ZMovement ( mobj ) )
return ; // mobj was removed
P_CheckPosition ( mobj , mobj - > x , mobj - > y ) ; // Need this to pick up objects!
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
else
{
mobj - > pmomz = 0 ; // to prevent that weird rocketing gargoyle bug
mobj - > eflags & = ~ MFE_JUSTHITFLOOR ;
}
2016-07-06 04:09:17 +00:00
# ifdef ESLOPE // Sliding physics for slidey mobjs!
if ( mobj - > type = = MT_FLINGRING
| | mobj - > type = = MT_FLINGCOIN
| | P_WeaponOrPanel ( mobj - > type )
| | mobj - > type = = MT_FLINGEMERALD
| | mobj - > type = = MT_BIGTUMBLEWEED
| | mobj - > type = = MT_LITTLETUMBLEWEED
| | mobj - > type = = MT_CANNONBALLDECOR
| | mobj - > type = = MT_FALLINGROCK ) {
P_TryMove ( mobj , mobj - > x , mobj - > y , true ) ; // Sets mo->standingslope correctly
//if (mobj->standingslope) CONS_Printf("slope physics on mobj\n");
P_ButteredSlope ( mobj ) ;
}
# endif
2014-03-15 16:59:03 +00:00
if ( mobj - > flags & ( MF_ENEMY | MF_BOSS ) & & mobj - > health
& & P_CheckDeathPitCollide ( mobj ) ) // extra pit check in case these didn't have momz
{
P_KillMobj ( mobj , NULL , NULL ) ;
return ;
}
// Crush enemies!
if ( mobj - > ceilingz - mobj - > floorz < mobj - > height )
{
if ( (
( mobj - > flags & ( MF_ENEMY | MF_BOSS )
& & mobj - > flags & MF_SHOOTABLE )
| | mobj - > type = = MT_EGGSHIELD )
& & ! ( mobj - > flags & MF_NOCLIPHEIGHT )
& & mobj - > health > 0 )
{
P_KillMobj ( mobj , NULL , NULL ) ;
return ;
}
}
// Can end up here if a player dies.
if ( mobj - > player )
P_CyclePlayerMobjState ( mobj ) ;
else
P_CycleMobjState ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) )
return ;
switch ( mobj - > type )
{
case MT_BOUNCEPICKUP :
case MT_RAILPICKUP :
case MT_AUTOPICKUP :
case MT_EXPLODEPICKUP :
case MT_SCATTERPICKUP :
case MT_GRENADEPICKUP :
if ( mobj - > health = = 0 ) // Fading tile
{
INT32 value = mobj - > info - > damage / 10 ;
value = mobj - > fuse / value ;
value = 10 - value ;
value - - ;
if ( value < = 0 )
value = 1 ;
mobj - > frame & = ~ FF_TRANSMASK ;
mobj - > frame | = value < < FF_TRANSSHIFT ;
}
break ;
default :
break ;
}
}
// Quick, optimized function for the Rail Rings
// Returns true if move failed or mobj was removed by movement (death pit, missile hits wall, etc.)
boolean P_RailThinker ( mobj_t * mobj )
{
fixed_t x , y , z ;
I_Assert ( mobj ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mobj ) ) ;
x = mobj - > x , y = mobj - > y , z = mobj - > z ;
if ( mobj - > momx | | mobj - > momy )
{
P_XYMovement ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) )
return true ;
}
if ( mobj - > momz )
{
if ( ! P_ZMovement ( mobj ) )
return true ; // mobj was removed
//P_CheckPosition(mobj, mobj->x, mobj->y);
}
return P_MobjWasRemoved ( mobj ) | | ( x = = mobj - > x & & y = = mobj - > y & & z = = mobj - > z ) ;
}
// Unquick, unoptimized function for pushables
void P_PushableThinker ( mobj_t * mobj )
{
sector_t * sec ;
I_Assert ( mobj ! = NULL ) ;
I_Assert ( ! P_MobjWasRemoved ( mobj ) ) ;
sec = mobj - > subsector - > sector ;
if ( GETSECSPECIAL ( sec - > special , 2 ) = = 1 & & mobj - > z = = sec - > floorheight )
P_LinedefExecute ( sec - > tag , mobj , sec ) ;
// else if (GETSECSPECIAL(sec->special, 2) == 8)
{
sector_t * sec2 ;
sec2 = P_ThingOnSpecial3DFloor ( mobj ) ;
if ( sec2 & & GETSECSPECIAL ( sec2 - > special , 2 ) = = 1 )
P_LinedefExecute ( sec2 - > tag , mobj , sec2 ) ;
}
// it has to be pushable RIGHT NOW for this part to happen
if ( mobj - > flags & MF_PUSHABLE & & ! ( mobj - > momx | | mobj - > momy ) )
P_TryMove ( mobj , mobj - > x , mobj - > y , true ) ;
if ( mobj - > fuse = = 1 ) // it would explode in the MobjThinker code
{
mobj_t * spawnmo ;
fixed_t x , y , z ;
subsector_t * ss ;
// Left here just in case we'd
// want to make pushable bombs
// or something in the future.
switch ( mobj - > type )
{
case MT_SNOWMAN :
case MT_GARGOYLE :
x = mobj - > spawnpoint - > x < < FRACBITS ;
y = mobj - > spawnpoint - > y < < FRACBITS ;
ss = R_PointInSubsector ( x , y ) ;
if ( mobj - > spawnpoint - > z ! = 0 )
z = mobj - > spawnpoint - > z < < FRACBITS ;
else
z = ss - > sector - > floorheight ;
spawnmo = P_SpawnMobj ( x , y , z , mobj - > type ) ;
spawnmo - > spawnpoint = mobj - > spawnpoint ;
P_UnsetThingPosition ( spawnmo ) ;
spawnmo - > flags = mobj - > flags ;
P_SetThingPosition ( spawnmo ) ;
spawnmo - > flags2 = mobj - > flags2 ;
spawnmo - > flags | = MF_PUSHABLE ;
P_RemoveMobj ( mobj ) ;
break ;
default :
break ;
}
}
}
// Quick, optimized function for scenery
void P_SceneryThinker ( mobj_t * mobj )
{
if ( mobj - > flags & MF_BOXICON )
{
if ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) )
{
if ( mobj - > z < mobj - > floorz + FixedMul ( mobj - > info - > damage , mobj - > scale ) )
mobj - > momz = FixedMul ( mobj - > info - > speed , mobj - > scale ) ;
else
mobj - > momz = 0 ;
}
else
{
if ( mobj - > z + FixedMul ( mobj - > info - > height , mobj - > scale ) > mobj - > ceilingz - FixedMul ( mobj - > info - > damage , mobj - > scale ) )
mobj - > momz = - FixedMul ( mobj - > info - > speed , mobj - > scale ) ;
else
mobj - > momz = 0 ;
}
}
// momentum movement
if ( mobj - > momx | | mobj - > momy )
{
P_SceneryXYMovement ( mobj ) ;
if ( P_MobjWasRemoved ( mobj ) )
return ;
}
// always do the gravity bit now, that's simpler
// BUT CheckPosition only if wasn't done before.
if ( ! ( mobj - > eflags & MFE_ONGROUND ) | | mobj - > momz
| | ( ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z + mobj - > height ! = mobj - > ceilingz )
| | ( ! ( mobj - > eflags & MFE_VERTICALFLIP ) & & mobj - > z ! = mobj - > floorz )
2014-08-04 03:49:33 +00:00
| | P_IsObjectInGoop ( mobj ) )
2014-03-15 16:59:03 +00:00
{
if ( ! P_SceneryZMovement ( mobj ) )
return ; // mobj was removed
P_CheckPosition ( mobj , mobj - > x , mobj - > y ) ; // Need this to pick up objects!
if ( P_MobjWasRemoved ( mobj ) )
return ;
mobj - > floorz = tmfloorz ;
mobj - > ceilingz = tmceilingz ;
}
else
{
mobj - > pmomz = 0 ; // to prevent that weird rocketing gargoyle bug
mobj - > eflags & = ~ MFE_JUSTHITFLOOR ;
}
P_CycleMobjState ( mobj ) ;
2018-09-12 18:03:45 +00:00
if ( mobj - > type ! = MT_RANDOMAUDIENCE )
return ;
{
if ( ! mobj - > colorized ) // a fan of someone?
return ;
if ( mobj - > threshold > = 0 ) // not already happy or sad?
{
if ( ! playeringame [ mobj - > threshold ] | | players [ mobj - > threshold ] . spectator ) // focused on a valid player?
return ;
if ( ! ( players [ mobj - > threshold ] . exiting ) & & ! ( players [ mobj - > threshold ] . pflags & PF_TIMEOVER ) ) // not finished yet?
return ;
if ( K_IsPlayerLosing ( & players [ mobj - > threshold ] ) )
mobj - > threshold = - 2 ;
else
{
mobj - > threshold = - 1 ;
S_StartSound ( mobj , sfx_chaooo ) ;
}
}
if ( mobj - > threshold = = - 1 )
mobj - > angle + = ANGLE_22h ;
if ( ( ( statenum_t ) ( mobj - > state - states ) ! = S_AUDIENCE_CHAO_CHEER2 ) | | ( mobj - > tics ! = states [ S_AUDIENCE_CHAO_CHEER2 ] . tics ) ) // not at the start of your cheer jump?
return ;
2018-09-13 13:40:50 +00:00
mobj - > momz = 0 ;
2018-09-12 18:03:45 +00:00
P_SetMobjState ( mobj , ( ( mobj - > threshold = = - 1 ) ? S_AUDIENCE_CHAO_WIN2 : S_AUDIENCE_CHAO_LOSE ) ) ;
}
2014-03-15 16:59:03 +00:00
}
//
// GAME SPAWN FUNCTIONS
//
//
// P_SpawnMobj
//
mobj_t * P_SpawnMobj ( fixed_t x , fixed_t y , fixed_t z , mobjtype_t type )
{
const mobjinfo_t * info = & mobjinfo [ type ] ;
state_t * st ;
mobj_t * mobj = Z_Calloc ( sizeof ( * mobj ) , PU_LEVEL , NULL ) ;
// this is officially a mobj, declared as soon as possible.
mobj - > thinker . function . acp1 = ( actionf_p1 ) P_MobjThinker ;
mobj - > type = type ;
mobj - > info = info ;
mobj - > x = x ;
mobj - > y = y ;
mobj - > radius = info - > radius ;
mobj - > height = info - > height ;
mobj - > flags = info - > flags ;
mobj - > health = info - > spawnhealth ;
mobj - > reactiontime = info - > reactiontime ;
mobj - > lastlook = - 1 ; // stuff moved in P_enemy.P_LookForPlayer
// do not set the state with P_SetMobjState,
// because action routines can not be called yet
st = & states [ info - > spawnstate ] ;
mobj - > state = st ;
mobj - > tics = st - > tics ;
mobj - > sprite = st - > sprite ;
mobj - > frame = st - > frame ; // FF_FRAMEMASK for frame, and other bits..
2016-07-06 04:09:17 +00:00
mobj - > anim_duration = ( UINT16 ) st - > var2 ; // only used if FF_ANIMATE is set
2014-03-15 16:59:03 +00:00
mobj - > friction = ORIG_FRICTION ;
2016-08-24 01:03:58 +00:00
mobj - > movefactor = FRACUNIT ; //mobj->movefactor = ORIG_FRICTION_FACTOR;
2014-03-15 16:59:03 +00:00
// All mobjs are created at 100% scale.
mobj - > scale = FRACUNIT ;
mobj - > destscale = mobj - > scale ;
mobj - > scalespeed = FRACUNIT / 12 ;
2017-12-16 20:38:15 +00:00
if ( mapheaderinfo [ gamemap - 1 ] & & mapheaderinfo [ gamemap - 1 ] - > mobj_scale ! = FRACUNIT ) //&& !(mobj->type == MT_BLACKEGGMAN)
mobj - > destscale = mapheaderinfo [ gamemap - 1 ] - > mobj_scale ;
2014-03-15 16:59:03 +00:00
// set subsector and/or block links
P_SetThingPosition ( mobj ) ;
I_Assert ( mobj - > subsector ! = NULL ) ;
// Make sure scale matches destscale immediately when spawned
P_SetScale ( mobj , mobj - > destscale ) ;
2016-07-06 04:09:17 +00:00
mobj - > floorz =
# ifdef ESLOPE
mobj - > subsector - > sector - > f_slope ? P_GetZAt ( mobj - > subsector - > sector - > f_slope , x , y ) :
# endif
mobj - > subsector - > sector - > floorheight ;
mobj - > ceilingz =
# ifdef ESLOPE
mobj - > subsector - > sector - > c_slope ? P_GetZAt ( mobj - > subsector - > sector - > c_slope , x , y ) :
# endif
mobj - > subsector - > sector - > ceilingheight ;
2014-03-15 16:59:03 +00:00
// Tells MobjCheckWater that the water height was not set.
mobj - > watertop = INT32_MAX ;
if ( z = = ONFLOORZ )
{
mobj - > z = mobj - > floorz ;
if ( mobj - > type = = MT_UNIDUS )
mobj - > z + = FixedMul ( mobj - > info - > mass , mobj - > scale ) ;
// defaults onground
if ( mobj - > z = = mobj - > floorz )
mobj - > eflags | = MFE_ONGROUND ;
}
else if ( z = = ONCEILINGZ )
{
mobj - > z = mobj - > ceilingz - mobj - > height ;
if ( mobj - > type = = MT_UNIDUS )
mobj - > z - = FixedMul ( mobj - > info - > mass , mobj - > scale ) ;
2016-12-05 22:07:16 +00:00
// defaults onground
if ( mobj - > z + mobj - > height = = mobj - > ceilingz )
mobj - > eflags | = MFE_ONGROUND ;
2014-03-15 16:59:03 +00:00
}
else
mobj - > z = z ;
2018-02-05 00:00:36 +00:00
mobj - > colorized = false ;
2014-03-15 16:59:03 +00:00
# ifdef HAVE_BLUA
2014-08-04 03:49:33 +00:00
// DANGER! This can cause P_SpawnMobj to return NULL!
// Avoid using P_RemoveMobj on the newly created mobj in "MobjSpawn" Lua hooks!
if ( LUAh_MobjSpawn ( mobj ) )
{
if ( P_MobjWasRemoved ( mobj ) )
return NULL ;
}
else if ( P_MobjWasRemoved ( mobj ) )
return NULL ;
else
2014-03-15 16:59:03 +00:00
# endif
switch ( mobj - > type )
{
2014-03-23 16:00:29 +00:00
case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE :
mobj - > fuse = mobj - > info - > mass ;
2014-08-04 03:49:33 +00:00
break ;
2014-03-15 16:59:03 +00:00
case MT_BLACKEGGMAN :
{
mobj_t * spawn = P_SpawnMobj ( mobj - > x , mobj - > z , mobj - > z + mobj - > height - 16 * FRACUNIT , MT_BLACKEGGMAN_HELPER ) ;
spawn - > destscale = mobj - > scale ;
P_SetScale ( spawn , mobj - > scale ) ;
P_SetTarget ( & spawn - > target , mobj ) ;
}
break ;
case MT_BLACKEGGMAN_HELPER :
// Collision helper can be stood on but not pushed
mobj - > flags2 | = MF2_STANDONME ;
break ;
case MT_SPIKE :
mobj - > flags2 | = MF2_STANDONME ;
break ;
case MT_DETON :
mobj - > movedir = 0 ;
break ;
case MT_EGGGUARD :
{
mobj_t * spawn = P_SpawnMobj ( x , y , z , MT_EGGSHIELD ) ;
spawn - > destscale = mobj - > scale ;
P_SetScale ( spawn , mobj - > scale ) ;
P_SetTarget ( & mobj - > tracer , spawn ) ;
P_SetTarget ( & spawn - > target , mobj ) ;
}
break ;
case MT_UNIDUS :
{
INT32 i ;
mobj_t * ball ;
// Spawn "damage" number of "painchance" spikeball mobjs
// threshold is the distance they should keep from the MT_UNIDUS (touching radius + ball painchance)
for ( i = 0 ; i < mobj - > info - > damage ; i + + )
{
ball = P_SpawnMobj ( x , y , z , mobj - > info - > painchance ) ;
ball - > destscale = mobj - > scale ;
P_SetScale ( ball , mobj - > scale ) ;
P_SetTarget ( & ball - > target , mobj ) ;
ball - > movedir = FixedAngle ( FixedMul ( FixedDiv ( i < < FRACBITS , mobj - > info - > damage < < FRACBITS ) , 360 < < FRACBITS ) ) ;
ball - > threshold = ball - > radius + mobj - > radius + FixedMul ( ball - > info - > painchance , ball - > scale ) ;
var1 = ball - > state - > var1 , var2 = ball - > state - > var2 ;
ball - > state - > action . acp1 ( ball ) ;
}
break ;
}
case MT_POINTY :
{
INT32 q ;
mobj_t * ball , * lastball = mobj ;
for ( q = 0 ; q < mobj - > info - > painchance ; q + + )
{
ball = P_SpawnMobj ( x , y , z , mobj - > info - > mass ) ;
ball - > destscale = mobj - > scale ;
P_SetScale ( ball , mobj - > scale ) ;
P_SetTarget ( & lastball - > tracer , ball ) ;
P_SetTarget ( & ball - > target , mobj ) ;
lastball = ball ;
}
break ;
}
case MT_EGGMOBILE2 :
// Special condition for the 2nd boss.
mobj - > watertop = mobj - > info - > speed ;
break ;
case MT_BIRD :
case MT_BUNNY :
case MT_MOUSE :
case MT_CHICKEN :
case MT_COW :
case MT_REDBIRD :
mobj - > fuse = P_RandomRange ( 300 , 350 ) ;
break ;
case MT_REDRING : // Make MT_REDRING red by default
mobj - > color = skincolor_redring ;
break ;
case MT_SMALLBUBBLE : // Bubbles eventually dissipate, in case they get caught somewhere.
case MT_MEDIUMBUBBLE :
case MT_EXTRALARGEBUBBLE :
mobj - > fuse + = 30 * TICRATE ;
break ;
case MT_EGGCAPSULE :
mobj - > extravalue1 = - 1 ; // timer for how long a player has been at the capsule
2017-05-25 17:40:48 +00:00
break ;
2014-03-15 16:59:03 +00:00
case MT_REDTEAMRING :
mobj - > color = skincolor_redteam ;
break ;
case MT_BLUETEAMRING :
mobj - > color = skincolor_blueteam ;
break ;
case MT_RING :
case MT_COIN :
case MT_BLUEBALL :
nummaprings + + ;
2017-10-24 21:04:22 +00:00
break ;
2018-06-18 04:42:53 +00:00
case MT_KARMAHITBOX : // SRB2Kart
{
2018-07-01 18:11:48 +00:00
const fixed_t rad = FixedMul ( mobjinfo [ MT_PLAYER ] . radius , mobj - > scale ) ;
2018-06-18 04:42:53 +00:00
mobj_t * cur , * prev = mobj ;
INT32 i ;
for ( i = 0 ; i < 4 ; i + + )
{
fixed_t offx = rad ;
fixed_t offy = rad ;
if ( i = = 1 | | i = = 3 )
offx * = - 1 ;
if ( i = = 2 | | i = = 3 )
offy * = - 1 ;
cur = P_SpawnMobj ( mobj - > x + offx , mobj - > y + offy , mobj - > z , MT_KARMAWHEEL ) ;
cur - > destscale = mobj - > scale ;
P_SetScale ( cur , mobj - > scale ) ;
cur - > lastlook = i ;
P_SetTarget ( & cur - > hprev , prev ) ;
P_SetTarget ( & prev - > hnext , cur ) ;
prev = cur ;
}
}
break ;
2018-06-28 23:07:12 +00:00
case MT_BIGRING :
2018-09-12 18:03:45 +00:00
P_SetScale ( mobj , ( mobj - > destscale = 3 * FRACUNIT ) ) ;
break ;
case MT_RANDOMAUDIENCE :
{
fixed_t randu = P_RandomFixed ( ) ;
P_SetScale ( mobj , ( mobj - > destscale < < = 1 ) ) ;
if ( randu < ( FRACUNIT / 9 ) ) // a fan of someone?
{
UINT8 i , pcount = 0 ;
UINT8 pnum [ MAXPLAYERS ] ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
pnum [ pcount ] = i ;
pcount + + ;
}
if ( pcount )
{
mobj - > threshold = pnum [ P_RandomKey ( pcount ) ] ;
mobj - > color = players [ mobj - > threshold ] . skincolor ;
mobj - > colorized = true ;
break ;
}
}
if ( randu > ( FRACUNIT / 2 ) )
{
mobj - > color = P_RandomKey ( MAXSKINCOLORS - 1 ) + 1 ;
break ;
}
mobj - > color = SKINCOLOR_AQUA ;
2018-06-28 23:07:12 +00:00
break ;
2018-09-12 18:03:45 +00:00
}
2014-03-15 16:59:03 +00:00
default :
break ;
}
2017-10-13 19:41:36 +00:00
switch ( mobj - > type )
{
case MT_PLAYER :
2018-06-01 00:51:05 +00:00
case MT_BIGMACE : case MT_SMALLMACE :
2017-12-28 23:37:25 +00:00
case MT_FALLINGROCK :
2017-10-13 19:41:36 +00:00
//case MT_RANDOMITEM:
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
case MT_FLOATINGITEM :
2018-07-03 19:14:47 +00:00
case MT_BATTLEBUMPER :
2018-06-01 00:51:05 +00:00
case MT_BANANA : case MT_BANANA_SHIELD :
2018-07-23 00:55:18 +00:00
//case MT_FAKEITEM: case MT_FAKESHIELD:
case MT_ORBINAUT : case MT_ORBINAUT_SHIELD :
2018-06-01 00:51:05 +00:00
case MT_JAWZ : case MT_JAWZ_DUD : case MT_JAWZ_SHIELD :
case MT_SSMINE : case MT_SSMINE_SHIELD :
2018-06-25 21:12:01 +00:00
case MT_BALLHOG : case MT_SINK :
2018-10-18 08:43:50 +00:00
case MT_THUNDERSHIELD : case MT_SPB :
2017-10-13 19:41:36 +00:00
P_SpawnShadowMobj ( mobj ) ;
default :
break ;
}
2017-10-12 01:54:35 +00:00
2014-03-15 16:59:03 +00:00
if ( ! ( mobj - > flags & MF_NOTHINK ) )
P_AddThinker ( & mobj - > thinker ) ;
// Call action functions when the state is set
if ( st - > action . acp1 & & ( mobj - > flags & MF_RUNSPAWNFUNC ) )
{
if ( levelloading )
{
// Cache actions in a linked list
// with function pointer, and
// var1 & var2, which will be executed
// when the level finishes loading.
P_AddCachedAction ( mobj , mobj - > info - > spawnstate ) ;
}
else
{
var1 = st - > var1 ;
var2 = st - > var2 ;
# ifdef HAVE_BLUA
astate = st ;
# endif
st - > action . acp1 ( mobj ) ;
2014-08-04 03:49:33 +00:00
// DANGER! This can cause P_SpawnMobj to return NULL!
2014-03-18 17:56:54 +00:00
// Avoid using MF_RUNSPAWNFUNC on mobjs whose spawn state expects target or tracer to already be set!
if ( P_MobjWasRemoved ( mobj ) )
return NULL ;
2014-03-15 16:59:03 +00:00
}
}
if ( CheckForReverseGravity & & ! ( mobj - > flags & MF_NOBLOCKMAP ) )
P_CheckGravity ( mobj , false ) ;
return mobj ;
}
2017-10-12 01:54:35 +00:00
//
// P_SpawnShadowMobj
// warning: Do not send a shadow mobj as a caster into here, or try to spawn spawn shadows for shadows in P_SpawnMobj, we do not want recursive shadows
//
mobj_t * P_SpawnShadowMobj ( mobj_t * caster )
{
const mobjinfo_t * info = & mobjinfo [ MT_SHADOW ] ;
state_t * st ;
mobj_t * mobj = Z_Calloc ( sizeof ( * mobj ) , PU_LEVEL , NULL ) ;
// this is officially a mobj, declared as soon as possible.
mobj - > thinker . function . acp1 = ( actionf_p1 ) P_MobjThinker ;
mobj - > type = MT_SHADOW ;
mobj - > info = info ;
mobj - > x = caster - > x ;
mobj - > y = caster - > y ;
mobj - > radius = info - > radius ;
mobj - > height = info - > height ;
mobj - > flags = info - > flags ;
mobj - > health = info - > spawnhealth ;
mobj - > reactiontime = info - > reactiontime ;
mobj - > lastlook = - 1 ; // stuff moved in P_enemy.P_LookForPlayer
// do not set the state with P_SetMobjState,
// because action routines can not be called yet
if ( caster - > frame & FF_FULLBRIGHT )
st = & states [ S_WHITESHADOW ] ;
else
st = & states [ info - > spawnstate ] ;
mobj - > state = st ;
mobj - > tics = st - > tics ;
mobj - > sprite = st - > sprite ;
mobj - > frame = st - > frame ; // FF_FRAMEMASK for frame, and other bits..
mobj - > friction = ORIG_FRICTION ;
mobj - > movefactor = ORIG_FRICTION_FACTOR ;
// All mobjs are created at 100% scale.
mobj - > scale = FRACUNIT ;
mobj - > destscale = mobj - > scale ;
mobj - > scalespeed = FRACUNIT / 12 ;
2017-12-16 20:38:15 +00:00
if ( mapheaderinfo [ gamemap - 1 ] & & mapheaderinfo [ gamemap - 1 ] - > mobj_scale ! = FRACUNIT ) //&& !(mobj->type == MT_BLACKEGGMAN)
mobj - > destscale = mapheaderinfo [ gamemap - 1 ] - > mobj_scale ;
2017-10-12 01:54:35 +00:00
Dropping items!
* Shield Drop...
* Whatever you've got orbiting or trailing you, DROP THEM WHERE THEY STAND. (Except for the ghost sink. That one's OK.)
* Pops your Thunder Shield.
* Happens upon ANY hit, except for deathpits.
* HUD Drop...
* Also does the above, except for the Thunder Shield thing.
* If there's any item left in your item box, pop it out as a little hovering, rotating Minecraft item!
* You can pick up the Minecraft item by driving over it if your item box is sufficiently empty, or the item which is contained within it is of the same type.
* Happens upon Size Down and battle elimination.
* Can also be forced on with `cv_kartdebughuddrop on`!
* Some other random stuff.
* Fix a bunch of `a->scale = b`'s into `P_SetScale(a, b)` form, for maximum validity.
* Make K_CleanHnextList and K_UpdateHnextList one function, since they only differed by one continue clause (and the type of their input parameter).
* Allow shrunken players to pick up item boxes again.
* Fix MF_NOCLIPTHING. (Gonna pass this fix to vanilla when I get the chance, too.)
* Break NiGHTS a little through my machinations.
2018-09-06 21:17:29 +00:00
P_SetScale ( mobj , mobj - > destscale ) ;
2017-10-12 01:54:35 +00:00
// set subsector and/or block links
P_SetThingPosition ( mobj ) ;
I_Assert ( mobj - > subsector ! = NULL ) ;
// Make sure scale matches destscale immediately when spawned
P_SetScale ( mobj , mobj - > destscale ) ;
mobj - > floorz = mobj - > subsector - > sector - > floorheight ;
mobj - > ceilingz = mobj - > subsector - > sector - > ceilingheight ;
// Tells MobjCheckWater that the water height was not set.
mobj - > watertop = INT32_MAX ;
mobj - > z = mobj - > floorz ;
// defaults onground
if ( mobj - > z = = mobj - > floorz )
mobj - > eflags | = MFE_ONGROUND ;
if ( ! ( mobj - > flags & MF_NOTHINK ) )
P_AddThinker ( & mobj - > thinker ) ;
// Call action functions when the state is set
if ( st - > action . acp1 & & ( mobj - > flags & MF_RUNSPAWNFUNC ) )
{
if ( levelloading )
{
// Cache actions in a linked list
// with function pointer, and
// var1 & var2, which will be executed
// when the level finishes loading.
P_AddCachedAction ( mobj , mobj - > info - > spawnstate ) ;
}
else
{
var1 = st - > var1 ;
var2 = st - > var2 ;
# ifdef HAVE_BLUA
astate = st ;
# endif
st - > action . acp1 ( mobj ) ;
// DANGER! This is the ONLY way for P_SpawnMobj to return NULL!
// Avoid using MF_RUNSPAWNFUNC on mobjs whose spawn state expects target or tracer to already be set!
if ( P_MobjWasRemoved ( mobj ) )
return NULL ;
}
}
if ( CheckForReverseGravity & & ! ( mobj - > flags & MF_NOBLOCKMAP ) )
P_CheckGravity ( mobj , false ) ;
P_SetTarget ( & mobj - > target , caster ) ; // set the shadow's caster as the target
return mobj ;
}
2014-03-15 16:59:03 +00:00
static precipmobj_t * P_SpawnPrecipMobj ( fixed_t x , fixed_t y , fixed_t z , mobjtype_t type )
{
state_t * st ;
precipmobj_t * mobj = Z_Calloc ( sizeof ( * mobj ) , PU_LEVEL , NULL ) ;
2016-07-06 04:09:17 +00:00
fixed_t starting_floorz ;
2014-03-15 16:59:03 +00:00
mobj - > x = x ;
mobj - > y = y ;
mobj - > flags = mobjinfo [ type ] . flags ;
// do not set the state with P_SetMobjState,
// because action routines can not be called yet
st = & states [ mobjinfo [ type ] . spawnstate ] ;
mobj - > state = st ;
mobj - > tics = st - > tics ;
mobj - > sprite = st - > sprite ;
mobj - > frame = st - > frame ; // FF_FRAMEMASK for frame, and other bits..
2016-07-06 04:09:17 +00:00
mobj - > anim_duration = ( UINT16 ) st - > var2 ; // only used if FF_ANIMATE is set
2014-03-15 16:59:03 +00:00
// set subsector and/or block links
P_SetPrecipitationThingPosition ( mobj ) ;
2016-07-06 04:09:17 +00:00
mobj - > floorz = starting_floorz =
# ifdef ESLOPE
mobj - > subsector - > sector - > f_slope ? P_GetZAt ( mobj - > subsector - > sector - > f_slope , x , y ) :
# endif
mobj - > subsector - > sector - > floorheight ;
mobj - > ceilingz =
# ifdef ESLOPE
mobj - > subsector - > sector - > c_slope ? P_GetZAt ( mobj - > subsector - > sector - > c_slope , x , y ) :
# endif
mobj - > subsector - > sector - > ceilingheight ;
2014-03-15 16:59:03 +00:00
mobj - > z = z ;
mobj - > momz = mobjinfo [ type ] . speed ;
mobj - > thinker . function . acp1 = ( actionf_p1 ) P_NullPrecipThinker ;
P_AddThinker ( & mobj - > thinker ) ;
CalculatePrecipFloor ( mobj ) ;
2016-07-06 04:09:17 +00:00
if ( mobj - > floorz ! = starting_floorz )
2014-03-15 16:59:03 +00:00
mobj - > precipflags | = PCF_FOF ;
else if ( GETSECSPECIAL ( mobj - > subsector - > sector - > special , 1 ) = = 7
| | GETSECSPECIAL ( mobj - > subsector - > sector - > special , 1 ) = = 6
| | mobj - > subsector - > sector - > floorpic = = skyflatnum )
mobj - > precipflags | = PCF_PIT ;
return mobj ;
}
static inline precipmobj_t * P_SpawnRainMobj ( fixed_t x , fixed_t y , fixed_t z , mobjtype_t type )
{
precipmobj_t * mo = P_SpawnPrecipMobj ( x , y , z , type ) ;
2018-10-07 14:00:58 +00:00
mo - > precipflags | = PCF_RAIN ;
//mo->thinker.function.acp1 = (actionf_p1)P_RainThinker;
2014-03-15 16:59:03 +00:00
return mo ;
}
static inline precipmobj_t * P_SpawnSnowMobj ( fixed_t x , fixed_t y , fixed_t z , mobjtype_t type )
{
precipmobj_t * mo = P_SpawnPrecipMobj ( x , y , z , type ) ;
2018-10-07 14:00:58 +00:00
//mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker;
2014-03-15 16:59:03 +00:00
return mo ;
}
//
// P_RemoveMobj
//
mapthing_t * itemrespawnque [ ITEMQUESIZE ] ;
tic_t itemrespawntime [ ITEMQUESIZE ] ;
size_t iquehead , iquetail ;
# ifdef PARANOIA
# define SCRAMBLE_REMOVED // Force debug build to crash when Removed mobj is accessed
# endif
void P_RemoveMobj ( mobj_t * mobj )
{
I_Assert ( mobj ! = NULL ) ;
# ifdef HAVE_BLUA
if ( P_MobjWasRemoved ( mobj ) )
return ; // something already removing this mobj.
mobj - > thinker . function . acp1 = ( actionf_p1 ) P_RemoveThinkerDelayed ; // shh. no recursing.
LUAh_MobjRemoved ( mobj ) ;
mobj - > thinker . function . acp1 = ( actionf_p1 ) P_MobjThinker ; // needed for P_UnsetThingPosition, etc. to work.
# else
I_Assert ( ! P_MobjWasRemoved ( mobj ) ) ;
# endif
// Rings only, please!
if ( mobj - > spawnpoint & &
( mobj - > type = = MT_RING
| | mobj - > type = = MT_COIN
| | mobj - > type = = MT_BLUEBALL
| | mobj - > type = = MT_REDTEAMRING
| | mobj - > type = = MT_BLUETEAMRING
| | P_WeaponOrPanel ( mobj - > type ) )
& & ! ( mobj - > flags2 & MF2_DONTRESPAWN ) )
{
itemrespawnque [ iquehead ] = mobj - > spawnpoint ;
itemrespawntime [ iquehead ] = leveltime ;
iquehead = ( iquehead + 1 ) & ( ITEMQUESIZE - 1 ) ;
// lose one off the end?
if ( iquehead = = iquetail )
iquetail = ( iquetail + 1 ) & ( ITEMQUESIZE - 1 ) ;
}
2018-06-25 13:18:30 +00:00
if ( mobj - > type = = MT_KARMAHITBOX ) // Remove linked list objects for certain types
2018-06-25 11:41:49 +00:00
{
mobj_t * cur = mobj - > hnext ;
while ( cur & & ! P_MobjWasRemoved ( cur ) )
{
mobj_t * prev = cur ; // Kind of a dumb var, but we need to set cur before we remove the mobj
cur = cur - > hnext ;
P_RemoveMobj ( prev ) ;
}
}
2018-06-25 13:18:30 +00:00
if ( mobj - > type = = MT_OVERLAY )
P_RemoveOverlay ( mobj ) ;
if ( mobj - > type = = MT_SHADOW )
P_RemoveShadow ( mobj ) ;
2014-03-15 16:59:03 +00:00
mobj - > health = 0 ; // Just because
// unlink from sector and block lists
P_UnsetThingPosition ( mobj ) ;
if ( sector_list )
{
P_DelSeclist ( sector_list ) ;
sector_list = NULL ;
}
mobj - > flags | = MF_NOSECTOR | MF_NOBLOCKMAP ;
mobj - > subsector = NULL ;
mobj - > state = NULL ;
mobj - > player = NULL ;
// stop any playing sound
S_StopSound ( mobj ) ;
// killough 11/98:
//
// Remove any references to other mobjs.
P_SetTarget ( & mobj - > target , P_SetTarget ( & mobj - > tracer , NULL ) ) ;
2018-06-28 00:20:19 +00:00
// repair hnext chain
{
mobj_t * cachenext = mobj - > hnext ;
if ( mobj - > hnext & & ! P_MobjWasRemoved ( mobj - > hnext ) )
{
P_SetTarget ( & mobj - > hnext - > hprev , mobj - > hprev ) ;
P_SetTarget ( & mobj - > hnext , NULL ) ;
}
if ( mobj - > hprev & & ! P_MobjWasRemoved ( mobj - > hprev ) )
{
P_SetTarget ( & mobj - > hprev - > hnext , cachenext ) ;
P_SetTarget ( & mobj - > hprev , NULL ) ;
}
}
2014-03-15 16:59:03 +00:00
// free block
// DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error.
if ( mobj - > flags & MF_NOTHINK & & ! mobj - > thinker . next )
{ // Uh-oh, the mobj doesn't think, P_RemoveThinker would never go through!
if ( ! mobj - > thinker . references )
{
# ifdef SCRAMBLE_REMOVED
// Invalidate mobj_t data to cause crashes if accessed!
memset ( mobj , 0xff , sizeof ( mobj_t ) ) ;
# endif
Z_Free ( mobj ) ; // No refrences? Can be removed immediately! :D
}
else
{ // Add thinker just to delay removing it until refrences are gone.
mobj - > flags & = ~ MF_NOTHINK ;
P_AddThinker ( ( thinker_t * ) mobj ) ;
# ifdef SCRAMBLE_REMOVED
// Invalidate mobj_t data to cause crashes if accessed!
memset ( ( UINT8 * ) mobj + sizeof ( thinker_t ) , 0xff , sizeof ( mobj_t ) - sizeof ( thinker_t ) ) ;
# endif
P_RemoveThinker ( ( thinker_t * ) mobj ) ;
}
}
else
{
# ifdef SCRAMBLE_REMOVED
// Invalidate mobj_t data to cause crashes if accessed!
memset ( ( UINT8 * ) mobj + sizeof ( thinker_t ) , 0xff , sizeof ( mobj_t ) - sizeof ( thinker_t ) ) ;
# endif
P_RemoveThinker ( ( thinker_t * ) mobj ) ;
}
}
// This does not need to be added to Lua.
// To test it in Lua, check mobj.valid
boolean P_MobjWasRemoved ( mobj_t * mobj )
{
if ( mobj & & mobj - > thinker . function . acp1 = = ( actionf_p1 ) P_MobjThinker )
return false ;
return true ;
}
void P_RemovePrecipMobj ( precipmobj_t * mobj )
{
// unlink from sector and block lists
P_UnsetPrecipThingPosition ( mobj ) ;
if ( precipsector_list )
{
P_DelPrecipSeclist ( precipsector_list ) ;
precipsector_list = NULL ;
}
// free block
P_RemoveThinker ( ( thinker_t * ) mobj ) ;
}
// Clearing out stuff for savegames
void P_RemoveSavegameMobj ( mobj_t * mobj )
{
// unlink from sector and block lists
P_UnsetThingPosition ( mobj ) ;
// Remove touching_sectorlist from mobj.
if ( sector_list )
{
P_DelSeclist ( sector_list ) ;
sector_list = NULL ;
}
// stop any playing sound
S_StopSound ( mobj ) ;
// free block
P_RemoveThinker ( ( thinker_t * ) mobj ) ;
}
static CV_PossibleValue_t respawnitemtime_cons_t [ ] = { { 1 , " MIN " } , { 300 , " MAX " } , { 0 , NULL } } ;
2018-07-01 01:18:38 +00:00
consvar_t cv_itemrespawntime = { " respawnitemtime " , " 2 " , CV_NETVAR | CV_CHEAT , respawnitemtime_cons_t , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
2014-03-15 16:59:03 +00:00
consvar_t cv_itemrespawn = { " respawnitem " , " On " , CV_NETVAR , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
static CV_PossibleValue_t flagtime_cons_t [ ] = { { 0 , " MIN " } , { 300 , " MAX " } , { 0 , NULL } } ;
consvar_t cv_flagtime = { " flagtime " , " 30 " , CV_NETVAR | CV_CHEAT , flagtime_cons_t , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
consvar_t cv_suddendeath = { " suddendeath " , " Off " , CV_NETVAR | CV_CHEAT , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
void P_SpawnPrecipitation ( void )
{
2018-10-14 21:32:34 +00:00
INT32 i , mrand ;
2014-03-15 16:59:03 +00:00
fixed_t basex , basey , x , y , height ;
subsector_t * precipsector = NULL ;
precipmobj_t * rainmo = NULL ;
2018-10-14 21:32:34 +00:00
if ( dedicated | | /*!cv_precipdensity*/ ! cv_drawdist_precip . value | | curWeather = = PRECIP_NONE ) // SRB2Kart
2014-03-15 16:59:03 +00:00
return ;
// Use the blockmap to narrow down our placing patterns
for ( i = 0 ; i < bmapwidth * bmapheight ; + + i )
{
basex = bmaporgx + ( i % bmapwidth ) * MAPBLOCKSIZE ;
basey = bmaporgy + ( i / bmapwidth ) * MAPBLOCKSIZE ;
2018-10-14 21:32:34 +00:00
//for (j = 0; j < cv_precipdensity.value; ++j) -- density is 1 for kart always
2014-03-15 16:59:03 +00:00
{
x = basex + ( ( M_RandomKey ( MAPBLOCKUNITS < < 3 ) < < FRACBITS ) > > 3 ) ;
y = basey + ( ( M_RandomKey ( MAPBLOCKUNITS < < 3 ) < < FRACBITS ) > > 3 ) ;
precipsector = R_IsPointInSubsector ( x , y ) ;
// No sector? Stop wasting time,
// move on to the next entry in the blockmap
if ( ! precipsector )
2018-10-14 21:32:34 +00:00
continue ;
// Not in a sector with visible sky?
if ( precipsector - > sector - > ceilingpic ! = skyflatnum )
continue ;
2014-03-15 16:59:03 +00:00
// Exists, but is too small for reasonable precipitation.
if ( ! ( precipsector - > sector - > floorheight < = precipsector - > sector - > ceilingheight - ( 32 < < FRACBITS ) ) )
continue ;
// Don't set height yet...
height = precipsector - > sector - > ceilingheight ;
if ( curWeather = = PRECIP_SNOW )
{
rainmo = P_SpawnSnowMobj ( x , y , height , MT_SNOWFLAKE ) ;
2016-07-06 04:09:17 +00:00
mrand = M_RandomByte ( ) ;
2014-03-15 16:59:03 +00:00
if ( mrand < 64 )
P_SetPrecipMobjState ( rainmo , S_SNOW3 ) ;
else if ( mrand < 144 )
P_SetPrecipMobjState ( rainmo , S_SNOW2 ) ;
}
else // everything else.
rainmo = P_SpawnRainMobj ( x , y , height , MT_RAIN ) ;
// Randomly assign a height, now that floorz is set.
rainmo - > z = M_RandomRange ( rainmo - > floorz > > FRACBITS , rainmo - > ceilingz > > FRACBITS ) < < FRACBITS ;
}
}
if ( curWeather = = PRECIP_BLANK )
{
curWeather = PRECIP_RAIN ;
P_SwitchWeather ( PRECIP_BLANK ) ;
}
else if ( curWeather = = PRECIP_STORM_NORAIN )
{
curWeather = PRECIP_RAIN ;
P_SwitchWeather ( PRECIP_STORM_NORAIN ) ;
}
}
//
// P_PrecipitationEffects
//
void P_PrecipitationEffects ( void )
{
INT16 thunderchance = INT16_MAX ;
INT32 volume ;
size_t i ;
boolean sounds_rain = true ;
boolean sounds_thunder = true ;
boolean effects_lightning = true ;
boolean lightningStrike = false ;
// No thunder except every other tic.
if ( leveltime & 1 ) ;
// Before, consistency failures were possible if a level started
// with global rain and switched players to anything else ...
// If the global weather has lightning strikes,
// EVERYONE gets them at the SAME time!
else if ( globalweather = = PRECIP_STORM
| | globalweather = = PRECIP_STORM_NORAIN )
thunderchance = ( P_RandomKey ( 8192 ) ) ;
// But on the other hand, if the global weather is ANYTHING ELSE,
// don't sync lightning strikes.
// It doesn't matter whatever curWeather is, we'll only use
// the variable if we care about it.
else
thunderchance = ( M_RandomKey ( 8192 ) ) ;
if ( thunderchance < 70 )
lightningStrike = true ;
switch ( curWeather )
{
case PRECIP_RAIN : // no lightning or thunder whatsoever
sounds_thunder = false ;
2017-09-28 13:39:47 +00:00
/* FALLTHRU */
2014-03-15 16:59:03 +00:00
case PRECIP_STORM_NOSTRIKES : // no lightning strikes specifically
effects_lightning = false ;
break ;
case PRECIP_STORM_NORAIN : // no rain, lightning and thunder allowed
sounds_rain = false ;
case PRECIP_STORM : // everything.
break ;
default :
// Other weathers need not apply.
return ;
}
// Currently thunderstorming with lightning, and we're sounding the thunder...
// and where there's thunder, there's gotta be lightning!
if ( effects_lightning & & lightningStrike )
{
sector_t * ss = sectors ;
for ( i = 0 ; i < numsectors ; i + + , ss + + )
if ( ss - > ceilingpic = = skyflatnum ) // Only for the sky.
P_SpawnLightningFlash ( ss ) ; // Spawn a quick flash thinker
}
// Local effects from here on out!
// If we're not in game fully yet, we don't worry about them.
if ( ! playeringame [ displayplayer ] | | ! players [ displayplayer ] . mo )
return ;
if ( nosound | | sound_disabled )
return ; // Sound off? D'aw, no fun.
if ( players [ displayplayer ] . mo - > subsector - > sector - > ceilingpic = = skyflatnum )
volume = 255 ; // Sky above? We get it full blast.
else
{
fixed_t x , y , yl , yh , xl , xh ;
fixed_t closedist , newdist ;
// Essentially check in a 1024 unit radius of the player for an outdoor area.
yl = players [ displayplayer ] . mo - > y - 1024 * FRACUNIT ;
yh = players [ displayplayer ] . mo - > y + 1024 * FRACUNIT ;
xl = players [ displayplayer ] . mo - > x - 1024 * FRACUNIT ;
xh = players [ displayplayer ] . mo - > x + 1024 * FRACUNIT ;
closedist = 2048 * FRACUNIT ;
for ( y = yl ; y < = yh ; y + = FRACUNIT * 64 )
for ( x = xl ; x < = xh ; x + = FRACUNIT * 64 )
{
if ( R_PointInSubsector ( x , y ) - > sector - > ceilingpic = = skyflatnum ) // Found the outdoors!
{
newdist = S_CalculateSoundDistance ( players [ displayplayer ] . mo - > x , players [ displayplayer ] . mo - > y , 0 , x , y , 0 ) ;
if ( newdist < closedist )
closedist = newdist ;
}
}
volume = 255 - ( closedist > > ( FRACBITS + 2 ) ) ;
}
if ( volume < 0 )
volume = 0 ;
else if ( volume > 255 )
volume = 255 ;
if ( sounds_rain & & ( ! leveltime | | leveltime % 80 = = 1 ) )
S_StartSoundAtVolume ( players [ displayplayer ] . mo , sfx_rainin , volume ) ;
if ( ! sounds_thunder )
return ;
if ( effects_lightning & & lightningStrike & & volume )
{
// Large, close thunder sounds to go with our lightning.
S_StartSoundAtVolume ( players [ displayplayer ] . mo , sfx_litng1 + M_RandomKey ( 4 ) , volume ) ;
}
else if ( thunderchance < 20 )
{
// You can always faintly hear the thunder...
if ( volume < 80 )
volume = 80 ;
S_StartSoundAtVolume ( players [ displayplayer ] . mo , sfx_athun1 + M_RandomKey ( 2 ) , volume ) ;
}
}
//
// P_RespawnSpecials
//
void P_RespawnSpecials ( void )
{
fixed_t x , y , z ;
2014-08-04 03:49:33 +00:00
subsector_t * ss ;
2014-03-15 16:59:03 +00:00
mobj_t * mo = NULL ;
mapthing_t * mthing = NULL ;
2018-03-27 21:53:47 +00:00
if ( G_BattleGametype ( ) & & numgotboxes > = ( 4 * nummapboxes / 5 ) ) // Battle Mode respawns all boxes in a different way
2017-10-24 21:04:22 +00:00
{
2018-03-27 21:53:47 +00:00
thinker_t * th ;
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
mobj_t * box ;
mobj_t * newmobj ;
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker ) // not a mobj
continue ;
box = ( mobj_t * ) th ;
if ( box - > type ! = MT_RANDOMITEM | | box - > threshold ! = 68 | | box - > fuse ) // only popped items
continue ;
// Respawn from mapthing if you have one!
if ( box - > spawnpoint )
{
P_SpawnMapThing ( box - > spawnpoint ) ;
newmobj = box - > spawnpoint - > mobj ; // this is set to the new mobj in P_SpawnMapThing
2018-06-14 03:37:37 +00:00
P_SpawnMobj ( box - > spawnpoint - > mobj - > x , box - > spawnpoint - > mobj - > y , box - > spawnpoint - > mobj - > z , MT_EXPLODE ) ; // poof into existance
2018-03-27 21:53:47 +00:00
}
else
2018-06-14 03:37:37 +00:00
{
2018-03-27 21:53:47 +00:00
newmobj = P_SpawnMobj ( box - > x , box - > y , box - > z , box - > type ) ;
2018-06-14 03:37:37 +00:00
P_SpawnMobj ( newmobj - > x , newmobj - > y , newmobj - > z , MT_EXPLODE ) ; // poof into existance
}
2018-03-27 21:53:47 +00:00
// Transfer flags2 (strongbox, objectflip)
newmobj - > flags2 = box - > flags2 ;
P_RemoveMobj ( box ) ; // make sure they disappear
2018-08-27 16:25:22 +00:00
numgotboxes - - ; // you've restored a box, remove it from the count
//continue; -- irrelevant?
2018-03-27 21:53:47 +00:00
}
2018-08-27 16:25:22 +00:00
if ( numgotboxes < 0 )
numgotboxes = 0 ;
2017-10-24 21:04:22 +00:00
}
2014-03-15 16:59:03 +00:00
// only respawn items when cv_itemrespawn is on
2017-10-15 06:33:28 +00:00
if ( ! cv_itemrespawn . value )
2014-03-15 16:59:03 +00:00
return ;
// Don't respawn in special stages!
if ( G_IsSpecialStage ( gamemap ) )
return ;
// nothing left to respawn?
if ( iquehead = = iquetail )
return ;
// the first item in the queue is the first to respawn
// wait at least 30 seconds
if ( leveltime - itemrespawntime [ iquetail ] < ( tic_t ) cv_itemrespawntime . value * TICRATE )
return ;
mthing = itemrespawnque [ iquetail ] ;
# ifdef PARANOIA
if ( ! mthing )
I_Error ( " itemrespawnque[iquetail] is NULL! " ) ;
# endif
if ( mthing )
{
mobjtype_t i ;
x = mthing - > x < < FRACBITS ;
y = mthing - > y < < FRACBITS ;
2014-08-04 03:49:33 +00:00
ss = R_PointInSubsector ( x , y ) ;
2014-03-15 16:59:03 +00:00
// find which type to spawn
for ( i = 0 ; i < NUMMOBJTYPES ; i + + )
if ( mthing - > type = = mobjinfo [ i ] . doomednum )
break ;
2017-12-17 20:57:45 +00:00
if ( i = = NUMMOBJTYPES ) // prevent creation of objects with this type -- Monster Iestyn 17/12/17
{
// 3D Mode start Thing is unlikely to be added to the que,
// so don't bother checking for that specific type
CONS_Alert ( CONS_WARNING , M_GetText ( " P_RespawnSpecials: Unknown thing type %d attempted to respawn at (%d, %d) \n " ) , mthing - > type , mthing - > x , mthing - > y ) ;
// pull it from the que
iquetail = ( iquetail + 1 ) & ( ITEMQUESIZE - 1 ) ;
return ;
}
2014-03-15 16:59:03 +00:00
//CTF rings should continue to respawn as normal rings outside of CTF.
if ( gametype ! = GT_CTF )
{
if ( i = = MT_REDTEAMRING | | i = = MT_BLUETEAMRING )
i = MT_RING ;
}
if ( mthing - > options & MTF_OBJECTFLIP )
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
ss - > sector - > c_slope ? P_GetZAt ( ss - > sector - > c_slope , x , y ) :
# endif
ss - > sector - > ceilingheight ) - ( mthing - > options > > ZSHIFT ) * FRACUNIT ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options & MTF_AMBUSH
& & ( i = = MT_RING | | i = = MT_REDTEAMRING | | i = = MT_BLUETEAMRING | | i = = MT_COIN | | P_WeaponOrPanel ( i ) ) )
2014-08-04 03:49:33 +00:00
z - = 24 * FRACUNIT ;
z - = mobjinfo [ i ] . height ; // Don't forget the height!
2014-03-15 16:59:03 +00:00
}
else
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
ss - > sector - > f_slope ? P_GetZAt ( ss - > sector - > f_slope , x , y ) :
# endif
ss - > sector - > floorheight ) + ( mthing - > options > > ZSHIFT ) * FRACUNIT ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options & MTF_AMBUSH
& & ( i = = MT_RING | | i = = MT_REDTEAMRING | | i = = MT_BLUETEAMRING | | i = = MT_COIN | | P_WeaponOrPanel ( i ) ) )
2014-08-04 03:49:33 +00:00
z + = 24 * FRACUNIT ;
}
mo = P_SpawnMobj ( x , y , z , i ) ;
mo - > spawnpoint = mthing ;
mo - > angle = ANGLE_45 * ( mthing - > angle / 45 ) ;
if ( mthing - > options & MTF_OBJECTFLIP )
{
mo - > eflags | = MFE_VERTICALFLIP ;
mo - > flags2 | = MF2_OBJECTFLIP ;
2014-03-15 16:59:03 +00:00
}
}
// pull it from the que
iquetail = ( iquetail + 1 ) & ( ITEMQUESIZE - 1 ) ;
}
//
// P_SpawnPlayer
// Called when a player is spawned on the level.
// Most of the player structure stays unchanged between levels.
//
void P_SpawnPlayer ( INT32 playernum )
{
2018-07-04 01:12:25 +00:00
UINT8 i , pcount = 0 ;
2014-03-15 16:59:03 +00:00
player_t * p = & players [ playernum ] ;
mobj_t * mobj ;
if ( p - > playerstate = = PST_REBORN )
G_PlayerReborn ( playernum ) ;
2018-07-04 01:12:25 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
2014-08-04 03:49:33 +00:00
{
2018-07-04 01:12:25 +00:00
if ( i = = playernum )
continue ;
if ( ! playeringame [ i ] | | players [ i ] . spectator )
continue ;
pcount + + ;
2014-08-04 03:49:33 +00:00
}
2018-07-04 01:12:25 +00:00
// spawn as spectator determination
if ( ! G_GametypeHasSpectators ( ) )
p - > spectator = false ;
2018-07-21 15:45:08 +00:00
else if ( netgame & & p - > jointime < = 1 & & pcount )
{
2018-07-04 01:12:25 +00:00
p - > spectator = true ;
2018-07-22 04:31:02 +00:00
// Oni doesn't want this
/*if (pcount == 1 || leveltime < starttime)
2018-07-21 15:45:08 +00:00
p - > pflags | = PF_WANTSTOJOIN ;
2018-07-22 04:31:02 +00:00
p - > jointime = 2 ; */
2018-07-21 15:45:08 +00:00
}
2014-03-15 16:59:03 +00:00
else if ( multiplayer & & ! netgame )
{
// If you're in a team game and you don't have a team assigned yet...
if ( G_GametypeHasTeams ( ) & & p - > ctfteam = = 0 )
{
changeteam_union NetPacket ;
UINT16 usvalue ;
NetPacket . value . l = NetPacket . value . b = 0 ;
// Spawn as a spectator,
// yes even in splitscreen mode
p - > spectator = true ;
if ( playernum & 1 ) p - > skincolor = skincolor_redteam ;
else p - > skincolor = skincolor_blueteam ;
// but immediately send a team change packet.
NetPacket . packet . playernum = playernum ;
NetPacket . packet . verification = true ;
NetPacket . packet . newteam = ! ( playernum & 1 ) + 1 ;
usvalue = SHORT ( NetPacket . value . l | NetPacket . value . b ) ;
SendNetXCmd ( XD_TEAMCHANGE , & usvalue , sizeof ( usvalue ) ) ;
}
else // Otherwise, never spectator.
p - > spectator = false ;
}
2014-03-18 17:56:54 +00:00
if ( G_GametypeHasTeams ( ) )
{
// Fix stupid non spectator spectators.
if ( ! p - > spectator & & ! p - > ctfteam )
p - > spectator = true ;
// Fix team colors.
// This code isn't being done right somewhere else. Oh well.
if ( p - > ctfteam = = 1 )
p - > skincolor = skincolor_redteam ;
else if ( p - > ctfteam = = 2 )
p - > skincolor = skincolor_blueteam ;
}
2014-03-15 16:59:03 +00:00
mobj = P_SpawnMobj ( 0 , 0 , 0 , MT_PLAYER ) ;
( mobj - > player = p ) - > mo = mobj ;
mobj - > angle = 0 ;
// set color translations for player sprites
mobj - > color = p - > skincolor ;
// set 'spritedef' override in mobj for player skins.. (see ProjectSprite)
// (usefulness: when body mobj is detached from player (who respawns),
// the dead body mobj retains the skin through the 'spritedef' override).
mobj - > skin = & skins [ p - > skin ] ;
mobj - > health = p - > health ;
p - > playerstate = PST_LIVE ;
p - > bonustime = false ;
p - > realtime = leveltime ;
//awayview stuff
p - > awayviewmobj = NULL ;
p - > awayviewtics = 0 ;
// set the scale to the mobj's destscale so settings get correctly set. if we don't, they sometimes don't.
2018-07-12 05:31:33 +00:00
if ( cv_kartdebugshrink . value & & ! p - > bot )
mobj - > destscale = 6 * mobj - > destscale / 8 ;
2014-03-15 16:59:03 +00:00
P_SetScale ( mobj , mobj - > destscale ) ;
P_FlashPal ( p , 0 , 0 ) ; // Resets
// Spawn with a pity shield if necessary.
2017-10-22 07:06:35 +00:00
//P_DoPityCheck(p);
2018-06-11 04:59:20 +00:00
if ( G_BattleGametype ( ) ) // SRB2kart
2017-10-22 07:06:35 +00:00
{
2018-06-11 04:59:20 +00:00
mobj_t * overheadarrow = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z + P_GetPlayerHeight ( p ) + 16 * FRACUNIT , MT_PLAYERARROW ) ;
P_SetTarget ( & overheadarrow - > target , mobj ) ;
overheadarrow - > flags2 | = MF2_DONTDRAW ;
P_SetScale ( overheadarrow , mobj - > destscale ) ;
2018-07-21 15:45:08 +00:00
if ( p - > spectator & & pcount > 1 ) // HEY! No being cheap...
2018-07-04 01:12:25 +00:00
p - > kartstuff [ k_bumper ] = 0 ;
else if ( p - > kartstuff [ k_bumper ] > 0 | | leveltime < 1
| | ( p - > jointime < = 1 & & pcount < = 1 ) )
2017-11-05 06:43:47 +00:00
{
2018-07-04 01:12:25 +00:00
if ( leveltime < 1 | | ( p - > jointime < = 1 & & pcount < = 1 ) ) // Start of the map?
2018-07-03 19:14:47 +00:00
p - > kartstuff [ k_bumper ] = cv_kartbumpers . value ; // Reset those bumpers!
2017-10-22 21:26:43 +00:00
2018-07-21 15:45:08 +00:00
if ( p - > kartstuff [ k_bumper ] )
2017-11-05 06:43:47 +00:00
{
2018-07-21 15:45:08 +00:00
INT32 i ;
angle_t diff = FixedAngle ( 360 * FRACUNIT / p - > kartstuff [ k_bumper ] ) ;
angle_t newangle = mobj - > angle ;
fixed_t newx = mobj - > x + P_ReturnThrustX ( mobj , newangle + ANGLE_180 , 64 * FRACUNIT ) ;
fixed_t newy = mobj - > y + P_ReturnThrustY ( mobj , newangle + ANGLE_180 , 64 * FRACUNIT ) ;
mobj_t * mo ;
for ( i = 0 ; i < p - > kartstuff [ k_bumper ] ; i + + )
{
mo = P_SpawnMobj ( newx , newy , mobj - > z , MT_BATTLEBUMPER ) ;
mo - > threshold = i ;
P_SetTarget ( & mo - > target , mobj ) ;
mo - > angle = ( diff * ( i - 1 ) ) ;
mo - > color = mobj - > color ;
if ( mobj - > flags2 & MF2_DONTDRAW )
mo - > flags2 | = MF2_DONTDRAW ;
else
mo - > flags2 & = ~ MF2_DONTDRAW ;
}
2017-11-05 06:43:47 +00:00
}
2017-10-22 07:06:35 +00:00
}
2018-07-03 19:14:47 +00:00
else if ( p - > kartstuff [ k_bumper ] < = 0 )
2018-06-16 04:00:46 +00:00
{
mobj_t * karmahitbox = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , MT_KARMAHITBOX ) ; // Player hitbox is too small!!
P_SetTarget ( & karmahitbox - > target , mobj ) ;
karmahitbox - > destscale = mobj - > scale ;
P_SetScale ( karmahitbox , mobj - > scale ) ;
}
2017-10-22 07:06:35 +00:00
}
2014-03-15 16:59:03 +00:00
}
void P_AfterPlayerSpawn ( INT32 playernum )
{
player_t * p = & players [ playernum ] ;
mobj_t * mobj = p - > mo ;
if ( playernum = = consoleplayer )
localangle = mobj - > angle ;
else if ( playernum = = secondarydisplayplayer )
localangle2 = mobj - > angle ;
2017-12-17 03:32:43 +00:00
else if ( playernum = = thirddisplayplayer )
localangle3 = mobj - > angle ;
else if ( playernum = = fourthdisplayplayer )
localangle4 = mobj - > angle ;
2014-03-15 16:59:03 +00:00
2018-06-26 15:33:54 +00:00
p - > viewheight = 32 < < FRACBITS ;
2014-03-15 16:59:03 +00:00
if ( p - > mo - > eflags & MFE_VERTICALFLIP )
p - > viewz = p - > mo - > z + p - > mo - > height - p - > viewheight ;
else
p - > viewz = p - > mo - > z + p - > viewheight ;
2017-11-04 17:32:47 +00:00
P_SetPlayerMobjState ( p - > mo , S_KART_STND1 ) ; // SRB2kart - was S_PLAY_STND
2014-03-15 16:59:03 +00:00
p - > pflags & = ~ PF_SPINNING ;
if ( playernum = = consoleplayer )
{
// wake up the status bar
ST_Start ( ) ;
// wake up the heads up text
HU_Start ( ) ;
}
SV_SpawnPlayer ( playernum , mobj - > x , mobj - > y , mobj - > angle ) ;
if ( camera . chase )
{
if ( displayplayer = = playernum )
P_ResetCamera ( p , & camera ) ;
}
2017-12-19 01:59:04 +00:00
if ( camera2 . chase & & splitscreen )
2014-03-15 16:59:03 +00:00
{
if ( secondarydisplayplayer = = playernum )
P_ResetCamera ( p , & camera2 ) ;
}
2017-12-19 01:59:04 +00:00
if ( camera3 . chase & & splitscreen > 1 )
2017-12-17 03:32:43 +00:00
{
if ( thirddisplayplayer = = playernum )
P_ResetCamera ( p , & camera3 ) ;
}
2017-12-19 01:59:04 +00:00
if ( camera4 . chase & & splitscreen > 2 )
2017-12-17 03:32:43 +00:00
{
if ( fourthdisplayplayer = = playernum )
P_ResetCamera ( p , & camera4 ) ;
}
2014-03-15 16:59:03 +00:00
if ( CheckForReverseGravity )
P_CheckGravity ( mobj , false ) ;
}
// spawn it at a playerspawn mapthing
void P_MovePlayerToSpawn ( INT32 playernum , mapthing_t * mthing )
{
fixed_t x = 0 , y = 0 ;
angle_t angle = 0 ;
fixed_t z ;
sector_t * sector ;
2016-07-06 04:09:17 +00:00
fixed_t floor , ceiling ;
2014-03-15 16:59:03 +00:00
player_t * p = & players [ playernum ] ;
mobj_t * mobj = p - > mo ;
I_Assert ( mobj ! = NULL ) ;
if ( mthing )
{
x = mthing - > x < < FRACBITS ;
y = mthing - > y < < FRACBITS ;
angle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
}
//spawn at the origin as a desperation move if there is no mapthing
// set Z height
sector = R_PointInSubsector ( x , y ) - > sector ;
2016-07-06 04:09:17 +00:00
floor =
# ifdef ESLOPE
sector - > f_slope ? P_GetZAt ( sector - > f_slope , x , y ) :
# endif
sector - > floorheight ;
ceiling =
# ifdef ESLOPE
sector - > c_slope ? P_GetZAt ( sector - > c_slope , x , y ) :
# endif
sector - > ceilingheight ;
2014-03-15 16:59:03 +00:00
if ( mthing )
{
// Flagging a player's ambush will make them start on the ceiling
// Objectflip inverts
2014-08-04 03:49:33 +00:00
if ( ! ! ( mthing - > options & MTF_AMBUSH ) ^ ! ! ( mthing - > options & MTF_OBJECTFLIP ) )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
z = ceiling - mobjinfo [ MT_PLAYER ] . height ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options > > ZSHIFT )
z - = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2018-06-25 02:15:22 +00:00
if ( p - > kartstuff [ k_respawn ] )
2017-07-16 16:04:33 +00:00
z - = 128 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
}
else
{
2016-07-06 04:09:17 +00:00
z = floor ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options > > ZSHIFT )
z + = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2018-06-25 02:15:22 +00:00
if ( p - > kartstuff [ k_respawn ] )
2017-07-16 16:04:33 +00:00
z + = 128 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
if ( mthing - > options & MTF_OBJECTFLIP ) // flip the player!
{
mobj - > eflags | = MFE_VERTICALFLIP ;
mobj - > flags2 | = MF2_OBJECTFLIP ;
}
2014-03-15 16:59:03 +00:00
}
else
2016-07-06 04:09:17 +00:00
z = floor ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
if ( z < floor )
z = floor ;
else if ( z > ceiling - mobjinfo [ MT_PLAYER ] . height )
z = ceiling - mobjinfo [ MT_PLAYER ] . height ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
mobj - > floorz = floor ;
mobj - > ceilingz = ceiling ;
2014-03-15 16:59:03 +00:00
P_UnsetThingPosition ( mobj ) ;
mobj - > x = x ;
mobj - > y = y ;
P_SetThingPosition ( mobj ) ;
mobj - > z = z ;
2016-07-06 04:09:17 +00:00
if ( mobj - > z = = mobj - > floorz )
2014-03-15 16:59:03 +00:00
mobj - > eflags | = MFE_ONGROUND ;
mobj - > angle = angle ;
P_AfterPlayerSpawn ( playernum ) ;
}
void P_MovePlayerToStarpost ( INT32 playernum )
{
fixed_t z ;
sector_t * sector ;
2016-07-06 04:09:17 +00:00
fixed_t floor , ceiling ;
2014-03-15 16:59:03 +00:00
player_t * p = & players [ playernum ] ;
mobj_t * mobj = p - > mo ;
I_Assert ( mobj ! = NULL ) ;
P_UnsetThingPosition ( mobj ) ;
mobj - > x = p - > starpostx < < FRACBITS ;
mobj - > y = p - > starposty < < FRACBITS ;
P_SetThingPosition ( mobj ) ;
sector = R_PointInSubsector ( mobj - > x , mobj - > y ) - > sector ;
2016-07-06 04:09:17 +00:00
floor =
# ifdef ESLOPE
sector - > f_slope ? P_GetZAt ( sector - > f_slope , mobj - > x , mobj - > y ) :
# endif
sector - > floorheight ;
ceiling =
# ifdef ESLOPE
sector - > c_slope ? P_GetZAt ( sector - > c_slope , mobj - > x , mobj - > y ) :
# endif
sector - > ceilingheight ;
2018-06-25 02:15:22 +00:00
z = ( p - > starpostz + 128 ) < < FRACBITS ; // Respawn off the ground
2016-07-06 04:09:17 +00:00
if ( z < floor )
z = floor ;
else if ( z > ceiling - mobjinfo [ MT_PLAYER ] . height )
z = ceiling - mobjinfo [ MT_PLAYER ] . height ;
2014-03-15 16:59:03 +00:00
2016-07-06 04:09:17 +00:00
mobj - > floorz = floor ;
mobj - > ceilingz = ceiling ;
2014-03-15 16:59:03 +00:00
mobj - > z = z ;
if ( mobj - > z = = mobj - > floorz )
mobj - > eflags | = MFE_ONGROUND ;
mobj - > angle = p - > starpostangle ;
2017-02-17 02:33:00 +00:00
p - > kartstuff [ k_waypoint ] = p - > kartstuff [ k_starpostwp ] ; // SRB2kart
2014-03-15 16:59:03 +00:00
P_AfterPlayerSpawn ( playernum ) ;
2017-02-17 02:33:00 +00:00
//if (!(netgame || multiplayer))
// leveltime = p->starposttime;
2014-03-15 16:59:03 +00:00
}
# define MAXHUNTEMERALDS 64
mapthing_t * huntemeralds [ MAXHUNTEMERALDS ] ;
INT32 numhuntemeralds ;
//
// P_SpawnMapThing
// The fields of the mapthing should
// already be in host byte order.
//
void P_SpawnMapThing ( mapthing_t * mthing )
{
mobjtype_t i ;
mobj_t * mobj ;
fixed_t x , y , z ;
subsector_t * ss ;
if ( ! mthing - > type )
return ; // Ignore type-0 things as NOPs
// Always spawn in objectplace.
// Skip all returning code.
if ( objectplacing )
{
// find which type to spawn
for ( i = 0 ; i < NUMMOBJTYPES ; i + + )
if ( mthing - > type = = mobjinfo [ i ] . doomednum )
break ;
if ( i = = NUMMOBJTYPES )
{
if ( mthing - > type = = 3328 ) // 3D Mode start Thing
return ;
CONS_Alert ( CONS_WARNING , M_GetText ( " Unknown thing type %d placed at (%d, %d) \n " ) , mthing - > type , mthing - > x , mthing - > y ) ;
i = MT_UNKNOWN ;
}
goto noreturns ;
}
// count deathmatch start positions
if ( mthing - > type = = 33 )
{
if ( numdmstarts < MAX_DM_STARTS )
{
deathmatchstarts [ numdmstarts ] = mthing ;
mthing - > type = 0 ;
numdmstarts + + ;
}
return ;
}
else if ( mthing - > type = = 34 ) // Red CTF Starts
{
if ( numredctfstarts < MAXPLAYERS )
{
redctfstarts [ numredctfstarts ] = mthing ;
mthing - > type = 0 ;
numredctfstarts + + ;
}
return ;
}
else if ( mthing - > type = = 35 ) // Blue CTF Starts
{
if ( numbluectfstarts < MAXPLAYERS )
{
bluectfstarts [ numbluectfstarts ] = mthing ;
mthing - > type = 0 ;
numbluectfstarts + + ;
}
return ;
}
2016-07-06 04:09:17 +00:00
else if ( mthing - > type = = 750 ) // Slope vertex point (formerly chaos spawn)
return ;
2014-03-15 16:59:03 +00:00
else if ( mthing - > type = = 300 // Ring
| | mthing - > type = = 308 | | mthing - > type = = 309 // Team Rings
| | mthing - > type = = 1706 // Nights Wing
| | ( mthing - > type > = 600 & & mthing - > type < = 609 ) // Placement patterns
| | mthing - > type = = 1705 | | mthing - > type = = 1713 // NiGHTS Hoops
| | mthing - > type = = 1800 ) // Mario Coin
{
// Don't spawn hoops, wings, or rings yet!
return ;
}
// check for players specially
if ( mthing - > type > 0 & & mthing - > type < = 32 )
{
// save spots for respawning in network games
if ( ! metalrecording )
playerstarts [ mthing - > type - 1 ] = mthing ;
return ;
}
if ( metalrecording & & mthing - > type = = mobjinfo [ MT_METALSONIC_RACE ] . doomednum )
{ // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints.
playerstarts [ 0 ] = mthing ;
return ;
}
// find which type to spawn
for ( i = 0 ; i < NUMMOBJTYPES ; i + + )
if ( mthing - > type = = mobjinfo [ i ] . doomednum )
break ;
if ( i = = NUMMOBJTYPES )
{
2016-07-06 04:09:17 +00:00
if ( mthing - > type = = 3328 ) // 3D Mode start Thing
2014-03-15 16:59:03 +00:00
return ;
CONS_Alert ( CONS_WARNING , M_GetText ( " Unknown thing type %d placed at (%d, %d) \n " ) , mthing - > type , mthing - > x , mthing - > y ) ;
i = MT_UNKNOWN ;
}
if ( metalrecording ) // Metal Sonic can't use these things.
if ( mobjinfo [ i ] . flags & ( MF_ENEMY | MF_BOSS ) | | i = = MT_EMMY | | i = = MT_STARPOST )
return ;
if ( i > = MT_EMERALD1 & & i < = MT_EMERALD7 ) // Pickupable Emeralds
{
if ( gametype ! = GT_COOP ) // Don't place emeralds in non-coop modes
return ;
if ( metalrecording )
return ; // Metal Sonic isn't for collecting emeralds.
if ( emeralds & mobjinfo [ i ] . speed ) // You already have this emerald!
return ;
}
2018-02-08 22:13:06 +00:00
if ( ! G_BattleGametype ( ) | | ! cv_specialrings . value )
2014-03-15 16:59:03 +00:00
if ( P_WeaponOrPanel ( i ) )
return ; // Don't place weapons/panels in non-ringslinger modes
if ( i = = MT_EMERHUNT )
{
// Emerald Hunt is Coop only.
if ( gametype ! = GT_COOP )
return ;
ss = R_PointInSubsector ( mthing - > x < < FRACBITS , mthing - > y < < FRACBITS ) ;
2016-07-06 04:09:17 +00:00
mthing - > z = ( INT16 ) ( ( (
# ifdef ESLOPE
ss - > sector - > f_slope ? P_GetZAt ( ss - > sector - > f_slope , mthing - > x < < FRACBITS , mthing - > y < < FRACBITS ) :
# endif
ss - > sector - > floorheight ) > > FRACBITS ) + ( mthing - > options > > ZSHIFT ) ) ;
2014-03-15 16:59:03 +00:00
if ( numhuntemeralds < MAXHUNTEMERALDS )
huntemeralds [ numhuntemeralds + + ] = mthing ;
return ;
}
if ( i = = MT_EMERALDSPAWN )
{
if ( ! cv_powerstones . value )
return ;
2018-03-04 20:27:52 +00:00
if ( ! G_BattleGametype ( ) )
2014-03-15 16:59:03 +00:00
return ;
runemeraldmanager = true ;
}
2018-02-08 22:13:06 +00:00
if ( ! G_RaceGametype ( ) ) // No enemies in match or CTF modes
2014-03-15 16:59:03 +00:00
if ( ( mobjinfo [ i ] . flags & MF_ENEMY ) | | ( mobjinfo [ i ] . flags & MF_BOSS ) )
return ;
// Set powerup boxes to user settings for competition.
if ( gametype = = GT_COMPETITION )
{
if ( ( mobjinfo [ i ] . flags & MF_MONITOR ) & & cv_competitionboxes . value ) // not Normal
{
if ( cv_competitionboxes . value = = 1 ) // Random
i = MT_QUESTIONBOX ;
else if ( cv_competitionboxes . value = = 2 ) // Teleports
i = MT_MIXUPBOX ;
else if ( cv_competitionboxes . value = = 3 ) // None
return ; // Don't spawn!
}
}
// Set powerup boxes to user settings for other netplay modes
else if ( gametype ! = GT_COOP )
{
if ( ( mobjinfo [ i ] . flags & MF_MONITOR ) & & cv_matchboxes . value ) // not Normal
{
if ( cv_matchboxes . value = = 1 ) // Random
i = MT_QUESTIONBOX ;
else if ( cv_matchboxes . value = = 3 ) // Don't spawn
return ;
else // cv_matchboxes.value == 2, Non-Random
{
if ( i = = MT_QUESTIONBOX )
return ; // don't spawn in Non-Random
mthing - > options & = ~ ( MTF_AMBUSH | MTF_OBJECTSPECIAL ) ; // no random respawning!
}
}
}
if ( gametype ! = GT_CTF ) // CTF specific things
{
if ( i = = MT_BLUETEAMRING | | i = = MT_REDTEAMRING )
i = MT_RING ;
else if ( i = = MT_BLUERINGBOX | | i = = MT_REDRINGBOX )
i = MT_SUPERRINGBOX ;
else if ( i = = MT_BLUEFLAG | | i = = MT_REDFLAG )
return ; // No flags in non-CTF modes!
}
else
{
if ( ( i = = MT_BLUEFLAG & & blueflag ) | | ( i = = MT_REDFLAG & & redflag ) )
{
2014-08-05 23:59:40 +00:00
CONS_Alert ( CONS_ERROR , M_GetText ( " Only one flag per team allowed in CTF! \n " ) ) ;
2014-03-15 16:59:03 +00:00
return ;
}
}
2018-02-08 22:13:06 +00:00
if ( ! G_RaceGametype ( ) & & ( i = = MT_SIGN | | i = = MT_STARPOST ) )
2014-03-15 16:59:03 +00:00
return ; // Don't spawn exit signs or starposts in wrong game modes
if ( modeattacking ) // Record Attack special stuff
{
// Emerald Tokens -->> Score Tokens
2017-10-15 06:33:28 +00:00
if ( i = = MT_EMMY )
2014-03-15 16:59:03 +00:00
return ; /// \todo
// 1UPs -->> Score TVs
else if ( i = = MT_PRUP ) // 1UP
{
// Either or, doesn't matter which.
if ( mthing - > options & ( MTF_AMBUSH | MTF_OBJECTSPECIAL ) )
i = MT_SCORETVLARGE ; // 10,000
else
i = MT_SCORETVSMALL ; // 1,000
}
}
2014-04-14 05:14:58 +00:00
if ( ultimatemode )
{
if ( i = = MT_PITYTV | | i = = MT_GREENTV | | i = = MT_YELLOWTV | | i = = MT_BLUETV | | i = = MT_BLACKTV | | i = = MT_WHITETV )
return ; // No shields in Ultimate mode
if ( i = = MT_SUPERRINGBOX & & ! G_IsSpecialStage ( gamemap ) )
return ; // No rings in Ultimate mode (except special stages)
}
2014-03-15 16:59:03 +00:00
if ( i = = MT_EMMY & & ( gametype ! = GT_COOP | | ultimatemode | | tokenbits = = 30 | | tokenlist & ( 1 < < tokenbits + + ) ) )
return ; // you already got this token, or there are too many, or the gametype's not right
// Objectplace landing point
noreturns :
// spawn it
x = mthing - > x < < FRACBITS ;
y = mthing - > y < < FRACBITS ;
ss = R_PointInSubsector ( x , y ) ;
if ( i = = MT_NIGHTSBUMPER )
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
ss - > sector - > f_slope ? P_GetZAt ( ss - > sector - > f_slope , x , y ) :
# endif
ss - > sector - > floorheight ) + ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
else if ( i = = MT_AXIS | | i = = MT_AXISTRANSFER | | i = = MT_AXISTRANSFERLINE )
z = ONFLOORZ ;
else if ( i = = MT_SPECIALSPIKEBALL | | P_WeaponOrPanel ( i ) | | i = = MT_EMERALDSPAWN | | i = = MT_EMMY )
{
2014-08-04 03:49:33 +00:00
if ( mthing - > options & MTF_OBJECTFLIP )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
ss - > sector - > c_slope ? P_GetZAt ( ss - > sector - > c_slope , x , y ) :
# endif
ss - > sector - > ceilingheight ) ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options & MTF_AMBUSH ) // Special flag for rings
2014-08-04 03:49:33 +00:00
z - = 24 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options > > ZSHIFT )
2014-08-04 03:49:33 +00:00
z - = ( mthing - > options > > ZSHIFT ) * FRACUNIT ;
z - = mobjinfo [ i ] . height ; //Don't forget the height!
2014-03-15 16:59:03 +00:00
}
else
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
ss - > sector - > f_slope ? P_GetZAt ( ss - > sector - > f_slope , x , y ) :
# endif
ss - > sector - > floorheight ) ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options & MTF_AMBUSH ) // Special flag for rings
2014-08-04 03:49:33 +00:00
z + = 24 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options > > ZSHIFT )
2014-08-04 03:49:33 +00:00
z + = ( mthing - > options > > ZSHIFT ) * FRACUNIT ;
2014-03-15 16:59:03 +00:00
}
if ( z = = ONFLOORZ )
mthing - > z = 0 ;
else
mthing - > z = ( INT16 ) ( z > > FRACBITS ) ;
}
else
{
fixed_t offset = 0 ;
2014-08-04 03:49:33 +00:00
boolean flip = ( ! ! ( mobjinfo [ i ] . flags & MF_SPAWNCEILING ) ^ ! ! ( mthing - > options & MTF_OBJECTFLIP ) ) ;
2014-03-15 16:59:03 +00:00
// base positions
if ( flip )
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
ss - > sector - > c_slope ? P_GetZAt ( ss - > sector - > c_slope , x , y ) :
# endif
ss - > sector - > ceilingheight ) - mobjinfo [ i ] . height ;
2014-03-15 16:59:03 +00:00
else
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
ss - > sector - > f_slope ? P_GetZAt ( ss - > sector - > f_slope , x , y ) :
# endif
ss - > sector - > floorheight ) ;
2014-03-15 16:59:03 +00:00
// offsetting
if ( mthing - > options > > ZSHIFT )
offset = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
else if ( i = = MT_CRAWLACOMMANDER | | i = = MT_DETON | | i = = MT_JETTBOMBER | | i = = MT_JETTGUNNER | | i = = MT_EGGMOBILE2 )
offset = 33 * FRACUNIT ;
else if ( i = = MT_EGGMOBILE )
offset = 128 * FRACUNIT ;
else if ( i = = MT_GOLDBUZZ | | i = = MT_REDBUZZ )
offset = 288 * FRACUNIT ;
// applying offsets! (if any)
if ( flip )
{
if ( offset )
z - = offset ;
else
z = ONCEILINGZ ;
}
else
{
if ( offset )
z + = offset ;
else
z = ONFLOORZ ;
}
if ( z = = ONFLOORZ )
mthing - > z = 0 ;
else
mthing - > z = ( INT16 ) ( z > > FRACBITS ) ;
}
mobj = P_SpawnMobj ( x , y , z , i ) ;
mobj - > spawnpoint = mthing ;
switch ( mobj - > type )
{
case MT_SKYBOX :
mobj - > angle = 0 ;
if ( mthing - > options & MTF_OBJECTSPECIAL )
skyboxmo [ 1 ] = mobj ;
else
skyboxmo [ 0 ] = mobj ;
break ;
case MT_FAN :
if ( mthing - > options & MTF_OBJECTSPECIAL )
{
P_UnsetThingPosition ( mobj ) ;
if ( sector_list )
{
P_DelSeclist ( sector_list ) ;
sector_list = NULL ;
}
mobj - > flags | = MF_NOSECTOR ; // this flag basically turns it invisible
P_SetThingPosition ( mobj ) ;
}
if ( mthing - > angle )
mobj - > health = mthing - > angle ;
else
2014-08-04 03:49:33 +00:00
mobj - > health = FixedMul ( ss - > sector - > ceilingheight - ss - > sector - > floorheight , 3 * ( FRACUNIT / 4 ) ) > > FRACBITS ;
2014-03-15 16:59:03 +00:00
break ;
case MT_WATERDRIP :
if ( mthing - > angle )
mobj - > tics = 3 * TICRATE + mthing - > angle ;
else
mobj - > tics = 3 * TICRATE ;
break ;
case MT_FLAMEJET :
case MT_VERTICALFLAMEJET :
mobj - > threshold = ( mthing - > angle > > 10 ) & 7 ;
mobj - > movecount = ( mthing - > angle > > 13 ) ;
mobj - > threshold * = ( TICRATE / 2 ) ;
mobj - > movecount * = ( TICRATE / 2 ) ;
mobj - > movedir = mthing - > extrainfo ;
break ;
case MT_MACEPOINT :
case MT_SWINGMACEPOINT :
case MT_HANGMACEPOINT :
case MT_SPINMACEPOINT :
{
fixed_t mlength , mspeed , mxspeed , mzspeed , mstartangle , mmaxspeed ;
mobjtype_t chainlink = MT_SMALLMACECHAIN ;
mobjtype_t macetype = MT_SMALLMACE ;
boolean firsttime ;
mobj_t * spawnee ;
size_t line ;
const size_t mthingi = ( size_t ) ( mthing - mapthings ) ;
// Why does P_FindSpecialLineFromTag not work here?!?
2016-07-06 04:09:17 +00:00
// Monster Iestyn: tag lists haven't been initialised yet for the map, that's why
2014-03-15 16:59:03 +00:00
for ( line = 0 ; line < numlines ; line + + )
{
if ( lines [ line ] . special = = 9 & & lines [ line ] . tag = = mthing - > angle )
break ;
}
if ( line = = numlines )
{
CONS_Debug ( DBG_GAMELOGIC , " Mace chain (mapthing #%s) needs tagged to a #9 parameter line (trying to find tag %d). \n " , sizeu1 ( mthingi ) , mthing - > angle ) ;
return ;
}
/*
No deaf - small mace
Deaf - big mace
ML_NOCLIMB : Direction not controllable
*/
mlength = abs ( lines [ line ] . dx > > FRACBITS ) ;
mspeed = abs ( lines [ line ] . dy > > FRACBITS ) ;
mxspeed = sides [ lines [ line ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
mzspeed = sides [ lines [ line ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
mstartangle = lines [ line ] . frontsector - > floorheight > > FRACBITS ;
mmaxspeed = lines [ line ] . frontsector - > ceilingheight > > FRACBITS ;
mstartangle % = 360 ;
mxspeed % = 360 ;
mzspeed % = 360 ;
CONS_Debug ( DBG_GAMELOGIC , " Mace Chain (mapthing #%s): \n "
" Length is %d \n "
" Speed is %d \n "
" Xspeed is %d \n "
" Zspeed is %d \n "
" startangle is %d \n "
" maxspeed is %d \n " ,
sizeu1 ( mthingi ) , mlength , mspeed , mxspeed , mzspeed , mstartangle , mmaxspeed ) ;
mobj - > lastlook = mspeed < < 4 ;
mobj - > movecount = mobj - > lastlook ;
mobj - > health = ( FixedAngle ( mzspeed * FRACUNIT ) > > ANGLETOFINESHIFT ) + ( FixedAngle ( mstartangle * FRACUNIT ) > > ANGLETOFINESHIFT ) ;
mobj - > threshold = ( FixedAngle ( mxspeed * FRACUNIT ) > > ANGLETOFINESHIFT ) + ( FixedAngle ( mstartangle * FRACUNIT ) > > ANGLETOFINESHIFT ) ;
mobj - > movefactor = mobj - > threshold ;
mobj - > friction = mmaxspeed ;
if ( lines [ line ] . flags & ML_NOCLIMB )
mobj - > flags | = MF_SLIDEME ;
mobj - > reactiontime = 0 ;
if ( mthing - > options & MTF_AMBUSH )
{
chainlink = MT_BIGMACECHAIN ;
macetype = MT_BIGMACE ;
}
if ( mthing - > options & MTF_OBJECTSPECIAL )
mobj - > flags2 | = MF2_BOSSNOTRAP ; // shut up maces.
if ( mobj - > type = = MT_HANGMACEPOINT | | mobj - > type = = MT_SPINMACEPOINT )
firsttime = true ;
else
{
firsttime = false ;
spawnee = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , macetype ) ;
P_SetTarget ( & spawnee - > target , mobj ) ;
if ( mobj - > type = = MT_SWINGMACEPOINT )
spawnee - > movecount = FixedAngle ( mstartangle * FRACUNIT ) > > ANGLETOFINESHIFT ;
else
spawnee - > movecount = 0 ;
spawnee - > threshold = FixedAngle ( mstartangle * FRACUNIT ) > > ANGLETOFINESHIFT ;
spawnee - > reactiontime = mlength + 1 ;
}
while ( mlength > 0 )
{
spawnee = P_SpawnMobj ( mobj - > x , mobj - > y , mobj - > z , chainlink ) ;
P_SetTarget ( & spawnee - > target , mobj ) ;
if ( mobj - > type = = MT_HANGMACEPOINT | | mobj - > type = = MT_SWINGMACEPOINT )
spawnee - > movecount = FixedAngle ( mstartangle * FRACUNIT ) > > ANGLETOFINESHIFT ;
else
spawnee - > movecount = 0 ;
spawnee - > threshold = FixedAngle ( mstartangle * FRACUNIT ) > > ANGLETOFINESHIFT ;
spawnee - > reactiontime = mlength ;
if ( firsttime )
{
// This is the outermost link in the chain
2016-08-22 21:54:30 +00:00
spawnee - > flags2 | = MF2_AMBUSH ;
2014-03-15 16:59:03 +00:00
firsttime = false ;
}
mlength - - ;
}
break ;
}
case MT_ROCKSPAWNER :
mobj - > threshold = mthing - > angle ;
mobj - > movecount = mthing - > extrainfo ;
break ;
case MT_POPUPTURRET :
if ( mthing - > angle )
mobj - > threshold = mthing - > angle ;
else
mobj - > threshold = ( TICRATE * 2 ) - 1 ;
break ;
case MT_NIGHTSBUMPER :
// Lower 4 bits specify the angle of
// the bumper in 30 degree increments.
mobj - > threshold = ( mthing - > options & 15 ) % 12 ; // It loops over, etc
P_SetMobjState ( mobj , mobj - > info - > spawnstate + mobj - > threshold ) ;
// you can shut up now, OBJECTFLIP. And all of the other options, for that matter.
mthing - > options & = ~ 0xF ;
break ;
case MT_EGGCAPSULE :
if ( mthing - > angle < = 0 )
mthing - > angle = 20 ; // prevent 0 health
mobj - > health = mthing - > angle ;
mobj - > threshold = min ( mthing - > extrainfo , 7 ) ;
break ;
case MT_TUBEWAYPOINT :
mobj - > health = mthing - > angle & 255 ;
mobj - > threshold = mthing - > angle > > 8 ;
break ;
case MT_NIGHTSDRONE :
if ( mthing - > angle > 0 )
mobj - > health = mthing - > angle ;
break ;
case MT_TRAPGOYLE :
case MT_TRAPGOYLEUP :
case MT_TRAPGOYLEDOWN :
case MT_TRAPGOYLELONG :
if ( mthing - > angle > = 360 )
mobj - > tics + = 7 * ( mthing - > angle / 360 ) + 1 ; // starting delay
default :
break ;
}
if ( mobj - > flags & MF_BOSS )
{
if ( mthing - > options & MTF_OBJECTSPECIAL ) // No egg trap for this boss
mobj - > flags2 | = MF2_BOSSNOTRAP ;
}
if ( i = = MT_AXIS | | i = = MT_AXISTRANSFER | | i = = MT_AXISTRANSFERLINE ) // Axis Points
{
// Mare it belongs to
mobj - > threshold = min ( mthing - > extrainfo , 7 ) ;
// # in the mare
mobj - > health = mthing - > options ;
mobj - > flags2 | = MF2_AXIS ;
if ( i = = MT_AXIS )
{
// Inverted if uppermost bit is set
if ( mthing - > angle & 16384 )
2016-08-22 21:54:30 +00:00
mobj - > flags2 | = MF2_AMBUSH ;
2014-03-15 16:59:03 +00:00
if ( mthing - > angle > 0 )
mobj - > radius = ( mthing - > angle & 16383 ) * FRACUNIT ;
}
}
else if ( i = = MT_EMMY )
{
if ( mthing - > options & MTF_OBJECTSPECIAL ) // Mario Block version
mobj - > flags & = ~ ( MF_NOGRAVITY | MF_NOCLIPHEIGHT ) ;
else
{
fixed_t zheight = mobj - > z ;
mobj_t * tokenobj ;
if ( mthing - > options & MTF_OBJECTFLIP )
zheight + = mobj - > height - FixedMul ( mobjinfo [ MT_TOKEN ] . height , mobj - > scale ) ; // align with emmy properly!
tokenobj = P_SpawnMobj ( x , y , zheight , MT_TOKEN ) ;
P_SetTarget ( & mobj - > tracer , tokenobj ) ;
tokenobj - > destscale = mobj - > scale ;
P_SetScale ( tokenobj , mobj - > scale ) ;
if ( mthing - > options & MTF_OBJECTFLIP ) // flip token to match emmy
{
tokenobj - > eflags | = MFE_VERTICALFLIP ;
tokenobj - > flags2 | = MF2_OBJECTFLIP ;
}
}
// We advanced tokenbits earlier due to the return check.
// Subtract 1 here for the correct value.
mobj - > health = 1 < < ( tokenbits - 1 ) ;
}
else if ( i = = MT_CYBRAKDEMON & & mthing - > options & MTF_AMBUSH )
{
mobj_t * elecmobj ;
elecmobj = P_SpawnMobj ( x , y , z , MT_CYBRAKDEMON_ELECTRIC_BARRIER ) ;
P_SetTarget ( & elecmobj - > target , mobj ) ;
elecmobj - > angle = FixedAngle ( mthing - > angle * FRACUNIT ) ; ;
elecmobj - > destscale = mobj - > scale * 2 ;
P_SetScale ( elecmobj , elecmobj - > destscale ) ;
}
else if ( i = = MT_STARPOST )
{
thinker_t * th ;
mobj_t * mo2 ;
boolean foundanother = false ;
mobj - > health = ( mthing - > angle / 360 ) + 1 ;
// See if other starposts exist in this level that have the same value.
for ( th = thinkercap . next ; th ! = & thinkercap ; th = th - > next )
{
if ( th - > function . acp1 ! = ( actionf_p1 ) P_MobjThinker )
continue ;
mo2 = ( mobj_t * ) th ;
if ( mo2 = = mobj )
continue ;
if ( mo2 - > type = = MT_STARPOST & & mo2 - > health = = mobj - > health )
{
foundanother = true ;
break ;
}
}
if ( ! foundanother )
numstarposts + + ;
}
2017-02-13 04:24:49 +00:00
else if ( i = = MT_BOSS3WAYPOINT ) // SRB2kart 120217 - Used to store checkpoint num
{
mobj - > health = mthing - > angle ;
2018-09-29 19:28:27 +00:00
P_SetTarget ( & mobj - > tracer , waypointcap ) ;
P_SetTarget ( & waypointcap , mobj ) ;
2017-02-13 04:24:49 +00:00
}
2014-03-15 16:59:03 +00:00
else if ( i = = MT_SPIKE )
{
// Pop up spikes!
if ( mthing - > options & MTF_OBJECTSPECIAL )
{
mobj - > flags & = ~ MF_SCENERY ;
mobj - > fuse = mthing - > angle + mobj - > info - > speed ;
}
// Use per-thing collision for spikes if the deaf flag is checked.
if ( mthing - > options & MTF_AMBUSH & & ! metalrecording )
{
P_UnsetThingPosition ( mobj ) ;
mobj - > flags & = ~ ( MF_NOBLOCKMAP | MF_NOGRAVITY | MF_NOCLIPHEIGHT ) ;
mobj - > flags | = MF_SOLID ;
P_SetThingPosition ( mobj ) ;
}
}
//count 10 ring boxes into the number of rings equation too.
if ( i = = MT_SUPERRINGBOX )
nummaprings + = 10 ;
if ( i = = MT_BIGTUMBLEWEED | | i = = MT_LITTLETUMBLEWEED )
{
if ( mthing - > options & MTF_AMBUSH )
{
mobj - > momz + = FixedMul ( 16 * FRACUNIT , mobj - > scale ) ;
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 2 ) )
2014-03-15 16:59:03 +00:00
mobj - > momx + = FixedMul ( 16 * FRACUNIT , mobj - > scale ) ;
else
mobj - > momx - = FixedMul ( 16 * FRACUNIT , mobj - > scale ) ;
2016-07-06 04:09:17 +00:00
if ( P_RandomChance ( FRACUNIT / 2 ) )
2014-03-15 16:59:03 +00:00
mobj - > momy + = FixedMul ( 16 * FRACUNIT , mobj - > scale ) ;
else
mobj - > momy - = FixedMul ( 16 * FRACUNIT , mobj - > scale ) ;
}
}
// CTF flag pointers
if ( i = = MT_REDFLAG )
{
redflag = mobj ;
rflagpoint = mobj - > spawnpoint ;
}
if ( i = = MT_BLUEFLAG )
{
blueflag = mobj ;
bflagpoint = mobj - > spawnpoint ;
}
// special push/pull stuff
if ( i = = MT_PUSH | | i = = MT_PULL )
{
mobj - > health = 0 ; // Default behaviour: pushing uses XY, fading uses XYZ
if ( mthing - > options & MTF_AMBUSH )
mobj - > health | = 1 ; // If ambush is set, push using XYZ
if ( mthing - > options & MTF_OBJECTSPECIAL )
mobj - > health | = 2 ; // If object special is set, fade using XY
if ( G_IsSpecialStage ( gamemap ) )
{
if ( i = = MT_PUSH )
P_SetMobjState ( mobj , S_GRAVWELLGREEN ) ;
if ( i = = MT_PULL )
P_SetMobjState ( mobj , S_GRAVWELLRED ) ;
}
}
mobj - > angle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
if ( ( mthing - > options & MTF_AMBUSH )
& & ( mthing - > options & MTF_OBJECTSPECIAL )
& & ( mobj - > flags & MF_PUSHABLE ) )
mobj - > flags2 | = MF2_CLASSICPUSH ;
else
{
if ( mthing - > options & MTF_AMBUSH )
{
if ( i = = MT_YELLOWDIAG | | i = = MT_REDDIAG )
mobj - > angle + = ANGLE_22h ;
if ( mobj - > flags & MF_NIGHTSITEM )
{
// Spawn already displayed
mobj - > flags | = MF_SPECIAL ;
mobj - > flags & = ~ MF_NIGHTSITEM ;
P_SetMobjState ( mobj , mobj - > info - > seestate ) ;
}
if ( mobj - > flags & MF_PUSHABLE )
{
mobj - > flags & = ~ MF_PUSHABLE ;
mobj - > flags2 | = MF2_STANDONME ;
}
2014-04-14 05:14:58 +00:00
if ( mobj - > flags & MF_MONITOR )
{
// flag for strong/weak random boxes
if ( mthing - > type = = mobjinfo [ MT_SUPERRINGBOX ] . doomednum | | mthing - > type = = mobjinfo [ MT_PRUP ] . doomednum | |
mthing - > type = = mobjinfo [ MT_SNEAKERTV ] . doomednum | | mthing - > type = = mobjinfo [ MT_INV ] . doomednum | |
mthing - > type = = mobjinfo [ MT_WHITETV ] . doomednum | | mthing - > type = = mobjinfo [ MT_GREENTV ] . doomednum | |
mthing - > type = = mobjinfo [ MT_YELLOWTV ] . doomednum | | mthing - > type = = mobjinfo [ MT_BLUETV ] . doomednum | |
mthing - > type = = mobjinfo [ MT_BLACKTV ] . doomednum | | mthing - > type = = mobjinfo [ MT_PITYTV ] . doomednum | |
mthing - > type = = mobjinfo [ MT_RECYCLETV ] . doomednum | | mthing - > type = = mobjinfo [ MT_MIXUPBOX ] . doomednum )
2016-08-22 21:54:30 +00:00
mobj - > flags2 | = MF2_AMBUSH ;
2014-04-14 05:14:58 +00:00
}
else if ( mthing - > type ! = mobjinfo [ MT_AXIS ] . doomednum & &
2014-03-15 16:59:03 +00:00
mthing - > type ! = mobjinfo [ MT_AXISTRANSFER ] . doomednum & &
mthing - > type ! = mobjinfo [ MT_AXISTRANSFERLINE ] . doomednum & &
mthing - > type ! = mobjinfo [ MT_NIGHTSBUMPER ] . doomednum & &
2014-04-14 05:14:58 +00:00
mthing - > type ! = mobjinfo [ MT_STARPOST ] . doomednum )
2016-08-22 21:54:30 +00:00
mobj - > flags2 | = MF2_AMBUSH ;
2014-03-15 16:59:03 +00:00
}
if ( mthing - > options & MTF_OBJECTSPECIAL )
{
// flag for strong/weak random boxes
2014-04-14 05:14:58 +00:00
if ( mthing - > type = = mobjinfo [ MT_SUPERRINGBOX ] . doomednum | | mthing - > type = = mobjinfo [ MT_PRUP ] . doomednum | |
2014-03-15 16:59:03 +00:00
mthing - > type = = mobjinfo [ MT_SNEAKERTV ] . doomednum | | mthing - > type = = mobjinfo [ MT_INV ] . doomednum | |
mthing - > type = = mobjinfo [ MT_WHITETV ] . doomednum | | mthing - > type = = mobjinfo [ MT_GREENTV ] . doomednum | |
mthing - > type = = mobjinfo [ MT_YELLOWTV ] . doomednum | | mthing - > type = = mobjinfo [ MT_BLUETV ] . doomednum | |
2014-04-14 05:14:58 +00:00
mthing - > type = = mobjinfo [ MT_BLACKTV ] . doomednum | | mthing - > type = = mobjinfo [ MT_PITYTV ] . doomednum | |
mthing - > type = = mobjinfo [ MT_RECYCLETV ] . doomednum | | mthing - > type = = mobjinfo [ MT_MIXUPBOX ] . doomednum )
mobj - > flags2 | = MF2_STRONGBOX ;
2014-03-15 16:59:03 +00:00
// Requires you to be in bonus time to activate
if ( mobj - > flags & MF_NIGHTSITEM )
mobj - > flags2 | = MF2_STRONGBOX ;
// Pushables bounce and slide coolly with object special flag set
if ( mobj - > flags & MF_PUSHABLE )
{
mobj - > flags2 | = MF2_SLIDEPUSH ;
mobj - > flags | = MF_BOUNCE ;
}
}
}
// Generic reverse gravity for individual objects flag.
if ( mthing - > options & MTF_OBJECTFLIP )
{
mobj - > eflags | = MFE_VERTICALFLIP ;
mobj - > flags2 | = MF2_OBJECTFLIP ;
}
mthing - > mobj = mobj ;
}
void P_SpawnHoopsAndRings ( mapthing_t * mthing )
{
mobj_t * mobj = NULL ;
INT32 r , i ;
2014-08-04 03:49:33 +00:00
fixed_t x , y , z , finalx , finaly , finalz ;
sector_t * sec ;
2014-03-15 16:59:03 +00:00
TVector v , * res ;
angle_t closestangle , fa ;
x = mthing - > x < < FRACBITS ;
y = mthing - > y < < FRACBITS ;
2014-08-04 03:49:33 +00:00
sec = R_PointInSubsector ( x , y ) - > sector ;
2014-03-15 16:59:03 +00:00
// NiGHTS hoop!
if ( mthing - > type = = 1705 )
{
mobj_t * nextmobj = NULL ;
mobj_t * hoopcenter ;
INT16 spewangle ;
2014-08-04 03:49:33 +00:00
z = mthing - > options < < FRACBITS ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
hoopcenter = P_SpawnMobj ( x , y , z , MT_HOOPCENTER ) ;
2014-03-15 16:59:03 +00:00
hoopcenter - > spawnpoint = mthing ;
// Screw these damn hoops, I need this thinker.
//hoopcenter->flags |= MF_NOTHINK;
2016-07-06 04:09:17 +00:00
z + =
# ifdef ESLOPE
sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) :
# endif
sec - > floorheight ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
hoopcenter - > z = z - hoopcenter - > height / 2 ;
2014-03-15 16:59:03 +00:00
P_UnsetThingPosition ( hoopcenter ) ;
2014-08-04 03:49:33 +00:00
hoopcenter - > x = x ;
hoopcenter - > y = y ;
2014-03-15 16:59:03 +00:00
P_SetThingPosition ( hoopcenter ) ;
// Scale 0-255 to 0-359 =(
closestangle = FixedAngle ( FixedMul ( ( mthing - > angle > > 8 ) * FRACUNIT ,
360 * ( FRACUNIT / 256 ) ) ) ;
hoopcenter - > movedir = FixedInt ( FixedMul ( ( mthing - > angle & 255 ) * FRACUNIT ,
360 * ( FRACUNIT / 256 ) ) ) ;
hoopcenter - > movecount = FixedInt ( AngleFixed ( closestangle ) ) ;
// For the hoop when it flies away
hoopcenter - > extravalue1 = 32 ;
hoopcenter - > extravalue2 = 8 * FRACUNIT ;
spewangle = ( INT16 ) hoopcenter - > movedir ;
// Create the hoop!
for ( i = 0 ; i < 32 ; i + + )
{
fa = i * ( FINEANGLES / 32 ) ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , 96 * FRACUNIT ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , 96 * FRACUNIT ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( FixedAngle ( spewangle * FRACUNIT ) ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
2014-08-04 03:49:33 +00:00
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
2014-03-15 16:59:03 +00:00
mobj = P_SpawnMobj ( finalx , finaly , finalz , MT_HOOP ) ;
if ( maptol & TOL_XMAS )
P_SetMobjState ( mobj , mobj - > info - > seestate + ( i & 1 ) ) ;
mobj - > z - = mobj - > height / 2 ;
P_SetTarget ( & mobj - > target , hoopcenter ) ; // Link the sprite to the center.
mobj - > fuse = 0 ;
// Link all the sprites in the hoop together
if ( nextmobj )
{
mobj - > hprev = nextmobj ;
mobj - > hprev - > hnext = mobj ;
}
else
mobj - > hprev = mobj - > hnext = NULL ;
nextmobj = mobj ;
}
// Create the collision detectors!
for ( i = 0 ; i < 16 ; i + + )
{
fa = i * FINEANGLES / 16 ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , 32 * FRACUNIT ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , 32 * FRACUNIT ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( FixedAngle ( spewangle * FRACUNIT ) ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
2014-08-04 03:49:33 +00:00
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
2014-03-15 16:59:03 +00:00
mobj = P_SpawnMobj ( finalx , finaly , finalz , MT_HOOPCOLLIDE ) ;
mobj - > z - = mobj - > height / 2 ;
// Link all the collision sprites together.
mobj - > hnext = NULL ;
mobj - > hprev = nextmobj ;
mobj - > hprev - > hnext = mobj ;
nextmobj = mobj ;
}
// Create the collision detectors!
for ( i = 0 ; i < 16 ; i + + )
{
fa = i * FINEANGLES / 16 ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , 64 * FRACUNIT ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , 64 * FRACUNIT ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( FixedAngle ( spewangle * FRACUNIT ) ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
2014-08-04 03:49:33 +00:00
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
2014-03-15 16:59:03 +00:00
mobj = P_SpawnMobj ( finalx , finaly , finalz , MT_HOOPCOLLIDE ) ;
mobj - > z - = mobj - > height / 2 ;
// Link all the collision sprites together.
mobj - > hnext = NULL ;
mobj - > hprev = nextmobj ;
mobj - > hprev - > hnext = mobj ;
nextmobj = mobj ;
}
return ;
}
// CUSTOMIZABLE NiGHTS hoop!
else if ( mthing - > type = = 1713 )
{
mobj_t * nextmobj = NULL ;
mobj_t * hoopcenter ;
INT16 spewangle ;
INT32 hoopsize ;
INT32 hoopplacement ;
// Save our flags!
2014-08-04 03:49:33 +00:00
z = ( mthing - > options > > ZSHIFT ) < < FRACBITS ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
hoopcenter = P_SpawnMobj ( x , y , z , MT_HOOPCENTER ) ;
2014-03-15 16:59:03 +00:00
hoopcenter - > spawnpoint = mthing ;
2016-07-06 04:09:17 +00:00
z + =
# ifdef ESLOPE
sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) :
# endif
sec - > floorheight ;
2014-08-04 03:49:33 +00:00
hoopcenter - > z = z - hoopcenter - > height / 2 ;
2014-03-15 16:59:03 +00:00
P_UnsetThingPosition ( hoopcenter ) ;
2014-08-04 03:49:33 +00:00
hoopcenter - > x = x ;
hoopcenter - > y = y ;
2014-03-15 16:59:03 +00:00
P_SetThingPosition ( hoopcenter ) ;
// Scale 0-255 to 0-359 =(
closestangle = FixedAngle ( FixedMul ( ( mthing - > angle > > 8 ) * FRACUNIT ,
360 * ( FRACUNIT / 256 ) ) ) ;
hoopcenter - > movedir = FixedInt ( FixedMul ( ( mthing - > angle & 255 ) * FRACUNIT ,
360 * ( FRACUNIT / 256 ) ) ) ;
hoopcenter - > movecount = FixedInt ( AngleFixed ( closestangle ) ) ;
spewangle = ( INT16 ) hoopcenter - > movedir ;
// Super happy fun time
// For each flag add 4 fracunits to the size
// Default (0 flags) is 8 fracunits
hoopsize = 8 + ( 4 * ( mthing - > options & 0xF ) ) ;
hoopplacement = hoopsize * ( 4 * FRACUNIT ) ;
// For the hoop when it flies away
hoopcenter - > extravalue1 = hoopsize ;
hoopcenter - > extravalue2 = FixedDiv ( hoopplacement , 12 * FRACUNIT ) ;
// Create the hoop!
for ( i = 0 ; i < hoopsize ; i + + )
{
fa = i * ( FINEANGLES / hoopsize ) ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , hoopplacement ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , hoopplacement ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( FixedAngle ( spewangle * FRACUNIT ) ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
2014-08-04 03:49:33 +00:00
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
2014-03-15 16:59:03 +00:00
mobj = P_SpawnMobj ( finalx , finaly , finalz , MT_HOOP ) ;
if ( maptol & TOL_XMAS )
P_SetMobjState ( mobj , mobj - > info - > seestate + ( i & 1 ) ) ;
mobj - > z - = mobj - > height / 2 ;
P_SetTarget ( & mobj - > target , hoopcenter ) ; // Link the sprite to the center.
mobj - > fuse = 0 ;
// Link all the sprites in the hoop together
if ( nextmobj )
{
mobj - > hprev = nextmobj ;
mobj - > hprev - > hnext = mobj ;
}
else
mobj - > hprev = mobj - > hnext = NULL ;
nextmobj = mobj ;
}
// Create the collision detectors!
// Create them until the size is less than 8
// But always create at least ONE set of collision detectors
do
{
if ( hoopsize > = 32 )
hoopsize - = 16 ;
else
hoopsize / = 2 ;
hoopplacement = hoopsize * ( 4 * FRACUNIT ) ;
for ( i = 0 ; i < hoopsize ; i + + )
{
fa = i * FINEANGLES / hoopsize ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , hoopplacement ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , hoopplacement ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateXMatrix ( FixedAngle ( spewangle * FRACUNIT ) ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
2014-08-04 03:49:33 +00:00
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
2014-03-15 16:59:03 +00:00
mobj = P_SpawnMobj ( finalx , finaly , finalz , MT_HOOPCOLLIDE ) ;
mobj - > z - = mobj - > height / 2 ;
// Link all the collision sprites together.
mobj - > hnext = NULL ;
mobj - > hprev = nextmobj ;
mobj - > hprev - > hnext = mobj ;
nextmobj = mobj ;
}
} while ( hoopsize > = 8 ) ;
return ;
}
// Wing logo item.
else if ( mthing - > type = = mobjinfo [ MT_NIGHTSWING ] . doomednum )
{
2016-07-06 04:09:17 +00:00
z =
# ifdef ESLOPE
sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) :
# endif
sec - > floorheight ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options > > ZSHIFT )
2014-08-04 03:49:33 +00:00
z + = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
mthing - > z = ( INT16 ) ( z > > FRACBITS ) ;
mobj = P_SpawnMobj ( x , y , z , MT_NIGHTSWING ) ;
2014-03-15 16:59:03 +00:00
mobj - > spawnpoint = mthing ;
if ( G_IsSpecialStage ( gamemap ) & & useNightsSS )
P_SetMobjState ( mobj , mobj - > info - > meleestate ) ;
else if ( maptol & TOL_XMAS )
P_SetMobjState ( mobj , mobj - > info - > seestate ) ;
mobj - > angle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
2016-08-22 21:54:30 +00:00
mobj - > flags2 | = MF2_AMBUSH ;
2014-03-15 16:59:03 +00:00
mthing - > mobj = mobj ;
}
// All manners of rings and coins
2018-03-13 05:20:47 +00:00
else if ( mthing - > type = = mobjinfo [ MT_RING ] . doomednum | | mthing - > type = = mobjinfo [ MT_COIN ] . doomednum | |
2014-03-15 16:59:03 +00:00
mthing - > type = = mobjinfo [ MT_REDTEAMRING ] . doomednum | | mthing - > type = = mobjinfo [ MT_BLUETEAMRING ] . doomednum )
{
mobjtype_t ringthing = MT_RING ;
// No rings in Ultimate!
2014-08-04 03:49:33 +00:00
if ( ultimatemode & & ! ( G_IsSpecialStage ( gamemap ) | | maptol & TOL_NIGHTS ) )
2014-03-15 16:59:03 +00:00
return ;
// Which ringthing to use
switch ( mthing - > type )
{
case 1800 :
ringthing = MT_COIN ;
break ;
case 308 : // No team rings in non-CTF
ringthing = ( gametype = = GT_CTF ) ? MT_REDTEAMRING : MT_RING ;
break ;
case 309 : // No team rings in non-CTF
ringthing = ( gametype = = GT_CTF ) ? MT_BLUETEAMRING : MT_RING ;
break ;
default :
// Spawn rings as blue spheres in special stages, ala S3+K.
if ( G_IsSpecialStage ( gamemap ) & & useNightsSS )
ringthing = MT_BLUEBALL ;
break ;
}
// Set proper height
2014-08-04 03:49:33 +00:00
if ( mthing - > options & MTF_OBJECTFLIP )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
sec - > c_slope ? P_GetZAt ( sec - > c_slope , x , y ) :
# endif
sec - > ceilingheight ) - mobjinfo [ ringthing ] . height ;
2014-08-04 03:49:33 +00:00
if ( mthing - > options > > ZSHIFT )
z - = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
}
else
{
2016-07-06 04:09:17 +00:00
z =
# ifdef ESLOPE
sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) :
# endif
sec - > floorheight ;
2014-08-04 03:49:33 +00:00
if ( mthing - > options > > ZSHIFT )
z + = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
}
if ( mthing - > options & MTF_AMBUSH ) // Special flag for rings
{
2014-08-04 03:49:33 +00:00
if ( mthing - > options & MTF_OBJECTFLIP )
z - = 24 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
else
2014-08-04 03:49:33 +00:00
z + = 24 * FRACUNIT ;
2014-03-15 16:59:03 +00:00
}
2014-08-04 03:49:33 +00:00
mthing - > z = ( INT16 ) ( z > > FRACBITS ) ;
mobj = P_SpawnMobj ( x , y , z , ringthing ) ;
2014-03-15 16:59:03 +00:00
mobj - > spawnpoint = mthing ;
if ( mthing - > options & MTF_OBJECTFLIP )
{
mobj - > eflags | = MFE_VERTICALFLIP ;
mobj - > flags2 | = MF2_OBJECTFLIP ;
}
mobj - > angle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
2016-08-22 21:54:30 +00:00
mobj - > flags2 | = MF2_AMBUSH ;
2014-03-15 16:59:03 +00:00
mthing - > mobj = mobj ;
}
// ***
// Special placement patterns
// ***
// Vertical Rings - Stack of 5 (handles both red and yellow)
else if ( mthing - > type = = 600 | | mthing - > type = = 601 )
{
INT32 dist = 64 * FRACUNIT ;
mobjtype_t ringthing = MT_RING ;
if ( mthing - > type = = 601 )
dist = 128 * FRACUNIT ;
// No rings in Ultimate!
2014-08-04 03:49:33 +00:00
if ( ultimatemode & & ! ( G_IsSpecialStage ( gamemap ) | | maptol & TOL_NIGHTS ) )
2014-03-15 16:59:03 +00:00
return ;
// Spawn rings as blue spheres in special stages, ala S3+K.
if ( G_IsSpecialStage ( gamemap ) & & useNightsSS )
ringthing = MT_BLUEBALL ;
for ( r = 1 ; r < = 5 ; r + + )
{
2014-08-04 03:49:33 +00:00
if ( mthing - > options & MTF_OBJECTFLIP )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
sec - > c_slope ? P_GetZAt ( sec - > c_slope , x , y ) :
# endif
sec - > ceilingheight ) - mobjinfo [ ringthing ] . height - dist * r ;
2014-08-04 03:49:33 +00:00
if ( mthing - > options > > ZSHIFT )
z - = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
}
else
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) :
# endif
sec - > floorheight ) + dist * r ;
2014-08-04 03:49:33 +00:00
if ( mthing - > options > > ZSHIFT )
z + = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
}
mobj = P_SpawnMobj ( x , y , z , ringthing ) ;
if ( mthing - > options & MTF_OBJECTFLIP )
{
mobj - > eflags | = MFE_VERTICALFLIP ;
mobj - > flags2 | = MF2_OBJECTFLIP ;
}
mobj - > angle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
if ( mthing - > options & MTF_AMBUSH )
2016-08-22 21:54:30 +00:00
mobj - > flags2 | = MF2_AMBUSH ;
2014-03-15 16:59:03 +00:00
}
}
// Diagonal rings (handles both types)
else if ( mthing - > type = = 602 | | mthing - > type = = 603 ) // Diagonal rings (5)
{
2016-07-06 04:09:17 +00:00
angle_t angle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
2014-03-15 16:59:03 +00:00
mobjtype_t ringthing = MT_RING ;
INT32 iterations = 5 ;
if ( mthing - > type = = 603 )
iterations = 10 ;
// No rings in Ultimate!
2014-08-04 03:49:33 +00:00
if ( ultimatemode & & ! ( G_IsSpecialStage ( gamemap ) | | maptol & TOL_NIGHTS ) )
2014-03-15 16:59:03 +00:00
return ;
// Spawn rings as blue spheres in special stages, ala S3+K.
if ( G_IsSpecialStage ( gamemap ) & & useNightsSS )
ringthing = MT_BLUEBALL ;
angle > > = ANGLETOFINESHIFT ;
for ( r = 1 ; r < = iterations ; r + + )
{
x + = FixedMul ( 64 * FRACUNIT , FINECOSINE ( angle ) ) ;
y + = FixedMul ( 64 * FRACUNIT , FINESINE ( angle ) ) ;
2014-08-04 03:49:33 +00:00
if ( mthing - > options & MTF_OBJECTFLIP )
2014-03-15 16:59:03 +00:00
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
sec - > c_slope ? P_GetZAt ( sec - > c_slope , x , y ) :
# endif
sec - > ceilingheight ) - mobjinfo [ ringthing ] . height - 64 * FRACUNIT * r ;
2014-08-04 03:49:33 +00:00
if ( mthing - > options > > ZSHIFT )
z - = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
}
else
{
2016-07-06 04:09:17 +00:00
z = (
# ifdef ESLOPE
sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) :
# endif
sec - > floorheight ) + 64 * FRACUNIT * r ;
2014-08-04 03:49:33 +00:00
if ( mthing - > options > > ZSHIFT )
z + = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
}
mobj = P_SpawnMobj ( x , y , z , ringthing ) ;
if ( mthing - > options & MTF_OBJECTFLIP )
{
mobj - > eflags | = MFE_VERTICALFLIP ;
mobj - > flags2 | = MF2_OBJECTFLIP ;
}
mobj - > angle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
if ( mthing - > options & MTF_AMBUSH )
2016-08-22 21:54:30 +00:00
mobj - > flags2 | = MF2_AMBUSH ;
2014-03-15 16:59:03 +00:00
}
}
// Rings of items (all six of them)
else if ( mthing - > type > = 604 & & mthing - > type < = 609 )
{
INT32 numitems = 8 ;
INT32 size = 96 * FRACUNIT ;
mobjtype_t itemToSpawn = MT_NIGHTSWING ;
if ( mthing - > type & 1 )
{
numitems = 16 ;
size = 192 * FRACUNIT ;
}
2016-07-06 04:09:17 +00:00
z =
# ifdef ESLOPE
sec - > f_slope ? P_GetZAt ( sec - > f_slope , x , y ) :
# endif
sec - > floorheight ;
2014-03-15 16:59:03 +00:00
if ( mthing - > options > > ZSHIFT )
2014-08-04 03:49:33 +00:00
z + = ( ( mthing - > options > > ZSHIFT ) < < FRACBITS ) ;
2014-03-15 16:59:03 +00:00
closestangle = FixedAngle ( mthing - > angle * FRACUNIT ) ;
// Create the hoop!
for ( i = 0 ; i < numitems ; i + + )
{
switch ( mthing - > type )
{
case 604 :
case 605 :
itemToSpawn = MT_RING ;
break ;
case 608 :
case 609 :
itemToSpawn = ( i & 1 ) ? MT_NIGHTSWING : MT_RING ;
break ;
case 606 :
case 607 :
itemToSpawn = MT_NIGHTSWING ;
break ;
default :
break ;
}
// No rings in Ultimate!
if ( itemToSpawn = = MT_RING )
{
if ( ultimatemode & & ! ( G_IsSpecialStage ( gamemap ) | | ( maptol & TOL_NIGHTS ) ) )
continue ;
// Spawn rings as blue spheres in special stages, ala S3+K.
if ( G_IsSpecialStage ( gamemap ) & & useNightsSS )
itemToSpawn = MT_BLUEBALL ;
}
fa = i * FINEANGLES / numitems ;
v [ 0 ] = FixedMul ( FINECOSINE ( fa ) , size ) ;
v [ 1 ] = 0 ;
v [ 2 ] = FixedMul ( FINESINE ( fa ) , size ) ;
v [ 3 ] = FRACUNIT ;
res = VectorMatrixMultiply ( v , * RotateZMatrix ( closestangle ) ) ;
M_Memcpy ( & v , res , sizeof ( v ) ) ;
2014-08-04 03:49:33 +00:00
finalx = x + v [ 0 ] ;
finaly = y + v [ 1 ] ;
finalz = z + v [ 2 ] ;
2014-03-15 16:59:03 +00:00
mobj = P_SpawnMobj ( finalx , finaly , finalz , itemToSpawn ) ;
mobj - > z - = mobj - > height / 2 ;
if ( itemToSpawn = = MT_NIGHTSWING )
{
if ( G_IsSpecialStage ( gamemap ) & & useNightsSS )
P_SetMobjState ( mobj , mobj - > info - > meleestate ) ;
else if ( ( maptol & TOL_XMAS ) )
P_SetMobjState ( mobj , mobj - > info - > seestate ) ;
}
}
return ;
}
}
//
// P_CheckMissileSpawn
// Moves the missile forward a bit and possibly explodes it right there.
//
boolean P_CheckMissileSpawn ( mobj_t * th )
{
// move a little forward so an angle can be computed if it immediately explodes
2014-03-25 02:17:59 +00:00
if ( ! ( th - > flags & MF_GRENADEBOUNCE ) ) // hack: bad! should be a flag.
2014-03-15 16:59:03 +00:00
{
th - > x + = th - > momx > > 1 ;
th - > y + = th - > momy > > 1 ;
th - > z + = th - > momz > > 1 ;
}
if ( ! P_TryMove ( th , th - > x , th - > y , true ) )
{
P_ExplodeMissile ( th ) ;
return false ;
}
return true ;
}
//
// P_SpawnXYZMissile
//
// Spawns missile at specific coords
//
mobj_t * P_SpawnXYZMissile ( mobj_t * source , mobj_t * dest , mobjtype_t type ,
fixed_t x , fixed_t y , fixed_t z )
{
mobj_t * th ;
angle_t an ;
INT32 dist ;
fixed_t speed ;
I_Assert ( source ! = NULL ) ;
I_Assert ( dest ! = NULL ) ;
if ( source - > eflags & MFE_VERTICALFLIP )
z - = FixedMul ( mobjinfo [ type ] . height , source - > scale ) ;
th = P_SpawnMobj ( x , y , z , type ) ;
if ( source - > eflags & MFE_VERTICALFLIP )
th - > flags2 | = MF2_OBJECTFLIP ;
th - > destscale = source - > scale ;
P_SetScale ( th , source - > scale ) ;
speed = FixedMul ( th - > info - > speed , th - > scale ) ;
if ( speed = = 0 )
{
CONS_Debug ( DBG_GAMELOGIC , " P_SpawnXYZMissile - projectile has 0 speed! (mobj type %d) \n " , type ) ;
speed = mobjinfo [ MT_ROCKET ] . speed ;
}
if ( th - > info - > seesound )
S_StartSound ( th , th - > info - > seesound ) ;
P_SetTarget ( & th - > target , source ) ; // where it came from
an = R_PointToAngle2 ( x , y , dest - > x , dest - > y ) ;
th - > angle = an ;
an > > = ANGLETOFINESHIFT ;
th - > momx = FixedMul ( speed , FINECOSINE ( an ) ) ;
th - > momy = FixedMul ( speed , FINESINE ( an ) ) ;
dist = P_AproxDistance ( dest - > x - x , dest - > y - y ) ;
dist = dist / speed ;
if ( dist < 1 )
dist = 1 ;
th - > momz = ( dest - > z - z ) / dist ;
if ( th - > flags & MF_MISSILE )
dist = P_CheckMissileSpawn ( th ) ;
else
dist = 1 ;
return dist ? th : NULL ;
}
//
// P_SpawnAlteredDirectionMissile
//
// Spawns a missile with same source as spawning missile yet an altered direction
//
mobj_t * P_SpawnAlteredDirectionMissile ( mobj_t * source , mobjtype_t type , fixed_t x , fixed_t y , fixed_t z , INT32 shiftingAngle )
{
mobj_t * th ;
angle_t an ;
fixed_t dist , speed ;
I_Assert ( source ! = NULL ) ;
if ( ! ( source - > target ) | | ! ( source - > flags & MF_MISSILE ) )
return NULL ;
if ( source - > eflags & MFE_VERTICALFLIP )
z - = FixedMul ( mobjinfo [ type ] . height , source - > scale ) ;
th = P_SpawnMobj ( x , y , z , type ) ;
if ( source - > eflags & MFE_VERTICALFLIP )
th - > flags2 | = MF2_OBJECTFLIP ;
th - > destscale = source - > scale ;
P_SetScale ( th , source - > scale ) ;
speed = FixedMul ( th - > info - > speed , th - > scale ) ;
if ( speed = = 0 ) // Backwards compatibility with 1.09.2
{
CONS_Printf ( " P_SpawnAlteredDirectionMissile - projectile has 0 speed! (mobj type %d) \n Please update this SOC. " , type ) ;
speed = mobjinfo [ MT_ROCKET ] . speed ;
}
if ( th - > info - > seesound )
S_StartSound ( th , th - > info - > seesound ) ;
P_SetTarget ( & th - > target , source - > target ) ; // where it came from
2014-08-04 03:49:33 +00:00
an = R_PointToAngle2 ( 0 , 0 , source - > momx , source - > momy ) + ( ANG1 * shiftingAngle ) ;
2014-03-15 16:59:03 +00:00
th - > angle = an ;
an > > = ANGLETOFINESHIFT ;
th - > momx = FixedMul ( speed , FINECOSINE ( an ) ) ;
th - > momy = FixedMul ( speed , FINESINE ( an ) ) ;
dist = P_AproxDistance ( source - > momx * 800 , source - > momy * 800 ) ;
dist = dist / speed ;
if ( dist < 1 )
dist = 1 ;
th - > momz = ( source - > momz * 800 ) / dist ;
if ( th - > flags & MF_MISSILE )
{
dist = P_CheckMissileSpawn ( th ) ;
th - > x - = th - > momx > > 1 ;
th - > y - = th - > momy > > 1 ;
th - > z - = th - > momz > > 1 ;
}
else
dist = 1 ;
return dist ? th : NULL ;
}
//
// P_SpawnPointMissile
//
// Spawns a missile at specific coords
//
mobj_t * P_SpawnPointMissile ( mobj_t * source , fixed_t xa , fixed_t ya , fixed_t za , mobjtype_t type ,
fixed_t x , fixed_t y , fixed_t z )
{
mobj_t * th ;
angle_t an ;
fixed_t dist , speed ;
I_Assert ( source ! = NULL ) ;
if ( source - > eflags & MFE_VERTICALFLIP )
z - = FixedMul ( mobjinfo [ type ] . height , source - > scale ) ;
th = P_SpawnMobj ( x , y , z , type ) ;
if ( source - > eflags & MFE_VERTICALFLIP )
th - > flags2 | = MF2_OBJECTFLIP ;
th - > destscale = source - > scale ;
P_SetScale ( th , source - > scale ) ;
speed = FixedMul ( th - > info - > speed , th - > scale ) ;
if ( speed = = 0 ) // Backwards compatibility with 1.09.2
{
CONS_Printf ( " P_SpawnPointMissile - projectile has 0 speed! (mobj type %d) \n Please update this SOC. " , type ) ;
speed = mobjinfo [ MT_ROCKET ] . speed ;
}
if ( th - > info - > seesound )
S_StartSound ( th , th - > info - > seesound ) ;
P_SetTarget ( & th - > target , source ) ; // where it came from
an = R_PointToAngle2 ( x , y , xa , ya ) ;
th - > angle = an ;
an > > = ANGLETOFINESHIFT ;
th - > momx = FixedMul ( speed , FINECOSINE ( an ) ) ;
th - > momy = FixedMul ( speed , FINESINE ( an ) ) ;
dist = P_AproxDistance ( xa - x , ya - y ) ;
dist = dist / speed ;
if ( dist < 1 )
dist = 1 ;
th - > momz = ( za - z ) / dist ;
if ( th - > flags & MF_MISSILE )
dist = P_CheckMissileSpawn ( th ) ;
else
dist = 1 ;
return dist ? th : NULL ;
}
//
// P_SpawnMissile
//
mobj_t * P_SpawnMissile ( mobj_t * source , mobj_t * dest , mobjtype_t type )
{
mobj_t * th ;
angle_t an ;
INT32 dist ;
fixed_t z ;
const fixed_t gsf = ( fixed_t ) 6 ;
fixed_t speed ;
I_Assert ( source ! = NULL ) ;
I_Assert ( dest ! = NULL ) ;
if ( source - > type = = MT_JETTGUNNER )
{
if ( source - > eflags & MFE_VERTICALFLIP )
z = source - > z + source - > height - FixedMul ( 4 * FRACUNIT , source - > scale ) ;
else
z = source - > z + FixedMul ( 4 * FRACUNIT , source - > scale ) ;
}
else
z = source - > z + source - > height / 2 ;
if ( source - > eflags & MFE_VERTICALFLIP )
z - = FixedMul ( mobjinfo [ type ] . height , source - > scale ) ;
th = P_SpawnMobj ( source - > x , source - > y , z , type ) ;
if ( source - > eflags & MFE_VERTICALFLIP )
th - > flags2 | = MF2_OBJECTFLIP ;
th - > destscale = source - > scale ;
P_SetScale ( th , source - > scale ) ;
if ( source - > type = = MT_METALSONIC_BATTLE & & source - > health < 4 )
speed = FixedMul ( FixedMul ( th - > info - > speed , 3 * FRACUNIT / 2 ) , th - > scale ) ;
else
speed = FixedMul ( th - > info - > speed , th - > scale ) ;
if ( speed = = 0 )
{
CONS_Debug ( DBG_GAMELOGIC , " P_SpawnMissile - projectile has 0 speed! (mobj type %d) \n " , type ) ;
speed = FixedMul ( mobjinfo [ MT_TURRETLASER ] . speed , th - > scale ) ;
}
if ( th - > info - > seesound )
S_StartSound ( source , th - > info - > seesound ) ;
P_SetTarget ( & th - > target , source ) ; // where it came from
if ( type = = MT_TURRETLASER | | type = = MT_ENERGYBALL ) // More accurate!
an = R_PointToAngle2 ( source - > x , source - > y ,
dest - > x + ( dest - > momx * gsf ) ,
dest - > y + ( dest - > momy * gsf ) ) ;
else
an = R_PointToAngle2 ( source - > x , source - > y , dest - > x , dest - > y ) ;
th - > angle = an ;
an > > = ANGLETOFINESHIFT ;
th - > momx = FixedMul ( speed , FINECOSINE ( an ) ) ;
th - > momy = FixedMul ( speed , FINESINE ( an ) ) ;
if ( type = = MT_TURRETLASER | | type = = MT_ENERGYBALL ) // More accurate!
dist = P_AproxDistance ( dest - > x + ( dest - > momx * gsf ) - source - > x , dest - > y + ( dest - > momy * gsf ) - source - > y ) ;
else
dist = P_AproxDistance ( dest - > x - source - > x , dest - > y - source - > y ) ;
dist = dist / speed ;
if ( dist < 1 )
dist = 1 ;
if ( type = = MT_TURRETLASER | | type = = MT_ENERGYBALL ) // More accurate!
th - > momz = ( dest - > z + ( dest - > momz * gsf ) - z ) / dist ;
else
th - > momz = ( dest - > z - z ) / dist ;
if ( th - > flags & MF_MISSILE )
dist = P_CheckMissileSpawn ( th ) ;
else
dist = 1 ;
return dist ? th : NULL ;
}
//
// P_ColorTeamMissile
// Colors a player's ring based on their team
//
void P_ColorTeamMissile ( mobj_t * missile , player_t * source )
{
if ( G_GametypeHasTeams ( ) )
{
if ( source - > ctfteam = = 2 )
missile - > color = skincolor_bluering ;
else if ( source - > ctfteam = = 1 )
missile - > color = skincolor_redring ;
}
/*
else
missile - > color = player - > mo - > color ; //copy color
*/
}
//
// P_SPMAngle
// Fires missile at angle from what is presumably a player
//
mobj_t * P_SPMAngle ( mobj_t * source , mobjtype_t type , angle_t angle , UINT8 allowaim , UINT32 flags2 )
{
mobj_t * th ;
angle_t an ;
fixed_t x , y , z , slope = 0 ;
// angle at which you fire, is player angle
an = angle ;
if ( allowaim ) // aiming allowed?
slope = AIMINGTOSLOPE ( source - > player - > aiming ) ;
x = source - > x ;
y = source - > y ;
if ( source - > eflags & MFE_VERTICALFLIP )
z = source - > z + 2 * source - > height / 3 - FixedMul ( mobjinfo [ type ] . height , source - > scale ) ;
else
z = source - > z + source - > height / 3 ;
th = P_SpawnMobj ( x , y , z , type ) ;
if ( source - > eflags & MFE_VERTICALFLIP )
th - > flags2 | = MF2_OBJECTFLIP ;
th - > destscale = source - > scale ;
P_SetScale ( th , source - > scale ) ;
th - > flags2 | = flags2 ;
// The rail ring has no unique thrown object, so we must do this.
if ( th - > info - > seesound & & ! ( th - > flags2 & MF2_RAILRING ) )
S_StartSound ( source , th - > info - > seesound ) ;
P_SetTarget ( & th - > target , source ) ;
th - > angle = an ;
th - > momx = FixedMul ( th - > info - > speed , FINECOSINE ( an > > ANGLETOFINESHIFT ) ) ;
th - > momy = FixedMul ( th - > info - > speed , FINESINE ( an > > ANGLETOFINESHIFT ) ) ;
if ( allowaim )
{
th - > momx = FixedMul ( th - > momx , FINECOSINE ( source - > player - > aiming > > ANGLETOFINESHIFT ) ) ;
th - > momy = FixedMul ( th - > momy , FINECOSINE ( source - > player - > aiming > > ANGLETOFINESHIFT ) ) ;
}
th - > momz = FixedMul ( th - > info - > speed , slope ) ;
//scaling done here so it doesn't clutter up the code above
th - > momx = FixedMul ( th - > momx , th - > scale ) ;
th - > momy = FixedMul ( th - > momy , th - > scale ) ;
th - > momz = FixedMul ( th - > momz , th - > scale ) ;
slope = P_CheckMissileSpawn ( th ) ;
return slope ? th : NULL ;
}
//
// P_FlashPal
// Flashes a player's palette. ARMAGEDDON BLASTS!
//
void P_FlashPal ( player_t * pl , UINT16 type , UINT16 duration )
{
if ( ! pl )
return ;
pl - > flashcount = duration ;
pl - > flashpal = type ;
}