2019-04-11 22:46:54 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
# include <engine/shared/config.h>
# include <game/mapitems.h>
2020-09-26 19:41:58 +00:00
# include <new>
2019-04-11 22:46:54 +00:00
# include "character.h"
# include "laser.h"
2020-09-26 19:41:58 +00:00
# include "projectile.h"
2019-04-11 22:46:54 +00:00
// Character, "physical" player's part
void CCharacter : : SetWeapon ( int W )
{
if ( W = = m_Core . m_ActiveWeapon )
return ;
m_LastWeapon = m_Core . m_ActiveWeapon ;
m_QueuedWeapon = - 1 ;
2020-07-15 00:47:51 +00:00
SetActiveWeapon ( W ) ;
2019-04-11 22:46:54 +00:00
if ( m_Core . m_ActiveWeapon < 0 | | m_Core . m_ActiveWeapon > = NUM_WEAPONS )
2020-07-15 00:47:51 +00:00
SetActiveWeapon ( 0 ) ;
2019-04-11 22:46:54 +00:00
}
void CCharacter : : SetSolo ( bool Solo )
{
2020-04-25 23:12:34 +00:00
m_Core . m_Solo = Solo ;
2019-04-11 22:46:54 +00:00
TeamsCore ( ) - > SetSolo ( GetCID ( ) , Solo ) ;
}
bool CCharacter : : IsGrounded ( )
{
2020-09-26 19:41:58 +00:00
if ( Collision ( ) - > CheckPoint ( m_Pos . x + m_ProximityRadius / 2 , m_Pos . y + m_ProximityRadius / 2 + 5 ) )
2019-04-11 22:46:54 +00:00
return true ;
2020-09-26 19:41:58 +00:00
if ( Collision ( ) - > CheckPoint ( m_Pos . x - m_ProximityRadius / 2 , m_Pos . y + m_ProximityRadius / 2 + 5 ) )
2019-04-11 22:46:54 +00:00
return true ;
2018-08-15 15:47:07 +00:00
int MoveRestrictionsBelow = Collision ( ) - > GetMoveRestrictions ( m_Pos + vec2 ( 0 , m_ProximityRadius / 2 + 4 ) , 0.0f ) ;
2022-01-22 16:34:23 +00:00
return ( MoveRestrictionsBelow & CANTMOVE_DOWN ) ! = 0 ;
2019-04-11 22:46:54 +00:00
}
void CCharacter : : HandleJetpack ( )
{
if ( m_NumInputs < 2 )
return ;
vec2 Direction = normalize ( vec2 ( m_LatestInput . m_TargetX , m_LatestInput . m_TargetY ) ) ;
bool FullAuto = false ;
2019-11-22 14:37:18 +00:00
if ( m_Core . m_ActiveWeapon = = WEAPON_GRENADE | | m_Core . m_ActiveWeapon = = WEAPON_SHOTGUN | | m_Core . m_ActiveWeapon = = WEAPON_LASER )
2019-04-11 22:46:54 +00:00
FullAuto = true ;
2020-09-26 19:41:58 +00:00
if ( m_Jetpack & & m_Core . m_ActiveWeapon = = WEAPON_GUN )
2019-04-11 22:46:54 +00:00
FullAuto = true ;
// check if we gonna fire
bool WillFire = false ;
if ( CountInput ( m_LatestPrevInput . m_Fire , m_LatestInput . m_Fire ) . m_Presses )
WillFire = true ;
2022-03-21 22:50:41 +00:00
if ( FullAuto & & ( m_LatestInput . m_Fire & 1 ) & & m_Core . m_aWeapons [ m_Core . m_ActiveWeapon ] . m_Ammo )
2019-04-11 22:46:54 +00:00
WillFire = true ;
if ( ! WillFire )
return ;
// check for ammo
2022-03-21 22:50:41 +00:00
if ( ! m_Core . m_aWeapons [ m_Core . m_ActiveWeapon ] . m_Ammo | | m_FreezeTime )
2019-04-11 22:46:54 +00:00
{
return ;
}
switch ( m_Core . m_ActiveWeapon )
{
2020-09-26 19:41:58 +00:00
case WEAPON_GUN :
{
if ( m_Jetpack )
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
float Strength = GetTuning ( m_TuneZone ) - > m_JetpackStrength ;
if ( ! m_TuneZone )
Strength = m_LastJetpackStrength ;
TakeDamage ( Direction * - 1.0f * ( Strength / 100.0f / 6.11f ) , 0 , GetCID ( ) , m_Core . m_ActiveWeapon ) ;
2019-04-11 22:46:54 +00:00
}
}
2020-09-26 19:41:58 +00:00
}
2019-04-11 22:46:54 +00:00
}
void CCharacter : : RemoveNinja ( )
{
2022-03-24 00:05:41 +00:00
m_Core . m_Ninja . m_CurrentMoveTime = 0 ;
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ WEAPON_NINJA ] . m_Got = false ;
2019-04-11 22:46:54 +00:00
m_Core . m_ActiveWeapon = m_LastWeapon ;
SetWeapon ( m_Core . m_ActiveWeapon ) ;
}
void CCharacter : : HandleNinja ( )
{
if ( m_Core . m_ActiveWeapon ! = WEAPON_NINJA )
return ;
2022-03-24 00:05:41 +00:00
if ( ( GameWorld ( ) - > GameTick ( ) - m_Core . m_Ninja . m_ActivationTick ) > ( g_pData - > m_Weapons . m_Ninja . m_Duration * GameWorld ( ) - > GameTickSpeed ( ) / 1000 ) )
2019-04-11 22:46:54 +00:00
{
// time's up, return
RemoveNinja ( ) ;
return ;
}
// force ninja Weapon
SetWeapon ( WEAPON_NINJA ) ;
2022-03-24 00:05:41 +00:00
m_Core . m_Ninja . m_CurrentMoveTime - - ;
2019-04-11 22:46:54 +00:00
2022-03-24 00:05:41 +00:00
if ( m_Core . m_Ninja . m_CurrentMoveTime = = 0 )
2019-04-11 22:46:54 +00:00
{
// reset velocity
2022-03-24 00:05:41 +00:00
m_Core . m_Vel = m_Core . m_Ninja . m_ActivationDir * m_Core . m_Ninja . m_OldVelAmount ;
2019-04-11 22:46:54 +00:00
}
2022-03-24 00:05:41 +00:00
if ( m_Core . m_Ninja . m_CurrentMoveTime > 0 )
2019-04-11 22:46:54 +00:00
{
// Set velocity
2022-03-24 00:05:41 +00:00
m_Core . m_Vel = m_Core . m_Ninja . m_ActivationDir * g_pData - > m_Weapons . m_Ninja . m_Velocity ;
2019-04-11 22:46:54 +00:00
vec2 OldPos = m_Pos ;
Collision ( ) - > MoveBox ( & m_Core . m_Pos , & m_Core . m_Vel , vec2 ( m_ProximityRadius , m_ProximityRadius ) , 0.f ) ;
// reset velocity so the client doesn't predict stuff
m_Core . m_Vel = vec2 ( 0.f , 0.f ) ;
// check if we Hit anything along the way
{
CCharacter * aEnts [ MAX_CLIENTS ] ;
vec2 Dir = m_Pos - OldPos ;
float Radius = m_ProximityRadius * 2.0f ;
vec2 Center = OldPos + Dir * 0.5f ;
2020-09-26 19:41:58 +00:00
int Num = GameWorld ( ) - > FindEntities ( Center , Radius , ( CEntity * * ) aEnts , MAX_CLIENTS , CGameWorld : : ENTTYPE_CHARACTER ) ;
2019-04-11 22:46:54 +00:00
// check that we're not in solo part
2020-09-26 19:41:58 +00:00
if ( TeamsCore ( ) - > GetSolo ( GetCID ( ) ) )
2019-04-11 22:46:54 +00:00
return ;
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < Num ; + + i )
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
if ( aEnts [ i ] = = this )
2019-04-11 22:46:54 +00:00
continue ;
// Don't hit players in other teams
2020-09-26 19:41:58 +00:00
if ( Team ( ) ! = aEnts [ i ] - > Team ( ) )
2019-04-11 22:46:54 +00:00
continue ;
// Don't hit players in solo parts
2020-09-26 19:41:58 +00:00
if ( TeamsCore ( ) - > GetSolo ( aEnts [ i ] - > GetCID ( ) ) )
2019-04-11 22:46:54 +00:00
return ;
// make sure we haven't Hit this object before
bool bAlreadyHit = false ;
2020-09-26 19:41:58 +00:00
for ( int j = 0 ; j < m_NumObjectsHit ; j + + )
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_aHitObjects [ j ] = = aEnts [ i ] - > GetCID ( ) )
2019-04-11 22:46:54 +00:00
bAlreadyHit = true ;
}
2020-09-26 19:41:58 +00:00
if ( bAlreadyHit )
2019-04-11 22:46:54 +00:00
continue ;
// check so we are sufficiently close
2020-09-26 19:41:58 +00:00
if ( distance ( aEnts [ i ] - > m_Pos , m_Pos ) > ( m_ProximityRadius * 2.0f ) )
2019-04-11 22:46:54 +00:00
continue ;
// Hit a player, give him damage and stuffs...
// set his velocity to fast upward (for now)
if ( m_NumObjectsHit < 10 )
m_aHitObjects [ m_NumObjectsHit + + ] = aEnts [ i ] - > GetCID ( ) ;
CCharacter * pChar = GameWorld ( ) - > GetCharacterByID ( aEnts [ i ] - > GetCID ( ) ) ;
if ( pChar )
pChar - > TakeDamage ( vec2 ( 0 , - 10.0f ) , g_pData - > m_Weapons . m_Ninja . m_pBase - > m_Damage , GetCID ( ) , WEAPON_NINJA ) ;
}
}
return ;
}
}
void CCharacter : : DoWeaponSwitch ( )
{
// make sure we can switch
2022-03-21 22:50:41 +00:00
if ( m_ReloadTimer ! = 0 | | m_QueuedWeapon = = - 1 | | m_Core . m_aWeapons [ WEAPON_NINJA ] . m_Got | | ! m_Core . m_aWeapons [ m_QueuedWeapon ] . m_Got )
2019-04-11 22:46:54 +00:00
return ;
// switch Weapon
SetWeapon ( m_QueuedWeapon ) ;
}
void CCharacter : : HandleWeaponSwitch ( )
{
if ( m_NumInputs < 2 )
return ;
int WantedWeapon = m_Core . m_ActiveWeapon ;
if ( m_QueuedWeapon ! = - 1 )
WantedWeapon = m_QueuedWeapon ;
bool Anything = false ;
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < NUM_WEAPONS - 1 ; + + i )
2022-03-21 22:50:41 +00:00
if ( m_Core . m_aWeapons [ i ] . m_Got )
2020-09-26 19:41:58 +00:00
Anything = true ;
if ( ! Anything )
return ;
2019-04-11 22:46:54 +00:00
// select Weapon
int Next = CountInput ( m_LatestPrevInput . m_NextWeapon , m_LatestInput . m_NextWeapon ) . m_Presses ;
int Prev = CountInput ( m_LatestPrevInput . m_PrevWeapon , m_LatestInput . m_PrevWeapon ) . m_Presses ;
if ( Next < 128 ) // make sure we only try sane stuff
{
while ( Next ) // Next Weapon selection
{
2020-09-26 19:41:58 +00:00
WantedWeapon = ( WantedWeapon + 1 ) % NUM_WEAPONS ;
2022-03-21 22:50:41 +00:00
if ( m_Core . m_aWeapons [ WantedWeapon ] . m_Got )
2019-04-11 22:46:54 +00:00
Next - - ;
}
}
if ( Prev < 128 ) // make sure we only try sane stuff
{
while ( Prev ) // Prev Weapon selection
{
2020-09-26 19:41:58 +00:00
WantedWeapon = ( WantedWeapon - 1 ) < 0 ? NUM_WEAPONS - 1 : WantedWeapon - 1 ;
2022-03-21 22:50:41 +00:00
if ( m_Core . m_aWeapons [ WantedWeapon ] . m_Got )
2019-04-11 22:46:54 +00:00
Prev - - ;
}
}
// Direct Weapon selection
if ( m_LatestInput . m_WantedWeapon )
2020-09-26 19:41:58 +00:00
WantedWeapon = m_Input . m_WantedWeapon - 1 ;
2019-04-11 22:46:54 +00:00
// check for insane values
2022-03-21 22:50:41 +00:00
if ( WantedWeapon > = 0 & & WantedWeapon < NUM_WEAPONS & & WantedWeapon ! = m_Core . m_ActiveWeapon & & m_Core . m_aWeapons [ WantedWeapon ] . m_Got )
2019-04-11 22:46:54 +00:00
m_QueuedWeapon = WantedWeapon ;
DoWeaponSwitch ( ) ;
}
void CCharacter : : FireWeapon ( )
{
if ( m_NumInputs < 2 )
return ;
if ( ! GameWorld ( ) - > m_WorldConfig . m_PredictWeapons )
return ;
if ( m_ReloadTimer ! = 0 )
return ;
DoWeaponSwitch ( ) ;
vec2 Direction = normalize ( vec2 ( m_LatestInput . m_TargetX , m_LatestInput . m_TargetY ) ) ;
bool FullAuto = false ;
2019-11-22 14:37:18 +00:00
if ( m_Core . m_ActiveWeapon = = WEAPON_GRENADE | | m_Core . m_ActiveWeapon = = WEAPON_SHOTGUN | | m_Core . m_ActiveWeapon = = WEAPON_LASER )
2019-04-11 22:46:54 +00:00
FullAuto = true ;
2020-04-25 23:12:34 +00:00
if ( m_Jetpack & & m_Core . m_ActiveWeapon = = WEAPON_GUN )
FullAuto = true ;
if ( m_FrozenLastTick )
2019-04-11 22:46:54 +00:00
FullAuto = true ;
2019-10-15 13:13:23 +00:00
// don't fire hammer when player is deep and sv_deepfly is disabled
2019-10-16 05:08:44 +00:00
if ( ! g_Config . m_SvDeepfly & & m_Core . m_ActiveWeapon = = WEAPON_HAMMER & & m_DeepFreeze )
2019-04-11 22:46:54 +00:00
return ;
// check if we gonna fire
bool WillFire = false ;
if ( CountInput ( m_LatestPrevInput . m_Fire , m_LatestInput . m_Fire ) . m_Presses )
WillFire = true ;
2022-03-21 22:50:41 +00:00
if ( FullAuto & & ( m_LatestInput . m_Fire & 1 ) & & m_Core . m_aWeapons [ m_Core . m_ActiveWeapon ] . m_Ammo )
2019-04-11 22:46:54 +00:00
WillFire = true ;
if ( ! WillFire )
return ;
// check for ammo
2022-03-21 22:50:41 +00:00
if ( ! m_Core . m_aWeapons [ m_Core . m_ActiveWeapon ] . m_Ammo | | m_FreezeTime )
2019-04-11 22:46:54 +00:00
{
return ;
}
2020-09-26 19:41:58 +00:00
vec2 ProjStartPos = m_Pos + Direction * m_ProximityRadius * 0.75f ;
2019-04-11 22:46:54 +00:00
switch ( m_Core . m_ActiveWeapon )
{
2020-09-26 19:41:58 +00:00
case WEAPON_HAMMER :
{
// reset objects Hit
m_NumObjectsHit = 0 ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
if ( m_Hit & DISABLE_HIT_HAMMER )
break ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
CCharacter * apEnts [ MAX_CLIENTS ] ;
int Hits = 0 ;
int Num = GameWorld ( ) - > FindEntities ( ProjStartPos , m_ProximityRadius * 0.5f , ( CEntity * * ) apEnts ,
MAX_CLIENTS , CGameWorld : : ENTTYPE_CHARACTER ) ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < Num ; + + i )
{
CCharacter * pTarget = apEnts [ i ] ;
2019-04-11 22:46:54 +00:00
2022-05-26 21:06:17 +00:00
if ( ( pTarget = = this | | ! CanCollide ( pTarget - > GetCID ( ) ) ) )
2020-09-26 19:41:58 +00:00
continue ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
// set his velocity to fast upward (for now)
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
vec2 Dir ;
if ( length ( pTarget - > m_Pos - m_Pos ) > 0.0f )
Dir = normalize ( pTarget - > m_Pos - m_Pos ) ;
else
Dir = vec2 ( 0.f , - 1.f ) ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
float Strength = GetTuning ( m_TuneZone ) - > m_HammerStrength ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
vec2 Temp = pTarget - > m_Core . m_Vel + normalize ( Dir + vec2 ( 0.f , - 1.1f ) ) * 10.0f ;
Temp = ClampVel ( pTarget - > m_MoveRestrictions , Temp ) ;
Temp - = pTarget - > m_Core . m_Vel ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
vec2 Force = vec2 ( 0.f , - 1.0f ) + Temp ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
if ( GameWorld ( ) - > m_WorldConfig . m_IsFNG )
{
if ( m_GameTeam = = pTarget - > m_GameTeam & & pTarget - > m_LastSnapWeapon = = WEAPON_NINJA ) // melt hammer
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
Force . x * = 50 * 0.01f ;
Force . y * = 50 * 0.01f ;
2019-04-11 22:46:54 +00:00
}
else
2020-09-26 19:41:58 +00:00
{
Force . x * = 320 * 0.01f ;
Force . y * = 120 * 0.01f ;
}
2019-04-11 22:46:54 +00:00
}
2020-09-26 19:41:58 +00:00
else
Force * = Strength ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
pTarget - > TakeDamage ( Force , g_pData - > m_Weapons . m_Hammer . m_pBase - > m_Damage ,
GetCID ( ) , m_Core . m_ActiveWeapon ) ;
pTarget - > UnFreeze ( ) ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
Hits + + ;
}
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
// if we Hit anything, we have to wait for the reload
if ( Hits )
2021-04-25 09:29:07 +00:00
{
float FireDelay = GetTuning ( m_TuneZone ) - > m_HammerHitFireDelay ;
m_ReloadTimer = FireDelay * GameWorld ( ) - > GameTickSpeed ( ) / 1000 ;
}
2020-09-26 19:41:58 +00:00
}
break ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
case WEAPON_GUN :
{
if ( ! m_Jetpack )
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
int Lifetime = ( int ) ( GameWorld ( ) - > GameTickSpeed ( ) * GetTuning ( m_TuneZone ) - > m_GunLifetime ) ;
new CProjectile (
GameWorld ( ) ,
WEAPON_GUN , //Type
GetCID ( ) , //Owner
ProjStartPos , //Pos
Direction , //Dir
Lifetime , //Span
2022-02-14 23:12:52 +00:00
false , //Freeze
false , //Explosive
2020-09-26 19:41:58 +00:00
0 , //Force
- 1 //SoundImpact
) ;
}
}
break ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
case WEAPON_SHOTGUN :
{
if ( GameWorld ( ) - > m_WorldConfig . m_IsVanilla )
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
int ShotSpread = 2 ;
for ( int i = - ShotSpread ; i < = ShotSpread ; + + i )
{
float Spreading [ ] = { - 0.185f , - 0.070f , 0 , 0.070f , 0.185f } ;
2014-02-18 16:20:28 +00:00
float a = angle ( Direction ) ;
2020-09-26 19:41:58 +00:00
a + = Spreading [ i + 2 ] ;
float v = 1 - ( absolute ( i ) / ( float ) ShotSpread ) ;
float Speed = mix ( ( float ) Tuning ( ) - > m_ShotgunSpeeddiff , 1.0f , v ) ;
new CProjectile (
2019-04-11 22:46:54 +00:00
GameWorld ( ) ,
2020-09-26 19:41:58 +00:00
WEAPON_SHOTGUN , //Type
GetCID ( ) , //Owner
ProjStartPos , //Pos
vec2 ( cosf ( a ) , sinf ( a ) ) * Speed , //Dir
( int ) ( GameWorld ( ) - > GameTickSpeed ( ) * Tuning ( ) - > m_ShotgunLifetime ) , //Span
2022-02-14 23:12:52 +00:00
false , //Freeze
false , //Explosive
2020-09-26 19:41:58 +00:00
0 , //Force
- 1 //SoundImpact
) ;
}
}
else if ( GameWorld ( ) - > m_WorldConfig . m_IsDDRace )
2019-04-11 22:46:54 +00:00
{
2019-09-15 22:07:42 +00:00
float LaserReach = GetTuning ( m_TuneZone ) - > m_LaserReach ;
2019-09-08 22:53:07 +00:00
2020-09-26 19:41:58 +00:00
new CLaser ( GameWorld ( ) , m_Pos , Direction , LaserReach , GetCID ( ) , WEAPON_SHOTGUN ) ;
}
}
break ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
case WEAPON_GRENADE :
{
int Lifetime = ( int ) ( GameWorld ( ) - > GameTickSpeed ( ) * GetTuning ( m_TuneZone ) - > m_GrenadeLifetime ) ;
new CProjectile (
GameWorld ( ) ,
WEAPON_GRENADE , //Type
GetCID ( ) , //Owner
ProjStartPos , //Pos
Direction , //Dir
Lifetime , //Span
2022-02-14 23:12:52 +00:00
false , //Freeze
2020-09-26 19:41:58 +00:00
true , //Explosive
0 , //Force
SOUND_GRENADE_EXPLODE //SoundImpact
) ; //SoundImpact
}
break ;
case WEAPON_LASER :
{
float LaserReach = GetTuning ( m_TuneZone ) - > m_LaserReach ;
new CLaser ( GameWorld ( ) , m_Pos , Direction , LaserReach , GetCID ( ) , WEAPON_LASER ) ;
}
break ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
case WEAPON_NINJA :
{
// reset Hit objects
m_NumObjectsHit = 0 ;
2019-04-11 22:46:54 +00:00
2022-03-24 00:05:41 +00:00
m_Core . m_Ninja . m_ActivationDir = Direction ;
m_Core . m_Ninja . m_CurrentMoveTime = g_pData - > m_Weapons . m_Ninja . m_Movetime * GameWorld ( ) - > GameTickSpeed ( ) / 1000 ;
m_Core . m_Ninja . m_OldVelAmount = length ( m_Core . m_Vel ) ;
2020-09-26 19:41:58 +00:00
}
break ;
2019-04-11 22:46:54 +00:00
}
2019-05-04 18:24:48 +00:00
m_AttackTick = GameWorld ( ) - > GameTick ( ) ;
2019-04-11 22:46:54 +00:00
if ( ! m_ReloadTimer )
{
float FireDelay ;
2019-09-15 22:07:42 +00:00
GetTuning ( m_TuneZone ) - > Get ( 38 + m_Core . m_ActiveWeapon , & FireDelay ) ;
2019-09-08 22:53:07 +00:00
2019-04-11 22:46:54 +00:00
m_ReloadTimer = FireDelay * GameWorld ( ) - > GameTickSpeed ( ) / 1000 ;
}
}
void CCharacter : : HandleWeapons ( )
{
//ninja
HandleNinja ( ) ;
HandleJetpack ( ) ;
// check reload timer
if ( m_ReloadTimer )
{
m_ReloadTimer - - ;
return ;
}
// fire Weapon, if wanted
FireWeapon ( ) ;
}
void CCharacter : : GiveNinja ( )
{
2022-03-24 00:05:41 +00:00
m_Core . m_Ninja . m_ActivationTick = GameWorld ( ) - > GameTick ( ) ;
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ WEAPON_NINJA ] . m_Got = true ;
2020-09-26 19:41:58 +00:00
if ( ! m_FreezeTime )
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ WEAPON_NINJA ] . m_Ammo = - 1 ;
2020-09-26 19:41:58 +00:00
if ( m_Core . m_ActiveWeapon ! = WEAPON_NINJA )
2019-04-11 22:46:54 +00:00
m_LastWeapon = m_Core . m_ActiveWeapon ;
m_Core . m_ActiveWeapon = WEAPON_NINJA ;
}
void CCharacter : : OnPredictedInput ( CNetObj_PlayerInput * pNewInput )
{
2020-07-15 01:15:35 +00:00
// skip the input if chat is active
2022-05-21 16:17:10 +00:00
if ( ! GameWorld ( ) - > m_WorldConfig . m_BugDDRaceInput & & pNewInput - > m_PlayerFlags & PLAYERFLAG_CHATTING )
2022-05-19 21:05:15 +00:00
{
// save reseted input
mem_copy ( & m_SavedInput , & m_Input , sizeof ( m_SavedInput ) ) ;
2020-07-15 01:15:35 +00:00
return ;
2022-05-19 21:05:15 +00:00
}
2020-07-15 01:15:35 +00:00
2019-04-11 22:46:54 +00:00
// copy new input
mem_copy ( & m_Input , pNewInput , sizeof ( m_Input ) ) ;
//m_NumInputs++;
// it is not allowed to aim in the center
if ( m_Input . m_TargetX = = 0 & & m_Input . m_TargetY = = 0 )
m_Input . m_TargetY = - 1 ;
2020-04-25 23:12:34 +00:00
mem_copy ( & m_SavedInput , & m_Input , sizeof ( m_SavedInput ) ) ;
2019-04-11 22:46:54 +00:00
}
void CCharacter : : OnDirectInput ( CNetObj_PlayerInput * pNewInput )
{
2020-07-15 01:15:35 +00:00
// skip the input if chat is active
2022-05-21 16:17:10 +00:00
if ( ! GameWorld ( ) - > m_WorldConfig . m_BugDDRaceInput & & pNewInput - > m_PlayerFlags & PLAYERFLAG_CHATTING )
2020-07-15 01:15:35 +00:00
{
// reset input
ResetInput ( ) ;
2022-05-21 16:52:14 +00:00
// mods that do not allow inputs to be held while chatting also do not allow to hold hook
m_Input . m_Hook = 0 ;
2020-07-15 01:15:35 +00:00
return ;
}
2019-04-11 22:46:54 +00:00
m_NumInputs + + ;
mem_copy ( & m_LatestPrevInput , & m_LatestInput , sizeof ( m_LatestInput ) ) ;
mem_copy ( & m_LatestInput , pNewInput , sizeof ( m_LatestInput ) ) ;
// it is not allowed to aim in the center
if ( m_LatestInput . m_TargetX = = 0 & & m_LatestInput . m_TargetY = = 0 )
m_LatestInput . m_TargetY = - 1 ;
2022-04-28 13:34:25 +00:00
if ( m_NumInputs > 1 & & Team ( ) ! = TEAM_SPECTATORS )
2019-04-11 22:46:54 +00:00
{
HandleWeaponSwitch ( ) ;
FireWeapon ( ) ;
}
mem_copy ( & m_LatestPrevInput , & m_LatestInput , sizeof ( m_LatestInput ) ) ;
}
2020-07-15 01:15:35 +00:00
void CCharacter : : ResetInput ( )
{
2020-09-26 19:41:58 +00:00
m_Input . m_Direction = 0 ;
2022-05-21 16:52:14 +00:00
// m_Input.m_Hook = 0;
2020-09-26 19:41:58 +00:00
// simulate releasing the fire button
if ( ( m_Input . m_Fire & 1 ) ! = 0 )
m_Input . m_Fire + + ;
m_Input . m_Fire & = INPUT_STATE_MASK ;
m_Input . m_Jump = 0 ;
m_LatestPrevInput = m_LatestInput = m_Input ;
2020-07-15 01:15:35 +00:00
}
2019-04-11 22:46:54 +00:00
void CCharacter : : Tick ( )
{
DDRaceTick ( ) ;
m_Core . m_Input = m_Input ;
m_Core . Tick ( true ) ;
// handle Weapons
HandleWeapons ( ) ;
DDRacePostCoreTick ( ) ;
// Previnput
m_PrevInput = m_Input ;
2019-05-11 19:13:09 +00:00
m_PrevPrevPos = m_PrevPos ;
2019-04-11 22:46:54 +00:00
m_PrevPos = m_Core . m_Pos ;
}
void CCharacter : : TickDefered ( )
{
m_Core . Move ( ) ;
m_Core . Quantize ( ) ;
m_Pos = m_Core . m_Pos ;
}
bool CCharacter : : TakeDamage ( vec2 Force , int Dmg , int From , int Weapon )
{
2020-04-25 23:12:34 +00:00
vec2 Temp = m_Core . m_Vel + Force ;
m_Core . m_Vel = ClampVel ( m_MoveRestrictions , Temp ) ;
2019-04-11 22:46:54 +00:00
return true ;
}
// DDRace
bool CCharacter : : CanCollide ( int ClientID )
{
return TeamsCore ( ) - > CanCollide ( GetCID ( ) , ClientID ) ;
}
bool CCharacter : : SameTeam ( int ClientID )
{
return TeamsCore ( ) - > SameTeam ( GetCID ( ) , ClientID ) ;
}
int CCharacter : : Team ( )
{
return TeamsCore ( ) - > Team ( GetCID ( ) ) ;
}
void CCharacter : : HandleSkippableTiles ( int Index )
{
if ( Index < 0 )
return ;
// handle speedup tiles
if ( Collision ( ) - > IsSpeedup ( Index ) )
{
2020-11-20 11:14:04 +00:00
vec2 Direction , TempVel = m_Core . m_Vel ;
2019-04-11 22:46:54 +00:00
int Force , MaxSpeed = 0 ;
float TeeAngle , SpeederAngle , DiffAngle , SpeedLeft , TeeSpeed ;
Collision ( ) - > GetSpeedup ( Index , & Direction , & Force , & MaxSpeed ) ;
if ( Force = = 255 & & MaxSpeed )
{
2020-09-26 19:41:58 +00:00
m_Core . m_Vel = Direction * ( MaxSpeed / 5 ) ;
2019-04-11 22:46:54 +00:00
}
else
{
2020-09-26 19:41:58 +00:00
if ( MaxSpeed > 0 & & MaxSpeed < 5 )
MaxSpeed = 5 ;
2019-04-11 22:46:54 +00:00
if ( MaxSpeed > 0 )
{
if ( Direction . x > 0.0000001f )
SpeederAngle = - atan ( Direction . y / Direction . x ) ;
else if ( Direction . x < 0.0000001f )
SpeederAngle = atan ( Direction . y / Direction . x ) + 2.0f * asin ( 1.0f ) ;
else if ( Direction . y > 0.0000001f )
SpeederAngle = asin ( 1.0f ) ;
else
SpeederAngle = asin ( - 1.0f ) ;
if ( SpeederAngle < 0 )
SpeederAngle = 4.0f * asin ( 1.0f ) + SpeederAngle ;
if ( TempVel . x > 0.0000001f )
TeeAngle = - atan ( TempVel . y / TempVel . x ) ;
else if ( TempVel . x < 0.0000001f )
TeeAngle = atan ( TempVel . y / TempVel . x ) + 2.0f * asin ( 1.0f ) ;
else if ( TempVel . y > 0.0000001f )
TeeAngle = asin ( 1.0f ) ;
else
TeeAngle = asin ( - 1.0f ) ;
if ( TeeAngle < 0 )
TeeAngle = 4.0f * asin ( 1.0f ) + TeeAngle ;
TeeSpeed = sqrt ( pow ( TempVel . x , 2 ) + pow ( TempVel . y , 2 ) ) ;
DiffAngle = SpeederAngle - TeeAngle ;
SpeedLeft = MaxSpeed / 5.0f - cos ( DiffAngle ) * TeeSpeed ;
if ( abs ( ( int ) SpeedLeft ) > Force & & SpeedLeft > 0.0000001f )
TempVel + = Direction * Force ;
else if ( abs ( ( int ) SpeedLeft ) > Force )
TempVel + = Direction * - Force ;
else
TempVel + = Direction * SpeedLeft ;
}
else
TempVel + = Direction * Force ;
2020-04-25 23:12:34 +00:00
m_Core . m_Vel = ClampVel ( m_MoveRestrictions , TempVel ) ;
2019-04-11 22:46:54 +00:00
}
}
}
2018-08-15 15:47:07 +00:00
bool CCharacter : : IsSwitchActiveCb ( int Number , void * pUser )
{
2021-08-18 23:11:38 +00:00
CCharacter * pThis = ( CCharacter * ) pUser ;
CCollision * pCollision = pThis - > Collision ( ) ;
return pCollision - > m_pSwitchers & & pThis - > Team ( ) ! = TEAM_SUPER & & pCollision - > m_pSwitchers [ Number ] . m_Status [ pThis - > Team ( ) ] ;
2018-08-15 15:47:07 +00:00
}
2019-04-11 22:46:54 +00:00
void CCharacter : : HandleTiles ( int Index )
{
int MapIndex = Index ;
m_TileIndex = Collision ( ) - > GetTileIndex ( MapIndex ) ;
m_TileFIndex = Collision ( ) - > GetFTileIndex ( MapIndex ) ;
2018-08-15 15:47:07 +00:00
m_MoveRestrictions = Collision ( ) - > GetMoveRestrictions ( IsSwitchActiveCb , this , m_Pos ) ;
2019-05-03 18:57:01 +00:00
// stopper
2020-09-26 19:41:58 +00:00
if ( m_Core . m_Vel . y > 0 & & ( m_MoveRestrictions & CANTMOVE_DOWN ) )
2019-05-03 18:57:01 +00:00
{
m_Core . m_Jumped = 0 ;
m_Core . m_JumpedTotal = 0 ;
}
2020-04-25 23:12:34 +00:00
m_Core . m_Vel = ClampVel ( m_MoveRestrictions , m_Core . m_Vel ) ;
2019-05-03 18:57:01 +00:00
if ( ! GameWorld ( ) - > m_WorldConfig . m_PredictTiles )
return ;
2019-04-11 22:46:54 +00:00
if ( Index < 0 )
{
m_LastRefillJumps = false ;
return ;
}
2021-08-18 23:11:38 +00:00
// handle switch tiles
2021-12-19 11:05:51 +00:00
if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_FREEZE & & Team ( ) ! = TEAM_SUPER )
2021-08-18 23:11:38 +00:00
{
if ( Collision ( ) - > GetSwitchNumber ( MapIndex ) = = 0 | | Collision ( ) - > m_pSwitchers [ Collision ( ) - > GetSwitchNumber ( MapIndex ) ] . m_Status [ Team ( ) ] )
2022-03-27 16:18:53 +00:00
{
2021-08-18 23:11:38 +00:00
Freeze ( Collision ( ) - > GetSwitchDelay ( MapIndex ) ) ;
2022-03-27 16:18:53 +00:00
}
2021-08-18 23:11:38 +00:00
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_DFREEZE & & Team ( ) ! = TEAM_SUPER )
2021-08-18 23:11:38 +00:00
{
if ( Collision ( ) - > GetSwitchNumber ( MapIndex ) = = 0 | | Collision ( ) - > m_pSwitchers [ Collision ( ) - > GetSwitchNumber ( MapIndex ) ] . m_Status [ Team ( ) ] )
m_DeepFreeze = true ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_DUNFREEZE & & Team ( ) ! = TEAM_SUPER )
2021-08-18 23:11:38 +00:00
{
if ( Collision ( ) - > GetSwitchNumber ( MapIndex ) = = 0 | | Collision ( ) - > m_pSwitchers [ Collision ( ) - > GetSwitchNumber ( MapIndex ) ] . m_Status [ Team ( ) ] )
m_DeepFreeze = false ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_ENABLE & & m_Hit & DISABLE_HIT_HAMMER & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_HAMMER )
2021-08-18 23:11:38 +00:00
{
m_Hit & = ~ DISABLE_HIT_HAMMER ;
m_Core . m_NoHammerHit = false ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_DISABLE & & ! ( m_Hit & DISABLE_HIT_HAMMER ) & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_HAMMER )
2021-08-18 23:11:38 +00:00
{
m_Hit | = DISABLE_HIT_HAMMER ;
m_Core . m_NoHammerHit = true ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_ENABLE & & m_Hit & DISABLE_HIT_SHOTGUN & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_SHOTGUN )
2021-08-18 23:11:38 +00:00
{
m_Hit & = ~ DISABLE_HIT_SHOTGUN ;
m_Core . m_NoShotgunHit = false ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_DISABLE & & ! ( m_Hit & DISABLE_HIT_SHOTGUN ) & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_SHOTGUN )
2021-08-18 23:11:38 +00:00
{
m_Hit | = DISABLE_HIT_SHOTGUN ;
m_Core . m_NoShotgunHit = true ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_ENABLE & & m_Hit & DISABLE_HIT_GRENADE & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_GRENADE )
2021-08-18 23:11:38 +00:00
{
m_Hit & = ~ DISABLE_HIT_GRENADE ;
m_Core . m_NoGrenadeHit = false ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_DISABLE & & ! ( m_Hit & DISABLE_HIT_GRENADE ) & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_GRENADE )
2021-08-18 23:11:38 +00:00
{
m_Hit | = DISABLE_HIT_GRENADE ;
m_Core . m_NoGrenadeHit = true ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_ENABLE & & m_Hit & DISABLE_HIT_LASER & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_LASER )
2021-08-18 23:11:38 +00:00
{
m_Hit & = ~ DISABLE_HIT_LASER ;
m_Core . m_NoLaserHit = false ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_HIT_DISABLE & & ! ( m_Hit & DISABLE_HIT_LASER ) & & Collision ( ) - > GetSwitchDelay ( MapIndex ) = = WEAPON_LASER )
2021-08-18 23:11:38 +00:00
{
m_Hit | = DISABLE_HIT_LASER ;
m_Core . m_NoLaserHit = true ;
}
2021-12-19 11:05:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_JUMP )
2021-08-18 23:11:38 +00:00
{
2022-01-31 14:43:03 +00:00
int NewJumps = Collision ( ) - > GetSwitchDelay ( MapIndex ) ;
2022-01-31 14:43:49 +00:00
if ( NewJumps = = 255 )
{
NewJumps = - 1 ;
}
2022-01-31 14:43:03 +00:00
if ( NewJumps ! = m_Core . m_Jumps )
m_Core . m_Jumps = NewJumps ;
2021-08-18 23:11:38 +00:00
}
2022-01-08 11:30:51 +00:00
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_LFREEZE & & Team ( ) ! = TEAM_SUPER )
2022-01-07 15:53:40 +00:00
{
if ( Collision ( ) - > GetSwitchNumber ( MapIndex ) = = 0 | | Collision ( ) - > m_pSwitchers [ Collision ( ) - > GetSwitchNumber ( MapIndex ) ] . m_Status [ Team ( ) ] )
{
m_LiveFreeze = true ;
m_Core . m_LiveFrozen = true ;
}
}
else if ( Collision ( ) - > GetSwitchType ( MapIndex ) = = TILE_LUNFREEZE & & Team ( ) ! = TEAM_SUPER )
{
if ( Collision ( ) - > GetSwitchNumber ( MapIndex ) = = 0 | | Collision ( ) - > m_pSwitchers [ Collision ( ) - > GetSwitchNumber ( MapIndex ) ] . m_Status [ Team ( ) ] )
{
m_LiveFreeze = false ;
m_Core . m_LiveFrozen = false ;
}
}
2021-08-18 23:11:38 +00:00
2019-04-11 22:46:54 +00:00
// freeze
2019-04-21 22:38:24 +00:00
if ( ( ( m_TileIndex = = TILE_FREEZE ) | | ( m_TileFIndex = = TILE_FREEZE ) ) & & ! m_Super & & ! m_DeepFreeze )
2019-04-11 22:46:54 +00:00
{
Freeze ( ) ;
}
else if ( ( ( m_TileIndex = = TILE_UNFREEZE ) | | ( m_TileFIndex = = TILE_UNFREEZE ) ) & & ! m_DeepFreeze )
{
UnFreeze ( ) ;
}
// deep freeze
2019-04-21 22:38:24 +00:00
if ( ( ( m_TileIndex = = TILE_DFREEZE ) | | ( m_TileFIndex = = TILE_DFREEZE ) ) & & ! m_Super & & ! m_DeepFreeze )
2019-04-11 22:46:54 +00:00
{
m_DeepFreeze = true ;
}
2019-04-21 22:38:24 +00:00
else if ( ( ( m_TileIndex = = TILE_DUNFREEZE ) | | ( m_TileFIndex = = TILE_DUNFREEZE ) ) & & ! m_Super & & m_DeepFreeze )
2019-04-11 22:46:54 +00:00
{
m_DeepFreeze = false ;
}
2022-01-07 15:53:40 +00:00
// live freeze
if ( ( ( m_TileIndex = = TILE_LFREEZE ) | | ( m_TileFIndex = = TILE_LFREEZE ) ) & & ! m_Super )
{
m_LiveFreeze = true ;
m_Core . m_LiveFrozen = true ;
}
else if ( ( ( m_TileIndex = = TILE_LUNFREEZE ) | | ( m_TileFIndex = = TILE_LUNFREEZE ) ) & & ! m_Super )
{
m_LiveFreeze = false ;
m_Core . m_LiveFrozen = false ;
}
2019-04-11 22:46:54 +00:00
// endless hook
2020-09-13 20:00:49 +00:00
if ( ( ( m_TileIndex = = TILE_EHOOK_ENABLE ) | | ( m_TileFIndex = = TILE_EHOOK_ENABLE ) ) & & ! m_EndlessHook )
2019-04-11 22:46:54 +00:00
{
m_EndlessHook = true ;
2020-04-25 23:12:34 +00:00
m_Core . m_EndlessHook = true ;
2019-04-11 22:46:54 +00:00
}
2020-09-13 20:00:49 +00:00
else if ( ( ( m_TileIndex = = TILE_EHOOK_DISABLE ) | | ( m_TileFIndex = = TILE_EHOOK_DISABLE ) ) & & m_EndlessHook )
2019-04-11 22:46:54 +00:00
{
m_EndlessHook = false ;
2020-04-25 23:12:34 +00:00
m_Core . m_EndlessHook = false ;
2019-04-11 22:46:54 +00:00
}
// collide with others
2020-09-13 20:00:49 +00:00
if ( ( ( m_TileIndex = = TILE_NPC_DISABLE ) | | ( m_TileFIndex = = TILE_NPC_DISABLE ) ) & & m_Core . m_Collision )
2019-04-11 22:46:54 +00:00
{
m_Core . m_Collision = false ;
}
2020-09-13 20:00:49 +00:00
else if ( ( ( m_TileIndex = = TILE_NPC_ENABLE ) | | ( m_TileFIndex = = TILE_NPC_ENABLE ) ) & & ! m_Core . m_Collision )
2019-04-11 22:46:54 +00:00
{
m_Core . m_Collision = true ;
}
// hook others
2020-09-13 20:00:49 +00:00
if ( ( ( m_TileIndex = = TILE_NPH_DISABLE ) | | ( m_TileFIndex = = TILE_NPH_DISABLE ) ) & & m_Core . m_Hook )
2019-04-11 22:46:54 +00:00
{
m_Core . m_Hook = false ;
}
2020-09-13 20:00:49 +00:00
else if ( ( ( m_TileIndex = = TILE_NPH_ENABLE ) | | ( m_TileFIndex = = TILE_NPH_ENABLE ) ) & & ! m_Core . m_Hook )
2019-04-11 22:46:54 +00:00
{
m_Core . m_Hook = true ;
}
// unlimited air jumps
2020-09-13 20:00:49 +00:00
if ( ( ( m_TileIndex = = TILE_UNLIMITED_JUMPS_ENABLE ) | | ( m_TileFIndex = = TILE_UNLIMITED_JUMPS_ENABLE ) ) & & ! m_SuperJump )
2019-04-11 22:46:54 +00:00
{
m_SuperJump = true ;
2020-04-25 23:12:34 +00:00
m_Core . m_EndlessJump = true ;
2019-04-11 22:46:54 +00:00
}
2020-09-13 20:00:49 +00:00
else if ( ( ( m_TileIndex = = TILE_UNLIMITED_JUMPS_DISABLE ) | | ( m_TileFIndex = = TILE_UNLIMITED_JUMPS_DISABLE ) ) & & m_SuperJump )
2019-04-11 22:46:54 +00:00
{
m_SuperJump = false ;
2020-04-25 23:12:34 +00:00
m_Core . m_EndlessJump = false ;
2019-04-11 22:46:54 +00:00
}
// walljump
if ( ( m_TileIndex = = TILE_WALLJUMP ) | | ( m_TileFIndex = = TILE_WALLJUMP ) )
{
if ( m_Core . m_Vel . y > 0 & & m_Core . m_Colliding & & m_Core . m_LeftWall )
{
m_Core . m_LeftWall = false ;
2022-05-16 21:17:19 +00:00
m_Core . m_JumpedTotal = m_Core . m_Jumps > = 2 ? m_Core . m_Jumps - 2 : 0 ;
2019-04-11 22:46:54 +00:00
m_Core . m_Jumped = 1 ;
}
}
// jetpack gun
2020-09-13 20:00:49 +00:00
if ( ( ( m_TileIndex = = TILE_JETPACK_ENABLE ) | | ( m_TileFIndex = = TILE_JETPACK_ENABLE ) ) & & ! m_Jetpack )
2019-04-11 22:46:54 +00:00
{
m_Jetpack = true ;
2020-04-25 23:12:34 +00:00
m_Core . m_Jetpack = true ;
2019-04-11 22:46:54 +00:00
}
2020-09-13 20:00:49 +00:00
else if ( ( ( m_TileIndex = = TILE_JETPACK_DISABLE ) | | ( m_TileFIndex = = TILE_JETPACK_DISABLE ) ) & & m_Jetpack )
2019-04-11 22:46:54 +00:00
{
m_Jetpack = false ;
2020-04-25 23:12:34 +00:00
m_Core . m_Jetpack = false ;
2019-04-11 22:46:54 +00:00
}
// solo part
2020-09-13 20:00:49 +00:00
if ( ( ( m_TileIndex = = TILE_SOLO_ENABLE ) | | ( m_TileFIndex = = TILE_SOLO_ENABLE ) ) & & ! TeamsCore ( ) - > GetSolo ( GetCID ( ) ) )
2019-04-11 22:46:54 +00:00
{
SetSolo ( true ) ;
}
2020-09-13 20:00:49 +00:00
else if ( ( ( m_TileIndex = = TILE_SOLO_DISABLE ) | | ( m_TileFIndex = = TILE_SOLO_DISABLE ) ) & & TeamsCore ( ) - > GetSolo ( GetCID ( ) ) )
2019-04-11 22:46:54 +00:00
{
SetSolo ( false ) ;
}
// refill jumps
if ( ( ( m_TileIndex = = TILE_REFILL_JUMPS ) | | ( m_TileFIndex = = TILE_REFILL_JUMPS ) ) & & ! m_LastRefillJumps )
{
m_Core . m_JumpedTotal = 0 ;
m_Core . m_Jumped = 0 ;
m_LastRefillJumps = true ;
}
if ( ( m_TileIndex ! = TILE_REFILL_JUMPS ) & & ( m_TileFIndex ! = TILE_REFILL_JUMPS ) )
{
m_LastRefillJumps = false ;
}
}
2019-09-08 22:53:07 +00:00
void CCharacter : : HandleTuneLayer ( )
{
int CurrentIndex = Collision ( ) - > GetMapIndex ( m_Pos ) ;
2021-05-12 16:57:50 +00:00
SetTuneZone ( GameWorld ( ) - > m_WorldConfig . m_UseTuneZones ? Collision ( ) - > IsTune ( CurrentIndex ) : 0 ) ;
2019-09-08 22:53:07 +00:00
2021-05-12 16:57:50 +00:00
if ( m_IsLocal )
m_Core . m_pWorld - > m_Tuning [ g_Config . m_ClDummy ] = * GetTuning ( m_TuneZone ) ; // throw tunings (from specific zone if in a tunezone) into gamecore if the character is local
m_Core . m_Tuning = * GetTuning ( m_TuneZone ) ;
2019-09-08 22:53:07 +00:00
}
2019-04-11 22:46:54 +00:00
void CCharacter : : DDRaceTick ( )
{
mem_copy ( & m_Input , & m_SavedInput , sizeof ( m_Input ) ) ;
2022-04-18 13:40:39 +00:00
if ( m_LiveFreeze & & ! m_CanMoveInFreeze & & ! m_Super )
2022-01-07 15:53:40 +00:00
{
m_Input . m_Direction = 0 ;
m_Input . m_Jump = 0 ;
//Hook and weapons are possible in live freeze
}
2019-04-11 22:46:54 +00:00
if ( m_FreezeTime > 0 | | m_FreezeTime = = - 1 )
{
if ( m_FreezeTime > 0 )
m_FreezeTime - - ;
else
2022-03-24 00:05:41 +00:00
m_Core . m_Ninja . m_ActivationTick = GameWorld ( ) - > GameTick ( ) ;
2019-05-02 20:35:08 +00:00
if ( ! m_CanMoveInFreeze )
{
m_Input . m_Direction = 0 ;
m_Input . m_Jump = 0 ;
m_Input . m_Hook = 0 ;
}
2020-09-26 19:41:58 +00:00
if ( m_FreezeTime = = 1 )
2019-04-11 22:46:54 +00:00
UnFreeze ( ) ;
}
2019-09-08 22:53:07 +00:00
HandleTuneLayer ( ) ;
2022-03-29 21:24:39 +00:00
// check if the tee is in any type of freeze
int Index = Collision ( ) - > GetPureMapIndex ( m_Pos ) ;
const int aTiles [ ] = {
Collision ( ) - > GetTileIndex ( Index ) ,
Collision ( ) - > GetFTileIndex ( Index ) ,
Collision ( ) - > GetSwitchType ( Index ) } ;
m_Core . m_IsInFreeze = false ;
for ( const int Tile : aTiles )
{
if ( Tile = = TILE_FREEZE | | Tile = = TILE_DFREEZE | | Tile = = TILE_LFREEZE )
{
m_Core . m_IsInFreeze = true ;
break ;
}
}
2019-04-11 22:46:54 +00:00
}
void CCharacter : : DDRacePostCoreTick ( )
{
2019-05-03 18:57:01 +00:00
if ( ! GameWorld ( ) - > m_WorldConfig . m_PredictDDRace )
return ;
2020-09-26 19:41:58 +00:00
if ( m_EndlessHook )
2019-04-11 22:46:54 +00:00
m_Core . m_HookTick = 0 ;
2020-04-25 23:12:34 +00:00
m_FrozenLastTick = false ;
2020-09-26 19:41:58 +00:00
if ( m_DeepFreeze & & ! m_Super )
2019-04-11 22:46:54 +00:00
Freeze ( ) ;
2022-05-20 19:37:05 +00:00
// following jump rules can be overridden by tiles, like Refill Jumps, Stopper and Wall Jump
2022-05-16 21:17:19 +00:00
if ( m_Core . m_Jumps = = - 1 )
{
// The player has only one ground jump, so his feet are always dark
m_Core . m_Jumped | = 2 ;
}
else if ( m_Core . m_Jumps = = 0 )
{
// The player has no jumps at all, so his feet are always dark
2022-01-31 14:43:49 +00:00
m_Core . m_Jumped | = 2 ;
2022-05-16 21:17:19 +00:00
}
2020-09-26 19:41:58 +00:00
else if ( m_Core . m_Jumps = = 1 & & m_Core . m_Jumped > 0 )
2022-05-16 21:17:19 +00:00
{
// If the player has only one jump, each jump is the last one
m_Core . m_Jumped | = 2 ;
}
2020-09-26 19:41:58 +00:00
else if ( m_Core . m_JumpedTotal < m_Core . m_Jumps - 1 & & m_Core . m_Jumped > 1 )
2022-05-16 21:17:19 +00:00
{
// The player has not yet used up all his jumps, so his feet remain light
2019-04-11 22:46:54 +00:00
m_Core . m_Jumped = 1 ;
2022-05-16 21:17:19 +00:00
}
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
if ( ( m_Super | | m_SuperJump ) & & m_Core . m_Jumped > 1 )
2022-05-16 21:17:19 +00:00
{
// Super players and players with infinite jumps always have light feet
2019-04-11 22:46:54 +00:00
m_Core . m_Jumped = 1 ;
2022-05-16 21:17:19 +00:00
}
2019-04-11 22:46:54 +00:00
2019-05-03 18:57:01 +00:00
int CurrentIndex = Collision ( ) - > GetMapIndex ( m_Pos ) ;
HandleSkippableTiles ( CurrentIndex ) ;
2019-05-02 01:33:40 +00:00
2019-05-03 18:57:01 +00:00
// handle Anti-Skip tiles
2020-09-26 19:41:58 +00:00
std : : list < int > Indices = Collision ( ) - > GetMapIndices ( m_PrevPos , m_Pos ) ;
2019-05-03 18:57:01 +00:00
if ( ! Indices . empty ( ) )
2020-10-26 14:14:07 +00:00
for ( int Index : Indices )
HandleTiles ( Index ) ;
2019-05-03 18:57:01 +00:00
else
{
HandleTiles ( CurrentIndex ) ;
2019-04-11 22:46:54 +00:00
}
}
bool CCharacter : : Freeze ( int Seconds )
{
if ( ! GameWorld ( ) - > m_WorldConfig . m_PredictFreeze )
return false ;
2020-09-26 19:41:58 +00:00
if ( ( Seconds < = 0 | | m_Super | | m_FreezeTime = = - 1 | | m_FreezeTime > Seconds * GameWorld ( ) - > GameTickSpeed ( ) ) & & Seconds ! = - 1 )
return false ;
2022-03-25 11:54:11 +00:00
if ( m_Core . m_FreezeTick < GameWorld ( ) - > GameTick ( ) - GameWorld ( ) - > GameTickSpeed ( ) | | Seconds = = - 1 )
2019-04-11 22:46:54 +00:00
{
m_FreezeTime = Seconds = = - 1 ? Seconds : Seconds * GameWorld ( ) - > GameTickSpeed ( ) ;
2022-03-25 11:54:11 +00:00
m_Core . m_FreezeTick = GameWorld ( ) - > GameTick ( ) ;
2019-04-11 22:46:54 +00:00
return true ;
}
return false ;
}
bool CCharacter : : Freeze ( )
{
return Freeze ( g_Config . m_SvFreezeDelay ) ;
}
bool CCharacter : : UnFreeze ( )
{
2020-09-26 19:41:58 +00:00
if ( m_FreezeTime > 0 )
2019-04-11 22:46:54 +00:00
{
2022-03-21 22:50:41 +00:00
if ( ! m_Core . m_aWeapons [ m_Core . m_ActiveWeapon ] . m_Got )
2019-04-11 22:46:54 +00:00
m_Core . m_ActiveWeapon = WEAPON_GUN ;
m_FreezeTime = 0 ;
2022-03-25 11:54:11 +00:00
m_Core . m_FreezeTick = 0 ;
2020-04-25 23:12:34 +00:00
m_FrozenLastTick = true ;
2019-04-11 22:46:54 +00:00
return true ;
}
return false ;
}
2020-04-25 23:12:34 +00:00
void CCharacter : : GiveWeapon ( int Weapon , bool Remove )
{
if ( Weapon = = WEAPON_NINJA )
{
if ( Remove )
RemoveNinja ( ) ;
else
GiveNinja ( ) ;
return ;
}
if ( Remove )
{
if ( GetActiveWeapon ( ) = = Weapon )
SetActiveWeapon ( WEAPON_GUN ) ;
}
else
{
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ Weapon ] . m_Ammo = - 1 ;
2020-04-25 23:12:34 +00:00
}
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ Weapon ] . m_Got = ! Remove ;
2020-04-25 23:12:34 +00:00
}
2019-04-11 22:46:54 +00:00
void CCharacter : : GiveAllWeapons ( )
{
2020-09-26 19:41:58 +00:00
for ( int i = WEAPON_GUN ; i < NUM_WEAPONS - 1 ; i + + )
2019-04-11 22:46:54 +00:00
{
2020-04-25 23:12:34 +00:00
GiveWeapon ( i ) ;
2019-04-11 22:46:54 +00:00
}
}
2020-09-26 19:41:58 +00:00
CTeamsCore * CCharacter : : TeamsCore ( )
2019-04-11 22:46:54 +00:00
{
return m_Core . m_pTeams ;
}
2022-03-29 09:17:09 +00:00
CCharacter : : CCharacter ( CGameWorld * pGameWorld , int ID , CNetObj_Character * pChar , CNetObj_DDNetCharacter * pExtended , CNetObj_DDNetCharacterDisplayInfo * pExtendedDisplayInfo ) :
2020-09-26 19:41:58 +00:00
CEntity ( pGameWorld , CGameWorld : : ENTTYPE_CHARACTER )
2019-04-11 22:46:54 +00:00
{
m_ID = ID ;
2021-05-12 16:57:50 +00:00
m_IsLocal = false ;
2019-04-11 22:46:54 +00:00
m_LastWeapon = WEAPON_HAMMER ;
m_QueuedWeapon = - 1 ;
m_LastRefillJumps = false ;
2019-05-11 19:13:09 +00:00
m_PrevPrevPos = m_PrevPos = m_Pos = vec2 ( pChar - > m_X , pChar - > m_Y ) ;
2019-04-11 22:46:54 +00:00
m_Core . Reset ( ) ;
m_Core . Init ( & GameWorld ( ) - > m_Core , GameWorld ( ) - > Collision ( ) , GameWorld ( ) - > Teams ( ) ) ;
m_Core . m_Id = ID ;
2022-03-24 00:05:41 +00:00
mem_zero ( & m_Core . m_Ninja , sizeof ( m_Core . m_Ninja ) ) ;
2019-04-11 22:46:54 +00:00
mem_zero ( & m_SavedInput , sizeof ( m_SavedInput ) ) ;
m_LatestInput = m_LatestPrevInput = m_PrevInput = m_Input = m_SavedInput ;
m_ProximityRadius = ms_PhysSize ;
2022-02-14 23:12:52 +00:00
m_Core . m_LeftWall = true ;
2019-04-11 22:46:54 +00:00
m_ReloadTimer = 0 ;
m_NumObjectsHit = 0 ;
m_LastRefillJumps = false ;
2019-07-08 21:08:42 +00:00
m_LastJetpackStrength = 400.0f ;
2019-04-21 22:38:24 +00:00
m_Super = false ;
2019-05-02 20:35:08 +00:00
m_CanMoveInFreeze = false ;
2019-06-30 21:47:33 +00:00
m_TeleCheckpoint = 0 ;
m_StrongWeakID = 0 ;
2019-04-11 22:46:54 +00:00
2022-05-22 08:39:18 +00:00
// never initialize both to zero
2020-10-17 16:17:13 +00:00
m_Input . m_TargetX = 0 ;
m_Input . m_TargetY = - 1 ;
m_LatestPrevInput = m_LatestInput = m_PrevInput = m_SavedInput = m_Input ;
2019-05-04 01:48:17 +00:00
ResetPrediction ( ) ;
2022-03-29 09:17:09 +00:00
Read ( pChar , pExtended , pExtendedDisplayInfo , false ) ;
2019-04-11 22:46:54 +00:00
GameWorld ( ) - > InsertEntity ( this ) ;
}
2019-05-04 01:48:17 +00:00
void CCharacter : : ResetPrediction ( )
{
SetSolo ( false ) ;
m_EndlessHook = false ;
m_Hit = HIT_ALL ;
m_SuperJump = false ;
m_Jetpack = false ;
2019-05-12 23:45:49 +00:00
m_NinjaJetpack = false ;
2019-05-04 01:48:17 +00:00
m_Core . m_Jumps = 2 ;
2020-06-14 20:50:21 +00:00
m_Core . m_Hook = true ;
m_Core . m_Collision = true ;
2019-05-04 01:48:17 +00:00
m_NumInputs = 0 ;
m_FreezeTime = 0 ;
2022-03-25 11:54:11 +00:00
m_Core . m_FreezeTick = 0 ;
2022-03-27 16:18:53 +00:00
m_Core . m_IsInFreeze = false ;
2022-02-14 23:12:52 +00:00
m_DeepFreeze = false ;
m_LiveFreeze = false ;
2020-04-25 23:12:34 +00:00
m_FrozenLastTick = false ;
2019-05-04 01:48:17 +00:00
m_Super = false ;
for ( int w = 0 ; w < NUM_WEAPONS ; w + + )
2019-06-30 21:47:33 +00:00
{
2019-05-04 01:48:17 +00:00
SetWeaponGot ( w , false ) ;
2019-06-30 21:47:33 +00:00
SetWeaponAmmo ( w , - 1 ) ;
}
2019-05-05 12:28:39 +00:00
if ( m_Core . m_HookedPlayer > = 0 )
{
2022-05-22 19:40:15 +00:00
m_Core . SetHookedPlayer ( - 1 ) ;
2019-05-05 12:28:39 +00:00
m_Core . m_HookState = HOOK_IDLE ;
}
2020-07-15 00:47:51 +00:00
m_LastWeaponSwitchTick = 0 ;
m_LastTuneZoneTick = 0 ;
2019-05-04 01:48:17 +00:00
}
2022-03-29 09:17:09 +00:00
void CCharacter : : Read ( CNetObj_Character * pChar , CNetObj_DDNetCharacter * pExtended , CNetObj_DDNetCharacterDisplayInfo * pExtendedDisplayInfo , bool IsLocal )
2019-04-11 22:46:54 +00:00
{
2022-03-23 17:19:23 +00:00
m_Core . ReadCharacterCore ( ( const CNetObj_CharacterCore * ) pChar ) ;
2021-05-12 16:57:50 +00:00
m_IsLocal = IsLocal ;
2019-04-11 22:46:54 +00:00
2019-06-30 21:47:33 +00:00
if ( pExtended )
{
m_Core . ReadDDNet ( pExtended ) ;
2019-04-11 22:46:54 +00:00
2019-06-30 21:47:33 +00:00
SetSolo ( pExtended - > m_Flags & CHARACTERFLAG_SOLO ) ;
m_Super = pExtended - > m_Flags & CHARACTERFLAG_SUPER ;
if ( m_Super )
TeamsCore ( ) - > Team ( GetCID ( ) , TeamsCore ( ) - > m_IsDDRace16 ? VANILLA_TEAM_SUPER : TEAM_SUPER ) ;
m_EndlessHook = pExtended - > m_Flags & CHARACTERFLAG_ENDLESS_HOOK ;
m_SuperJump = pExtended - > m_Flags & CHARACTERFLAG_ENDLESS_JUMP ;
m_Jetpack = pExtended - > m_Flags & CHARACTERFLAG_JETPACK ;
m_TeleCheckpoint = pExtended - > m_TeleCheckpoint ;
m_StrongWeakID = pExtended - > m_StrongWeakID ;
m_Hit = HIT_ALL ;
if ( pExtended - > m_Flags & CHARACTERFLAG_NO_GRENADE_HIT )
m_Hit | = DISABLE_HIT_GRENADE ;
if ( pExtended - > m_Flags & CHARACTERFLAG_NO_HAMMER_HIT )
m_Hit | = DISABLE_HIT_HAMMER ;
2019-11-22 14:37:18 +00:00
if ( pExtended - > m_Flags & CHARACTERFLAG_NO_LASER_HIT )
m_Hit | = DISABLE_HIT_LASER ;
2019-06-30 21:47:33 +00:00
if ( pExtended - > m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT )
m_Hit | = DISABLE_HIT_SHOTGUN ;
2019-04-11 22:46:54 +00:00
2019-06-30 21:47:33 +00:00
const bool Ninja = ( pExtended - > m_Flags & CHARACTERFLAG_WEAPON_NINJA ) ! = 0 ;
if ( Ninja & & m_Core . m_ActiveWeapon ! = WEAPON_NINJA )
GiveNinja ( ) ;
else if ( ! Ninja & & m_Core . m_ActiveWeapon = = WEAPON_NINJA )
RemoveNinja ( ) ;
2020-04-19 10:50:06 +00:00
m_DeepFreeze = false ;
2022-01-07 15:53:40 +00:00
m_LiveFreeze = ( pExtended - > m_Flags & CHARACTERFLAG_NO_MOVEMENTS ) ! = 0 ;
2020-04-19 10:50:06 +00:00
if ( GameWorld ( ) - > m_WorldConfig . m_PredictFreeze & & pExtended - > m_FreezeEnd ! = 0 )
{
if ( pExtended - > m_FreezeEnd > 0 )
{
if ( m_FreezeTime = = 0 )
Freeze ( ) ;
m_FreezeTime = pExtended - > m_FreezeEnd - GameWorld ( ) - > GameTick ( ) ;
}
else if ( pExtended - > m_FreezeEnd = = - 1 )
m_DeepFreeze = true ;
}
else
UnFreeze ( ) ;
2019-06-30 21:47:33 +00:00
}
else
2019-04-11 22:46:54 +00:00
{
2019-06-30 21:47:33 +00:00
// ddnetcharacter is not available, try to get some info from the tunings and the character netobject instead.
// remove weapons that are unavailable. if the current weapon is ninja just set ammo to zero in case the player is frozen
if ( pChar - > m_Weapon ! = m_Core . m_ActiveWeapon )
2019-04-11 22:46:54 +00:00
{
2019-06-30 21:47:33 +00:00
if ( pChar - > m_Weapon = = WEAPON_NINJA )
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ m_Core . m_ActiveWeapon ] . m_Ammo = 0 ;
2019-06-30 21:47:33 +00:00
else
2019-04-11 22:46:54 +00:00
{
2019-06-30 21:47:33 +00:00
if ( m_Core . m_ActiveWeapon = = WEAPON_NINJA )
{
2020-09-26 19:41:58 +00:00
SetNinjaActivationDir ( vec2 ( 0 , 0 ) ) ;
2019-06-30 21:47:33 +00:00
SetNinjaActivationTick ( - 500 ) ;
SetNinjaCurrentMoveTime ( 0 ) ;
}
if ( pChar - > m_Weapon = = m_LastSnapWeapon )
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ m_Core . m_ActiveWeapon ] . m_Got = false ;
2019-04-11 22:46:54 +00:00
}
}
2019-06-30 21:47:33 +00:00
// add weapon
if ( pChar - > m_Weapon ! = WEAPON_NINJA )
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ pChar - > m_Weapon ] . m_Got = true ;
2019-04-11 22:46:54 +00:00
2019-06-30 21:47:33 +00:00
// jetpack
if ( GameWorld ( ) - > m_WorldConfig . m_PredictWeapons & & Tuning ( ) - > m_JetpackStrength > 0 )
{
m_LastJetpackStrength = Tuning ( ) - > m_JetpackStrength ;
m_Jetpack = true ;
2021-08-08 10:36:25 +00:00
m_Core . m_Jetpack = true ;
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ WEAPON_GUN ] . m_Got = true ;
m_Core . m_aWeapons [ WEAPON_GUN ] . m_Ammo = - 1 ;
2019-06-30 21:47:33 +00:00
m_NinjaJetpack = pChar - > m_Weapon = = WEAPON_NINJA ;
}
else if ( pChar - > m_Weapon ! = WEAPON_NINJA )
2021-08-08 10:36:25 +00:00
{
2019-06-30 21:47:33 +00:00
m_Jetpack = false ;
2021-08-08 10:36:25 +00:00
m_Core . m_Jetpack = false ;
}
2019-06-30 21:47:33 +00:00
// number of jumps
if ( GameWorld ( ) - > m_WorldConfig . m_PredictTiles )
{
2020-09-26 19:41:58 +00:00
if ( pChar - > m_Jumped & 2 )
2019-06-30 21:47:33 +00:00
{
m_SuperJump = false ;
if ( m_Core . m_Jumps > m_Core . m_JumpedTotal & & m_Core . m_JumpedTotal > 0 & & m_Core . m_Jumps > 2 )
m_Core . m_Jumps = m_Core . m_JumpedTotal + 1 ;
}
else if ( m_Core . m_Jumps < 2 )
m_Core . m_Jumps = m_Core . m_JumpedTotal + 2 ;
if ( Tuning ( ) - > m_AirJumpImpulse = = 0 )
{
m_Core . m_Jumps = 0 ;
m_Core . m_Jumped = 3 ;
}
}
// set player collision
SetSolo ( ! Tuning ( ) - > m_PlayerCollision & & ! Tuning ( ) - > m_PlayerHooking ) ;
m_Core . m_Collision = Tuning ( ) - > m_PlayerCollision ;
m_Core . m_Hook = Tuning ( ) - > m_PlayerHooking ;
if ( m_Core . m_HookTick ! = 0 )
m_EndlessHook = false ;
2019-04-11 22:46:54 +00:00
2020-04-19 10:50:06 +00:00
// detect unfreeze (in case the player was frozen in the tile prediction and not correctly unfrozen)
if ( pChar - > m_Emote ! = EMOTE_PAIN & & pChar - > m_Emote ! = EMOTE_NORMAL )
m_DeepFreeze = false ;
2022-03-25 11:54:11 +00:00
if ( pChar - > m_Weapon ! = WEAPON_NINJA | | pChar - > m_AttackTick > m_Core . m_FreezeTick | | absolute ( pChar - > m_VelX ) = = 256 * 10 | | ! GameWorld ( ) - > m_WorldConfig . m_PredictFreeze )
2020-04-19 10:50:06 +00:00
{
m_DeepFreeze = false ;
UnFreeze ( ) ;
}
2019-04-11 22:46:54 +00:00
}
2019-06-30 21:47:33 +00:00
vec2 PosBefore = m_Pos ;
m_Pos = m_Core . m_Pos ;
2019-04-11 22:46:54 +00:00
2019-06-30 21:47:33 +00:00
if ( distance ( PosBefore , m_Pos ) > 2.f ) // misprediction, don't use prevpos
m_PrevPos = m_Pos ;
2019-04-11 22:46:54 +00:00
2019-06-30 21:47:33 +00:00
if ( distance ( m_PrevPos , m_Pos ) > 10.f * 32.f ) // reset prevpos if the distance is high
m_PrevPos = m_Pos ;
2019-04-11 22:46:54 +00:00
2020-09-26 19:41:58 +00:00
if ( pChar - > m_Jumped & 2 )
2019-06-30 21:47:33 +00:00
m_Core . m_JumpedTotal = m_Core . m_Jumps ;
m_AttackTick = pChar - > m_AttackTick ;
m_LastSnapWeapon = pChar - > m_Weapon ;
2021-05-12 16:57:50 +00:00
SetTuneZone ( GameWorld ( ) - > m_WorldConfig . m_UseTuneZones ? Collision ( ) - > IsTune ( Collision ( ) - > GetMapIndex ( m_Pos ) ) : 0 ) ;
2019-09-08 22:53:07 +00:00
2019-06-30 21:47:33 +00:00
// set the current weapon
if ( pChar - > m_Weapon ! = WEAPON_NINJA )
{
2022-03-21 22:50:41 +00:00
m_Core . m_aWeapons [ pChar - > m_Weapon ] . m_Ammo = ( GameWorld ( ) - > m_WorldConfig . m_InfiniteAmmo | | GameWorld ( ) - > m_WorldConfig . m_IsDDRace | | pChar - > m_Weapon = = WEAPON_HAMMER ) ? - 1 : pChar - > m_AmmoCount ;
2020-07-15 00:47:51 +00:00
if ( pChar - > m_Weapon ! = m_Core . m_ActiveWeapon )
SetActiveWeapon ( pChar - > m_Weapon ) ;
2019-06-30 21:47:33 +00:00
}
2019-04-11 22:46:54 +00:00
// reset all input except direction and hook for non-local players (as in vanilla prediction)
if ( ! IsLocal )
{
mem_zero ( & m_Input , sizeof ( m_Input ) ) ;
mem_zero ( & m_SavedInput , sizeof ( m_SavedInput ) ) ;
m_Input . m_Direction = m_SavedInput . m_Direction = m_Core . m_Direction ;
2019-06-05 00:01:31 +00:00
m_Input . m_Hook = m_SavedInput . m_Hook = ( m_Core . m_HookState ! = HOOK_IDLE ) ;
2020-10-17 17:02:58 +00:00
m_Input . m_TargetX = m_SavedInput . m_TargetX = cosf ( pChar - > m_Angle / 256.0f ) * 256.0f ;
m_Input . m_TargetY = m_SavedInput . m_TargetY = sinf ( pChar - > m_Angle / 256.0f ) * 256.0f ;
2019-04-11 22:46:54 +00:00
}
2020-07-15 00:47:51 +00:00
// in most cases the reload timer can be determined from the last attack tick
// (this is only needed for autofire weapons to prevent the predicted reload timer from desyncing)
if ( IsLocal & & m_Core . m_ActiveWeapon ! = WEAPON_HAMMER )
{
if ( maximum ( m_LastTuneZoneTick , m_LastWeaponSwitchTick ) + GameWorld ( ) - > GameTickSpeed ( ) < GameWorld ( ) - > GameTick ( ) )
{
float FireDelay ;
GetTuning ( m_TuneZone ) - > Get ( 38 + m_Core . m_ActiveWeapon , & FireDelay ) ;
const int FireDelayTicks = FireDelay * GameWorld ( ) - > GameTickSpeed ( ) / 1000 ;
m_ReloadTimer = maximum ( 0 , m_AttackTick + FireDelayTicks - GameWorld ( ) - > GameTick ( ) ) ;
}
}
2022-03-29 09:17:09 +00:00
if ( pExtendedDisplayInfo )
{
if ( GameWorld ( ) - > m_WorldConfig . m_PredictFreeze )
{
m_Core . m_FreezeTick = pExtendedDisplayInfo - > m_FreezeTick ;
}
m_Core . m_IsInFreeze = pExtendedDisplayInfo - > m_IsInFreeze ;
m_Core . m_Ninja . m_ActivationTick = pExtendedDisplayInfo - > m_NinjaActivationTick ;
m_Core . m_JumpedTotal = pExtendedDisplayInfo - > m_JumpedTotal ;
2022-04-14 11:31:00 +00:00
if ( ! IsLocal )
{
m_Input . m_TargetX = pExtendedDisplayInfo - > m_TargetX ;
m_Input . m_TargetY = pExtendedDisplayInfo - > m_TargetY ;
}
2022-03-29 09:17:09 +00:00
}
2019-04-11 22:46:54 +00:00
}
void CCharacter : : SetCoreWorld ( CGameWorld * pGameWorld )
{
m_Core . m_pWorld = & pGameWorld - > m_Core ;
m_Core . m_pCollision = pGameWorld - > Collision ( ) ;
m_Core . m_pTeams = pGameWorld - > Teams ( ) ;
}
bool CCharacter : : Match ( CCharacter * pChar )
{
2022-01-22 16:34:23 +00:00
return distance ( pChar - > m_Core . m_Pos , m_Core . m_Pos ) < = 32.f ;
2019-04-11 22:46:54 +00:00
}
2020-07-15 00:47:51 +00:00
void CCharacter : : SetActiveWeapon ( int ActiveWeap )
{
m_Core . m_ActiveWeapon = ActiveWeap ;
m_LastWeaponSwitchTick = GameWorld ( ) - > GameTick ( ) ;
}
void CCharacter : : SetTuneZone ( int Zone )
{
if ( Zone = = m_TuneZone )
return ;
m_TuneZone = Zone ;
m_LastTuneZoneTick = GameWorld ( ) - > GameTick ( ) ;
}
2022-05-26 17:04:13 +00:00
CCharacter : : ~ CCharacter ( )
{
if ( GameWorld ( ) )
GameWorld ( ) - > RemoveCharacter ( this ) ;
}