Merge branch 'develop' into mapbase/feature/protagonist-system

This commit is contained in:
Blixibon 2025-02-28 21:14:26 -06:00 committed by GitHub
commit 940745c7fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
112 changed files with 29695 additions and 1454 deletions

7
.gitignore vendored
View File

@ -19,6 +19,8 @@ ipch
*.idb
*.vcxproj
*.sln
*.vcxproj.FileListAbsolute.txt
*.pdb
# OSX/Linux build products
*.mak
@ -49,6 +51,8 @@ client.dylib.dSYM/
server.dylib
server.dylib.dSYM/
sp/game/bin
# files generated by running a mod
config.cfg
@ -61,6 +65,7 @@ config.cfg
*.filters
*.vpc_crc
*.sentinel
*.recipe
# Backup files
*.bak
@ -90,4 +95,4 @@ sp/src/vgui2/*.dll
sp/src/vgui2/*.pdb
# Build support files
sp/src/devtools/gcc9+support.o
sp/src/devtools/gcc9+support.o

View File

@ -1531,35 +1531,32 @@ float C_BaseAnimating::ClampCycle( float flCycle, bool isLooping )
//-----------------------------------------------------------------------------
const Vector& C_BaseAnimating::ScriptGetAttachmentOrigin( int iAttachment )
{
static Vector absOrigin;
static QAngle qa;
QAngle qa;
C_BaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
return absOrigin;
}
const Vector& C_BaseAnimating::ScriptGetAttachmentAngles( int iAttachment )
const QAngle& C_BaseAnimating::ScriptGetAttachmentAngles( int iAttachment )
{
static Vector absOrigin;
static Vector absAngles;
static QAngle qa;
Vector absOrigin;
C_BaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
absAngles.x = qa.x;
absAngles.y = qa.y;
absAngles.z = qa.z;
return absAngles;
return qa;
}
HSCRIPT C_BaseAnimating::ScriptGetAttachmentMatrix( int iAttachment )
HSCRIPT_RC C_BaseAnimating::ScriptGetAttachmentMatrix( int iAttachment )
{
static matrix3x4_t matrix;
matrix3x4_t *matrix = new matrix3x4_t;
C_BaseAnimating::GetAttachment( iAttachment, matrix );
return g_pScriptVM->RegisterInstance( &matrix );
if ( C_BaseAnimating::GetAttachment( iAttachment, *matrix ) )
return g_pScriptVM->RegisterInstance( matrix, true );
delete matrix;
return NULL;
}
void C_BaseAnimating::ScriptGetBoneTransform( int iBone, HSCRIPT hTransform )

View File

@ -464,8 +464,8 @@ public:
#ifdef MAPBASE_VSCRIPT
int ScriptLookupAttachment( const char *pAttachmentName ) { return LookupAttachment( pAttachmentName ); }
const Vector& ScriptGetAttachmentOrigin(int iAttachment);
const Vector& ScriptGetAttachmentAngles(int iAttachment);
HSCRIPT ScriptGetAttachmentMatrix(int iAttachment);
const QAngle& ScriptGetAttachmentAngles(int iAttachment);
HSCRIPT_RC ScriptGetAttachmentMatrix(int iAttachment);
void ScriptGetBoneTransform( int iBone, HSCRIPT hTransform );
void ScriptSetBoneTransform( int iBone, HSCRIPT hTransform );

View File

@ -90,11 +90,10 @@ static inline bool ShouldDrawLocalPlayerViewModel( void )
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
if (localplayer)
{
if (localplayer->m_bDrawPlayerModelExternally)
if (localplayer->DrawingPlayerModelExternally() && localplayer->InFirstPersonView())
{
// If this isn't the main view, draw the weapon.
view_id_t viewID = CurrentViewID();
if (viewID != VIEW_MAIN && viewID != VIEW_INTRO_CAMERA)
if (!localplayer->InPerspectiveView())
return false;
}
@ -224,8 +223,16 @@ ShadowType_t C_BaseCombatWeapon::ShadowCastType()
if (!IsBeingCarried())
return SHADOWS_RENDER_TO_TEXTURE;
if (IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer())
return SHADOWS_NONE;
if (IsCarriedByLocalPlayer())
{
if (!C_BasePlayer::ShouldDrawLocalPlayer())
return SHADOWS_NONE;
#ifdef MAPBASE
if (C_BasePlayer::GetLocalPlayer() && C_BasePlayer::GetLocalPlayer()->ShadowCastType() == SHADOWS_NONE)
return SHADOWS_NONE;
#endif
}
return SHADOWS_RENDER_TO_TEXTURE;
}
@ -458,7 +465,7 @@ bool C_BaseCombatWeapon::ShouldDraw( void )
#ifdef MAPBASE
// We're drawing this in non-main views, handle it in DrawModel()
if ( pLocalPlayer->m_bDrawPlayerModelExternally )
if ( pLocalPlayer->DrawingPlayerModelExternally() )
return true;
#endif
@ -511,11 +518,10 @@ int C_BaseCombatWeapon::DrawModel( int flags )
if ( localplayer )
{
#ifdef MAPBASE
if (localplayer->m_bDrawPlayerModelExternally)
if (GetOwner() == localplayer && localplayer->DrawingPlayerModelExternally())
{
// If this isn't the main view, draw the weapon.
view_id_t viewID = CurrentViewID();
if ( (!localplayer->InFirstPersonView() || (viewID != VIEW_MAIN && viewID != VIEW_INTRO_CAMERA)) && (viewID != VIEW_SHADOW_DEPTH_TEXTURE || !localplayer->IsEffectActive(EF_DIMLIGHT)) )
if ( (!localplayer->InPerspectiveView() || !localplayer->InFirstPersonView()) && (CurrentViewID() != VIEW_SHADOW_DEPTH_TEXTURE || !localplayer->IsEffectActive(EF_DIMLIGHT)))
{
// TODO: Is this inefficient?
int nModelIndex = GetModelIndex();
@ -534,6 +540,10 @@ int C_BaseCombatWeapon::DrawModel( int flags )
return iDraw;
}
else
{
return 0;
}
}
#endif
if ( localplayer->IsObserver() && GetOwner() )
@ -551,6 +561,24 @@ int C_BaseCombatWeapon::DrawModel( int flags )
return BaseClass::DrawModel( flags );
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::DispatchMuzzleEffect( const char *options, bool isFirstPerson )
{
// Don't show muzzle flashes in first-person
C_BasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if (pPlayer)
{
if (pPlayer->DrawingPlayerModelExternally() && pPlayer->InFirstPersonView())
return false;
}
return BaseClass::DispatchMuzzleEffect( options, isFirstPerson );
}
#endif
//-----------------------------------------------------------------------------
// Allows the client-side entity to override what the network tells it to use for

View File

@ -433,8 +433,7 @@ ScriptHook_t C_BaseEntity::g_Hook_UpdateOnRemove;
ScriptHook_t C_BaseEntity::g_Hook_ModifyEmitSoundParams;
#endif
BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities" )
DEFINE_SCRIPT_INSTANCE_HELPER( &g_BaseEntityScriptInstanceHelper )
BEGIN_ENT_SCRIPTDESC_ROOT_WITH_HELPER( C_BaseEntity, "Root class of all client-side entities", &g_BaseEntityScriptInstanceHelper )
DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" )
#ifdef MAPBASE_VSCRIPT

View File

@ -125,6 +125,16 @@ ConVar demo_fov_override( "demo_fov_override", "0", FCVAR_CLIENTDLL | FCVAR_DONT
// This value is found by hand, and a good value depends more on the in-game models than on actual human shapes.
ConVar cl_meathook_neck_pivot_ingame_up( "cl_meathook_neck_pivot_ingame_up", "7.0" );
ConVar cl_meathook_neck_pivot_ingame_fwd( "cl_meathook_neck_pivot_ingame_fwd", "3.0" );
#ifdef MAPBASE
ConVar cl_meathook_neck_pivot_override( "cl_meathook_neck_pivot_override", "0", FCVAR_NONE, "Overrides playermodel values for meathook and uses cvars only" );
//-------------------------------------------------------------------------------------
ConVar cl_playermodel_draw_externally_override( "cl_playermodel_draw_externally_override", "-1", FCVAR_ARCHIVE, "Overrides developer-placed options to draw the player's model externally." );
ConVar cl_playermodel_legs_override( "cl_playermodel_legs_override", "-1", FCVAR_ARCHIVE, "Overrides developer-placed options to draw the player's model below the camera." );
ConVar cl_playermodel_legs_scale_bones( "cl_playermodel_legs_scale_bones", "1" );
#endif
void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut );
@ -280,6 +290,7 @@ END_RECV_TABLE()
// See baseplayer_shared.h for more details.
RecvPropInt ( RECVINFO( m_spawnflags ), 0, RecvProxy_ShiftPlayerSpawnflags ),
RecvPropBool ( RECVINFO( m_bDrawPlayerLegs ) ),
RecvPropBool ( RECVINFO( m_bDrawPlayerModelExternally ) ),
RecvPropBool ( RECVINFO( m_bInTriggerFall ) ),
#endif
@ -1486,13 +1497,186 @@ bool C_BasePlayer::ShouldInterpolate()
}
#ifdef MAPBASE
bool C_BasePlayer::InPerspectiveView() const
{
// VIEW_NONE is used by the water intersection view, see CAboveWaterView::CIntersectionView::Draw()
// (TODO: Consider changing the view ID at the source to VIEW_REFRACTION? VIEW_NONE could be an oversight)
view_id_t viewID = CurrentViewID();
return (viewID == VIEW_MAIN || viewID == VIEW_INTRO_CAMERA || viewID == VIEW_REFRACTION || viewID == VIEW_NONE);
}
bool C_BasePlayer::DrawingPlayerModelExternally() const
{
if (cl_playermodel_draw_externally_override.GetInt() > -1)
return cl_playermodel_draw_externally_override.GetBool();
return m_bDrawPlayerModelExternally;
}
bool C_BasePlayer::DrawingLegs() const
{
if (cl_playermodel_legs_override.GetInt() > -1)
return cl_playermodel_legs_override.GetBool();
// For now, don't draw legs if looking up in any way
// (fixes issues with some animations causing clipping with chest)
if (GetAbsAngles().x < 0.0f)
return false;
return m_bDrawPlayerLegs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CStudioHdr *C_BasePlayer::OnNewModel( void )
{
CStudioHdr *hdr = BaseClass::OnNewModel();
if (!hdr)
return NULL;
KeyValues *modelKeyValues = new KeyValues( "" );
CUtlBuffer buf( 1024, 0, CUtlBuffer::TEXT_BUFFER );
// Init values
m_FirstPersonModelData.Reset();
if (!modelinfo->GetModelKeyValue( GetModel(), buf ))
{
modelKeyValues->deleteThis();
return hdr;
}
if (modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), buf ))
{
CUtlVector<string_t> iszUsedNames;
for (KeyValues *pkvModelBlock = modelKeyValues; pkvModelBlock != nullptr; pkvModelBlock = pkvModelBlock->GetNextKey())
{
KeyValues *pkvPlayerModelData = pkvModelBlock->FindKey( "playermodel_data" );
if (pkvPlayerModelData)
{
m_FirstPersonModelData.ParseModelData( this, pkvPlayerModelData );
break;
}
}
}
modelKeyValues->deleteThis();
return hdr;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_BasePlayer::FirstPersonModelData_t::ParseModelData( C_BasePlayer *pPlayer, KeyValues *pkvPlayerModelData )
{
m_flFirstPersonNeckPivotUp = pkvPlayerModelData->GetFloat( "neck_pivot_up", FLT_MAX );
m_flFirstPersonNeckPivotFwd = pkvPlayerModelData->GetFloat( "neck_pivot_fwd", FLT_MAX );
m_flFirstPersonNeckPivotDuckUp = pkvPlayerModelData->GetFloat( "neck_pivot_duck_up", FLT_MAX );
m_flFirstPersonNeckPivotDuckFwd = pkvPlayerModelData->GetFloat( "neck_pivot_duck_fwd", FLT_MAX );
KeyValues *pkvBoneScales = pkvPlayerModelData->FindKey( "bone_transforms" );
if (pkvBoneScales)
{
KeyValues *pkvSpineTransforms = pkvBoneScales->FindKey( "spine" );
if (pkvSpineTransforms)
{
for (KeyValues *pkvBone = pkvSpineTransforms->GetFirstSubKey(); pkvBone != nullptr; pkvBone = pkvBone->GetNextKey())
{
int nBone = pPlayer->LookupBone( pkvBone->GetName() );
if (nBone == -1)
continue;
m_FirstPersonBoneScales[BoneScales_Spine].Insert(nBone, pkvBone->GetFloat());
}
}
KeyValues *pkvArmsTransforms = pkvBoneScales->FindKey( "arms" );
if (pkvArmsTransforms)
{
for (KeyValues *pkvBone = pkvArmsTransforms->GetFirstSubKey(); pkvBone != nullptr; pkvBone = pkvBone->GetNextKey())
{
int nBone = pPlayer->LookupBone( pkvBone->GetName() );
if (nBone == -1)
continue;
m_FirstPersonBoneScales[BoneScales_Arms].Insert( nBone, pkvBone->GetFloat() );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: move position and rotation transforms into global matrices
//-----------------------------------------------------------------------------
void C_BasePlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion *q, const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed )
{
BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );
if (DrawingLegs() && InPerspectiveView() && InFirstPersonView())
{
//BuildFirstPersonMeathookTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed, "ValveBiped.Bip01_Head1" );
if (cl_playermodel_legs_scale_bones.GetBool())
{
// For now, only do transforms when we have an active weapon
// (since we typically just cull stuff influenced by viewmodels and upper-body weapon posture, like arms)
if ((GetActiveWeapon() && !GetActiveWeapon()->IsEffectActive( EF_NODRAW )) || GetUseEntity())
{
matrix3x4_t *pFirstZero = NULL;
for (int nMap = 0; nMap < FirstPersonModelData_t::BoneScales_Max; nMap++)
{
const CUtlMap<int, float> &scaleMap = m_FirstPersonModelData.m_FirstPersonBoneScales[nMap];
FOR_EACH_MAP( scaleMap, i )
{
int nBone = scaleMap.Key(i);
if (nBone == -1)
continue;
if (!(hdr->boneFlags( nBone ) & boneMask))
continue;
float flScale = scaleMap.Element(i);
matrix3x4_t &mTransform = GetBoneForWrite( nBone );
if (flScale == 0.0f)
{
if (!pFirstZero)
{
MatrixScaleByZero( mTransform );
pFirstZero = &mTransform;
}
else
{
// Keep zeroes in one place
MatrixCopy( *pFirstZero, mTransform );
}
}
else
{
MatrixScaleBy( flScale, mTransform );
}
}
}
}
}
}
}
#endif
bool C_BasePlayer::ShouldDraw()
{
#ifdef MAPBASE
// We have to "always draw" a player with m_bDrawPlayerModelExternally in order to show up in whatever rendering list all of the views use,
// but we can't put this in ShouldDrawThisPlayer() because we would have no way of knowing if it stomps the other checks that draw the player model anyway.
// As a result, we have to put it here in the central ShouldDraw() function. DrawModel() makes sure we only draw in non-main views and nothing's drawing the model anyway.
return (ShouldDrawThisPlayer() || m_bDrawPlayerModelExternally) && BaseClass::ShouldDraw();
return (ShouldDrawThisPlayer() || DrawingPlayerModelExternally() || DrawingLegs()) && BaseClass::ShouldDraw();
#else
return ShouldDrawThisPlayer() && BaseClass::ShouldDraw();
#endif
@ -1501,12 +1685,16 @@ bool C_BasePlayer::ShouldDraw()
int C_BasePlayer::DrawModel( int flags )
{
#ifdef MAPBASE
if (m_bDrawPlayerModelExternally)
if (DrawingLegs() && InFirstPersonView() && InPerspectiveView())
{
return BaseClass::DrawModel( flags );
}
if (DrawingPlayerModelExternally())
{
// Draw the player in any view except the main or "intro" view, both of which are default first-person views.
// HACKHACK: Also don't draw in shadow depth textures if the player's flashlight is on, as that causes the playermodel to block it.
view_id_t viewID = CurrentViewID();
if (viewID == VIEW_MAIN || viewID == VIEW_INTRO_CAMERA || (viewID == VIEW_SHADOW_DEPTH_TEXTURE && IsEffectActive(EF_DIMLIGHT)))
if (InPerspectiveView() || (CurrentViewID() == VIEW_SHADOW_DEPTH_TEXTURE && IsEffectActive(EF_DIMLIGHT)))
{
// Make sure the player model wouldn't draw anyway...
if (!ShouldDrawThisPlayer())
@ -3057,13 +3245,21 @@ void C_BasePlayer::BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vec
return;
}
#ifdef MAPBASE
if ( !InPerspectiveView() )
#else
if ( !DrawingMainView() )
#endif
{
return;
}
// If we aren't drawing the player anyway, don't mess with the bones. This can happen in Portal.
#ifdef MAPBASE
if ( !ShouldDrawThisPlayer() && !DrawingPlayerModelExternally() && !DrawingLegs() )
#else
if( !ShouldDrawThisPlayer() )
#endif
{
return;
}
@ -3084,6 +3280,63 @@ void C_BasePlayer::BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vec
Vector vHeadTransformTranslation ( mHeadTransform[0][3], mHeadTransform[1][3], mHeadTransform[2][3] );
float flNeckPivotUp = cl_meathook_neck_pivot_ingame_up.GetFloat();
float flNeckPivotFwd = cl_meathook_neck_pivot_ingame_fwd.GetFloat();
#ifdef MAPBASE
if (DrawingLegs() && !cl_meathook_neck_pivot_override.GetBool())
{
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotUp != FLT_MAX || m_FirstPersonModelData.m_flFirstPersonNeckPivotFwd != FLT_MAX)
{
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotUp != FLT_MAX)
flNeckPivotUp = m_FirstPersonModelData.m_flFirstPersonNeckPivotUp;
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotFwd != FLT_MAX)
flNeckPivotFwd = m_FirstPersonModelData.m_flFirstPersonNeckPivotFwd;
if (GetFlags() & FL_DUCKING || m_Local.m_flDucktime > 0.0f)
{
if (!IsLocalPlayer() || m_Local.m_flDucktime <= 0.0f)
{
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckUp != FLT_MAX)
flNeckPivotUp = m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckUp;
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckFwd != FLT_MAX)
flNeckPivotFwd = m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckFwd;
}
else
{
bool bDucking;
if (IsLocalPlayer())
bDucking = input->GetButtonBits(0) & IN_DUCK;
else
bDucking = GetCurrentUserCommand()->buttons & IN_DUCK;
// HACKHACK using constants from game movement
float flPerc = SimpleSpline( RemapValClamped( m_Local.m_flDucktime, bDucking ? 600.0f : 800.0f, 1000.0f, 0.0f, 1.0f ) );
if (bDucking)
{
// Ducking
//Msg( "Ducking with perc %f (%f)\n", flPerc, m_Local.m_flDucktime );
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckUp != FLT_MAX)
flNeckPivotUp = FLerp( m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckUp, flNeckPivotUp, flPerc );
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckFwd != FLT_MAX)
flNeckPivotFwd = FLerp( m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckFwd, flNeckPivotFwd, flPerc );
}
else
{
// Unducking
//Msg( "Unducking with perc %f (%f)\n", flPerc, m_Local.m_flDucktime );
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckUp != FLT_MAX)
flNeckPivotUp = FLerp( flNeckPivotUp, m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckUp, flPerc );
if (m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckFwd != FLT_MAX)
flNeckPivotFwd = FLerp( flNeckPivotFwd, m_FirstPersonModelData.m_flFirstPersonNeckPivotDuckFwd, flPerc );
}
}
}
}
}
#endif
// Find out where the player's head (driven by the HMD) is in the world.
// We can't move this with animations or effects without causing nausea, so we need to move
// the whole body so that the animated head is in the right place to match the player-controlled head.
@ -3100,7 +3353,7 @@ void C_BasePlayer::BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vec
// The head bone is the neck pivot point of the in-game character.
Vector vRealMidEyePos = mWorldFromMideye.GetTranslation();
vRealPivotPoint = vRealMidEyePos - ( mWorldFromMideye.GetUp() * cl_meathook_neck_pivot_ingame_up.GetFloat() ) - ( mWorldFromMideye.GetForward() * cl_meathook_neck_pivot_ingame_fwd.GetFloat() );
vRealPivotPoint = vRealMidEyePos - ( mWorldFromMideye.GetUp() * flNeckPivotUp ) - ( mWorldFromMideye.GetForward() * flNeckPivotFwd );
}
else
{
@ -3108,7 +3361,7 @@ void C_BasePlayer::BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vec
Vector vForward, vRight, vUp;
AngleVectors( MainViewAngles(), &vForward, &vRight, &vUp );
vRealPivotPoint = MainViewOrigin() - ( vUp * cl_meathook_neck_pivot_ingame_up.GetFloat() ) - ( vForward * cl_meathook_neck_pivot_ingame_fwd.GetFloat() );
vRealPivotPoint = MainViewOrigin() - ( vUp * flNeckPivotUp ) - ( vForward * flNeckPivotFwd );
}
Vector vDeltaToAdd = vRealPivotPoint - vHeadTransformTranslation;

View File

@ -293,6 +293,15 @@ public:
virtual bool ShouldInterpolate();
#ifdef MAPBASE
bool InPerspectiveView() const; // In a view that renders directly from the player's perspective (and may, for example, render the playermodel)
bool DrawingPlayerModelExternally() const;
bool DrawingLegs() const;
virtual CStudioHdr *OnNewModel( void );
virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed );
#endif
virtual bool ShouldDraw();
virtual int DrawModel( int flags );
@ -468,6 +477,9 @@ public:
inline void RemoveSpawnFlags( int flags ) { m_spawnflags &= ~flags; }
inline void AddSpawnFlags( int flags ) { m_spawnflags |= flags; }
// Draws the player's model below the camera, visible when the player looks down.
bool m_bDrawPlayerLegs;
// Allows the player's model to draw on non-main views, like monitors or mirrors.
bool m_bDrawPlayerModelExternally;
@ -502,6 +514,10 @@ protected:
virtual void FireGameEvent( IGameEvent *event );
#ifdef MAPBASE
inline CUtlMap<int, float> &GetFirstPersonArmScales() { return m_FirstPersonModelData.m_FirstPersonBoneScales[FirstPersonModelData_t::BoneScales_Arms]; }
#endif
protected:
// Did we just enter a vehicle this frame?
bool JustEnteredVehicle();
@ -556,6 +572,41 @@ private:
bool m_bFiredWeapon;
#ifdef MAPBASE
struct FirstPersonModelData_t
{
void Reset()
{
m_flFirstPersonNeckPivotUp = m_flFirstPersonNeckPivotFwd = FLT_MAX;
m_flFirstPersonNeckPivotDuckUp = m_flFirstPersonNeckPivotDuckFwd = FLT_MAX;
for (int i = 0; i < BoneScales_Max; i++)
{
m_FirstPersonBoneScales[i].RemoveAll();
m_FirstPersonBoneScales[i].SetLessFunc( DefLessFunc( int ) );
}
}
void ParseModelData( C_BasePlayer *pPlayer, KeyValues *pkvPlayerModelData );
enum
{
BoneScales_Spine,
BoneScales_Arms,
BoneScales_Max
};
// Values to scale bones by when drawing playermodel in first person
CUtlMap<int, float> m_FirstPersonBoneScales[BoneScales_Max];
float m_flFirstPersonNeckPivotUp, m_flFirstPersonNeckPivotFwd = FLT_MAX;
float m_flFirstPersonNeckPivotDuckUp, m_flFirstPersonNeckPivotDuckFwd = FLT_MAX;
};
FirstPersonModelData_t m_FirstPersonModelData;
#endif
// Player flashlight dynamic light pointers
CFlashlightEffect *m_pFlashlight;

View File

@ -399,10 +399,38 @@ int C_SpriteRenderer::DrawSprite(
if ( group == RENDER_GROUP_VIEW_MODEL_TRANSLUCENT || group == RENDER_GROUP_VIEW_MODEL_OPAQUE )
return 0;
}
#ifdef MAPBASE
if (ent->m_iViewHideFlags > 0)
{
// Hide this entity if it's not supposed to be drawn in this view.
if (ent->m_iViewHideFlags & (1 << CurrentViewID()))
{
return 0;
}
}
#endif
QAngle temp;
ent->GetAttachment( attachmentindex, effect_origin, temp );
}
}
#ifdef MAPBASE
if ( entity )
{
C_BaseEntity *ent = entity->GetBaseEntity();
if ( ent )
{
if (ent->m_iViewHideFlags > 0)
{
// Hide this entity if it's not supposed to be drawn in this view.
if (ent->m_iViewHideFlags & (1 << CurrentViewID()))
{
return 0;
}
}
}
}
#endif
if ( rendermode != kRenderNormal )
{

View File

@ -47,8 +47,8 @@ $Project
$File "$SRCDIR\game\shared\mapbase\MapEdit.h"
$File "$SRCDIR\game\shared\mapbase\matchers.cpp"
$File "$SRCDIR\game\shared\mapbase\matchers.h"
$File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.cpp"
$File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.h"
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.h"
$File "$SRCDIR\game\shared\mapbase\protagonist_system.cpp"
$File "$SRCDIR\game\shared\mapbase\protagonist_system.h"
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]

View File

@ -157,6 +157,22 @@ void CColorCorrectionMgr::CommitColorCorrectionWeights()
}
m_colorCorrectionWeights.RemoveAll();
}
void CColorCorrectionMgr::LevelShutdownPreEntity()
{
//Clean up the vectors when shuting down a level
//will keep dangling pointers inside of the vector causing a nullptr crash
if (g_ColorCorrectionVolumeList.Base())
{
g_ColorCorrectionVolumeList.Purge();
}
if (g_ColorCorrectionList.Base())
{
g_ColorCorrectionList.Purge();
}
}
#else
void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight )
{

View File

@ -76,6 +76,8 @@ private:
CUtlVector< SetWeightParams_t > m_colorCorrectionWeights;
void CommitColorCorrectionWeights();
void LevelShutdownPreEntity();
#endif
};

View File

@ -36,6 +36,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_BaseHLPlayer, DT_HL2_Player, CHL2_Player)
#endif
#ifdef SP_ANIM_STATE
RecvPropFloat( RECVINFO( m_flAnimRenderYaw ) ),
RecvPropFloat( RECVINFO( m_flAnimRenderZ ) ),
#endif
END_RECV_TABLE()
@ -108,6 +109,22 @@ void C_BaseHLPlayer::OnDataChanged( DataUpdateType_t updateType )
BaseClass::OnDataChanged( updateType );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::AddEntity( void )
{
BaseClass::AddEntity();
#ifdef MAPBASE_MP
if (m_pPlayerAnimState)
{
QAngle angEyeAngles = EyeAngles();
m_pPlayerAnimState->Update( angEyeAngles.y, angEyeAngles.x );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -669,24 +686,76 @@ bool C_BaseHLPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
void C_BaseHLPlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
{
BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );
/*#ifdef MAPBASE
// BuildFirstPersonMeathookTransformations is used prior to this when drawing legs
if (!DrawingLegs() || !InPerspectiveView() || !InFirstPersonView())
#endif*/
BuildFirstPersonMeathookTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed, "ValveBiped.Bip01_Head1" );
}
#ifdef SP_ANIM_STATE
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &C_BaseHLPlayer::GetRenderOrigin()
{
if (m_flAnimRenderZ != 0.0f)
{
static Vector vecRender;
vecRender = BaseClass::GetRenderOrigin();
vecRender.z += m_flAnimRenderZ;
return vecRender;
}
return BaseClass::GetRenderOrigin();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const QAngle& C_BaseHLPlayer::GetRenderAngles( void )
{
#ifdef MAPBASE_MP
if ( m_pPlayerAnimState )
{
return m_pPlayerAnimState->GetRenderAngles();
}
#else
if ( m_flAnimRenderYaw != FLT_MAX )
{
return m_angAnimRender;
}
#endif
else
{
return BaseClass::GetRenderAngles();
}
}
//-----------------------------------------------------------------------------
// Purpose: model-change notification. Fires on dynamic load completion as well
//-----------------------------------------------------------------------------
CStudioHdr *C_BaseHLPlayer::OnNewModel()
{
CStudioHdr *hdr = BaseClass::OnNewModel();
#ifdef MAPBASE_MP
// Clears the animation state if we already have one.
if ( m_pPlayerAnimState != NULL )
{
m_pPlayerAnimState->Release();
m_pPlayerAnimState = NULL;
}
if ( hdr && hdr->HaveSequenceForActivity(ACT_HL2MP_IDLE) /*&& hl2_use_sp_animstate.GetBool()*/ )
{
// Here we create and init the player animation state.
m_pPlayerAnimState = CreatePlayerAnimationState(this);
}
#endif
return hdr;
}
#endif

View File

@ -16,7 +16,7 @@
#include "c_hl2_playerlocaldata.h"
#if !defined( HL2MP ) && defined ( MAPBASE )
#include "mapbase/singleplayer_animstate.h"
#include "mapbase/mapbase_playeranimstate.h"
#endif
class C_BaseHLPlayer : public C_BasePlayer
@ -29,6 +29,7 @@ public:
C_BaseHLPlayer();
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void AddEntity( void );
void Weapon_DropPrimary( void );
@ -67,7 +68,9 @@ public:
#endif
#ifdef SP_ANIM_STATE
virtual const Vector& GetRenderOrigin();
virtual const QAngle& GetRenderAngles( void );
virtual CStudioHdr *OnNewModel();
#endif
public:
@ -95,10 +98,13 @@ private:
int m_nProtagonistIndex;
#endif
#ifdef SP_ANIM_STATE
#ifdef MAPBASE_MP
CSinglePlayerAnimState *m_pPlayerAnimState;
#elif MAPBASE
// At the moment, we network the render angles since almost none of the player anim stuff is done on the client in SP.
// If any of this is ever adapted for MP, this method should be replaced with replicating/moving the anim state to the client.
float m_flAnimRenderYaw;
float m_flAnimRenderZ;
QAngle m_angAnimRender;
#endif

View File

@ -100,7 +100,11 @@ void CHudSuitPower::OnThink( void )
}
bool flashlightActive = pPlayer->IsFlashlightActive();
#ifdef MAPBASE
bool sprintActive = pPlayer->IsSprintActive();
#else
bool sprintActive = pPlayer->IsSprinting();
#endif
bool breatherActive = pPlayer->IsBreatherActive();
int activeDevices = (int)flashlightActive + (int)sprintActive + (int)breatherActive;
@ -250,7 +254,11 @@ void CHudSuitPower::Paint()
ypos += text2_gap;
}
#ifdef MAPBASE
if (pPlayer->IsSprintActive())
#else
if (pPlayer->IsSprinting())
#endif
{
tempString = g_pVGuiLocalize->Find("#Valve_Hud_SPRINT");

View File

@ -1031,7 +1031,7 @@ void CScriptSurface::DrawColoredTextRect( int font, int x, int y, int w, int h,
#define __base() this->_base
#define BEGIN_SCRIPTDESC_VGUI( panelClass )\
BEGIN_SCRIPTDESC_NAMED( CScript_##panelClass##_Helper, IScriptVGUIObject, #panelClass, "" )\
BEGIN_SCRIPTDESC_NAMED_WITH_HELPER( CScript_##panelClass##_Helper, IScriptVGUIObject, #panelClass, "", VGUI_SCRIPT_INSTANCE_HELPER )\
DEFINE_VGUI_SCRIPTFUNC_##panelClass()
//
@ -1235,9 +1235,9 @@ class CScriptVGUIScriptInstanceHelper : public IScriptInstanceHelper
static CScriptVGUIScriptInstanceHelper g_ScriptVGUIScriptInstanceHelper;
#define DEFINE_VGUI_SCRIPT_INSTANCE_HELPER() DEFINE_SCRIPT_INSTANCE_HELPER( &g_ScriptVGUIScriptInstanceHelper )
#define VGUI_SCRIPT_INSTANCE_HELPER &g_ScriptVGUIScriptInstanceHelper
#else
#define DEFINE_VGUI_SCRIPT_INSTANCE_HELPER()
#define VGUI_SCRIPT_INSTANCE_HELPER NULL
#endif
@ -1866,8 +1866,6 @@ public:
};
#define DEFINE_VGUI_SCRIPTFUNC_Panel()\
DEFINE_VGUI_SCRIPT_INSTANCE_HELPER()\
\
DEFINE_SCRIPTFUNC( Destroy, "" )\
DEFINE_SCRIPTFUNC( MakeReadyForUse, "" )\
DEFINE_SCRIPTFUNC( GetName, "" )\
@ -2612,9 +2610,17 @@ public:
static inline void SetHScript( HSCRIPT &var, HSCRIPT val )
{
if ( var && g_pScriptVM )
g_pScriptVM->ReleaseScript( var );
var = val;
if ( g_pScriptVM )
{
if ( var )
g_pScriptVM->ReleaseScript( var );
var = g_pScriptVM->CopyObject( val );
}
else
{
var = NULL;
}
}
#define CheckCallback(s)\

View File

@ -855,7 +855,7 @@ void CPrediction::RunCommand( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper
C_BaseCombatWeapon *weapon = dynamic_cast< C_BaseCombatWeapon * >( CBaseEntity::Instance( ucmd->weaponselect ) );
if ( weapon )
{
player->SelectItem( weapon->GetClassname(), ucmd->weaponsubtype );
player->SelectItem( weapon->GetName(), ucmd->weaponsubtype );
}
}

View File

@ -129,6 +129,7 @@ ConVar gl_clear_randomcolor( "gl_clear_randomcolor", "0", FCVAR_CHEAT, "Clear th
static ConVar r_farz( "r_farz", "-1", FCVAR_CHEAT, "Override the far clipping plane. -1 means to use the value in env_fog_controller." );
#ifdef MAPBASE
static ConVar r_nearz( "r_nearz", "-1", FCVAR_CHEAT, "Override the near clipping plane. -1 means to use the default value (usually 7)." );
static ConVar cl_camera_anim_intensity("cl_camera_anim_intensity", "1.0", FCVAR_ARCHIVE, "Intensity of cambone animations");
#endif
static ConVar cl_demoviewoverride( "cl_demoviewoverride", "0", 0, "Override view during demo playback" );
@ -1306,6 +1307,37 @@ void CViewRender::Render( vrect_t *rect )
g_ClientVirtualReality.OverlayHUDQuadWithUndistort( view, bDoUndistort, g_pClientMode->ShouldBlackoutAroundHUD(), bTranslucent );
}
}
#ifdef MAPBASE
//--------------------------------
// Handle camera anims
//--------------------------------
if (!UseVR() && pPlayer && cl_camera_anim_intensity.GetFloat() > 0)
{
if (pPlayer->GetViewModel(0))
{
int attachment = pPlayer->GetViewModel(0)->LookupAttachment("camera");
if (attachment != -1)
{
int rootBone = pPlayer->GetViewModel(0)->LookupAttachment("camera_root");
Vector cameraOrigin = Vector(0, 0, 0);
QAngle cameraAngles = QAngle(0, 0, 0);
Vector rootOrigin = Vector(0, 0, 0);
QAngle rootAngles = QAngle(0, 0, 0);
pPlayer->GetViewModel(0)->GetAttachmentLocal(attachment, cameraOrigin, cameraAngles);
if (rootBone != -1)
{
pPlayer->GetViewModel(0)->GetAttachmentLocal(rootBone, rootOrigin, rootAngles);
cameraOrigin -= rootOrigin;
cameraAngles -= rootAngles;
}
view.angles += cameraAngles * cl_camera_anim_intensity.GetFloat();
view.origin += cameraOrigin * cl_camera_anim_intensity.GetFloat();
}
}
}
#endif // MAPBASE
}

View File

@ -28,6 +28,10 @@
extern IScriptManager *scriptmanager;
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
#ifdef MAPBASE_VSCRIPT
extern int vscript_debugger_port;
#endif
// #define VMPROFILE 1
#ifdef VMPROFILE
@ -234,8 +238,7 @@ class CMaterialProxyScriptInstanceHelper : public IScriptInstanceHelper
CMaterialProxyScriptInstanceHelper g_MaterialProxyScriptInstanceHelper;
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptMaterialProxy, "CScriptMaterialProxy", "Material proxy for VScript" )
DEFINE_SCRIPT_INSTANCE_HELPER( &g_MaterialProxyScriptInstanceHelper )
BEGIN_SCRIPTDESC_ROOT_NAMED_WITH_HELPER( CScriptMaterialProxy, "CScriptMaterialProxy", "Material proxy for VScript", &g_MaterialProxyScriptInstanceHelper )
DEFINE_SCRIPTFUNC( GetVarString, "Gets a material var's string value" )
DEFINE_SCRIPTFUNC( GetVarInt, "Gets a material var's int value" )
DEFINE_SCRIPTFUNC( GetVarFloat, "Gets a material var's float value" )
@ -683,6 +686,14 @@ bool VScriptClientInit()
//g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" );
#endif
#ifdef MAPBASE_VSCRIPT
if ( vscript_debugger_port )
{
g_pScriptVM->ConnectDebugger( vscript_debugger_port );
vscript_debugger_port = 0;
}
#endif
if (scriptLanguage == SL_SQUIRREL)
{
g_pScriptVM->Run( g_Script_vscript_client );
@ -771,11 +782,19 @@ public:
VScriptClientTerm();
}
virtual void FrameUpdatePostEntityThink()
#ifdef MAPBASE_VSCRIPT
virtual void Update( float frametime )
{
if ( g_pScriptVM )
g_pScriptVM->Frame( frametime );
}
#else
virtual void FrameUpdatePostEntityThink()
{
if ( g_pScriptVM )
g_pScriptVM->Frame( gpGlobals->frametime );
}
#endif
bool m_bAllowEntityCreationInScripts;
};

View File

@ -16,6 +16,10 @@
#include "saverestore_utlvector.h"
#include "dt_utlvector_send.h"
#ifdef MAPBASE_VSCRIPT
#include "mapbase/vscript_funcs_shared.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -471,7 +475,8 @@ void CAnimationLayer::DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAni
}
#ifdef MAPBASE_VSCRIPT
if (eventHandler->m_ScriptScope.IsInitialized() && eventHandler->ScriptHookHandleAnimEvent( &event ) == false)
scriptanimevent_t wrapper( event );
if (eventHandler->m_ScriptScope.IsInitialized() && !eventHandler->ScriptHookHandleAnimEvent( wrapper ))
continue;
#endif

View File

@ -2594,6 +2594,18 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_CROSSBOW );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_PISTOL );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_SHOTGUN );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_SMG1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_AR2 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_PHYSGUN );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_GRENADE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_RPG );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_CROSSBOW );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_MELEE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_SLAM );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_REVOLVER );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_REVOLVER );
@ -2603,6 +2615,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_REVOLVER );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_REVOLVER );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_REVOLVER );
#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES
@ -2614,6 +2627,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_AR1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_AR1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_AR1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_AR3 );
@ -2624,6 +2638,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_AR3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_AR3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_AR3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SMG2 );
@ -2634,6 +2649,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG2 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_SMG2 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_SMG2 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_SMG2 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SMG3 );
@ -2644,6 +2660,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_SMG3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_SMG3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_SMG3 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_HMG1 );
@ -2654,6 +2671,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_HMG1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_HMG1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_HMG1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_HMG1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_HMG1 );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SNIPER_RIFLE );
@ -2664,6 +2682,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_SNIPER_RIFLE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SNIPER_RIFLE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_SNIPER_RIFLE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_SNIPER_RIFLE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_SNIPER_RIFLE );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_DUAL_PISTOLS );
@ -2674,6 +2693,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_DUAL_PISTOLS );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_DUAL_PISTOLS );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_DUAL_PISTOLS );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELAX_DUAL_PISTOLS );
ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_DUAL_PISTOLS );
#endif

View File

@ -318,6 +318,14 @@ ScriptHook_t CAI_BaseNPC::g_Hook_TranslateSchedule;
ScriptHook_t CAI_BaseNPC::g_Hook_GetActualShootPosition;
ScriptHook_t CAI_BaseNPC::g_Hook_OverrideMove;
ScriptHook_t CAI_BaseNPC::g_Hook_ShouldPlayFakeSequenceGesture;
ScriptHook_t CAI_BaseNPC::g_Hook_IsValidEnemy;
ScriptHook_t CAI_BaseNPC::g_Hook_CanBeAnEnemyOf;
ScriptHook_t CAI_BaseNPC::g_Hook_UpdateEnemyMemory;
ScriptHook_t CAI_BaseNPC::g_Hook_OnSeeEntity;
ScriptHook_t CAI_BaseNPC::g_Hook_OnListened;
ScriptHook_t CAI_BaseNPC::g_Hook_BuildScheduleTestBits;
ScriptHook_t CAI_BaseNPC::g_Hook_StartTask;
ScriptHook_t CAI_BaseNPC::g_Hook_RunTask;
#endif
//
@ -746,10 +754,19 @@ Vector CAI_BaseNPC::VScriptGetEnemyLKP()
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptFindEnemyMemory( HSCRIPT pEnemy )
int CAI_BaseNPC::VScriptNumEnemies()
{
return GetEnemies()->NumEnemies();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetFirstEnemyMemory()
{
HSCRIPT hScript = NULL;
AI_EnemyInfo_t *info = GetEnemies()->Find( ToEnt(pEnemy) );
AIEnemiesIter_t iter;
AI_EnemyInfo_t *info = GetEnemies()->GetFirst( &iter );
if (info)
{
hScript = g_pScriptVM->RegisterInstance( reinterpret_cast<Script_AI_EnemyInfo_t*>(info) );
@ -758,6 +775,70 @@ HSCRIPT CAI_BaseNPC::VScriptFindEnemyMemory( HSCRIPT pEnemy )
return hScript;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetNextEnemyMemory( HSCRIPT hMemory )
{
Script_AI_EnemyInfo_t *pCurEMemory = HScriptToClass<Script_AI_EnemyInfo_t>( hMemory );
if (!pCurEMemory)
return NULL;
HSCRIPT hScript = NULL;
AIEnemiesIter_t iter = (AIEnemiesIter_t)GetEnemies()->FindIndex( pCurEMemory->hEnemy );
AI_EnemyInfo_t *pEMemory = GetEnemies()->GetNext( &iter );
if (pEMemory)
{
hScript = g_pScriptVM->RegisterInstance( reinterpret_cast<Script_AI_EnemyInfo_t*>(pEMemory) );
}
return hScript;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptFindEnemyMemory( HSCRIPT hEnemy )
{
HSCRIPT hScript = NULL;
AI_EnemyInfo_t *info = GetEnemies()->Find( ToEnt(hEnemy) );
if (info)
{
hScript = g_pScriptVM->RegisterInstance( reinterpret_cast<Script_AI_EnemyInfo_t*>(info) );
}
return hScript;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::VScriptUpdateEnemyMemory( HSCRIPT hEnemy, const Vector &position, HSCRIPT hInformer )
{
return UpdateEnemyMemory( ToEnt( hEnemy ), position, ToEnt( hInformer ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_BaseNPC::VScriptClearEnemyMemory( HSCRIPT hEnemy )
{
CBaseEntity *pEnemy = ToEnt( hEnemy );
if (!pEnemy)
return;
GetEnemies()->ClearMemory( pEnemy );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_BaseNPC::VScriptSetFreeKnowledgeDuration( float flDuration )
{
GetEnemies()->SetFreeKnowledgeDuration( flDuration );
}
void CAI_BaseNPC::VScriptSetEnemyDiscardTime( float flDuration )
{
GetEnemies()->SetEnemyDiscardTime( flDuration );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CAI_BaseNPC::VScriptGetState()
@ -765,6 +846,34 @@ int CAI_BaseNPC::VScriptGetState()
return (int)GetState();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CAI_BaseNPC::VScriptGetIdealState()
{
return (int)GetIdealState();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_BaseNPC::VScriptSetIdealState( int nNPCState )
{
SetIdealState( (NPC_STATE)nNPCState );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetTarget()
{
return ToHScript( GetTarget() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_BaseNPC::VScriptSetTarget( HSCRIPT hTarget )
{
SetTarget( ToEnt( hTarget ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetHintNode()
@ -832,7 +941,7 @@ int CAI_BaseNPC::VScriptGetTaskID()
const Task_t *pTask = GetTask();
int iID = -1;
if (pTask)
iID = GetTaskID( TaskName( pTask->iTask ) );
iID = AI_RemapFromGlobal( GetTaskID( TaskName( pTask->iTask ) ) );
return iID;
}
@ -867,6 +976,70 @@ HSCRIPT CAI_BaseNPC::VScriptGetSquad()
return hScript;
}
HSCRIPT CAI_BaseNPC::VScriptGetBestSound( int validTypes )
{
HSCRIPT hScript = NULL;
CSound *pSound = GetBestSound( validTypes );
if (pSound)
{
hScript = g_pScriptVM->RegisterInstance( pSound );
}
return hScript;
}
HSCRIPT CAI_BaseNPC::VScriptGetFirstHeardSound()
{
HSCRIPT hScript = NULL;
AISoundIter_t iter;
CSound *pSound = GetSenses()->GetFirstHeardSound( &iter );
if (pSound)
{
hScript = g_pScriptVM->RegisterInstance( pSound );
}
return hScript;
}
HSCRIPT CAI_BaseNPC::VScriptGetNextHeardSound( HSCRIPT hSound )
{
CSound *pCurSound = HScriptToClass<CSound>( hSound );
if (!pCurSound)
return NULL;
int iCurrent = pCurSound->m_iNextAudible;
if ( iCurrent == SOUNDLIST_EMPTY )
return NULL;
HSCRIPT hScript = NULL;
CSound *pNextSound = CSoundEnt::SoundPointerForIndex( iCurrent );
if (pNextSound)
{
hScript = g_pScriptVM->RegisterInstance( pNextSound );
}
return hScript;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetFirstSeenEntity( int nSeenType )
{
AISightIter_t iter;
return ToHScript( GetSenses()->GetFirstSeenEntity( &iter, (seentype_t)nSeenType ) );
}
HSCRIPT CAI_BaseNPC::VScriptGetNextSeenEntity( HSCRIPT hEnt, int nSeenType )
{
CBaseEntity *pEnt = ToEnt( hEnt );
AISightIter_t iter;
GetSenses()->GetSeenEntityIndex( &iter, pEnt, (seentype_t)nSeenType );
return ToHScript( GetSenses()->GetNextSeenEntity( &iter ) );
}
#endif
bool CAI_BaseNPC::PassesDamageFilter( const CTakeDamageInfo &info )
@ -2595,6 +2768,29 @@ void CAI_BaseNPC::OnListened()
{
m_OnHearCombat.FireOutput(this, this);
}
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_OnListened.CanRunInScope( m_ScriptScope ))
{
ScriptVariant_t functionReturn;
g_Hook_OnListened.Call( m_ScriptScope, &functionReturn, NULL );
}
#endif
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::OnSeeEntity( CBaseEntity *pEntity )
{
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_OnSeeEntity.CanRunInScope( m_ScriptScope ))
{
// entity
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { ToHScript( pEntity ) };
g_Hook_OnSeeEntity.Call( m_ScriptScope, &functionReturn, args );
}
#endif
}
//=========================================================
@ -6107,6 +6303,22 @@ bool CAI_BaseNPC::UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position
if ( GetEnemies() )
{
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_UpdateEnemyMemory.CanRunInScope( m_ScriptScope ))
{
// enemy, position, informer
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { ToHScript( pEnemy ), position, ToHScript( pInformer ) };
if (g_Hook_UpdateEnemyMemory.Call( m_ScriptScope, &functionReturn, args ))
{
// Returning false normally indicates this is a known enemy
// Most uses of that functionality involve checking for new enemies, so this is acceptable
if (functionReturn.m_bool == false)
return false;
}
}
#endif
// If the was eluding me and allow the NPC to play a sound
if (GetEnemies()->HasEludedMe(pEnemy))
{
@ -8979,6 +9191,20 @@ bool CAI_BaseNPC::IsValidEnemy( CBaseEntity *pEnemy )
if ( m_hEnemyFilter.Get()!= NULL && m_hEnemyFilter->PassesFilter( this, pEnemy ) == false )
return false;
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_IsValidEnemy.CanRunInScope(m_ScriptScope))
{
// enemy
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { ToHScript( pEnemy ) };
if (g_Hook_IsValidEnemy.Call( m_ScriptScope, &functionReturn, args ))
{
if (functionReturn.m_bool == false)
return false;
}
}
#endif
return true;
}
@ -8988,6 +9214,20 @@ bool CAI_BaseNPC::CanBeAnEnemyOf( CBaseEntity *pEnemy )
if ( GetSleepState() > AISS_WAITING_FOR_THREAT )
return false;
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_CanBeAnEnemyOf.CanRunInScope(m_ScriptScope))
{
// enemy
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { ToHScript( pEnemy ) };
if (g_Hook_CanBeAnEnemyOf.Call( m_ScriptScope, &functionReturn, args ))
{
if (functionReturn.m_bool == false)
return false;
}
}
#endif
return true;
}
@ -11529,6 +11769,13 @@ float CAI_BaseNPC::GetEnemyLastTimeSeen() const
void CAI_BaseNPC::MarkEnemyAsEluded()
{
GetEnemies()->MarkAsEluded( GetEnemy() );
#ifdef MAPBASE
if (m_pSquad)
{
m_pSquad->MarkEnemyAsEluded( this, GetEnemy() );
}
#endif
}
void CAI_BaseNPC::ClearEnemyMemory()
@ -12307,7 +12554,17 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC
DEFINE_SCRIPTFUNC_NAMED( VScriptSetEnemy, "SetEnemy", "Set the NPC's current enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetEnemyLKP, "GetEnemyLKP", "Get the last known position of the NPC's current enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptNumEnemies, "NumEnemies", "Get the number of enemies this NPC knows about." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetFirstEnemyMemory, "GetFirstEnemyMemory", "Get information about the NPC's first enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetNextEnemyMemory, "GetNextEnemyMemory", "Get information about the NPC's next enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptFindEnemyMemory, "FindEnemyMemory", "Get information about the NPC's current enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptUpdateEnemyMemory, "UpdateEnemyMemory", "Update information on this enemy. First parameter is the enemy, second is the position we now know the enemy is at, third parameter is the informer (e.g. squadmate who sees enemy, null if I see it myself). Returns true if this is a new enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptClearEnemyMemory, "ClearEnemyMemory", "Makes the NPC forget about the specified enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetFreeKnowledgeDuration, "SetFreeKnowledgeDuration", "Sets the amount of time the NPC can always know an enemy's location after losing sight." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetEnemyDiscardTime, "SetEnemyDiscardTime", "Sets the amount of time needed before the NPC discards an unseen enemy's memory." )
DEFINE_SCRIPTFUNC( GetLastAttackTime, "Get the last time the NPC has used an attack (e.g. fired a bullet from a gun)." )
DEFINE_SCRIPTFUNC( GetLastDamageTime, "Get the last time the NPC has been damaged." )
@ -12315,6 +12572,11 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC
DEFINE_SCRIPTFUNC( GetLastEnemyTime, "Get the last time the NPC has seen an enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetState, "GetNPCState", "Get the NPC's current state." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetIdealState, "GetIdealNPCState", "Get the NPC's ideal state." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetIdealState, "SetIdealNPCState", "Set the NPC's ideal state." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetTarget, "GetNPCTarget", "Get the NPC's AI target." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetTarget, "SetNPCTarget", "Set the NPC's AI target." )
DEFINE_SCRIPTFUNC_NAMED( VScriptWake, "Wake", "Awakens the NPC if it is currently asleep." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSleep, "Sleep", "Puts the NPC into a sleeping state." )
@ -12362,6 +12624,16 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC
DEFINE_SCRIPTFUNC_NAMED( VScriptClearCondition, "ClearCondition", "Clear a condition on the NPC." )
DEFINE_SCRIPTFUNC_NAMED( ClearCondition, "ClearConditionID", "Clear a condition on the NPC by ID." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetCustomInterruptCondition, "SetCustomInterruptCondition", "Use with BuildScheduleTestBits to define conditions which should interrupt the schedule." )
DEFINE_SCRIPTFUNC_NAMED( VScriptIsCustomInterruptConditionSet, "IsCustomInterruptConditionSet", "Use with BuildScheduleTestBits to define conditions which should interrupt the schedule." )
DEFINE_SCRIPTFUNC_NAMED( VScriptClearCustomInterruptCondition, "ClearCustomInterruptCondition", "Use with BuildScheduleTestBits to define conditions which should interrupt the schedule." )
DEFINE_SCRIPTFUNC_NAMED( VScriptChainStartTask, "ChainStartTask", "Use with StartTask to redirect to the specified task." )
DEFINE_SCRIPTFUNC_NAMED( VScriptChainRunTask, "ChainRunTask", "Use with RunTask to redirect to the specified task." )
DEFINE_SCRIPTFUNC_NAMED( VScriptFailTask, "FailTask", "Fails the currently running task with the specified error message." )
DEFINE_SCRIPTFUNC_NAMED( VScriptCompleteTask, "CompleteTask", "Completes the currently running task." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetTaskStatus, "GetTaskStatus", "Gets the current task's status." )
DEFINE_SCRIPTFUNC( IsMoving, "Check if the NPC is moving." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetExpresser, "GetExpresser", "Get a handle for this NPC's expresser." )
@ -12380,6 +12652,13 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC
DEFINE_SCRIPTFUNC( IsCrouching, "Returns true if the NPC is crouching." )
DEFINE_SCRIPTFUNC( Crouch, "Tells the NPC to crouch." )
DEFINE_SCRIPTFUNC( Stand, "Tells the NPC to stand if it is crouching." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetBestSound, "GetBestSound", "Get the NPC's best sound of the specified type(s). Use 'ALL_SOUNDS' to get any sound." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetFirstHeardSound, "GetFirstHeardSound", "Get the NPC's first heard sound." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetNextHeardSound, "GetNextHeardSound", "Get the NPC's next heard sound." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetFirstSeenEntity, "GetFirstSeenEntity", "Get the NPC's first seen entity in the specified 'SEEN_' list." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetNextSeenEntity, "GetNextSeenEntity", "Get the NPC's next seen entity in the specified 'SEEN_' list." )
//
// Hooks
@ -12409,6 +12688,32 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC
DEFINE_SCRIPTHOOK_PARAM( "activity", FIELD_CSTRING )
DEFINE_SCRIPTHOOK_PARAM( "translatedActivity", FIELD_CSTRING )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_IsValidEnemy, "IsValidEnemy", FIELD_BOOLEAN, "Whether or not the specified enemy should be considered valid." )
DEFINE_SCRIPTHOOK_PARAM( "enemy", FIELD_HSCRIPT )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_CanBeAnEnemyOf, "CanBeAnEnemyOf", FIELD_BOOLEAN, "Whether or not this NPC can be an enemy of another NPC." )
DEFINE_SCRIPTHOOK_PARAM( "enemy", FIELD_HSCRIPT )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_UpdateEnemyMemory, "UpdateEnemyMemory", FIELD_BOOLEAN, "Whether or not this NPC can be an enemy of another NPC." )
DEFINE_SCRIPTHOOK_PARAM( "enemy", FIELD_HSCRIPT )
DEFINE_SCRIPTHOOK_PARAM( "position", FIELD_VECTOR )
DEFINE_SCRIPTHOOK_PARAM( "informer", FIELD_HSCRIPT )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_OnSeeEntity, "OnSeeEntity", FIELD_VOID, "Called when the NPC sees an entity." )
DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT )
END_SCRIPTHOOK()
DEFINE_SIMPLE_SCRIPTHOOK( CAI_BaseNPC::g_Hook_OnListened, "OnListened", FIELD_VOID, "Called when the NPC assigns sound conditions after checking for sounds it hears." )
DEFINE_SIMPLE_SCRIPTHOOK( CAI_BaseNPC::g_Hook_BuildScheduleTestBits, "BuildScheduleTestBits", FIELD_VOID, "Called when the NPC is determining which conditions can interrupt the current schedule." )
BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_StartTask, "StartTask", FIELD_VOID, "Called when a task is starting. The task is provided in both string and ID form. Return false to override actual task functionality." )
DEFINE_SCRIPTHOOK_PARAM( "task", FIELD_CSTRING )
DEFINE_SCRIPTHOOK_PARAM( "task_id", FIELD_INTEGER )
DEFINE_SCRIPTHOOK_PARAM( "task_data", FIELD_FLOAT )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_RunTask, "RunTask", FIELD_VOID, "Called every think while the task is running. The task is provided in both string and ID form. Return false to override actual task functionality." )
DEFINE_SCRIPTHOOK_PARAM( "task", FIELD_CSTRING )
DEFINE_SCRIPTHOOK_PARAM( "task_id", FIELD_INTEGER )
DEFINE_SCRIPTHOOK_PARAM( "task_data", FIELD_FLOAT )
END_SCRIPTHOOK()
END_SCRIPTDESC();
#endif

View File

@ -1104,7 +1104,7 @@ public:
virtual void OnLooked( int iDistance );
virtual void OnListened();
virtual void OnSeeEntity( CBaseEntity *pEntity ) {}
virtual void OnSeeEntity( CBaseEntity *pEntity );
// If true, AI will try to see this entity regardless of distance.
virtual bool ShouldNotDistanceCull() { return false; }
@ -1271,9 +1271,24 @@ private:
void VScriptSetEnemy( HSCRIPT pEnemy );
Vector VScriptGetEnemyLKP();
HSCRIPT VScriptFindEnemyMemory( HSCRIPT pEnemy );
int VScriptNumEnemies();
HSCRIPT VScriptGetFirstEnemyMemory();
HSCRIPT VScriptGetNextEnemyMemory( HSCRIPT hMemory );
HSCRIPT VScriptFindEnemyMemory( HSCRIPT hEnemy );
bool VScriptUpdateEnemyMemory( HSCRIPT hEnemy, const Vector &position, HSCRIPT hInformer );
void VScriptClearEnemyMemory( HSCRIPT hEnemy );
void VScriptSetFreeKnowledgeDuration( float flDuration );
void VScriptSetEnemyDiscardTime( float flDuration );
int VScriptGetState();
int VScriptGetIdealState();
void VScriptSetIdealState( int nNPCState );
HSCRIPT VScriptGetTarget();
void VScriptSetTarget( HSCRIPT hTarget );
void VScriptWake( HSCRIPT hActivator ) { Wake( ToEnt(hActivator) ); }
void VScriptSleep() { Sleep(); }
@ -1308,12 +1323,29 @@ private:
void VScriptSetCondition( const char *szCondition ) { SetCondition( GetConditionID( szCondition ) ); }
void VScriptClearCondition( const char *szCondition ) { ClearCondition( GetConditionID( szCondition ) ); }
void VScriptSetCustomInterruptCondition( const char *szCondition ) { SetCustomInterruptCondition( GetConditionID( szCondition ) ); }
bool VScriptIsCustomInterruptConditionSet( const char *szCondition ) { return IsCustomInterruptConditionSet( GetConditionID( szCondition ) ); }
void VScriptClearCustomInterruptCondition( const char *szCondition ) { ClearCustomInterruptCondition( GetConditionID( szCondition ) ); }
void VScriptChainStartTask( const char *szTask, float flTaskData ) { ChainStartTask( AI_RemapFromGlobal( GetTaskID( szTask ) ), flTaskData ); }
void VScriptChainRunTask( const char *szTask, float flTaskData ) { ChainRunTask( AI_RemapFromGlobal( GetTaskID( szTask ) ), flTaskData ); }
void VScriptFailTask( const char *szFailReason ) { TaskFail( szFailReason ); }
void VScriptCompleteTask() { TaskComplete(); }
int VScriptGetTaskStatus() { return (int)GetTaskStatus(); }
HSCRIPT VScriptGetExpresser();
HSCRIPT VScriptGetCine();
int GetScriptState() { return m_scriptState; }
HSCRIPT VScriptGetSquad();
HSCRIPT VScriptGetBestSound( int validTypes );
HSCRIPT VScriptGetFirstHeardSound();
HSCRIPT VScriptGetNextHeardSound( HSCRIPT hSound );
HSCRIPT VScriptGetFirstSeenEntity( int nSeenType );
HSCRIPT VScriptGetNextSeenEntity( HSCRIPT hEnt, int nSeenType );
#endif
//-----------------------------------------------------
@ -2399,6 +2431,14 @@ public:
static ScriptHook_t g_Hook_GetActualShootPosition;
static ScriptHook_t g_Hook_OverrideMove;
static ScriptHook_t g_Hook_ShouldPlayFakeSequenceGesture;
static ScriptHook_t g_Hook_IsValidEnemy;
static ScriptHook_t g_Hook_CanBeAnEnemyOf;
static ScriptHook_t g_Hook_UpdateEnemyMemory;
static ScriptHook_t g_Hook_OnSeeEntity;
static ScriptHook_t g_Hook_OnListened;
static ScriptHook_t g_Hook_BuildScheduleTestBits;
static ScriptHook_t g_Hook_StartTask;
static ScriptHook_t g_Hook_RunTask;
#endif
private:

View File

@ -45,6 +45,10 @@ extern ConVar ai_use_think_optimizations;
ConVar ai_simulate_task_overtime( "ai_simulate_task_overtime", "0" );
#ifdef MAPBASE
ConVar ai_enemy_memory_fixes( "ai_enemy_memory_fixes", "0", FCVAR_NONE, "Toggles Mapbase fixes for certain NPC AI not using enemy memory when it should." );
#endif
#define MAX_TASKS_RUN 10
struct TaskTimings
@ -276,6 +280,14 @@ void CAI_BaseNPC::NextScheduledTask ( void )
void CAI_BaseNPC::BuildScheduleTestBits( void )
{
//NOTENOTE: Always defined in the leaf classes
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_BuildScheduleTestBits.CanRunInScope( m_ScriptScope ))
{
ScriptVariant_t functionReturn;
g_Hook_BuildScheduleTestBits.Call( m_ScriptScope, &functionReturn, NULL );
}
#endif
}
@ -730,6 +742,23 @@ void CAI_BaseNPC::MaintainSchedule ( void )
AI_PROFILE_SCOPE_BEGIN_( pszTaskName );
AI_PROFILE_SCOPE_BEGIN(CAI_BaseNPC_StartTask);
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_StartTask.CanRunInScope( m_ScriptScope ))
{
// task, task_id, task_data
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { (bDebugTaskNames) ? pszTaskName : TaskName( pTask->iTask ), pTask->iTask, pTask->flTaskData };
if (g_Hook_StartTask.Call( m_ScriptScope, &functionReturn, args ))
{
// Returning false overrides original functionality
if (functionReturn.m_bool != false)
StartTask( pTask );
}
else
StartTask( pTask );
}
else
#endif
StartTask( pTask );
AI_PROFILE_SCOPE_END();
@ -766,6 +795,23 @@ void CAI_BaseNPC::MaintainSchedule ( void )
int j;
for (j = 0; j < 8; j++)
{
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_RunTask.CanRunInScope( m_ScriptScope ))
{
// task, task_id, task_data
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { (bDebugTaskNames) ? pszTaskName : TaskName( pTask->iTask ), pTask->iTask, pTask->flTaskData };
if (g_Hook_RunTask.Call( m_ScriptScope, &functionReturn, args ))
{
// Returning false overrides original functionality
if (functionReturn.m_bool != false)
RunTask( pTask );
}
else
RunTask( pTask );
}
else
#endif
RunTask( pTask );
if ( GetTaskInterrupt() == 0 || TaskIsComplete() || HasCondition(COND_TASK_FAILED) )
@ -1971,7 +2017,17 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask )
flMaxRange = m_flDistTooFar;
}
#ifdef MAPBASE
// By default, TASK_GET_PATH_TO_ENEMY_LKP_LOS acts identical to TASK_GET_PATH_TO_ENEMY_LOS.
// Considering the fact TASK_GET_PATH_TO_ENEMY_LKP doesn't use this code, this appears to be a mistake.
// In HL2, this task is used by Combine soldiers, metrocops, striders, and hunters.
// With this change, these NPCs will establish LOS according to enemy memory instead of where the enemy
// actually is. This may make the NPCs more consistent and fair, but their AI and levels built around it
// may have been designed around this bug, so this is currently being tied to a cvar.
Vector vecEnemy = ( task != TASK_GET_PATH_TO_ENEMY_LKP_LOS || !ai_enemy_memory_fixes.GetBool() ) ? GetEnemy()->GetAbsOrigin() : GetEnemyLKP();
#else
Vector vecEnemy = ( task != TASK_GET_PATH_TO_ENEMY_LKP ) ? GetEnemy()->GetAbsOrigin() : GetEnemyLKP();
#endif
Vector vecEnemyEye = vecEnemy + GetEnemy()->GetViewOffset();
Vector posLos;

View File

@ -500,6 +500,13 @@ public:
g_AI_SensedObjectsManager.Init();
}
#ifdef MAPBASE_VSCRIPT
virtual void RegisterVScript()
{
g_pScriptVM->RegisterInstance( &g_AI_SensedObjectsManager, "SensedObjectsManager" );
}
#endif
void LevelShutdownPreEntity()
{
CBaseCombatCharacter::ResetVisibilityCache();

View File

@ -78,6 +78,7 @@ static void DispatchComeback( CAI_ExpresserWithFollowup *pExpress, CBaseEntity *
// See DispatchFollowupThroughQueue()
criteria.AppendCriteria( "From_idx", CNumStr( pSpeaker->entindex() ) );
criteria.AppendCriteria( "From_class", pSpeaker->GetClassname() );
pSpeaker->AppendContextToCriteria( criteria, "From_" );
#endif
// if a SUBJECT criteria is missing, put it back in.
if ( criteria.FindCriterionIndex( "Subject" ) == -1 )

View File

@ -225,6 +225,18 @@ AI_EnemyInfo_t *CAI_Enemies::Find( CBaseEntity *pEntity, bool bTryDangerMemory )
}
//-----------------------------------------------------------------------------
#ifdef MAPBASE
unsigned char CAI_Enemies::FindIndex( CBaseEntity *pEntity )
{
if ( pEntity == AI_UNKNOWN_ENEMY )
pEntity = NULL;
return m_Map.Find( pEntity );
}
#endif
//-----------------------------------------------------------------------------
AI_EnemyInfo_t *CAI_Enemies::GetDangerMemory()

View File

@ -63,6 +63,9 @@ public:
AI_EnemyInfo_t *GetFirst( AIEnemiesIter_t *pIter );
AI_EnemyInfo_t *GetNext( AIEnemiesIter_t *pIter );
AI_EnemyInfo_t *Find( CBaseEntity *pEntity, bool bTryDangerMemory = false );
#ifdef MAPBASE
unsigned char FindIndex( CBaseEntity *pEntity );
#endif
AI_EnemyInfo_t *GetDangerMemory();
int NumEnemies() const { return m_Map.Count(); }

View File

@ -298,6 +298,43 @@ CBaseEntity *CAI_Senses::GetNextSeenEntity( AISightIter_t *pIter ) const
return NULL;
}
//-----------------------------------------------------------------------------
#ifdef MAPBASE
bool CAI_Senses::GetSeenEntityIndex( AISightIter_t *pIter, CBaseEntity *pSightEnt, seentype_t iSeenType ) const
{
COMPILE_TIME_ASSERT( sizeof( AISightIter_t ) == sizeof( AISightIterVal_t ) );
AISightIterVal_t *pIterVal = (AISightIterVal_t *)pIter;
// If we're searching for a specific type, start in that array
pIterVal->SeenArray = (char)iSeenType;
int iFirstArray = ( iSeenType == SEEN_ALL ) ? 0 : iSeenType;
for ( int i = iFirstArray; i < ARRAYSIZE( m_SeenArrays ); i++ )
{
for ( int j = pIterVal->iNext; j < m_SeenArrays[i]->Count(); j++ )
{
if ( (*m_SeenArrays[i])[j].Get() == pSightEnt )
{
pIterVal->array = i;
pIterVal->iNext = j+1;
return true;
}
}
pIterVal->iNext = 0;
// If we're searching for a specific type, don't move to the next array
if ( pIterVal->SeenArray != SEEN_ALL )
break;
}
(*pIter) = (AISightIter_t)(-1);
return false;
}
#endif
//-----------------------------------------------------------------------------
void CAI_Senses::BeginGather()
@ -749,4 +786,27 @@ void CAI_SensedObjectsManager::AddEntity( CBaseEntity *pEntity )
m_SensedObjects.AddToTail( pEntity );
}
#ifdef MAPBASE
void CAI_SensedObjectsManager::RemoveEntity( CBaseEntity *pEntity )
{
int i = m_SensedObjects.Find( pEntity );
if (i == m_SensedObjects.InvalidIndex())
return;
pEntity->RemoveFlag( FL_OBJECT );
m_SensedObjects.FastRemove( i );
}
#endif
//-----------------------------------------------------------------------------
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CAI_SensedObjectsManager, SCRIPT_SINGLETON "Manager which handles sensed objects." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddEntity, "AddEntity", "Adds an entity to the sensed object list." )
DEFINE_SCRIPTFUNC_NAMED( ScriptRemoveEntity, "RemoveEntity", "Removes an entity from the sensed object list." )
END_SCRIPTDESC();
#endif
//=============================================================================

View File

@ -82,6 +82,9 @@ public:
CBaseEntity * GetFirstSeenEntity( AISightIter_t *pIter, seentype_t iSeenType = SEEN_ALL ) const;
CBaseEntity * GetNextSeenEntity( AISightIter_t *pIter ) const;
#ifdef MAPBASE
bool GetSeenEntityIndex( AISightIter_t *pIter, CBaseEntity *pSightEnt, seentype_t iSeenType ) const;
#endif
CSound * GetFirstHeardSound( AISoundIter_t *pIter );
CSound * GetNextHeardSound( AISoundIter_t *pIter );
@ -152,6 +155,14 @@ public:
CBaseEntity * GetNext( int *pIter );
virtual void AddEntity( CBaseEntity *pEntity );
#ifdef MAPBASE
virtual void RemoveEntity( CBaseEntity *pEntity );
#endif
#ifdef MAPBASE_VSCRIPT
void ScriptAddEntity( HSCRIPT hEnt ) { AddEntity( ToEnt( hEnt ) ); }
void ScriptRemoveEntity( HSCRIPT hEnt ) { RemoveEntity( ToEnt( hEnt ) ); }
#endif
private:
virtual void OnEntitySpawned( CBaseEntity *pEntity );

View File

@ -18,6 +18,7 @@
#include "sceneentity.h"
#include "ai_speechqueue.h"
#ifdef MAPBASE
#include "mapbase/choreosentence.h"
#include "ai_squad.h"
#endif
@ -846,6 +847,9 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t concept, AI_Response *res
case ResponseRules::RESPONSE_NONE:
break;
#ifdef MAPBASE
case ResponseRules::RESPONSE_CHOREOSENTENCE:
#endif
case ResponseRules::RESPONSE_SPEAK:
{
if ( !result->ShouldntUseScene() )
@ -918,7 +922,7 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t concept, AI_Response *res
textParams.g1 = 255;
textParams.b1 = 255;
if (ai_speech_print_mode.GetBool() && GetOuter()->GetGameTextSpeechParams( textParams ))
if (ai_speech_print_mode.GetBool() && GetOuter()->DispatchGetGameTextSpeechParams( textParams ))
{
CRecipientFilter filter;
filter.AddAllPlayers();
@ -1194,6 +1198,15 @@ float CAI_Expresser::GetResponseDuration( AI_Response *result )
case ResponseRules::RESPONSE_NONE:
case ResponseRules::RESPONSE_ENTITYIO:
return 0.0f;
#ifdef MAPBASE
case ResponseRules::RESPONSE_CHOREOSENTENCE:
{
const ChoreoSentence_t *pSentence = LookupChoreoSentence( GetOuter(), response );
if (pSentence)
return GetChoreoSentenceDuration( GetOuter(), *pSentence );
}
break;
#endif
}
return 0.0f;

View File

@ -18,6 +18,10 @@
CAI_SquadManager g_AI_SquadManager;
#ifdef MAPBASE
ConVar ai_squad_broadcast_elusion("ai_squad_broadcast_elusion", "0", FCVAR_NONE, "Tells the entire squad when an enemy is eluded");
#endif
//-----------------------------------------------------------------------------
// CAI_SquadManager
//
@ -740,6 +744,25 @@ void CAI_Squad::UpdateEnemyMemory( CAI_BaseNPC *pUpdater, CBaseEntity *pEnemy, c
//------------------------------------------------------------------------------
#ifdef MAPBASE
void CAI_Squad::MarkEnemyAsEluded( CAI_BaseNPC *pUpdater, CBaseEntity *pEnemy )
{
if (!ai_squad_broadcast_elusion.GetBool())
return;
//Broadcast to all members of the squad
for ( int i = 0; i < m_SquadMembers.Count(); i++ )
{
if ( m_SquadMembers[i] != pUpdater )
{
m_SquadMembers[i]->GetEnemies()->MarkAsEluded( pEnemy );
}
}
}
#endif
//------------------------------------------------------------------------------
#ifdef PER_ENEMY_SQUADSLOTS
AISquadEnemyInfo_t *CAI_Squad::FindEnemyInfo( CBaseEntity *pEnemy )
@ -883,14 +906,14 @@ void CAI_Squad::ScriptRemoveFromSquad( HSCRIPT hNPC ) { RemoveFromSquad( HScrip
bool CAI_Squad::ScriptIsSilentMember( HSCRIPT hNPC ) { return IsSilentMember( HScriptToClass<CAI_BaseNPC>( hNPC ) ); }
void CAI_Squad::ScriptSetSquadData( int iSlot, const char *data )
void CAI_Squad::ScriptSetSquadData( int iSlot, int data )
{
SetSquadData( iSlot, data );
}
const char *CAI_Squad::ScriptGetSquadData( int iSlot )
int CAI_Squad::ScriptGetSquadData( int iSlot )
{
const char *data;
int data;
GetSquadData( iSlot, &data );
return data;
}

View File

@ -107,6 +107,12 @@ public:
void SquadNewEnemy ( CBaseEntity *pEnemy );
void UpdateEnemyMemory( CAI_BaseNPC *pUpdater, CBaseEntity *pEnemy, const Vector &position );
#ifdef MAPBASE
// The idea behind this is that, if one squad member fails to locate the enemy, nobody in the squad knows where the enemy is
// Makes combat utilizing elusion a bit smoother
// (gated by ai_squad_broadcast_elusion cvar)
void MarkEnemyAsEluded( CAI_BaseNPC *pUpdater, CBaseEntity *pEnemy );
#endif
bool OccupyStrategySlotRange( CBaseEntity *pEnemy, int slotIDStart, int slotIDEnd, int *pSlot );
void VacateStrategySlot( CBaseEntity *pEnemy, int slot);
@ -186,8 +192,8 @@ private:
bool ScriptIsSilentMember( HSCRIPT hNPC );
void ScriptSetSquadData( int iSlot, const char *data );
const char *ScriptGetSquadData( int iSlot );
void ScriptSetSquadData( int iSlot, int data );
int ScriptGetSquadData( int iSlot );
#endif
private:

View File

@ -317,7 +317,7 @@ BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceActivity, "GetSequenceActivity", "Gets the activity ID of the specified sequence index" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSelectWeightedSequence, "SelectWeightedSequence", "Selects a sequence for the specified activity ID" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSelectHeaviestSequence, "SelectHeaviestSequence", "Selects the sequence with the heaviest weight for the specified activity ID" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceKeyValues, "GetSequenceKeyValues", "Get a KeyValue class instance on the specified sequence. WARNING: This uses the same KeyValue pointer as GetModelKeyValues!" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceKeyValues, "GetSequenceKeyValues", "Get a KeyValue class instance on the specified sequence" )
DEFINE_SCRIPTFUNC( ResetSequenceInfo, "" )
DEFINE_SCRIPTFUNC( StudioFrameAdvance, "" )
DEFINE_SCRIPTFUNC( GetPlaybackRate, "" )
@ -1261,7 +1261,8 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler )
}
#ifdef MAPBASE_VSCRIPT
if (eventHandler->ScriptHookHandleAnimEvent( &event ) == false)
scriptanimevent_t wrapper( event );
if (!eventHandler->ScriptHookHandleAnimEvent( wrapper ))
continue;
#endif
@ -1299,11 +1300,11 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseAnimating::ScriptHookHandleAnimEvent( animevent_t *pEvent )
bool CBaseAnimating::ScriptHookHandleAnimEvent( scriptanimevent_t &event )
{
if (m_ScriptScope.IsInitialized() && g_Hook_HandleAnimEvent.CanRunInScope(m_ScriptScope))
{
HSCRIPT hEvent = g_pScriptVM->RegisterInstance( reinterpret_cast<scriptanimevent_t*>(pEvent) );
HSCRIPT hEvent = g_pScriptVM->RegisterInstance( &event );
// event
ScriptVariant_t args[] = { hEvent };
@ -2305,21 +2306,14 @@ void CBaseAnimating::ScriptGetBoneTransform( int iBone, HSCRIPT hTransform )
//-----------------------------------------------------------------------------
// VScript access to sequence's key values
// for iteration and value access, use:
// ScriptFindKey, ScriptGetFirstSubKey, ScriptGetString,
// ScriptGetInt, ScriptGetFloat, ScriptGetNextKey
// NOTE: This is recycled from ScriptGetModelKeyValues() and uses its pointer!!!
//-----------------------------------------------------------------------------
HSCRIPT CBaseAnimating::ScriptGetSequenceKeyValues( int iSequence )
HSCRIPT_RC CBaseAnimating::ScriptGetSequenceKeyValues( int iSequence )
{
KeyValues *pSeqKeyValues = GetSequenceKeyValues( iSequence );
HSCRIPT hScript = NULL;
if ( pSeqKeyValues )
{
// UNDONE: how does destructor get called on this
m_pScriptModelKeyValues = hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pSeqKeyValues, true );
// UNDONE: who calls ReleaseInstance on this??? Does name need to be unique???
hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pSeqKeyValues );
}
return hScript;

View File

@ -16,6 +16,9 @@
#include "datacache/idatacache.h"
#include "tier0/threadtools.h"
#ifdef MAPBASE_VSCRIPT
struct scriptanimevent_t;
#endif
struct animevent_t;
struct matrix3x4_t;
@ -146,7 +149,7 @@ public:
virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); // Handle events that have happend since last time called up until X seconds into the future
virtual void HandleAnimEvent( animevent_t *pEvent );
#ifdef MAPBASE_VSCRIPT
bool ScriptHookHandleAnimEvent( animevent_t *pEvent );
bool ScriptHookHandleAnimEvent( scriptanimevent_t &event );
#endif
int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName );
@ -208,7 +211,7 @@ public:
int ScriptSelectHeaviestSequence( int activity ) { return SelectHeaviestSequence( (Activity)activity ); }
int ScriptSelectWeightedSequence( int activity, int curSequence ) { return SelectWeightedSequence( (Activity)activity, curSequence ); }
HSCRIPT ScriptGetSequenceKeyValues( int iSequence );
HSCRIPT_RC ScriptGetSequenceKeyValues( int iSequence );
// For VScript
int GetSkin() { return m_nSkin; }

View File

@ -3482,13 +3482,13 @@ void CBaseCombatCharacter::AddRelationship( const char *pszRelationship, CBaseEn
bool bFoundEntity = false;
// Try to get pointer to an entity of this name
CBaseEntity *entity = gEntList.FindEntityByName( NULL, entityString );
CBaseEntity *entity = gEntList.FindEntityByName( NULL, entityString, this, pActivator );
while( entity )
{
// make sure you catch all entities of this name.
bFoundEntity = true;
AddEntityRelationship(entity, disposition, priority );
entity = gEntList.FindEntityByName( entity, entityString );
entity = gEntList.FindEntityByName( entity, entityString, this, pActivator );
}
if( !bFoundEntity )

View File

@ -1628,10 +1628,53 @@ void CBaseEntity::TakeDamage( const CTakeDamageInfo &inputInfo )
DamageFilterDamageMod(info);
#endif
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_OnTakeDamage.CanRunInScope( m_ScriptScope ))
{
HSCRIPT hInfo = g_pScriptVM->RegisterInstance( &info );
// info
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { ScriptVariant_t( hInfo ) };
if ( g_Hook_OnTakeDamage.Call( m_ScriptScope, &functionReturn, args ) )
{
if (functionReturn.m_type == FIELD_BOOLEAN && functionReturn.m_bool == false)
{
g_pScriptVM->RemoveInstance( hInfo );
return;
}
}
g_pScriptVM->RemoveInstance( hInfo );
}
#endif
OnTakeDamage( info );
}
}
//-----------------------------------------------------------------------------
// Purpose: Allows entities to be 'invisible' to NPC senses.
//-----------------------------------------------------------------------------
bool CBaseEntity::CanBeSeenBy( CAI_BaseNPC *pNPC )
{
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_CanBeSeenBy.CanRunInScope(m_ScriptScope))
{
// npc
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { ToHScript( pNPC ) };
if (g_Hook_CanBeSeenBy.Call( m_ScriptScope, &functionReturn, args ))
{
if (functionReturn.m_bool == false)
return false;
}
}
#endif
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a value that scales all damage done by this entity.
//-----------------------------------------------------------------------------
@ -2251,14 +2294,16 @@ ScriptHook_t CBaseEntity::g_Hook_OnEntText;
ScriptHook_t CBaseEntity::g_Hook_VPhysicsCollision;
ScriptHook_t CBaseEntity::g_Hook_FireBullets;
ScriptHook_t CBaseEntity::g_Hook_OnDeath;
ScriptHook_t CBaseEntity::g_Hook_OnTakeDamage;
ScriptHook_t CBaseEntity::g_Hook_OnKilledOther;
ScriptHook_t CBaseEntity::g_Hook_HandleInteraction;
ScriptHook_t CBaseEntity::g_Hook_ModifyEmitSoundParams;
ScriptHook_t CBaseEntity::g_Hook_ModifySentenceParams;
ScriptHook_t CBaseEntity::g_Hook_ModifyOrAppendCriteria;
ScriptHook_t CBaseEntity::g_Hook_CanBeSeenBy;
#endif
BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" )
DEFINE_SCRIPT_INSTANCE_HELPER( &g_BaseEntityScriptInstanceHelper )
BEGIN_ENT_SCRIPTDESC_ROOT_WITH_HELPER( CBaseEntity, "Root class of all server-side entities", &g_BaseEntityScriptInstanceHelper )
DEFINE_SCRIPTFUNC_NAMED( ConnectOutputToScript, "ConnectOutput", "Adds an I/O connection that will call the named function when the specified output fires" )
DEFINE_SCRIPTFUNC_NAMED( DisconnectOutputFromScript, "DisconnectOutput", "Removes a connected script function from an I/O event." )
@ -2377,6 +2422,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities"
DEFINE_SCRIPTFUNC_NAMED( ScriptGetContext, "GetContext", "Get a response context value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddContext, "AddContext", "Add a response context value" )
DEFINE_SCRIPTFUNC( RemoveContext, "Remove a response context" )
DEFINE_SCRIPTFUNC( GetContextExpireTime, "Get a response context's expiration time" )
DEFINE_SCRIPTFUNC( GetContextCount, "Get the number of response contexts" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetContextIndex, "GetContextIndex", "Get a response context at a specific index in the form of a table" )
@ -2515,14 +2561,15 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities"
DEFINE_SCRIPTHOOK_PARAM( "normal", FIELD_VECTOR )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_FireBullets, "FireBullets", FIELD_VOID, "Called for every single VPhysics-related collision experienced by this entity." )
DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT )
DEFINE_SCRIPTHOOK_PARAM( "speed", FIELD_FLOAT )
DEFINE_SCRIPTHOOK_PARAM( "point", FIELD_VECTOR )
DEFINE_SCRIPTHOOK_PARAM( "normal", FIELD_VECTOR )
BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_FireBullets, "FireBullets", FIELD_VOID, "Called when the entity fires bullets from itself or from a weapon. The parameter is the associated FireBulletsInfo_t handle. Return false to cancel bullet firing." )
DEFINE_SCRIPTHOOK_PARAM( "info", FIELD_HSCRIPT )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_OnDeath, "OnDeath", FIELD_BOOLEAN, "Called when the entity dies (Event_Killed). Returning false makes the entity cancel death, although this could have unforeseen consequences. For hooking any damage instead of just death, see filter_script and PassesFinalDamageFilter." )
BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_OnDeath, "OnDeath", FIELD_BOOLEAN, "Called when the entity dies (Event_Killed). Returning false makes the entity cancel death, although this could have unforeseen consequences. For hooking any damage instead of just death, use OnTakeDamage." )
DEFINE_SCRIPTHOOK_PARAM( "info", FIELD_HSCRIPT )
END_SCRIPTHOOK()
BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_OnTakeDamage, "OnTakeDamage", FIELD_BOOLEAN, "Called when the entity takes damage (OnTakeDamage). Returning false makes the entity cancel the damage, similar to a damage filter. This is called after any damage filter operations." )
DEFINE_SCRIPTHOOK_PARAM( "info", FIELD_HSCRIPT )
END_SCRIPTHOOK()
@ -2544,6 +2591,12 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities"
BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_ModifySentenceParams, "ModifySentenceParams", FIELD_VOID, "Called every time a sentence is emitted on this entity, allowing for its parameters to be modified." )
DEFINE_SCRIPTHOOK_PARAM( "params", FIELD_HSCRIPT )
END_SCRIPTHOOK()
DEFINE_SIMPLE_SCRIPTHOOK( CBaseEntity::g_Hook_ModifyOrAppendCriteria, "ModifyOrAppendCriteria", FIELD_HSCRIPT, "Called when the criteria set is collected for a response. Return a table of keyvalues to add to the criteria set." )
BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_CanBeSeenBy, "CanBeSeenBy", FIELD_BOOLEAN, "Whether or not this entity can be seen by the specified NPC." )
DEFINE_SCRIPTHOOK_PARAM( "npc", FIELD_HSCRIPT )
END_SCRIPTHOOK()
#endif
END_SCRIPTDESC();
@ -7544,6 +7597,61 @@ void CBaseEntity::ModifyOrAppendCriteria( AI_CriteriaSet& set )
set.AppendCriteria("spawnflags", UTIL_VarArgs("%i", GetSpawnFlags()));
set.AppendCriteria("flags", UTIL_VarArgs("%i", GetFlags()));
#endif
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_ModifyOrAppendCriteria.CanRunInScope(m_ScriptScope))
{
ScriptVariant_t functionReturn;
if (g_Hook_ModifyOrAppendCriteria.Call( m_ScriptScope, &functionReturn, NULL ))
{
if (functionReturn.m_hScript != NULL)
{
int nIterator = -1;
ScriptVariant_t varKey, varValue;
while ((nIterator = g_pScriptVM->GetKeyValue( functionReturn.m_hScript, nIterator, &varKey, &varValue )) != -1)
{
float flWeight = 1.0f;
char szValue[128];
switch (varValue.m_type)
{
case FIELD_CSTRING:
{
char *colon = V_strstr( varValue.m_pszString, ":" );
if (colon)
{
// Use as weight
flWeight = atof(colon+1);
*colon = NULL;
}
V_strncpy( szValue, varValue.m_pszString, sizeof( szValue ) );
}
break;
case FIELD_BOOLEAN:
V_snprintf( szValue, sizeof( szValue ), "%d", varValue.m_bool );
break;
case FIELD_INTEGER:
V_snprintf( szValue, sizeof( szValue ), "%i", varValue.m_int );
break;
case FIELD_FLOAT:
V_snprintf( szValue, sizeof( szValue ), "%f", varValue.m_float );
break;
case FIELD_VECTOR:
V_snprintf( szValue, sizeof( szValue ), "%f %f %f", varValue.m_pVector->x, varValue.m_pVector->y, varValue.m_pVector->z );
break;
default:
Warning( "ModifyOrAppendCriteria doesn't know how to handle field %i for %s\n", varValue.m_type, varKey.m_pszString );
break;
}
set.AppendCriteria( varKey.m_pszString, szValue, flWeight );
g_pScriptVM->ReleaseValue( varKey );
g_pScriptVM->ReleaseValue( varValue );
}
}
}
}
#endif
}
//-----------------------------------------------------------------------------
@ -10154,7 +10262,7 @@ void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner)
// ScriptFindKey, ScriptGetFirstSubKey, ScriptGetString,
// ScriptGetInt, ScriptGetFloat, ScriptGetNextKey
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetModelKeyValues( void )
HSCRIPT_RC CBaseEntity::ScriptGetModelKeyValues( void )
{
KeyValues *pModelKeyValues = new KeyValues("");
HSCRIPT hScript = NULL;
@ -10163,16 +10271,12 @@ HSCRIPT CBaseEntity::ScriptGetModelKeyValues( void )
if ( pModelKeyValues->LoadFromBuffer( pszModelName, pBuffer ) )
{
// UNDONE: how does destructor get called on this
#ifdef MAPBASE_VSCRIPT
m_pScriptModelKeyValues = hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pModelKeyValues, true ); // Allow VScript to delete this when the instance is removed.
hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pModelKeyValues );
#else
// UNDONE: how does destructor get called on this
m_pScriptModelKeyValues = new CScriptKeyValues( pModelKeyValues );
#endif
// UNDONE: who calls ReleaseInstance on this??? Does name need to be unique???
#ifndef MAPBASE_VSCRIPT
hScript = g_pScriptVM->RegisterInstance( m_pScriptModelKeyValues );
#endif

View File

@ -1440,7 +1440,7 @@ public:
virtual bool FVisible ( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL );
virtual bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL );
virtual bool CanBeSeenBy( CAI_BaseNPC *pNPC ) { return true; } // allows entities to be 'invisible' to NPC senses.
virtual bool CanBeSeenBy( CAI_BaseNPC *pNPC ); // allows entities to be 'invisible' to NPC senses.
// This function returns a value that scales all damage done by this entity.
// Use CDamageModifier to hook in damage modifiers on a guy.
@ -2114,7 +2114,7 @@ public:
#endif
const char* ScriptGetModelName(void) const;
HSCRIPT ScriptGetModelKeyValues(void);
HSCRIPT_RC ScriptGetModelKeyValues(void);
void ScriptStopSound(const char* soundname);
void ScriptEmitSound(const char* soundname);
@ -2177,10 +2177,13 @@ public:
static ScriptHook_t g_Hook_VPhysicsCollision;
static ScriptHook_t g_Hook_FireBullets;
static ScriptHook_t g_Hook_OnDeath;
static ScriptHook_t g_Hook_OnTakeDamage;
static ScriptHook_t g_Hook_OnKilledOther;
static ScriptHook_t g_Hook_HandleInteraction;
static ScriptHook_t g_Hook_ModifyEmitSoundParams;
static ScriptHook_t g_Hook_ModifySentenceParams;
static ScriptHook_t g_Hook_ModifyOrAppendCriteria;
static ScriptHook_t g_Hook_CanBeSeenBy;
#endif
string_t m_iszVScripts;
@ -2188,9 +2191,7 @@ public:
CScriptScope m_ScriptScope;
HSCRIPT m_hScriptInstance;
string_t m_iszScriptId;
#ifdef MAPBASE_VSCRIPT
HSCRIPT m_pScriptModelKeyValues;
#else
#ifndef MAPBASE_VSCRIPT
CScriptKeyValues* m_pScriptModelKeyValues;
#endif
};

View File

@ -816,7 +816,7 @@ bool CBaseFlex::StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CCh
textParams.g1 = 255;
textParams.b1 = 255;
if ( GetGameTextSpeechParams( textParams ) )
if ( DispatchGetGameTextSpeechParams( textParams ) )
{
CRecipientFilter filter;
filter.AddAllPlayers();
@ -1654,6 +1654,12 @@ bool CBaseFlex::ProcessSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, C
case CChoreoEvent::SPEAK:
return true;
#ifdef MAPBASE
// Prevents "unknown type" console spam on players
case CChoreoEvent::GENERIC:
return true;
#endif
default:
{
Msg( "unknown type %d in ProcessSceneEvent()\n", event->GetType() );
@ -2093,8 +2099,16 @@ float CBaseFlex::PlayScene( const char *pszScene, float flDelay, AI_Response *re
#ifdef MAPBASE
float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname, float flDelay, AI_Response *response, IRecipientFilter *filter )
{
if (response && response->GetType() == ResponseRules::RESPONSE_CHOREOSENTENCE)
return InstancedChoreoSentenceScene( this, soundname, NULL, flDelay, false, response, false, filter );
return InstancedAutoGeneratedSoundScene( this, soundname, NULL, flDelay, false, response, false, filter );
}
float CBaseFlex::PlayChoreoSentenceScene( const char *pszSentence, float flDelay, AI_Response *response, IRecipientFilter *filter )
{
return InstancedChoreoSentenceScene( this, pszSentence, NULL, flDelay, false, response, false, filter );
}
#else
float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname )
{
@ -2106,11 +2120,17 @@ float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname )
//-----------------------------------------------------------------------------
// Purpose: Parameters for scene event AI_GameText
//-----------------------------------------------------------------------------
bool CBaseFlex::GetGameTextSpeechParams( hudtextparms_t &params )
bool CBaseFlex::DispatchGetGameTextSpeechParams( hudtextparms_t &params )
{
// First, get any default values overridden by this class
bool bReturn = GetGameTextSpeechParams( params );
// Allow VScript to override after
ScriptVariant_t varTable;
if (g_pScriptVM->GetValue(m_ScriptScope, "m_GameTextSpeechParams", &varTable) && varTable.m_type == FIELD_HSCRIPT)
if (g_pScriptVM->GetValue( m_ScriptScope, "m_GameTextSpeechParams", &varTable ) && varTable.m_type == FIELD_HSCRIPT)
{
bReturn = true;
int nIterator = -1;
ScriptVariant_t varKey, varValue;
while ((nIterator = g_pScriptVM->GetKeyValue( varTable.m_hScript, nIterator, &varKey, &varValue )) != -1)
@ -2147,13 +2167,18 @@ bool CBaseFlex::GetGameTextSpeechParams( hudtextparms_t &params )
{
params.fxTime = varValue.m_float;
}
else if (FStrEq( varKey.m_pszString, "disabled" ))
{
// Allow the params to disable game_text choreo if needed
bReturn = !(varValue.m_int > 0);
}
g_pScriptVM->ReleaseValue( varKey );
g_pScriptVM->ReleaseValue( varValue );
}
}
return true;
return bReturn;
}
#endif

View File

@ -129,6 +129,7 @@ public:
virtual float PlayScene( const char *pszScene, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL );
#ifdef MAPBASE
virtual float PlayChoreoSentenceScene( const char *pszSentenceName, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL );
virtual float PlayAutoGeneratedSoundScene( const char *soundname, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL );
#else
virtual float PlayAutoGeneratedSoundScene( const char *soundname );
@ -141,7 +142,8 @@ public:
virtual int GetSpecialDSP( void ) { return 0; }
#ifdef MAPBASE
virtual bool GetGameTextSpeechParams( hudtextparms_t &params );
bool DispatchGetGameTextSpeechParams( hudtextparms_t &params );
virtual bool GetGameTextSpeechParams( hudtextparms_t &params ) { return true; }
#endif
protected:

View File

@ -42,6 +42,10 @@ virtual void NullThink( void );
ConVar g_debug_basehelicopter( "g_debug_basehelicopter", "0", FCVAR_CHEAT );
#ifdef MAPBASE
ConVar g_helicopter_use_sight_condition( "g_helicopter_use_sight_condition", "0", 0, "If enabled, helicopters will use the AI sight condition instead of just checking if there's a clear path to the player. This prevents them from cheating." );
#endif
//---------------------------------------------------------
//---------------------------------------------------------
// TODOs
@ -702,7 +706,11 @@ void CBaseHelicopter::UpdateEnemy()
{
CBaseEntity *pEnemy = GetEnemy();
GatherEnemyConditions( pEnemy );
#ifdef MAPBASE
if ( (g_helicopter_use_sight_condition.GetBool() && pEnemy->Classify() != CLASS_BULLSEYE) ? HasCondition( COND_SEE_ENEMY ) : FVisible( pEnemy ) )
#else
if ( FVisible( pEnemy ) )
#endif
{
if (m_flLastSeen < gpGlobals->curtime - 2)
{

View File

@ -297,6 +297,19 @@ void CSpeaker::DispatchResponse( const char *conceptName )
CAI_Expresser::RunScriptResponse( pTarget, response, &set, true );
break;
}
#endif
#ifdef MAPBASE
case ResponseRules::RESPONSE_CHOREOSENTENCE:
{
CBaseFlex *pFlex = NULL;
if (pTarget != this)
{
// Attempt to get flex on the target
pFlex = dynamic_cast<CBaseFlex*>(pTarget);
}
InstancedAutoGeneratedSoundScene(pFlex, response);
break;
}
#endif
default:
break;

View File

@ -122,6 +122,7 @@ ConVar player_autoswitch_enabled( "player_autoswitch_enabled", "1", FCVAR_NONE,
#ifdef SP_ANIM_STATE
ConVar hl2_use_sp_animstate( "hl2_use_sp_animstate", "1", FCVAR_NONE, "Allows SP HL2 players to use HL2:DM animations for custom player models. (changes may not apply until model is reloaded)" );
ConVar player_process_scene_events( "player_process_scene_events", "1", FCVAR_NONE, "Allows players to process scene events." );
#endif
#endif
@ -268,6 +269,7 @@ public:
void InputSetHandModelBodyGroup( inputdata_t &inputdata );
void InputSetPlayerModel( inputdata_t &inputdata );
void InputSetPlayerDrawLegs( inputdata_t &inputdata );
void InputSetPlayerDrawExternally( inputdata_t &inputdata );
#endif
@ -691,6 +693,7 @@ IMPLEMENT_SERVERCLASS_ST(CHL2_Player, DT_HL2_Player)
#endif
#ifdef SP_ANIM_STATE
SendPropFloat( SENDINFO(m_flAnimRenderYaw), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flAnimRenderZ), 0, SPROP_NOSCALE ),
#endif
END_SEND_TABLE()
@ -1183,6 +1186,18 @@ void CHL2_Player::PostThink( void )
m_pPlayerAnimState->Update( angEyeAngles.y, angEyeAngles.x );
m_flAnimRenderYaw.Set( m_pPlayerAnimState->GetRenderAngles().y );
if (m_pPlayerAnimState->IsJumping() && !m_pPlayerAnimState->IsDuckJumping())
{
m_flAnimRenderZ.Set( -(GetViewOffset().z) );
}
else
m_flAnimRenderZ.Set( 0.0f );
if (player_process_scene_events.GetBool())
{
ProcessSceneEvents();
}
}
#endif
}
@ -1505,6 +1520,7 @@ CStudioHdr *CHL2_Player::OnNewModel()
}
extern char g_szDefaultPlayerModel[MAX_PATH];
extern bool g_bDefaultPlayerLegs;
extern bool g_bDefaultPlayerDrawExternally;
extern char g_szDefaultProtagonist[MAX_PROTAGONIST_NAME];
@ -1539,6 +1555,7 @@ void CHL2_Player::Spawn(void)
RemoveEffects( EF_NODRAW );
}
SetDrawPlayerLegs( g_bDefaultPlayerLegs );
SetDrawPlayerModelExternally( g_bDefaultPlayerDrawExternally );
if (m_iszProtagonistName == NULL_STRING && *g_szDefaultProtagonist)
@ -3376,6 +3393,11 @@ void CHL2_Player::Weapon_Equip( CBaseCombatWeapon *pWeapon )
if( GetActiveWeapon() == NULL )
{
m_HL2Local.m_bWeaponLowered = false;
#ifdef SP_ANIM_STATE
if (m_pPlayerAnimState)
m_pPlayerAnimState->StopWeaponRelax();
#endif
}
BaseClass::Weapon_Equip( pWeapon );
@ -3781,6 +3803,11 @@ bool CHL2_Player::Weapon_Lower( void )
m_HL2Local.m_bWeaponLowered = true;
#ifdef SP_ANIM_STATE
if (m_pPlayerAnimState)
m_pPlayerAnimState->StartWeaponRelax();
#endif
CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>(GetActiveWeapon());
if ( pWeapon == NULL )
@ -3803,6 +3830,11 @@ bool CHL2_Player::Weapon_Ready( void )
m_HL2Local.m_bWeaponLowered = false;
#ifdef SP_ANIM_STATE
if (m_pPlayerAnimState)
m_pPlayerAnimState->StopWeaponRelax();
#endif
CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>(GetActiveWeapon());
if ( pWeapon == NULL )
@ -4016,6 +4048,21 @@ void CHL2_Player::OnRestore()
{
BaseClass::OnRestore();
m_pPlayerAISquad = g_AI_SquadManager.FindCreateSquad(AllocPooledString(PLAYER_SQUADNAME));
#ifdef SP_ANIM_STATE
if ( m_pPlayerAnimState == NULL )
{
if ( GetModelPtr() && GetModelPtr()->HaveSequenceForActivity(ACT_HL2MP_IDLE) && hl2_use_sp_animstate.GetBool() )
{
// Here we create and init the player animation state.
m_pPlayerAnimState = CreatePlayerAnimationState(this);
}
else
{
m_flAnimRenderYaw = FLT_MAX;
}
}
#endif
}
//---------------------------------------------------------
@ -4763,6 +4810,7 @@ BEGIN_DATADESC( CLogicPlayerProxy )
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHandModelSkin", InputSetHandModelSkin ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHandModelBodyGroup", InputSetHandModelBodyGroup ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetPlayerModel", InputSetPlayerModel ),
DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetPlayerDrawLegs", InputSetPlayerDrawLegs ),
DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetPlayerDrawExternally", InputSetPlayerDrawExternally ),
DEFINE_INPUT( m_MaxArmor, FIELD_INTEGER, "SetMaxInputArmor" ),
DEFINE_INPUT( m_SuitZoomFOV, FIELD_INTEGER, "SetSuitZoomFOV" ),
@ -5241,6 +5289,15 @@ void CLogicPlayerProxy::InputSetPlayerModel( inputdata_t &inputdata )
m_hPlayer->SetModel( STRING(iszModel) );
}
void CLogicPlayerProxy::InputSetPlayerDrawLegs( inputdata_t &inputdata )
{
if (!m_hPlayer)
return;
CBasePlayer *pPlayer = static_cast<CBasePlayer*>(m_hPlayer.Get());
pPlayer->SetDrawPlayerLegs( inputdata.value.Bool() );
}
void CLogicPlayerProxy::InputSetPlayerDrawExternally( inputdata_t &inputdata )
{
if (!m_hPlayer)

View File

@ -19,7 +19,7 @@
#if defined ( HL2MP )
#include "basemultiplayerplayer.h"
#elif defined ( MAPBASE )
#include "mapbase/singleplayer_animstate.h"
#include "mapbase/mapbase_playeranimstate.h"
#endif
class CAI_Squad;
@ -458,11 +458,12 @@ private:
#endif
#ifdef SP_ANIM_STATE
CSinglePlayerAnimState* m_pPlayerAnimState;
CMapbasePlayerAnimState* m_pPlayerAnimState;
// At the moment, we network the render angles since almost none of the player anim stuff is done on the client in SP.
// If any of this is ever adapted for MP, this method should be replaced with replicating/moving the anim state to the client.
CNetworkVar( float, m_flAnimRenderYaw );
CNetworkVar( float, m_flAnimRenderZ );
#endif
};

View File

@ -63,3 +63,88 @@ BEGIN_DATADESC( CItemBattery )
END_DATADESC()
#endif
#ifdef MAPBASE
extern ConVar sk_battery;
//-----------------------------------------------------------------------------
// Custom player battery. Heals the player when picked up.
//-----------------------------------------------------------------------------
class CItemBatteryCustom : public CItem
{
public:
DECLARE_CLASS( CItemBatteryCustom, CItem );
CItemBatteryCustom();
void Spawn( void );
void Precache( void );
bool MyTouch( CBasePlayer *pPlayer );
float GetItemAmount() { return m_flPowerAmount; }
void InputSetPowerAmount( inputdata_t &inputdata ) { m_flPowerAmount = inputdata.value.Float(); }
float m_flPowerAmount;
string_t m_iszTouchSound;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( item_battery_custom, CItemBatteryCustom );
#ifdef MAPBASE
BEGIN_DATADESC( CItemBatteryCustom )
DEFINE_KEYFIELD( m_flPowerAmount, FIELD_FLOAT, "PowerAmount" ),
DEFINE_KEYFIELD( m_iszTouchSound, FIELD_STRING, "TouchSound" ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPowerAmount", InputSetPowerAmount ),
END_DATADESC()
#endif
CItemBatteryCustom::CItemBatteryCustom()
{
SetModelName( AllocPooledString( "models/items/battery.mdl" ) );
m_flPowerAmount = sk_battery.GetFloat();
m_iszTouchSound = AllocPooledString( "ItemBattery.Touch" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemBatteryCustom::Spawn( void )
{
Precache();
SetModel( STRING( GetModelName() ) );
BaseClass::Spawn();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemBatteryCustom::Precache( void )
{
PrecacheModel( STRING( GetModelName() ) );
PrecacheScriptSound( STRING( m_iszTouchSound ) );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pPlayer -
// Output :
//-----------------------------------------------------------------------------
bool CItemBatteryCustom::MyTouch( CBasePlayer *pPlayer )
{
CHL2_Player *pHL2Player = assert_cast<CHL2_Player *>(pPlayer);
if (!pHL2Player || sk_battery.GetFloat() == 0.0f)
return false;
float flPowerMult = m_flPowerAmount / sk_battery.GetFloat();
return pHL2Player->ApplyBattery( flPowerMult );
}
#endif

View File

@ -44,6 +44,7 @@
#ifdef MAPBASE
#include "filters.h"
#include "ai_hint.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
@ -164,6 +165,15 @@ ConVar g_helicopter_bullrush_mega_bomb_health( "g_helicopter_bullrush_mega_bomb_
ConVar g_helicopter_bomb_danger_radius( "g_helicopter_bomb_danger_radius", "120" );
#ifdef MAPBASE
ConVar g_helicopter_crashpoint_nearest( "g_helicopter_crashpoint_nearest", "1", 0, "Selects the nearest crash point instead of just the first in the entity list." );
#ifdef HL2_EPISODIC
ConVar g_helicopter_phys_follow_while_crashing( "g_helicopter_phys_follow_while_crashing", "0", 0, "Allows the phys_bone_followers to follow the helicopter while flying to crash point" );
#endif
#endif
Activity ACT_HELICOPTER_DROP_BOMB;
Activity ACT_HELICOPTER_CRASHING;
@ -191,7 +201,60 @@ enum
#define GRENADE_HELICOPTER_MODEL "models/combine_helicopter/helicopter_bomb01.mdl"
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTargetHelicopterCrash : public CPointEntity
{
DECLARE_CLASS( CTargetHelicopterCrash, CPointEntity );
public:
DECLARE_DATADESC();
void InputEnable( inputdata_t &inputdata )
{
m_bDisabled = false;
}
void InputDisable( inputdata_t &inputdata )
{
m_bDisabled = true;
}
bool IsDisabled( void )
{
return m_bDisabled;
}
void HelicopterCrashedOnTarget( CBaseHelicopter *pChopper )
{
m_OnCrashed.FireOutput( pChopper, this );
}
void HelicopterAcquiredCrashTarget( CBaseHelicopter *pChopper )
{
m_OnBeginCrash.FireOutput( pChopper, this );
}
private:
bool m_bDisabled;
COutputEvent m_OnCrashed;
COutputEvent m_OnBeginCrash;
};
LINK_ENTITY_TO_CLASS( info_target_helicopter_crash, CTargetHelicopterCrash );
BEGIN_DATADESC( CTargetHelicopterCrash )
DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
// Outputs
DEFINE_OUTPUT( m_OnCrashed, "OnCrashed" ),
DEFINE_OUTPUT( m_OnBeginCrash, "OnBeginCrash" ),
END_DATADESC()
#else
LINK_ENTITY_TO_CLASS( info_target_helicopter_crash, CPointEntity );
#endif
//------------------------------------------------------------------------------
@ -499,6 +562,13 @@ private:
// Death, etc.
void InputSelfDestruct( inputdata_t &inputdata );
#ifdef MAPBASE
// This is identical to SelfDestruct, except the helicopter won't throw out chunks while flying to a crash point.
// This input is meant to be used when the pilot is killed and there's nothing wrong with the helicopter itself.
// If there are no crash points, the helicopter will explode in place as normal.
void InputSelfDestructNoFX( inputdata_t &inputdata );
#endif
// Enemy visibility check
CBaseEntity *FindTrackBlocker( const Vector &vecViewPoint, const Vector &vecTargetPos );
@ -522,6 +592,7 @@ private:
// Various states of the helicopter firing...
bool PoseGunTowardTargetDirection( const Vector &vTargetDir );
float GetGunPoseSpeed() const;
// Compute the position to fire at (vehicle + non-vehicle case)
void ComputeFireAtPosition( Vector *pVecActualTargetPosition );
@ -533,6 +604,17 @@ private:
bool DoGunFiring( const Vector &vBasePos, const Vector &vGunDir, const Vector &vecFireAtPosition );
void FireElectricityGun( );
#ifdef MAPBASE
// Idle aiming
bool FindIdleAimTarget();
bool ValidIdleAimTarget( CBaseEntity *pAimTarget );
bool FValidateHintType( CAI_Hint *pHint );
inline CBaseEntity *GetIdleAimTarget() const { return m_hIdleAimTarget; }
inline void SetIdleAimTarget( CBaseEntity *pNewAimTarget ) { m_hIdleAimTarget = pNewAimTarget; }
#endif
// Chooses a point within the circle of death to fire in
void PickDirectionToCircleOfDeath( const Vector &vBasePos, const Vector &vecFireAtPosition, Vector *pResult );
@ -650,6 +732,7 @@ private:
void SpotlightStartup();
void SpotlightShutdown();
CBaseEntity *FindCrashPoint();
CBaseEntity *GetCrashPoint() { return m_hCrashPoint.Get(); }
private:
@ -721,6 +804,17 @@ private:
bool m_bBombsExplodeOnContact;
bool m_bNonCombat;
#ifdef MAPBASE
bool m_bIdleAimAround;
EHANDLE m_hIdleAimTarget;
Vector m_vecIdleAimDir;
float m_flNextIdleAimTime;
bool m_bDisableSmokeTrails;
bool m_bDisableCorpses;
bool m_bDisableExplosions;
#endif
int m_nNearShots;
int m_nMaxNearShots;
@ -860,6 +954,15 @@ BEGIN_DATADESC( CNPC_AttackHelicopter )
#ifdef MAPBASE
DEFINE_KEYFIELD( m_flFieldOfView, FIELD_FLOAT, "FieldOfView" ),
DEFINE_KEYFIELD( m_bIdleAimAround, FIELD_BOOLEAN, "IdleAimAround" ),
DEFINE_FIELD( m_hIdleAimTarget, FIELD_EHANDLE ),
DEFINE_FIELD( m_vecIdleAimDir, FIELD_VECTOR ),
DEFINE_FIELD( m_flNextIdleAimTime, FIELD_TIME ),
DEFINE_KEYFIELD( m_bDisableSmokeTrails, FIELD_BOOLEAN, "DisableSmokeTrails" ),
DEFINE_KEYFIELD( m_bDisableCorpses, FIELD_BOOLEAN, "DisableCorpses" ),
DEFINE_KEYFIELD( m_bDisableExplosions, FIELD_BOOLEAN, "DisableExplosions" ),
#endif
DEFINE_FIELD( m_hCrashPoint, FIELD_EHANDLE ),
@ -896,6 +999,9 @@ BEGIN_DATADESC( CNPC_AttackHelicopter )
DEFINE_INPUTFUNC( FIELD_VOID, "EnablePathVisibilityTests", InputEnablePathVisibilityTests ),
DEFINE_INPUTFUNC( FIELD_VOID, "SelfDestruct", InputSelfDestruct ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_VOID, "SelfDestructNoFX", InputSelfDestructNoFX ),
#endif
DEFINE_THINKFUNC( BlinkLightsThink ),
DEFINE_THINKFUNC( SpotlightThink ),
@ -1646,6 +1752,21 @@ void CNPC_AttackHelicopter::InputSelfDestruct( inputdata_t &inputdata )
TakeDamage( info );
}
#ifdef MAPBASE
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void CNPC_AttackHelicopter::InputSelfDestructNoFX( inputdata_t &inputdata )
{
m_bDisableSmokeTrails = true;
m_bDisableCorpses = true;
m_bDisableExplosions = true;
m_lifeState = LIFE_ALIVE; // Force to die properly.
CTakeDamageInfo info( this, this, Vector(0, 0, 1), WorldSpaceCenter(), GetMaxHealth(), CLASS_MISSILE );
TakeDamage( info );
}
#endif
//-----------------------------------------------------------------------------
// For scripted times where it *has* to shoot
//-----------------------------------------------------------------------------
@ -2245,21 +2366,23 @@ bool CNPC_AttackHelicopter::PoseGunTowardTargetDirection( const Vector &vTargetD
}
}
float flPoseSpeed = GetGunPoseSpeed();
if (angles.x > m_angGun.x)
{
m_angGun.x = MIN( angles.x, m_angGun.x + 12 );
m_angGun.x = MIN( angles.x, m_angGun.x + flPoseSpeed );
}
if (angles.x < m_angGun.x)
{
m_angGun.x = MAX( angles.x, m_angGun.x - 12 );
m_angGun.x = MAX( angles.x, m_angGun.x - flPoseSpeed );
}
if (angles.y > m_angGun.y)
{
m_angGun.y = MIN( angles.y, m_angGun.y + 12 );
m_angGun.y = MIN( angles.y, m_angGun.y + flPoseSpeed );
}
if (angles.y < m_angGun.y)
{
m_angGun.y = MAX( angles.y, m_angGun.y - 12 );
m_angGun.y = MAX( angles.y, m_angGun.y - flPoseSpeed );
}
SetPoseParameter( m_poseWeapon_Pitch, -m_angGun.x );
@ -2269,6 +2392,20 @@ bool CNPC_AttackHelicopter::PoseGunTowardTargetDirection( const Vector &vTargetD
}
//------------------------------------------------------------------------------
// Various states of the helicopter firing...
//------------------------------------------------------------------------------
float CNPC_AttackHelicopter::GetGunPoseSpeed() const
{
#ifdef MAPBASE
if (m_bIdleAimAround && !GetEnemy())
return 4.0f;
#endif
return 12.0f;
}
//------------------------------------------------------------------------------
// Compute the enemy position (non-vehicle case)
//------------------------------------------------------------------------------
@ -2363,6 +2500,87 @@ bool CNPC_AttackHelicopter::DoGunIdle( const Vector &vGunDir, const Vector &vTar
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Finds an idle aim target. Based on CNPC_PlayerCompanion code
//-----------------------------------------------------------------------------
bool CNPC_AttackHelicopter::FindIdleAimTarget()
{
CAI_Hint *pHint;
CHintCriteria hintCriteria;
CBaseEntity *pPriorAimTarget = GetIdleAimTarget();
hintCriteria.SetHintType( HINT_WORLD_VISUALLY_INTERESTING );
hintCriteria.SetFlag( bits_HINT_NODE_VISIBLE | bits_HINT_NODE_IN_VIEWCONE | bits_HINT_NPC_IN_NODE_FOV | bits_HINT_NODE_USE_GROUP | bits_HINT_NODE_NEAREST );
hintCriteria.AddIncludePosition( GetAbsOrigin(), CHOPPER_MAX_GUN_DIST );
pHint = CAI_HintManager::FindHint( this, hintCriteria );
if( pHint )
{
if ( !ValidIdleAimTarget( pHint ) )
{
return false;
}
if ( pHint != pPriorAimTarget )
{
// Notify of the change.
SetIdleAimTarget( pHint );
return true;
}
}
// Didn't find an aim target, or found the same one.
return false;
}
//-----------------------------------------------------------------------------
// Finds an idle aim target. Based on CNPC_PlayerCompanion code
//-----------------------------------------------------------------------------
bool CNPC_AttackHelicopter::ValidIdleAimTarget( CBaseEntity *pAimTarget )
{
Vector vecTargetOrigin = pAimTarget->GetAbsOrigin();
Vector vBasePos;
GetAttachment( m_nGunBaseAttachment, vBasePos );
if ( vecTargetOrigin.z > vBasePos.z || (vecTargetOrigin - vBasePos).Length() < 128.0f )
{
// Too close!
return false;
}
trace_t tr;
UTIL_TraceLine( vBasePos, vecTargetOrigin, MASK_BLOCKLOS, this, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction < 1.0f && tr.m_pEnt != pAimTarget )
{
// No LOS
return false;
}
return true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CNPC_AttackHelicopter::FValidateHintType( CAI_Hint *pHint )
{
switch( pHint->HintType() )
{
case HINT_WORLD_VISUALLY_INTERESTING:
return true;
break;
default:
break;
}
return BaseClass::FValidateHintType( pHint );
}
#endif
//------------------------------------------------------------------------------
// How easy is the target to hit?
//------------------------------------------------------------------------------
@ -3653,12 +3871,20 @@ int CNPC_AttackHelicopter::OnTakeDamage_Alive( const CTakeDamageInfo &info )
}
}
#ifdef MAPBASE
if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_SMOKE_TRAILS ) && !m_bDisableSmokeTrails )
#else
if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_SMOKE_TRAILS ) )
#endif
{
AddSmokeTrail( info.GetDamagePosition() );
}
#ifdef MAPBASE
if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_CORPSES ) && !m_bDisableCorpses )
#else
if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_CORPSES ) )
#endif
{
if ( nPrevHealth != GetMaxHealth() )
{
@ -3666,7 +3892,11 @@ int CNPC_AttackHelicopter::OnTakeDamage_Alive( const CTakeDamageInfo &info )
}
}
#ifdef MAPBASE
if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_EXPLOSIONS ) && !m_bDisableExplosions )
#else
if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_EXPLOSIONS ) )
#endif
{
ExplodeAndThrowChunk( info.GetDamagePosition() );
}
@ -3774,6 +4004,46 @@ void Chopper_BecomeChunks( CBaseEntity *pChopper )
pBodyChunk->m_pCockpitConstraint = physenv->CreateFixedConstraint( pBodyObject, pCockpitObject, pGroup, fixed );
}
//-----------------------------------------------------------------------------
// Purpose: Find a valid crash point
//-----------------------------------------------------------------------------
CBaseEntity *CNPC_AttackHelicopter::FindCrashPoint()
{
#ifdef MAPBASE
float flNearest = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH;
CTargetHelicopterCrash *pNearest = NULL;
CBaseEntity *pEnt = NULL;
while( (pEnt = gEntList.FindEntityByClassname(pEnt, "info_target_helicopter_crash")) != NULL )
{
CTargetHelicopterCrash *pCrashTarget = assert_cast<CTargetHelicopterCrash*>(pEnt);
if ( pCrashTarget->IsDisabled() )
continue;
if (g_helicopter_crashpoint_nearest.GetBool())
{
float flDist = ( pEnt->WorldSpaceCenter() - WorldSpaceCenter() ).LengthSqr();
if( flDist < flNearest )
{
pNearest = pCrashTarget;
flNearest = flDist;
}
}
else
{
pNearest = pCrashTarget;
break;
}
}
if (pNearest)
pNearest->HelicopterAcquiredCrashTarget( this );
return pNearest;
#else
return gEntList.FindEntityByClassname( NULL, "info_target_helicopter_crash" );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Start us crashing
//-----------------------------------------------------------------------------
@ -3791,7 +4061,7 @@ void CNPC_AttackHelicopter::Event_Killed( const CTakeDamageInfo &info )
if( GetCrashPoint() == NULL )
{
CBaseEntity *pCrashPoint = gEntList.FindEntityByClassname( NULL, "info_target_helicopter_crash" );
CBaseEntity *pCrashPoint = FindCrashPoint();
if( pCrashPoint != NULL )
{
m_hCrashPoint.Set( pCrashPoint );
@ -3812,6 +4082,12 @@ void CNPC_AttackHelicopter::Event_Killed( const CTakeDamageInfo &info )
return;
}
}
#ifdef MAPBASE
else
{
assert_cast<CTargetHelicopterCrash*>( GetCrashPoint() )->HelicopterCrashedOnTarget( this );
}
#endif
Chopper_BecomeChunks( this );
StopLoopingSounds();
@ -3869,7 +4145,11 @@ void CNPC_AttackHelicopter::PrescheduleThink( void )
SetDesiredPosition( GetCrashPoint()->WorldSpaceCenter() );
}
#ifdef MAPBASE
if ( !m_bDisableExplosions && random->RandomInt( 0, 4 ) == 0 )
#else
if ( random->RandomInt( 0, 4 ) == 0 )
#endif
{
Vector explodePoint;
CollisionProp()->RandomPointInBounds( Vector(0.25,0.25,0.25), Vector(0.75,0.75,0.75), &explodePoint );
@ -4821,6 +5101,15 @@ void CNPC_AttackHelicopter::Hunt( void )
{
Flight();
UpdatePlayerDopplerShift( );
#if defined(MAPBASE) && defined(HL2_EPISODIC)
if (g_helicopter_phys_follow_while_crashing.GetBool())
{
// Update our bone followers
m_BoneFollowerManager.UpdateBoneFollowers( this );
}
#endif // HL2_EPISODIC
return;
}
@ -4885,6 +5174,55 @@ void CNPC_AttackHelicopter::Hunt( void )
#endif
}
#ifdef MAPBASE
if (m_bIdleAimAround)
{
if (!GetEnemy())
{
if (GetIdleAimTarget())
{
if (!ValidIdleAimTarget( GetIdleAimTarget() ))
{
SetIdleAimTarget( NULL );
m_flNextIdleAimTime = gpGlobals->curtime;
}
}
if (m_flNextIdleAimTime < gpGlobals->curtime)
{
if (!FindIdleAimTarget())
{
SetIdleAimTarget( NULL );
// Find a random direction in front of us instead
Vector vBasePos, vecForward, vecRight, vecUp;
GetAttachment( m_nGunBaseAttachment, vBasePos, &vecForward, &vecRight, &vecUp );
m_vecIdleAimDir = vecForward + (vecRight * RandomFloat( -0.25f, 0.25f )) + (vecUp * RandomFloat( -0.8f, -0.25f ));
}
m_flNextIdleAimTime = gpGlobals->curtime + RandomFloat( 4.0f, 6.0f );
}
if (GetIdleAimTarget())
{
// Get gun attachment points
Vector vBasePos;
GetAttachment( m_nGunBaseAttachment, vBasePos );
m_vecIdleAimDir = GetIdleAimTarget()->GetAbsOrigin() - vBasePos;
VectorNormalize( m_vecIdleAimDir );
}
PoseGunTowardTargetDirection( m_vecIdleAimDir );
}
else if (GetIdleAimTarget())
{
SetIdleAimTarget( NULL );
}
}
#endif
#ifdef HL2_EPISODIC
// Update our bone followers
m_BoneFollowerManager.UpdateBoneFollowers(this);

View File

@ -2551,6 +2551,24 @@ int CNPC_Combine::TranslateSchedule( int scheduleType )
}
}
#ifdef MAPBASE
extern ConVar ai_enemy_memory_fixes;
// SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE uses TASK_GET_PATH_TO_ENEMY_LKP_LOS, a task with a mistake
// detailed in CAI_BaseNPC::StartTask and fixed by ai_enemy_memory_fixes.
//
// However, SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE only stops being used once the NPC has LOS to its target.
// Since the fixed task now uses the enemy's last known position instead of the enemy's actual position,
// this schedule risks getting stuck in a loop.
//
// This code makes the soldier run up directly to the last known position if it's visible, allowing the AI
// to mark the enemy as eluded.
if ( ai_enemy_memory_fixes.GetBool() && FVisible( GetEnemyLKP() ) )
{
return SCHED_COMBINE_PRESS_ATTACK;
}
#endif
return SCHED_COMBINE_ESTABLISH_LINE_OF_FIRE;
}
break;

View File

@ -69,6 +69,7 @@ public:
int RangeAttack2Conditions( float flDot, float flDist ); // For innate grenade attack
int MeleeAttack1Conditions( float flDot, float flDist ); // For kick/punch
bool FVisible( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL );
bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ) { return BaseClass::FVisible( vecTarget, traceMask, ppBlocker ); }
virtual bool IsCurTaskContinuousMove();
virtual float GetJumpGravity() const { return 1.8f; }

View File

@ -134,6 +134,11 @@ enum LandingState_t
LANDING_HOVER_DESCEND,
LANDING_HOVER_TOUCHDOWN,
LANDING_END_HOVER,
#ifdef MAPBASE
// Strider dropoff
LANDING_STRIDER,
#endif
};
@ -295,6 +300,9 @@ private:
bool IsHovering();
void UpdateGroundRotorWashSound( float flAltitude );
void UpdateRotorWashVolume( CSoundPatch *pRotorSound, float flVolume, float flDeltaTime );
#ifdef MAPBASE
void DeathNotice(CBaseEntity* pVictim);
#endif
private:
// Timers
@ -353,6 +361,12 @@ private:
string_t m_sRollermineTemplate;
string_t m_sRollermineTemplateData;
#ifdef MAPBASE
// Template for strider carried by this dropship
string_t m_sStriderTemplate;
string_t m_sStriderTemplateData;
#endif
// Cached attachment points
int m_iMuzzleAttachment;
int m_iMachineGunBaseAttachment;
@ -827,6 +841,11 @@ BEGIN_DATADESC( CNPC_CombineDropship )
DEFINE_KEYFIELD( m_sRollermineTemplate, FIELD_STRING, "RollermineTemplate" ),
DEFINE_FIELD( m_sRollermineTemplateData, FIELD_STRING ),
#ifdef MAPBASE
DEFINE_KEYFIELD(m_sStriderTemplate, FIELD_STRING, "StriderTemplate"),
DEFINE_FIELD(m_sStriderTemplateData, FIELD_STRING),
#endif
DEFINE_ARRAY( m_sNPCTemplateData, FIELD_STRING, DROPSHIP_MAX_SOLDIERS ),
DEFINE_KEYFIELD( m_sNPCTemplate[0], FIELD_STRING, "NPCTemplate" ),
DEFINE_KEYFIELD( m_sNPCTemplate[1], FIELD_STRING, "NPCTemplate2" ),
@ -962,12 +981,60 @@ void CNPC_CombineDropship::Spawn( void )
break;
case CRATE_STRIDER:
#ifdef MAPBASE
if ( m_sStriderTemplate != NULL_STRING )
{
m_sStriderTemplateData = Templates_FindByTargetName( STRING( m_sStriderTemplate ) );
if (m_sStriderTemplateData == NULL_STRING)
{
Warning("npc_combinedropship %s: Strider Template %s not found!\n", STRING(GetEntityName()), STRING(m_sStriderTemplate));
break;
}
CAI_BaseNPC* pent = NULL;
CBaseEntity* pEntity = NULL;
MapEntity_ParseEntity( pEntity, STRING( m_sStriderTemplateData ), NULL);
if ( pEntity != NULL )
{
pent = ( CAI_BaseNPC* )pEntity;
}
if ( !FClassnameIs(pent, "npc_strider"))
{
Warning("npc_combinedropship %s: Strider Template %s is not a strider!\n", STRING(GetEntityName()), STRING(m_sStriderTemplate));
break;
}
m_OnSpawnNPC.Set( pEntity, pEntity, this );
pent->RemoveSpawnFlags( SF_NPC_TEMPLATE );
pent->SetOwnerEntity( this );
m_hContainer = pent;
m_hContainer->SetAbsOrigin( GetAbsOrigin() - Vector(0, 0, 100) );
m_hContainer->SetAbsAngles( GetAbsAngles() );
m_hContainer->SetParent( this, 0 );
m_hContainer->SetOwnerEntity( this );
DispatchSpawn(pent);
}
else
{
m_hContainer = ( CBaseAnimating* )CreateEntityByName("npc_strider");
m_hContainer->SetAbsOrigin( GetAbsOrigin() - Vector(0, 0, 100) );
m_hContainer->SetAbsAngles( GetAbsAngles() );
m_hContainer->SetParent( this, 0 );
m_hContainer->SetOwnerEntity( this );
m_hContainer->Spawn();
}
#else
m_hContainer = (CBaseAnimating*)CreateEntityByName( "npc_strider" );
m_hContainer->SetAbsOrigin( GetAbsOrigin() - Vector( 0, 0 , 100 ) );
m_hContainer->SetAbsAngles( GetAbsAngles() );
m_hContainer->SetParent(this, 0);
m_hContainer->SetOwnerEntity(this);
m_hContainer->Spawn();
#endif
m_hContainer->SetAbsOrigin( GetAbsOrigin() - Vector( 0, 0 , 100 ) );
#ifdef MAPBASE
m_OnSpawnNPC.Set( m_hContainer, m_hContainer, this );
@ -1201,13 +1268,24 @@ void CNPC_CombineDropship::Precache( void )
void CNPC_CombineDropship::Flight( void )
{
// Only run the flight model in some flight states
#ifdef MAPBASE
bool bRunFlight = ( GetLandingState() == LANDING_NO ||
GetLandingState() == LANDING_LEVEL_OUT ||
GetLandingState() == LANDING_LIFTOFF ||
GetLandingState() == LANDING_SWOOPING ||
GetLandingState() == LANDING_DESCEND ||
GetLandingState() == LANDING_HOVER_LEVEL_OUT ||
GetLandingState() == LANDING_HOVER_DESCEND );
GetLandingState() == LANDING_HOVER_DESCEND ||
GetLandingState() == LANDING_STRIDER );
#else
bool bRunFlight = (GetLandingState() == LANDING_NO ||
GetLandingState() == LANDING_LEVEL_OUT ||
GetLandingState() == LANDING_LIFTOFF ||
GetLandingState() == LANDING_SWOOPING ||
GetLandingState() == LANDING_DESCEND ||
GetLandingState() == LANDING_HOVER_LEVEL_OUT ||
GetLandingState() == LANDING_HOVER_DESCEND );
#endif
Vector forward, right, up;
GetVectors( &forward, &right, &up );
@ -1429,8 +1507,14 @@ void CNPC_CombineDropship::Flight( void )
}
// If we're landing, deliberately tuck in the back end
#ifdef MAPBASE
if ( GetLandingState() == LANDING_DESCEND || GetLandingState() == LANDING_TOUCHDOWN ||
GetLandingState() == LANDING_UNLOADING || GetLandingState() == LANDING_UNLOADED ||
GetLandingState() == LANDING_STRIDER || IsHovering() )
#else
if ( GetLandingState() == LANDING_DESCEND || GetLandingState() == LANDING_TOUCHDOWN ||
GetLandingState() == LANDING_UNLOADING || GetLandingState() == LANDING_UNLOADED || IsHovering() )
#endif
{
finspeed = -60;
}
@ -1779,6 +1863,16 @@ void CNPC_CombineDropship::InputDropStrider( inputdata_t &inputdata )
return;
}
#ifdef MAPBASE
if (m_iszLandTarget != NULL_STRING)
{
LandCommon();
}
else
{
SetLandingState(LANDING_STRIDER);
}
#else
QAngle angles = GetAbsAngles();
angles.x = 0.0;
@ -1790,6 +1884,7 @@ void CNPC_CombineDropship::InputDropStrider( inputdata_t &inputdata )
m_hContainer->SetAbsVelocity( vec3_origin );
m_hContainer = NULL;
#endif
}
//-----------------------------------------------------------------------------
@ -2016,7 +2111,11 @@ void CNPC_CombineDropship::SetLandingState( LandingState_t landingState )
if ( m_pDescendingWarningSound )
{
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
#ifdef MAPBASE
if ( ( landingState == LANDING_DESCEND ) || ( landingState == LANDING_TOUCHDOWN ) || ( landingState == LANDING_UNLOADING ) || ( landingState == LANDING_UNLOADED ) || ( landingState == LANDING_HOVER_DESCEND ) || ( landingState == LANDING_STRIDER ) )
#else
if ( ( landingState == LANDING_DESCEND ) || ( landingState == LANDING_TOUCHDOWN ) || ( landingState == LANDING_UNLOADING ) || ( landingState == LANDING_UNLOADED ) || ( landingState == LANDING_HOVER_DESCEND ) )
#endif
{
controller.SoundChangeVolume( m_pDescendingWarningSound, m_bSuppressSound ? 0.0f : 1.0f, 0.3f );
}
@ -2112,8 +2211,15 @@ void CNPC_CombineDropship::PrescheduleThink( void )
if ( flDistance < 70 && flSpeed < 100 )
{
m_flLandingSpeed = flSpeed;
if( IsHovering() )
#ifdef MAPBASE
if ( m_iCrateType == CRATE_STRIDER )
{
SetLandingState( LANDING_STRIDER );
}
else if( IsHovering() )
#else
if ( IsHovering() )
#endif
{
SetLandingState( LANDING_HOVER_DESCEND );
}
@ -2315,6 +2421,98 @@ void CNPC_CombineDropship::PrescheduleThink( void )
}
break;
#ifdef MAPBASE
case LANDING_STRIDER:
{
if (!m_hContainer)
{
// Strider died, get out of here
SetLandingState(LANDING_LIFTOFF);
return;
}
// Orient myself to the desired direction
bool bStillOrienting = false;
Vector targetDir;
if (m_hLandTarget)
{
// We've got a land target, so match it's orientation
AngleVectors(m_hLandTarget->GetAbsAngles(), &targetDir);
}
else
{
// No land target.
targetDir = GetDesiredPosition() - GetAbsOrigin();
}
// Don't unload until we're facing the way the dropoff point specifies
float flTargetYaw = UTIL_VecToYaw(targetDir);
float flDeltaYaw = UTIL_AngleDiff(flTargetYaw, GetAbsAngles().y);
if (fabs(flDeltaYaw) > 5)
{
bStillOrienting = true;
}
// Ensure we land on the drop point. Stop dropping if we're still turning.
Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin());
float flDistance = vecToTarget.Length();
float flRampedSpeed = m_flLandingSpeed * (flDistance / 70);
Vector vecVelocity = (flRampedSpeed / flDistance) * vecToTarget;
#define STRIDER_LANDING_HEIGHT 540.0f
float flFactor = MIN(1.0, MAX(0.1f, (flAltitude - STRIDER_LANDING_HEIGHT) / flAltitude));
float flDescendVelocity = MIN(-75, MAX_LAND_VEL * flFactor);
vecVelocity.z = flDescendVelocity;
SetAbsVelocity(vecVelocity);
if (flAltitude < 600)
{
QAngle angles = GetLocalAngles();
// Level out quickly.
angles.x = UTIL_Approach(0.0, angles.x, 0.2);
angles.z = UTIL_Approach(0.0, angles.z, 0.2);
SetLocalAngles(angles);
}
else
{
// randomly move as if buffeted by ground effects
// gently flatten ship from starting pitch/yaw
m_existPitch = UTIL_Approach(0.0, m_existPitch, 1);
m_existRoll = UTIL_Approach(0.0, m_existRoll, 1);
QAngle angles = GetLocalAngles();
angles.x = m_existPitch + (sin(gpGlobals->curtime * 3.5f) * DROPSHIP_MAX_LAND_TILT);
angles.z = m_existRoll + (sin(gpGlobals->curtime * 3.75f) * DROPSHIP_MAX_LAND_TILT);
SetLocalAngles(angles);
}
DoRotorWash();
if (!bStillOrienting && flAltitude < STRIDER_LANDING_HEIGHT)
{
QAngle angles = GetAbsAngles();
m_hContainer->SetParent(NULL, 0);
m_hContainer->SetOwnerEntity(NULL);
m_hContainer->SetAbsAngles(angles);
m_hContainer->SetAbsVelocity(vec3_origin);
m_hContainer = NULL;
m_flTimeTakeOff = gpGlobals->curtime + 3.5f;
SetLandingState(LANDING_UNLOADING);
return;
}
}
break;
#endif
case LANDING_UNLOADING:
{
// If we've got no specified takeoff time, we're still waiting for troops to exit. Idle.
@ -2817,7 +3015,11 @@ void CNPC_CombineDropship::UpdatePickupNavigation( void )
void CNPC_CombineDropship::UpdateLandTargetNavigation( void )
{
Vector vecPickup = m_hLandTarget->WorldSpaceCenter();
#ifdef MAPBASE
vecPickup.z += ( m_iCrateType == CRATE_STRIDER ) ? 732 : 256;
#else
vecPickup.z += 256;
#endif
SetDesiredPosition( vecPickup );
//NDebugOverlay::Cross3D( GetDesiredPosition(), -Vector(32,32,32), Vector(32,32,32), 0, 255, 255, true, 0.1f );
@ -2850,7 +3052,11 @@ void CNPC_CombineDropship::Hunt( void )
// Face our desired position.
m_vecDesiredFaceDir = desiredDir;
#ifdef MAPBASE
if ( GetLandingState() == LANDING_DESCEND || GetLandingState() == LANDING_LEVEL_OUT || GetLandingState() == LANDING_STRIDER || IsHovering() )
#else
if ( GetLandingState() == LANDING_DESCEND || GetLandingState() == LANDING_LEVEL_OUT || IsHovering() )
#endif
{
if ( m_hLandTarget )
{
@ -3150,6 +3356,19 @@ void CNPC_CombineDropship::MakeTracer( const Vector &vecTracerSrc, const trace_t
}
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Need a way to tell if our strider died
//-----------------------------------------------------------------------------
void CNPC_CombineDropship::DeathNotice( CBaseEntity *pVictim )
{
if ( m_iCrateType == CRATE_STRIDER && GetLandingState() == LANDING_NO )
{
m_OnContainerShotDownBeforeDropoff.Set( 1, m_hContainer, this );
}
}
#endif
AI_BEGIN_CUSTOM_NPC( npc_combinedropship, CNPC_CombineDropship )
DECLARE_ACTIVITY( ACT_DROPSHIP_FLY_IDLE );

View File

@ -187,15 +187,29 @@ public:
{
return m_bDisabled;
}
#ifdef MAPBASE
void GunshipCrashedOnTarget( CBaseHelicopter *pGunship )
{
m_OnCrashed.FireOutput( pGunship, this );
}
void GunshipAcquiredCrashTarget( CBaseHelicopter *pGunship )
{
m_OnBeginCrash.FireOutput( pGunship, this );
}
#else
void GunshipCrashedOnTarget( void )
{
m_OnCrashed.FireOutput( this, this );
}
#endif
private:
bool m_bDisabled;
COutputEvent m_OnCrashed;
#ifdef MAPBASE
COutputEvent m_OnBeginCrash;
#endif
};
LINK_ENTITY_TO_CLASS( info_target_gunshipcrash, CTargetGunshipCrash );
@ -209,6 +223,9 @@ BEGIN_DATADESC( CTargetGunshipCrash )
// Outputs
DEFINE_OUTPUT( m_OnCrashed, "OnCrashed" ),
#ifdef MAPBASE
DEFINE_OUTPUT( m_OnBeginCrash, "OnBeginCrash" ),
#endif
END_DATADESC()
@ -1564,7 +1581,11 @@ void CNPC_CombineGunship::PrescheduleThink( void )
{
BeginDestruct();
m_OnCrashed.FireOutput( this, this );
#ifdef MAPBASE
m_hCrashTarget->GunshipCrashedOnTarget( this );
#else
m_hCrashTarget->GunshipCrashedOnTarget();
#endif
return;
}
}
@ -1976,6 +1997,10 @@ bool CNPC_CombineGunship::FindNearestGunshipCrash( void )
m_flNextGunshipCrashFind = gpGlobals->curtime + 0.5;
m_flEndDestructTime = 0;
#ifdef MAPBASE
m_hCrashTarget->GunshipAcquiredCrashTarget( this );
#endif
if ( g_debug_gunship.GetInt() )
{
NDebugOverlay::Line(GetAbsOrigin(), m_hCrashTarget->GetAbsOrigin(), 0,255,0, true, 0.5);

View File

@ -1327,6 +1327,15 @@ void CNPC_Strider::BuildScheduleTestBits()
//---------------------------------------------------------
int CNPC_Strider::SelectSchedule()
{
#ifdef MAPBASE
if( GetMoveType() == MOVETYPE_NONE )
{
// Dropship just released me.
AddFlag(FL_FLY);
SetMoveType( MOVETYPE_STEP );
return SCHED_STRIDER_FALL_TO_GROUND;
}
#endif
/*
if( GetMoveType() != MOVETYPE_FLY )
{
@ -1511,6 +1520,26 @@ int CNPC_Strider::TranslateSchedule( int scheduleType )
return SCHED_COMBAT_PATROL;
}
}
else
{
#ifdef MAPBASE
extern ConVar ai_enemy_memory_fixes;
// Striders convert TASK_GET_PATH_TO_ENEMY_LOS to TASK_GET_PATH_TO_ENEMY_LKP_LOS, a task which incorrectly
// acts identically to the former. This is detailed in CAI_BaseNPC::StartTask and fixed by ai_enemy_memory_fixes.
//
// However, SCHED_ESTABLISH_LINE_OF_FIRE only stops being used once the NPC has LOS to its target.
// Since the fixed task now uses the enemy's last known position instead of the enemy's actual position,
// this schedule risks getting stuck in a loop.
//
// This code chains back up to SCHED_ESTABLISH_LINE_OF_FIRE_FALLBACK, which is what's supposed to happen when a
// strider is eluded in this way.
if ( ai_enemy_memory_fixes.GetBool() && FVisible( GetEnemyLKP() ) )
{
return TranslateSchedule( SCHED_ESTABLISH_LINE_OF_FIRE_FALLBACK );
}
#endif
}
break;
@ -5818,6 +5847,18 @@ AI_BEGIN_CUSTOM_NPC( npc_strider, CNPC_Strider )
" COND_STRIDER_SHOULD_STAND"
)
#ifdef MAPBASE
DEFINE_SCHEDULE
(
SCHED_STRIDER_FALL_TO_GROUND,
" Tasks "
" TASK_SOUND_WAKE 0"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_STRIDER_DEPLOY"
""
" Interrupts "
)
#else
DEFINE_SCHEDULE
(
SCHED_STRIDER_FALL_TO_GROUND,
@ -5827,7 +5868,7 @@ AI_BEGIN_CUSTOM_NPC( npc_strider, CNPC_Strider )
""
" Interrupts "
)
#endif
AI_END_CUSTOM_NPC()

View File

@ -188,6 +188,7 @@ public:
bool HasPass() { return m_PlayerFreePass.HasPass(); }
bool FVisible( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL );
bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ) { return BaseClass::FVisible( vecTarget, traceMask, ppBlocker ); }
Vector BodyTarget( const Vector &posSrc, bool bNoisy );
bool IsValidEnemy( CBaseEntity *pTarget );

View File

@ -2645,16 +2645,19 @@ Vector CProtoSniper::DesiredBodyTarget( CBaseEntity *pTarget )
{
// By default, aim for the center
Vector vecTarget = pTarget->WorldSpaceCenter();
const Vector vecBulletOrigin = GetBulletOrigin();
#ifdef MAPBASE_VSCRIPT
if (m_ScriptScope.IsInitialized() && g_Hook_GetActualShootPosition.CanRunInScope(m_ScriptScope))
if ( m_ScriptScope.IsInitialized() && g_Hook_GetActualShootPosition.CanRunInScope( m_ScriptScope ) )
{
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = { GetBulletOrigin(), ToHScript( pTarget ) };
if (g_Hook_GetActualShootPosition.Call( m_ScriptScope, &functionReturn, args ))
ScriptVariant_t args[] = { vecBulletOrigin, ToHScript( pTarget ) };
if ( g_Hook_GetActualShootPosition.Call( m_ScriptScope, &functionReturn, args ) )
{
if (functionReturn.m_type == FIELD_VECTOR && functionReturn.m_pVector->LengthSqr() != 0.0f)
if ( functionReturn.m_type == FIELD_VECTOR && functionReturn.m_pVector->LengthSqr() != 0.0f )
{
return *functionReturn.m_pVector;
}
}
}
#endif
@ -2682,12 +2685,12 @@ Vector CProtoSniper::DesiredBodyTarget( CBaseEntity *pTarget )
{
if( flTimeSinceLastMiss > 0.0f && flTimeSinceLastMiss < 4.0f && hl2_episodic.GetBool() )
{
vecTarget = pTarget->BodyTarget( GetBulletOrigin(), false );
vecTarget = pTarget->BodyTarget( vecBulletOrigin, false );
}
else
{
// Shoot zombies in the headcrab
vecTarget = pTarget->HeadTarget( GetBulletOrigin() );
vecTarget = pTarget->HeadTarget( vecBulletOrigin );
}
}
else if( pTarget->Classify() == CLASS_ANTLION )

View File

@ -0,0 +1,985 @@
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: VCD-based sentences.
//
//=============================================================================//
#include "cbase.h"
#include "utlhashtable.h"
#include "engine/IEngineSound.h"
#include "soundchars.h"
#include "choreosentence.h"
#include "mapbase/matchers.h"
#include "ai_speech_new.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//----------------------------------------------------------------------------
#define IsVirtualWord(pszWord) (pszWord[0] == 'V' && pszWord[1] == '_')
#define RemoveVirtualPrefix(pszWord) IsVirtualWord(pszWord) ? pszWord + 2 : pszWord
//----------------------------------------------------------------------------
class CChoreoSentenceSystem : public CAutoGameSystem
{
public:
struct VirtualWord_t;
struct VirtualWordDefinition_t;
struct VirtualWordDefinitionList_t;
struct SentenceContextPrerequisite_t;
//----------------------------------------------------------------------------
CChoreoSentenceSystem() : m_Strings( 256, 0, &StringLessThan ) { }
~CChoreoSentenceSystem() { PurgeSentences(); }
bool Init()
{
// Load the default choreo sentences files
LoadChoreoSentenceManifest( "scripts/choreosentences_manifest.txt" );
return true;
}
void Shutdown()
{
PurgeSentences();
}
//----------------------------------------------------------------------------
void LoadChoreoSentenceManifest( const char *pszFile )
{
KeyValues *pManifest = new KeyValues( "ChoreoSentencesManifest" );
if (pManifest->LoadFromFile( filesystem, pszFile ))
{
FOR_EACH_SUBKEY( pManifest, pSubKey )
{
LoadChoreoSentenceFile( pSubKey->GetString() );
}
}
pManifest->deleteThis();
//m_Strings.Compact( true );
}
void LoadChoreoSentenceFile( const char *pszFile )
{
KeyValues *pManifest = new KeyValues( "ChoreoSentences" );
if (pManifest->LoadFromFile( filesystem, pszFile ))
{
//----------------------------------------------------------------------------
// Context Prerequisites
//----------------------------------------------------------------------------
KeyValues *pSentenceContextPrerequisites = pManifest->FindKey( "SentenceContextPrerequisites" );
FOR_EACH_SUBKEY( pSentenceContextPrerequisites, pSubKey )
{
KeyValues *pCondition = pSubKey->GetFirstSubKey();
if (pCondition)
{
//
// Only add if there is a subkey for condition
//
int i = m_ContextPrerequisites.AddToTail();
m_ContextPrerequisites[i].nConditionType = DeduceCondition( pCondition->GetName(), V_strlen( pCondition->GetName() ) );
m_ContextPrerequisites[i].pszContextName = AllocateString( pSubKey->GetName() );
m_ContextPrerequisites[i].pszCondition = AllocateString( pCondition->GetString() );
}
}
//----------------------------------------------------------------------------
// Virtual Words
//----------------------------------------------------------------------------
KeyValues *pVirtualWords = pManifest->FindKey( "VirtualWords" );
FOR_EACH_SUBKEY( pVirtualWords, pSubKey )
{
//
// Determine if this has nested virtual words or not
//
KeyValues *pMatches = pSubKey->FindKey( "matches" );
if (pMatches)
{
//
// It has nested virtual words
//
int i = m_VirtualWordLists.Insert( RemoveVirtualPrefix( pSubKey->GetName() ) );
m_VirtualWordLists[i].pszCriterion = AllocateString( pSubKey->GetString( "criterion" ) );
bool bFirst = true;
FOR_EACH_SUBKEY( pMatches, pWordList )
{
if (bFirst)
{
// First one is always default
if (LoadVirtualWordDefinitionFromKV( pWordList, m_VirtualWordLists[i].m_DefaultWordDefinition, pSubKey->GetName() ))
bFirst = false;
}
else
{
int i2 = m_VirtualWordLists[i].m_WordDefinitions.Insert( pWordList->GetName() );
if (!LoadVirtualWordDefinitionFromKV( pWordList, m_VirtualWordLists[i].m_WordDefinitions[i2], pSubKey->GetName() ))
m_VirtualWordLists[i].m_WordDefinitions.RemoveAt( i2 );
}
}
}
else
{
//
// It is a virtual word
//
int i = m_VirtualWords.Insert( RemoveVirtualPrefix( pSubKey->GetName() ) );
if (!LoadVirtualWordDefinitionFromKV( pSubKey, m_VirtualWords[i], pSubKey->GetName() ))
m_VirtualWords.RemoveAt( i );
}
}
//----------------------------------------------------------------------------
// Sentences
//----------------------------------------------------------------------------
KeyValues *pSentences = pManifest->FindKey( "Sentences" );
FOR_EACH_SUBKEY( pSentences, pSetKey )
{
FOR_EACH_SUBKEY( pSetKey, pSubKey )
{
if (pSubKey->GetName() && *pSubKey->GetString())
{
int i = m_Sentences.Insert( pSubKey->GetName() );
char szPathName[MAX_PATH];
V_strncpy( szPathName, pSetKey->GetName(), sizeof( szPathName ) );
V_FixSlashes( szPathName );
m_Sentences[i].pszPrefix = AllocateString( szPathName );
//m_Sentences[i].pszPrefix = AllocateString( pSetKey->GetName() );
ParseChoreoSentence( NULL, pSubKey->GetString(), m_Sentences[i] );
m_Sentences[i].pszName = m_Sentences.GetElementName( i );
}
}
}
}
pManifest->deleteThis();
}
bool LoadVirtualWordDefinitionFromKV( KeyValues *pWordList, VirtualWordDefinition_t &wordDefinition, const char *pszWordName )
{
//
// Get the condition for this virtual word
//
KeyValues *pCondition = pWordList->FindKey( "condition" );
if (pCondition)
{
int nStrLen = V_strlen( pCondition->GetString() );
const char *pColon = V_strnchr( pCondition->GetString(), ':', nStrLen );
if (pColon)
{
wordDefinition.pszCondition = AllocateString( pColon + 1 );
wordDefinition.nConditionType = DeduceCondition( pCondition->GetString(), pColon - pCondition->GetString() );
}
else
{
wordDefinition.nConditionType = DeduceCondition( pCondition->GetString(), nStrLen );
}
}
else
{
wordDefinition.nConditionType = 0;
wordDefinition.pszCondition = "";
}
//
// Get the words themselves
//
KeyValues *pWords = pWordList->FindKey( "words" );
if (pWords)
{
FOR_EACH_SUBKEY( pWords, pWord )
{
int i = wordDefinition.m_Words.AddToTail();
V_strncpy( wordDefinition.m_Words[i].szWord, pWord->GetString(), sizeof( wordDefinition.m_Words[i].szWord ) );
}
}
else
{
pWords = pWordList->FindKey( "words_from" );
if (pWords)
{
const char *pszWordsTarget = RemoveVirtualPrefix( pWords->GetString() );
//
// Get from another virtual word
//
FOR_EACH_DICT_FAST( m_VirtualWords, i )
{
if (FStrEq( m_VirtualWords.GetElementName( i ), pszWordsTarget ))
{
wordDefinition.m_Words.AddVectorToTail( m_VirtualWords[i].m_Words );
}
}
}
}
if (wordDefinition.m_Words.Count() <= 0)
{
Warning( "WARNING: No words found on virtual word %s\n", pszWordName );
return false;
}
return true;
}
//----------------------------------------------------------------------------
void PurgeSentences()
{
m_ContextPrerequisites.RemoveAll();
m_VirtualWordLists.RemoveAll();
m_VirtualWords.RemoveAll();
m_Sentences.RemoveAll();
for (unsigned int i = 0; i < m_Strings.Count(); i++)
{
delete m_Strings[i];
}
m_Strings.Purge();
}
//----------------------------------------------------------------------------
void PrintEverything()
{
Msg( "CONTEXT PREREQUISITES\n\n" );
FOR_EACH_VEC( m_ContextPrerequisites, i )
{
Msg( "\t\"%s\"\n\t\tCondition: %i (\"%s\")\n\n", m_ContextPrerequisites[i].pszContextName, m_ContextPrerequisites[i].nConditionType, m_ContextPrerequisites[i].pszCondition );
}
Msg( "VIRTUAL WORDS\n\n" );
FOR_EACH_DICT_FAST( m_VirtualWords, i )
{
char szWords[256] = { 0 };
FOR_EACH_VEC( m_VirtualWords[i].m_Words, nWord )
{
V_strncat( szWords, "\t\t\t\"", sizeof( szWords ) );
V_strncat( szWords, m_VirtualWords[i].m_Words[nWord].szWord, sizeof( szWords ) );
V_strncat( szWords, "\"\n", sizeof( szWords ) );
}
Msg( "\t\"%s\"\n\t\tCondition: %i (\"%s\")\n\t\tWords:\n%s\n\n", m_VirtualWords.GetElementName( i ), m_VirtualWords[i].nConditionType, m_VirtualWords[i].pszCondition, szWords );
}
Msg( "SENTENCES\n\n" );
FOR_EACH_DICT_FAST( m_Sentences, i )
{
char szWords[128] = { 0 };
FOR_EACH_VEC( m_Sentences[i].m_Words, nWord )
{
if (m_Sentences[i].m_Words[nWord].nPitch != 100)
{
V_snprintf( szWords, sizeof( szWords ), "%s(p%i) ", szWords, m_Sentences[i].m_Words[nWord].nPitch );
}
if (m_Sentences[i].m_Words[nWord].nVol != 100)
{
V_snprintf( szWords, sizeof( szWords ), "%s(v%i) ", szWords, m_Sentences[i].m_Words[nWord].nVol );
}
V_strncat( szWords, "\"", sizeof( szWords ) );
V_strncat( szWords, m_Sentences[i].m_Words[nWord].pszWord, sizeof( szWords ) );
V_strncat( szWords, "\" ", sizeof( szWords ) );
}
Msg( "\t\"%s\"\n\t\tPrefix: \"%s\"\n\t\tCaption: \"%s\"\n\t\tWords: %s\n\n", m_Sentences.GetElementName( i ), m_Sentences[i].pszPrefix, m_Sentences[i].pszCaption ? m_Sentences[i].pszCaption : "N/A", szWords);
}
}
void PrintStrings()
{
CUtlVector<const char*> strings( 0, m_Strings.Count() );
for ( UtlHashHandle_t i = m_Strings.FirstInorder(); i != m_Strings.InvalidIndex(); i = m_Strings.NextInorder(i) )
{
strings.AddToTail( m_Strings[i] );
}
struct _Local {
static int __cdecl F(const char * const *a, const char * const *b) { return strcmp(*a, *b); }
};
strings.Sort( _Local::F );
for ( int i = 0; i < strings.Count(); ++i )
{
Msg( " %d (0x%p) : %s\n", i, strings[i], strings[i] );
}
Msg( "\n" );
Msg( "Size: %d items\n", strings.Count() );
}
//----------------------------------------------------------------------------
const ChoreoSentence_t *LookupChoreoSentence( CBaseEntity *pSpeaker, const char *pszSentenceName )
{
FOR_EACH_DICT_FAST( m_Sentences, i )
{
if (FStrEq( m_Sentences.GetElementName( i ), pszSentenceName ))
{
return &m_Sentences[i];
}
}
return NULL;
}
//----------------------------------------------------------------------------
void PrecacheVirtualWord( const char *pszWord, const char *pszPrefix, const char *pszSuffix )
{
pszWord = RemoveVirtualPrefix( pszWord );
FOR_EACH_DICT_FAST( m_VirtualWords, i )
{
if (FStrEq( m_VirtualWords.GetElementName( i ), pszWord ))
{
// Precache all words
FOR_EACH_VEC( m_VirtualWords[i].m_Words, i2 )
{
CBaseEntity::PrecacheScriptSound( UTIL_VarArgs( "%s%s%s", pszPrefix, m_VirtualWords[i].m_Words[i2].szWord, pszSuffix ) );
}
return;
}
}
FOR_EACH_DICT_FAST( m_VirtualWordLists, i )
{
if (FStrEq( m_VirtualWordLists.GetElementName( i ), pszWord ))
{
// Precache all words in default definition
FOR_EACH_VEC( m_VirtualWordLists[i].m_DefaultWordDefinition.m_Words, i2 )
{
CBaseEntity::PrecacheScriptSound( UTIL_VarArgs( "%s%s%s", pszPrefix, m_VirtualWordLists[i].m_DefaultWordDefinition.m_Words[i2].szWord, pszSuffix));
}
// Precache all words in nested definitions
FOR_EACH_DICT( m_VirtualWordLists[i].m_WordDefinitions, i2 )
{
FOR_EACH_VEC( m_VirtualWordLists[i].m_WordDefinitions[i2].m_Words, i3 )
{
CBaseEntity::PrecacheScriptSound( UTIL_VarArgs( "%s%s%s", pszPrefix, m_VirtualWordLists[i].m_WordDefinitions[i2].m_Words[i3].szWord, pszSuffix ) );
}
}
return;
}
}
}
inline const VirtualWord_t &ResolveVirtualWordDefinition( CBaseEntity *pSpeaker, const VirtualWordDefinition_t &wordDefinition )
{
// Resolve this condition
int nIndex = ResolveVirtualCondition( pSpeaker, wordDefinition.nConditionType, wordDefinition.pszCondition, wordDefinition.m_Words.Count() );
Assert( nIndex >= 0 && nIndex < wordDefinition.m_Words.Count() );
return wordDefinition.m_Words[nIndex];
}
const char *ResolveVirtualWord( CBaseEntity *pSpeaker, const char *pszWord )
{
pszWord = RemoveVirtualPrefix( pszWord );
FOR_EACH_DICT_FAST( m_VirtualWords, i )
{
if (FStrEq( m_VirtualWords.GetElementName( i ), pszWord ))
{
return ResolveVirtualWordDefinition( pSpeaker, m_VirtualWords[i] ).szWord;
}
}
FOR_EACH_DICT_FAST( m_VirtualWordLists, i )
{
if (FStrEq( m_VirtualWordLists.GetElementName( i ), pszWord ))
{
AI_CriteriaSet set;
if (pSpeaker)
pSpeaker->ModifyOrAppendCriteria( set );
int nCriterion = set.FindCriterionIndex( m_VirtualWordLists[i].pszCriterion );
if (set.IsValidIndex( nCriterion ))
{
const char *pszValue = set.GetValue( nCriterion );
// Find the set of virtual words that matches the criterion
FOR_EACH_DICT( m_VirtualWordLists[i].m_WordDefinitions, i2 )
{
if (Matcher_Match( m_VirtualWordLists[i].m_WordDefinitions.GetElementName(i2), pszValue ))
{
return ResolveVirtualWordDefinition( pSpeaker, m_VirtualWordLists[i].m_WordDefinitions[i2] ).szWord;
}
}
// Return the default
return ResolveVirtualWordDefinition( pSpeaker, m_VirtualWordLists[i].m_DefaultWordDefinition ).szWord;
}
}
}
CGWarning( 0, CON_GROUP_CHOREO, "Choreo sentence can't find virtual word \"%s\"\n", pszWord );
return "";
}
int ResolveVirtualCondition( CBaseEntity *pSpeaker, int nConditionType, const char *pszCondition, int nWordCount )
{
switch (nConditionType)
{
default:
case ConditionType_None:
// Randomize between each word
return RandomInt( 0, nWordCount - 1 );
break;
case ConditionType_Context:
// Return context as integer
if (pSpeaker)
{
if (pSpeaker->FindContextByName( pszCondition ) == -1)
{
// Check if this is a prerequisite, and if it is, then apply it
FOR_EACH_VEC( m_ContextPrerequisites, i )
{
if (FStrEq( m_ContextPrerequisites[i].pszContextName, pszCondition ))
{
pSpeaker->AddContext( pszCondition, UTIL_VarArgs("%i", ResolveVirtualCondition(pSpeaker, m_ContextPrerequisites[i].nConditionType, m_ContextPrerequisites[i].pszCondition, nWordCount)));
}
}
}
int nContext = clamp( atoi( pSpeaker->GetContextValue( pszCondition ) ), 0, nWordCount - 1 );
return nContext;
}
break;
case ConditionType_VScript:
{
// Return VScript code result
g_pScriptVM->SetValue( "_choreo_val", "" );
HSCRIPT hCreateChainScript = g_pScriptVM->CompileScript( UTIL_VarArgs( "_choreo_val = (%s)", pszCondition ) );
g_pScriptVM->Run( hCreateChainScript, pSpeaker ? pSpeaker->GetOrCreatePrivateScriptScope() : NULL );
ScriptVariant_t scriptVar;
g_pScriptVM->GetValue( "_choreo_val", &scriptVar );
g_pScriptVM->ClearValue( "_choreo_val" );
if (scriptVar.m_int < 0 || scriptVar.m_int >= nWordCount)
{
Warning("Choreo sentence script var %i from '%s' out of range\n", scriptVar.m_int, pszCondition );
scriptVar.m_int = 0;
}
return scriptVar.m_int;
}
break;
case ConditionType_DistTo:
case ConditionType_DirTo:
case ConditionType_GridX:
case ConditionType_GridY:
{
CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, pszCondition, pSpeaker );
if (pSpeaker && pTarget)
{
if (nConditionType == ConditionType_DistTo)
{
// Convert to meters
return (pSpeaker->GetAbsOrigin() - pTarget->GetAbsOrigin()).Length() / 52.49344;
}
else if (nConditionType == ConditionType_DirTo)
{
Vector vecDir = (pSpeaker->GetAbsOrigin() - pTarget->GetAbsOrigin());
return vecDir.y;
}
else if (nConditionType == ConditionType_GridX)
{
return (int)(pTarget->GetAbsOrigin().x / 10.0f) % 20;
}
else if (nConditionType == ConditionType_GridY)
{
return (int)(pTarget->GetAbsOrigin().y / 10.0f) % 20;
}
}
}
break;
}
return 0;
}
//----------------------------------------------------------------------------
enum
{
ConditionType_None, // No condition (random)
ConditionType_Context, // Word should match value from specified context
ConditionType_VScript, // Word should match value returned from specified VScript code
// HL2 sentence parameters
ConditionType_DistTo, // Word should match distance to specified target
ConditionType_DirTo, // Word should match direction to specified target
ConditionType_GridX, // Word should match world X axis grid of specified target
ConditionType_GridY, // Word should match world Y axis grid of specified target
};
int DeduceCondition( const char *pszCondition, int nNumChars )
{
if (V_strncmp( pszCondition, "context", nNumChars ) == 0)
return ConditionType_Context;
else if (V_strncmp( pszCondition, "vscript", nNumChars ) == 0)
return ConditionType_VScript;
else if (V_strncmp( pszCondition, "dist_to", nNumChars ) == 0)
return ConditionType_DistTo;
else if (V_strncmp( pszCondition, "dir_to", nNumChars ) == 0)
return ConditionType_DirTo;
else if (V_strncmp( pszCondition, "gridx", nNumChars ) == 0)
return ConditionType_GridX;
else if (V_strncmp( pszCondition, "gridy", nNumChars ) == 0)
return ConditionType_GridY;
return ConditionType_None;
}
struct VirtualWord_t
{
char szWord[MAX_CHOREO_SENTENCE_VIRTUAL_WORD_LEN];
};
struct VirtualWordDefinition_t
{
VirtualWordDefinition_t() {}
VirtualWordDefinition_t( const VirtualWordDefinition_t &src )
{
pszCondition = src.pszCondition;
nConditionType = src.nConditionType;
m_Words.RemoveAll();
m_Words.AddVectorToTail( src.m_Words );
}
const char *pszCondition;
int nConditionType;
CUtlVector< VirtualWord_t > m_Words;
};
struct VirtualWordDefinitionList_t
{
VirtualWordDefinitionList_t() {}
VirtualWordDefinitionList_t( const VirtualWordDefinitionList_t &src )
{
pszCriterion = src.pszCriterion;
m_DefaultWordDefinition = src.m_DefaultWordDefinition;
m_WordDefinitions.RemoveAll();
m_WordDefinitions.EnsureCapacity( src.m_WordDefinitions.Count() );
FOR_EACH_DICT_FAST( src.m_WordDefinitions, i )
m_WordDefinitions.Insert( src.m_WordDefinitions.GetElementName( i ), src.m_WordDefinitions[i] );
}
const char *pszCriterion;
VirtualWordDefinition_t m_DefaultWordDefinition;
CUtlDict< VirtualWordDefinition_t, int > m_WordDefinitions;
};
struct SentenceContextPrerequisite_t
{
SentenceContextPrerequisite_t() {}
SentenceContextPrerequisite_t( const SentenceContextPrerequisite_t &src )
{
pszContextName = src.pszContextName;
pszCondition = src.pszCondition;
nConditionType = src.nConditionType;
}
const char *pszContextName;
const char *pszCondition;
int nConditionType;
};
//----------------------------------------------------------------------------
const char *FindString( const char *string )
{
unsigned short i = m_Strings.Find( string );
return i == m_Strings.InvalidIndex() ? NULL : m_Strings[i];
}
const char *AllocateString( const char *string )
{
int i = m_Strings.Find( string );
if ( i != m_Strings.InvalidIndex() )
{
return m_Strings[i];
}
int len = Q_strlen( string );
char *out = new char[ len + 1 ];
Q_memcpy( out, string, len );
out[ len ] = 0;
return m_Strings[ m_Strings.Insert( out ) ];
}
//----------------------------------------------------------------------------
const CUtlDict< ChoreoSentence_t, int > &GetSentences() { return m_Sentences; }
private:
// Context prerequisites to be applied if not already applied
CUtlVector< SentenceContextPrerequisite_t > m_ContextPrerequisites;
// Embedded lists of virtual words based on a criterion
CUtlDict< VirtualWordDefinitionList_t, int > m_VirtualWordLists;
// Lists of virtual words (does not include nested ones)
CUtlDict< VirtualWordDefinition_t, int > m_VirtualWords;
// Sentences themselves
CUtlDict< ChoreoSentence_t, int > m_Sentences;
// Dedicated strings, copied from game string pool
CUtlRBTree<const char *> m_Strings;
};
static CChoreoSentenceSystem g_ChoreoSentenceSystem;
//-----------------------------------------------------------------------------
CON_COMMAND( choreosentence_reload, "Reloads choreo sentences" )
{
//int nStringCount = g_ChoreoSentenceSystem.GetStringCount();
g_ChoreoSentenceSystem.PurgeSentences();
//g_ChoreoSentenceSystem.ReserveStrings( nStringCount );
g_ChoreoSentenceSystem.LoadChoreoSentenceManifest( "scripts/choreosentences_manifest.txt" );
}
CON_COMMAND( choreosentence_dump, "Prints all choreo sentence stuff" )
{
g_ChoreoSentenceSystem.PrintEverything();
}
CON_COMMAND( choreosentence_dump_strings, "Prints all strings allocated by choreo sentences" )
{
g_ChoreoSentenceSystem.PrintStrings();
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
static int AutoCompleteChoreoSentences(const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0)
{
FOR_EACH_DICT_FAST( g_ChoreoSentenceSystem.GetSentences(), i )
{
CUtlString sym = g_ChoreoSentenceSystem.GetSentences().GetElementName( i );
if (Q_strnicmp( sym, substring, checklen ) != 0)
continue;
int idx = symbols.Find( sym );
if (idx == symbols.InvalidIndex())
{
symbols.Insert( sym );
}
// Too many
if (symbols.Count() >= COMMAND_COMPLETION_MAXITEMS)
break;
}
// Now fill in the results
for (int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder(i))
{
const char *name = symbols[i].String();
char buf[512];
Q_snprintf( buf, sizeof( buf ), "%s %s", cmdname, name );
Q_strlower( buf );
CUtlString command;
command = buf;
commands.AddToTail(command);
}
return symbols.Count();
}
class CChoreoSentenceAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
{
public:
virtual void CommandCallback( const CCommand &command )
{
if (command.ArgC() != 2)
{
Msg( "Format: choreosentence_play <sentence name>\n" );
return;
}
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
if (pPlayer)
{
const ChoreoSentence_t *pSentence = LookupChoreoSentence( pPlayer, command.Arg( 1 ) );
if (pSentence)
PrecacheChoreoSentence( *pSentence );
pPlayer->PlayChoreoSentenceScene( command.Arg( 1 ) );
}
}
virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands )
{
if ( !g_pGameRules )
{
return 0;
}
const char *cmdname = "choreosentence_play";
char *substring = (char *)partial;
if ( Q_strstr( partial, cmdname ) )
{
substring = (char *)partial + strlen( cmdname ) + 1;
}
int checklen = Q_strlen( substring );
extern bool UtlStringLessFunc( const CUtlString & lhs, const CUtlString & rhs );
CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
return AutoCompleteChoreoSentences(cmdname, commands, symbols, substring, checklen);
}
};
static CChoreoSentenceAutoCompletionFunctor g_ChoreoSentenceAutoComplete;
static ConCommand choreosentence_play("choreosentence_play", &g_ChoreoSentenceAutoComplete, "Plays the specified choreo sentence on the player", FCVAR_CHEAT, &g_ChoreoSentenceAutoComplete );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *ChoreoSentence_t::GetWordString( CBaseEntity *pSpeaker, int i ) const
{
const char *pszExtension = "";
if (V_strrchr( pszPrefix, CORRECT_PATH_SEPARATOR ))
{
// Use waves if our prefix is a path
pszExtension = ".wav";
}
// TODO: Something more elaborate than UTIL_VarArgs?
if (m_Words[i].bVirtual)
{
const char *pszVirtualWord = g_ChoreoSentenceSystem.ResolveVirtualWord( pSpeaker, m_Words[i].pszWord );
return UTIL_VarArgs( "%s%s%s", pszPrefix, pszVirtualWord, pszExtension );
}
return UTIL_VarArgs( "%s%s%s", pszPrefix, m_Words[i].pszWord, pszExtension );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void LoadChoreoSentenceFile( const char *pszFile )
{
g_ChoreoSentenceSystem.LoadChoreoSentenceFile( pszFile );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const ChoreoSentence_t *LookupChoreoSentence( CBaseEntity *pSpeaker, const char *pszSentenceName )
{
return g_ChoreoSentenceSystem.LookupChoreoSentence( pSpeaker, pszSentenceName );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void PrecacheChoreoSentence( const ChoreoSentence_t &sentence )
{
FOR_EACH_VEC( sentence.m_Words, i )
{
if (sentence.m_Words[i].bVirtual)
{
// Precache all virtual words
const char *pszExtension = "";
if (V_strrchr( sentence.pszPrefix, CORRECT_PATH_SEPARATOR ))
pszExtension = ".wav";
g_ChoreoSentenceSystem.PrecacheVirtualWord( sentence.m_Words[i].pszWord, sentence.pszPrefix, pszExtension );
}
else
{
CBaseEntity::PrecacheScriptSound( sentence.GetWordString( NULL, i ) );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool ParseChoreoSentence( CBaseEntity *pSpeaker, const char *pszRawSentence, ChoreoSentence_t &sentence )
{
if (pszRawSentence == NULL || *pszRawSentence == NULL)
return false;
char szSentence[256];
// First, try getting the prefix
const char *pColon = V_strnchr( pszRawSentence, ':', V_strlen( pszRawSentence ) );
if (pColon)
{
// Sentence is everything after colon
Q_strncpy( szSentence, pColon + 1, sizeof( szSentence ) );
// Copy everything before colon for prefix
char szPathName[MAX_PATH];
V_strncpy( szPathName, pszRawSentence, pColon - pszRawSentence + 1 );
V_FixSlashes( szPathName );
sentence.pszPrefix = g_ChoreoSentenceSystem.AllocateString( szPathName );
}
else
{
// It's all one sentence
Q_strncpy( szSentence, pszRawSentence, sizeof( szSentence ) );
}
// Now get any parameters
const char *pSemiColon = V_strnchr( szSentence, ';', sizeof( szSentence ) );
if (pSemiColon)
{
// Caption is whatever's after the semicolon
const char *pszCaption = pSemiColon+1;
if (pszCaption[0] == ' ')
pszCaption++;
sentence.pszCaption = g_ChoreoSentenceSystem.AllocateString( pszCaption );
// Replace semicolon with null terminator
szSentence[pSemiColon - szSentence] = '\0';
}
// Next, split up the sentence itself
bool success = ParseChoreoSentenceContents( pSpeaker, szSentence, sentence );
return success;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool ParseChoreoSentenceContents( CBaseEntity *pSpeaker, char *pszSentence, ChoreoSentence_t &sentence )
{
int nCurVol = 100, nCurPitch = 100;
char *pszToken = strtok( pszSentence, " " );
for (; pszToken != NULL; pszToken = strtok( NULL, " " ))
{
if (!pszToken || !*pszToken)
continue;
// Check if this is a command number
if (pszToken[0] == '(')
{
pszToken++;
// Remove closing parentheses
//int end = V_strlen( pszToken )-1;
//if (pszToken[end] == ')')
// pszToken[end] = '\0';
int nNum = atoi( pszToken + 1 );
if (nNum > 0)
{
switch (pszToken[0])
{
// TODO: Recognize e, t, etc.?
case 'v': nCurVol = nNum; break;
case 'p': nCurPitch = nNum; break;
}
continue;
}
else
{
Msg( "Zero command number in %s\n", pszSentence );
}
}
int nWord = sentence.m_Words.AddToTail();
sentence.m_Words[nWord].nVol = nCurVol;
sentence.m_Words[nWord].nPitch = nCurPitch;
// Check if this is virtual
if (IsVirtualWord( pszToken ))
sentence.m_Words[nWord].bVirtual = true;
// Check for periods or commas
int end = V_strlen( pszToken )-1;
if (pszToken[end] == ',')
{
int nWord2 = sentence.m_Words.AddToTail();
sentence.m_Words[nWord2].pszWord = g_ChoreoSentenceSystem.AllocateString( "_comma" );
sentence.m_Words[nWord2].nVol = nCurVol;
sentence.m_Words[nWord2].nPitch = nCurPitch;
pszToken[end] = '\0';
}
else if (pszToken[end] == '.')
{
int nWord2 = sentence.m_Words.AddToTail();
sentence.m_Words[nWord2].pszWord = g_ChoreoSentenceSystem.AllocateString( "_period" );
sentence.m_Words[nWord2].nVol = nCurVol;
sentence.m_Words[nWord2].nPitch = nCurPitch;
pszToken[end] = '\0';
}
sentence.m_Words[nWord].pszWord = g_ChoreoSentenceSystem.AllocateString( pszToken );
}
return sentence.m_Words.Count() > 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float GetChoreoSentenceDuration( CBaseFlex *pSpeaker, const ChoreoSentence_t &sentence )
{
const char *actormodel = (pSpeaker ? STRING( pSpeaker->GetModelName() ) : NULL);
float flLength = 0.0f;
FOR_EACH_VEC( sentence.m_Words, i )
{
//float duration = CBaseEntity::GetSoundDuration( sentence.GetWordString(pSpeaker, i), actormodel );
float duration;
const char *pszWord = sentence.GetWordString( pSpeaker, i );
// For now, call the engine functions manually instead of using CBaseEntity::GetSoundDuration so that we could get around the WaveTrace warning
if ( V_stristr( pszWord, ".wav" ) || V_stristr( pszWord, ".mp3" ) )
{
duration = enginesound->GetSoundDuration( PSkipSoundChars( pszWord ) );
}
else
{
extern ISoundEmitterSystemBase *soundemitterbase;
duration = enginesound->GetSoundDuration( PSkipSoundChars( soundemitterbase->GetWavFileForSound( pszWord, actormodel ) ) );
}
flLength += duration;
}
return flLength;
}

View File

@ -0,0 +1,67 @@
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: VCD-based sentences.
//
//=============================================================================//
#ifndef CHOREOSENTENCE_H
#define CHOREOSENTENCE_H
#include "cbase.h"
#define MAX_CHOREO_SENTENCE_PREFIX_LEN 64
#define MAX_CHOREO_SENTENCE_WORD_LEN 32
#define MAX_CHOREO_SENTENCE_CAPTION_LEN 64
#define MAX_CHOREO_SENTENCE_VIRTUAL_WORD_LEN 32
struct ChoreoSentenceWord_t
{
ChoreoSentenceWord_t() {}
ChoreoSentenceWord_t( const ChoreoSentenceWord_t &src )
{
pszWord = src.pszWord;
nPitch = src.nPitch; nVol = src.nVol;
bVirtual = src.bVirtual;
}
const char *pszWord;
int nPitch, nVol = 100;
bool bVirtual = false;
};
struct ChoreoSentence_t
{
ChoreoSentence_t() {}
ChoreoSentence_t( const ChoreoSentence_t &src )
{
pszName = src.pszName;
pszPrefix = src.pszPrefix;
pszCaption = src.pszCaption;
m_Words.RemoveAll();
m_Words.AddVectorToTail( src.m_Words );
}
const char *GetWordString( CBaseEntity *pSpeaker, int i ) const;
CUtlVector< ChoreoSentenceWord_t > m_Words;
const char *pszName;
const char *pszPrefix;
const char *pszCaption;
};
//----------------------------------------------------------------------------
extern void LoadChoreoSentenceFile( const char *pszFile );
extern const ChoreoSentence_t *LookupChoreoSentence( CBaseEntity *pSpeaker, const char *pszSentenceName );
extern void PrecacheChoreoSentence( const ChoreoSentence_t &sentence );
bool ParseChoreoSentence( CBaseEntity *pSpeaker, const char *pszRawSentence, ChoreoSentence_t &sentence );
bool ParseChoreoSentenceContents( CBaseEntity *pSpeaker, char *pszSentence, ChoreoSentence_t &sentence );
extern float GetChoreoSentenceDuration( CBaseFlex *pSpeaker, const ChoreoSentence_t &sentence );
#endif // CHOREOSENTENCE_H

View File

@ -38,8 +38,8 @@ public:
void InputReload( inputdata_t &inputdata );
#ifdef MAPBASE_VSCRIPT
HSCRIPT ScriptGetKeyValues( void );
HSCRIPT ScriptGetKeyValueBlock( void );
HSCRIPT_RC ScriptGetKeyValues( void );
HSCRIPT_RC ScriptGetKeyValueBlock( void );
void ScriptSetKeyValues( HSCRIPT hKV );
void ScriptSetKeyValueBlock( HSCRIPT hKV );
@ -275,7 +275,7 @@ void CLogicExternalData::InputReload( inputdata_t &inputdata )
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CLogicExternalData::ScriptGetKeyValues( void )
HSCRIPT_RC CLogicExternalData::ScriptGetKeyValues( void )
{
if (m_bReloadBeforeEachAction)
LoadFile();
@ -283,8 +283,9 @@ HSCRIPT CLogicExternalData::ScriptGetKeyValues( void )
HSCRIPT hScript = NULL;
if (m_pRoot)
{
// Does this need to be destructed or freed? m_pScriptModelKeyValues apparently doesn't.
hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, m_pRoot, false );
KeyValues *pCopy = new KeyValues( NULL );
*pCopy = *m_pRoot;
hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pCopy );
}
return hScript;
@ -292,7 +293,7 @@ HSCRIPT CLogicExternalData::ScriptGetKeyValues( void )
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CLogicExternalData::ScriptGetKeyValueBlock( void )
HSCRIPT_RC CLogicExternalData::ScriptGetKeyValueBlock( void )
{
if (m_bReloadBeforeEachAction)
LoadFile();
@ -300,8 +301,9 @@ HSCRIPT CLogicExternalData::ScriptGetKeyValueBlock( void )
HSCRIPT hScript = NULL;
if (m_pBlock)
{
// Does this need to be destructed or freed? m_pScriptModelKeyValues apparently doesn't.
hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, m_pBlock, false );
KeyValues *pCopy = new KeyValues( NULL );
*pCopy = *m_pBlock;
hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pCopy );
}
return hScript;
@ -321,7 +323,8 @@ void CLogicExternalData::ScriptSetKeyValues( HSCRIPT hKV )
KeyValues *pKV = scriptmanager->GetKeyValuesFromScriptKV( g_pScriptVM, hKV );
if (pKV)
{
m_pRoot = pKV;
m_pRoot = new KeyValues( NULL );
*m_pRoot = *pKV;
}
}
@ -336,7 +339,8 @@ void CLogicExternalData::ScriptSetKeyValueBlock( HSCRIPT hKV )
KeyValues *pKV = scriptmanager->GetKeyValuesFromScriptKV( g_pScriptVM, hKV );
if (pKV)
{
m_pBlock = pKV;
m_pBlock = new KeyValues( NULL );
*m_pBlock = *pKV;
}
}

View File

@ -93,6 +93,7 @@ public:
virtual Activity GetPrimaryAttackActivity(void) { return m_CustomData.m_bHitUsesMissAnim ? ACT_VM_MISSCENTER : BaseClass::GetPrimaryAttackActivity(); }
const char* GetWeaponScriptName() { return m_iszWeaponScriptName.Get(); }
const char* GetName( void ) const { return STRING( m_iClassname ); }
virtual int GetDamageType() { return g_nDamageClassTypeBits[m_CustomData.m_nDamageClass]; }
virtual void InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript);
@ -381,6 +382,7 @@ public:
CHLCustomWeaponGun();
virtual void InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript);
const char* GetWeaponScriptName() { return m_iszWeaponScriptName.Get(); }
const char* GetName( void ) const { return STRING( m_iClassname ); }
// Weapon behaviour
virtual void ItemPostFrame(void); // called each frame by the player PostThink

View File

@ -7964,7 +7964,7 @@ Activity CBasePlayer::Weapon_TranslateActivity( Activity baseAct, bool *pRequire
{
Activity weaponTranslation = BaseClass::Weapon_TranslateActivity( baseAct, pRequired );
if ( GetActiveWeapon() && GetActiveWeapon()->IsEffectActive(EF_NODRAW) && baseAct != ACT_ARM )
if ( GetActiveWeapon() && !GetActiveWeapon()->IsWeaponVisible() && baseAct != ACT_ARM )
{
// Our weapon is holstered. Use the base activity.
return baseAct;
@ -8871,6 +8871,7 @@ void SendProxy_ShiftPlayerSpawnflags( const SendProp *pProp, const void *pStruct
// See baseplayer_shared.h for more details.
SendPropInt ( SENDINFO( m_spawnflags ), 3, SPROP_UNSIGNED, SendProxy_ShiftPlayerSpawnflags ),
SendPropBool ( SENDINFO( m_bDrawPlayerLegs ) ),
SendPropBool ( SENDINFO( m_bDrawPlayerModelExternally ) ),
SendPropBool ( SENDINFO( m_bInTriggerFall ) ),
#endif

View File

@ -1179,6 +1179,9 @@ public:
int m_nNumCrateHudHints;
#ifdef MAPBASE
bool GetDrawPlayerLegs( void ) { return m_bDrawPlayerLegs; }
void SetDrawPlayerLegs( bool bToggle ) { m_bDrawPlayerLegs.Set( bToggle ); }
bool GetDrawPlayerModelExternally( void ) { return m_bDrawPlayerModelExternally; }
void SetDrawPlayerModelExternally( bool bToggle ) { m_bDrawPlayerModelExternally.Set( bToggle ); }
#endif
@ -1222,6 +1225,7 @@ private:
char m_szNetname[MAX_PLAYER_NAME_LENGTH];
#ifdef MAPBASE
CNetworkVar( bool, m_bDrawPlayerLegs );
CNetworkVar( bool, m_bDrawPlayerModelExternally );
#endif

View File

@ -393,7 +393,7 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper
if ( weapon )
{
VPROF( "player->SelectItem()" );
player->SelectItem( weapon->GetClassname(), ucmd->weaponsubtype );
player->SelectItem( weapon->GetName(), ucmd->weaponsubtype );
}
}

View File

@ -41,6 +41,10 @@
#include "npc_alyx_episodic.h"
#endif // HL2_EPISODIC
#ifdef MAPBASE
#include "mapbase/choreosentence.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -57,6 +61,10 @@ class CBaseFlex;
static ConVar scene_forcecombined( "scene_forcecombined", "0", 0, "When playing back, force use of combined .wav files even in english." );
static ConVar scene_maxcaptionradius( "scene_maxcaptionradius", "1200", 0, "Only show closed captions if recipient is within this many units of speaking actor (0==disabled)." );
#ifdef MAPBASE
static ConVar scene_resume_use_last_speaking( "scene_resume_use_last_speaking", "1", 0, "Uses the last actor who spoke for resume scene calls, rather than the first actor of the scene" );
#endif
// Assume sound system is 100 msec lagged (only used if we can't find snd_mixahead cvar!)
#define SOUND_SYSTEM_LATENCY_DEFAULT ( 0.1f )
@ -412,6 +420,10 @@ public:
// If this scene is waiting on an actor, give up and quit trying.
void InputStopWaitingForActor( inputdata_t &inputdata );
#ifdef MAPBASE
void InputPauseAtLastInterrupt( inputdata_t &inputdata );
#endif
virtual void StartPlayback( void );
virtual void PausePlayback( void );
virtual void ResumePlayback( void );
@ -482,6 +494,9 @@ public:
bool InvolvesActor( CBaseEntity *pActor ); // NOTE: returns false if scene hasn't loaded yet
void GenerateSoundScene( CBaseFlex *pActor, const char *soundname );
#ifdef MAPBASE
void GenerateChoreoSentenceScene( CBaseFlex *pActor, const char *pszSentenceName );
#endif
virtual float GetPostSpeakDelay() { return 1.0; }
@ -489,6 +504,7 @@ public:
bool HasFlexAnimation( void );
#ifdef MAPBASE
bool IsPlayingSpeech( void );
CBaseFlex *GetLastSpeakingActor( void );
#endif
void SetCurrentTime( float t, bool forceClientSync );
@ -594,6 +610,9 @@ private:
void PrecacheScene( CChoreoScene *scene );
CChoreoScene *GenerateSceneForSound( CBaseFlex *pFlexActor, const char *soundname );
#ifdef MAPBASE
CChoreoScene *GenerateSceneForSentenceName( CBaseFlex *pFlexActor, const char *pszSentenceName );
#endif
bool CheckActors();
@ -643,6 +662,9 @@ private:
bool m_bGenerated;
string_t m_iszSoundName;
CHandle< CBaseFlex > m_hActor;
#ifdef MAPBASE
bool m_bChoreoSentence;
#endif
EHANDLE m_hActivator;
@ -736,6 +758,9 @@ BEGIN_DATADESC( CSceneEntity )
DEFINE_FIELD( m_bGenerated, FIELD_BOOLEAN ),
DEFINE_FIELD( m_iszSoundName, FIELD_STRING ),
DEFINE_FIELD( m_hActor, FIELD_EHANDLE ),
#ifdef MAPBASE
DEFINE_FIELD( m_bChoreoSentence, FIELD_BOOLEAN ),
#endif
DEFINE_FIELD( m_hActivator, FIELD_EHANDLE ),
// DEFINE_FIELD( m_bSceneMissing, FIELD_BOOLEAN ),
@ -757,8 +782,9 @@ BEGIN_DATADESC( CSceneEntity )
DEFINE_INPUTFUNC( FIELD_STRING, "InterjectResponse", InputInterjectResponse ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopWaitingForActor", InputStopWaitingForActor ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "Trigger", InputTriggerEvent ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_VOID, "PauseAtLastInterrupt", InputPauseAtLastInterrupt ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget1", InputSetTarget1 ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget2", InputSetTarget2 ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget3", InputSetTarget3 ),
@ -953,6 +979,146 @@ CChoreoScene *CSceneEntity::GenerateSceneForSound( CBaseFlex *pFlexActor, const
return scene;
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *pszSentenceName -
// Output : CChoreoScene
//-----------------------------------------------------------------------------
CChoreoScene *CSceneEntity::GenerateSceneForSentenceName( CBaseFlex *pFlexActor, const char *pszSentenceName )
{
const ChoreoSentence_t *pSentence = LookupChoreoSentence( pFlexActor, pszSentenceName );
if ( !pSentence )
{
Warning( "CSceneEntity::GenerateSceneForSentenceName: Couldn't find sentence '%s'\n", pszSentenceName );
return NULL;
}
// TODO: Raw sentence support?
// ChoreoSentence_t sentence;
// if ( !ParseChoreoSentence( pFlexActor, pszSentence, sentence ) )
// {
// Warning( "CSceneEntity::GenerateSceneForSentence: Couldn't parse sentence from '%s'\n", pszSentence );
// return NULL;
// }
CChoreoScene *scene = new CChoreoScene( this );
if ( !scene )
{
Warning( "CSceneEntity::GenerateSceneForSentenceName: Failed to allocated new scene!!!\n" );
}
else
{
scene->SetPrintFunc( LocalScene_Printf );
CChoreoActor *actor = scene->AllocActor();
CChoreoChannel *channel = scene->AllocChannel();
Assert( actor );
Assert( channel );
if ( !actor || !channel )
{
Warning( "CSceneEntity::GenerateSceneForSentenceName: Alloc of actor or channel failed!!!\n" );
delete scene;
return NULL;
}
// Set us up the actorz
actor->SetName( "!self" ); // Could be pFlexActor->GetName()?
actor->SetActive( true );
// Set us up the channelz
channel->SetName( STRING( m_iszSceneFile ) );
channel->SetActor( actor );
// Add to actor
actor->AddChannel( channel );
// Set us up the eventz
const char *actormodel = (pFlexActor ? STRING( pFlexActor->GetModelName() ) : NULL);
float flCurTime = 0.0f;
FOR_EACH_VEC( pSentence->m_Words, i )
{
const char *pszWord = pSentence->GetWordString( pFlexActor, i );
float duration = CBaseEntity::GetSoundDuration( pszWord, actormodel );
if (duration <= 0.0f)
{
Warning( "CSceneEntity::GenerateSceneForSentenceName: Couldn't determine duration of %s\n", pszWord );
}
CChoreoEvent *event = scene->AllocEvent();
Assert( event );
if ( !event )
{
Warning( "CSceneEntity::GenerateSceneForSentenceName: Alloc of event failed!!!\n" );
delete scene;
return NULL;
}
if (pSentence->pszCaption)
{
// First word gets the caption, others fall back to it
if (i == 0)
{
event->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
event->SetCloseCaptionToken( pSentence->pszCaption );
}
else
{
event->SetCloseCaptionType( CChoreoEvent::CC_SLAVE );
}
}
//else if (pSentence->pszName)
//{
// // TODO: Caption from name?
//}
if (pSentence->m_Words[i].nVol != 100)
{
event->SetYaw( pSentence->m_Words[i].nVol );
}
if (pSentence->m_Words[i].nPitch != 100)
{
duration *= (100.0f / ((float)pSentence->m_Words[i].nPitch));
event->SetPitch( pSentence->m_Words[i].nPitch );
}
// HACKHACK: Need to be spaced away from repeated sound to avoid changing the previous sound's pitch instead
if (i+1 < pSentence->m_Words.Count() && pSentence->m_Words[i+1].pszWord == pSentence->m_Words[i].pszWord
&& pSentence->m_Words[i + 1].nPitch != 100)
duration += 0.1f;
event->SetType( CChoreoEvent::SPEAK );
event->SetName( pszWord );
event->SetParameters( pszWord );
event->SetStartTime( flCurTime );
event->SetUsingRelativeTag( false );
event->SetEndTime( flCurTime + duration );
event->SnapTimes();
//Msg( "%i %s: %f -> %f (%f)\n", i, pszWord, flCurTime, flCurTime + duration, duration );
// Add to channel
channel->AddEvent( event );
// Point back to our owners
event->SetChannel( channel );
event->SetActor( actor );
flCurTime += duration;
}
}
return scene;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -960,6 +1126,13 @@ void CSceneEntity::Activate()
{
if ( m_bGenerated && !m_pScene )
{
#ifdef MAPBASE
if (m_bChoreoSentence)
{
m_pScene = GenerateSceneForSentenceName( m_hActor, STRING( m_iszSoundName ) );
}
else
#endif
m_pScene = GenerateSceneForSound( m_hActor, STRING( m_iszSoundName ) );
}
@ -1138,6 +1311,22 @@ void CSceneEntity::GenerateSoundScene( CBaseFlex *pActor, const char *soundname
m_hActor = pActor;
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pActor -
// *pszSentenceName -
//-----------------------------------------------------------------------------
void CSceneEntity::GenerateChoreoSentenceScene( CBaseFlex *pActor, const char *pszSentenceName )
{
m_bGenerated = true;
m_iszSoundName = MAKE_STRING( pszSentenceName );
m_hActor = pActor;
m_bChoreoSentence = true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
@ -1185,6 +1374,33 @@ bool CSceneEntity::IsPlayingSpeech( void )
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseFlex *CSceneEntity::GetLastSpeakingActor( void )
{
if ( m_pScene )
{
CChoreoActor *pLastActor = NULL;
float flTime = m_pScene->GetTime();
for ( int i = 0; i < m_pScene->GetNumEvents(); i++ )
{
CChoreoEvent *e = m_pScene->GetEvent( i );
if ( e->GetType() == CChoreoEvent::SPEAK )
{
if ( flTime >= e->GetStartTime() )
pLastActor = e->GetActor();
}
}
if (pLastActor)
return FindNamedActor( pLastActor );
}
// Fall back to the first actor
return FindNamedActor( 0 );
}
#endif
@ -1930,6 +2146,26 @@ void CSceneEntity::DispatchStartSpeak( CChoreoScene *scene, CBaseFlex *actor, CC
// Warning( "Speak %s\n", soundname );
#ifdef MAPBASE
if ( m_fPitch != 1.0f || event->GetPitch() != 0 )
{
if ( es.m_nPitch && es.m_nPitch != 100 )
es.m_nPitch = static_cast<float>( es.m_nPitch ) * m_fPitch;
else
{
float flPitch = (event->GetPitch() != 0 ? event->GetPitch() : 100.0f);
es.m_nPitch = flPitch * m_fPitch;
}
es.m_nFlags |= SND_CHANGE_PITCH;
}
if ( event->GetYaw() != 0 )
{
es.m_flVolume = (((float)event->GetYaw()) / 100.0f);
es.m_nFlags |= SND_CHANGE_VOL;
}
#else
if ( m_fPitch != 1.0f )
{
if ( es.m_nPitch )
@ -1939,6 +2175,7 @@ void CSceneEntity::DispatchStartSpeak( CChoreoScene *scene, CBaseFlex *actor, CC
es.m_nFlags |= SND_CHANGE_PITCH;
}
#endif
EmitSound( filter2, actor->entindex(), es );
actor->AddSceneEvent( scene, event );
@ -2468,6 +2705,39 @@ void CSceneEntity::InputInterjectResponse( inputdata_t &inputdata )
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSceneEntity::InputPauseAtLastInterrupt( inputdata_t &inputdata )
{
PausePlayback();
m_bPausedViaInput = true;
if ( m_pScene )
{
float flLastInterrupt = 0.0f;
float flTime = m_pScene->GetTime();
for ( int i = 0; i < m_pScene->GetNumEvents(); i++ )
{
CChoreoEvent *e = m_pScene->GetEvent( i );
if ( e->GetType() == CChoreoEvent::INTERRUPT )
{
if ( flTime > e->GetEndTime() && e->GetEndTime() > flLastInterrupt )
{
// Set the scene's time to the last interrupt point's end time
flLastInterrupt = e->GetEndTime();
break;
}
}
}
if (flLastInterrupt != 0.0f)
{
// Set the scene's time to the last interrupt point's end time
m_pScene->SetTime( flLastInterrupt );
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSceneEntity::SetTarget( int nTarget, string_t pTargetName, CBaseEntity *pActivator, CBaseEntity *pCaller )
@ -3096,13 +3366,22 @@ void CSceneEntity::QueueResumePlayback( void )
// If it has ".vcd" somewhere in the string, try using it as a scene file first
if ( Q_stristr( STRING(m_iszResumeSceneFile), ".vcd" ) )
{
bStartedScene = InstancedScriptedScene( NULL, STRING(m_iszResumeSceneFile), &m_hWaitingForThisResumeScene, 0, false ) != 0;
#ifdef MAPBASE
CBaseFlex *pActor = scene_resume_use_last_speaking.GetBool() ? GetLastSpeakingActor() : FindNamedActor( 0 );
#else
CBaseFlex *pActor = NULL;
#endif
bStartedScene = InstancedScriptedScene( pActor, STRING(m_iszResumeSceneFile), &m_hWaitingForThisResumeScene, 0, false ) != 0;
}
// HACKHACK: For now, get the first target, and see if we can find a response for him
if ( !bStartedScene )
{
#ifdef MAPBASE
CBaseFlex *pActor = scene_resume_use_last_speaking.GetBool() ? GetLastSpeakingActor() : FindNamedActor( 0 );
#else
CBaseFlex *pActor = FindNamedActor( 0 );
#endif
if ( pActor )
{
CAI_BaseActor *pBaseActor = dynamic_cast<CAI_BaseActor*>(pActor);
@ -3115,7 +3394,7 @@ void CSceneEntity::QueueResumePlayback( void )
if ( result )
{
const char* szResponse = response.GetResponsePtr();
bStartedScene = InstancedScriptedScene( NULL, szResponse, &m_hWaitingForThisResumeScene, 0, false ) != 0;
bStartedScene = InstancedScriptedScene( pActor, szResponse, &m_hWaitingForThisResumeScene, 0, false ) != 0;
}
#else
AI_Response *result = pBaseActor->SpeakFindResponse( STRING(m_iszResumeSceneFile), NULL );
@ -5667,6 +5946,62 @@ void CInstancedSceneEntity::OnLoaded()
#endif
}
#ifdef MAPBASE
float InstancedChoreoSentenceScene( CBaseFlex *pActor, const char *pszSentence, EHANDLE *phSceneEnt,
float flPostDelay, bool bIsBackground, AI_Response *response,
bool bMultiplayer, IRecipientFilter *filter /* = NULL */ )
{
if ( !pActor )
{
Warning( "InstancedChoreoSentenceScene: Expecting non-NULL pActor for sound %s\n", pszSentence );
return 0;
}
CInstancedSceneEntity *pScene = (CInstancedSceneEntity *)CBaseEntity::CreateNoSpawn( "instanced_scripted_scene", vec3_origin, vec3_angle );
Q_strncpy( pScene->m_szInstanceFilename, UTIL_VarArgs( "AutoGenerated(%s)", pszSentence ), sizeof( pScene->m_szInstanceFilename ) );
pScene->m_iszSceneFile = MAKE_STRING( pScene->m_szInstanceFilename );
pScene->m_hOwner = pActor;
pScene->m_bHadOwner = pActor != NULL;
pScene->GenerateChoreoSentenceScene( pActor, pszSentence );
pScene->m_bMultiplayer = bMultiplayer;
pScene->SetPostSpeakDelay( flPostDelay );
DispatchSpawn( pScene );
pScene->Activate();
pScene->m_bIsBackground = bIsBackground;
pScene->SetBackground( bIsBackground );
pScene->SetRecipientFilter( filter );
if ( response )
{
float flPreDelay = response->GetPreDelay();
if ( flPreDelay )
{
pScene->SetPreDelay( flPreDelay );
}
}
pScene->StartPlayback();
if ( response )
{
// If the response wants us to abort on NPC state switch, remember that
pScene->SetBreakOnNonIdle( response->ShouldBreakOnNonIdle() );
}
if ( phSceneEnt )
{
*phSceneEnt = pScene;
}
return pScene->EstimateLength();
}
#endif
bool g_bClientFlex = true;
LINK_ENTITY_TO_CLASS( scene_manager, CSceneManager );

View File

@ -28,6 +28,7 @@ int GetRecentNPCSpeech( recentNPCSpeech_t speech[ SPEECH_LIST_MAX_SOUNDS ] );
float InstancedScriptedScene( CBaseFlex *pActor, const char *pszScene, EHANDLE *phSceneEnt = NULL, float flPostDelay = 0.0f, bool bIsBackground = false, AI_Response *response = NULL, bool bMultiplayer = false, IRecipientFilter *filter = NULL );
#ifdef MAPBASE
float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, char const *soundname, EHANDLE *phSceneEnt = NULL, float flPostDelay = 0.0f, bool bIsBackground = false, AI_Response *response = NULL, bool bMultiplayer = false, IRecipientFilter *filter = NULL );
float InstancedChoreoSentenceScene( CBaseFlex *pActor, char const *pszSentence, EHANDLE *phSceneEnt = NULL, float flPostDelay = 0.0f, bool bIsBackground = false, AI_Response *response = NULL, bool bMultiplayer = false, IRecipientFilter *filter = NULL );
#else
float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, char const *soundname, EHANDLE *phSceneEnt = NULL );
#endif

View File

@ -46,8 +46,8 @@ $Project
$File "$SRCDIR\game\shared\mapbase\MapEdit.h"
$File "$SRCDIR\game\shared\mapbase\matchers.cpp"
$File "$SRCDIR\game\shared\mapbase\matchers.h"
$File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.cpp"
$File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.h"
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.h"
$File "$SRCDIR\game\shared\mapbase\protagonist_system.cpp"
$File "$SRCDIR\game\shared\mapbase\protagonist_system.h"
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]
@ -65,6 +65,8 @@ $Project
$File "mapbase\ai_grenade.h"
$File "mapbase\ai_monitor.cpp"
$File "mapbase\ai_weaponmodifier.cpp"
$File "mapbase\choreosentence.cpp"
$File "mapbase\choreosentence.h"
$File "mapbase\custom_weapon_factory.cpp"
$File "mapbase\custom_weapon_factory.h"
$File "mapbase\closecaption_entity.cpp"

View File

@ -66,6 +66,7 @@ BEGIN_SCRIPTDESC_ROOT( CSound, "A sound NPCs can hear." )
DEFINE_SCRIPTFUNC( ValidateOwner, "Returns true if the sound's owner is still valid or if the sound never had an owner in the first place." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetOwner, "GetOwner", "Gets the sound's owner." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetTarget, "GetTarget", "Gets the sound's target." )
DEFINE_SCRIPTFUNC_NAMED( ScriptFreeSound, "FreeSound", "Frees the sound from the sound list." )
END_SCRIPTDESC();
#endif

View File

@ -140,6 +140,8 @@ public:
// For VScript functions
HSCRIPT ScriptGetOwner() const { return ToHScript( m_hOwner ); }
HSCRIPT ScriptGetTarget() const { return ToHScript( m_hTarget ); }
void ScriptFreeSound() { m_flExpireTime = gpGlobals->curtime; m_bNoExpirationTime = false; }
#endif
EHANDLE m_hOwner; // sound's owner

View File

@ -22,6 +22,10 @@
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
#ifdef MAPBASE_VSCRIPT
extern int vscript_debugger_port;
#endif
// #define VMPROFILE 1
#ifdef VMPROFILE
@ -663,6 +667,14 @@ bool VScriptServerInit()
RegisterSharedScriptFunctions();
#endif
#ifdef MAPBASE_VSCRIPT
if ( vscript_debugger_port )
{
g_pScriptVM->ConnectDebugger( vscript_debugger_port );
vscript_debugger_port = 0;
}
#endif
if (scriptLanguage == SL_SQUIRREL)
{
g_pScriptVM->Run( g_Script_vscript_server );

View File

@ -72,16 +72,16 @@ function ImpulseScale( flTargetMass, flDesiredSpeed )
}
__Documentation.RegisterHelp( "ImpulseScale", "float ImpulseScale(float, float)", "Returns an impulse scale required to push an object." );
local PrecacheModel = PrecacheModel
local PrecacheModel = DoPrecacheModel
function PrecacheModel( a, b = true )
{
return PrecacheModel( a, b )
}
local PrecacheOther = PrecacheOther
local PrecacheOther = DoPrecacheOther
function PrecacheOther( a, b = "" )
{
PrecacheOther( a, b )
return PrecacheOther( a, b )
}
function __ReplaceClosures( script, scope )
@ -106,10 +106,9 @@ function __ReplaceClosures( script, scope )
}
}
local __OutputsPattern = regexp("^On.*Output$");
function ConnectOutputs( table )
{
local __OutputsPattern = regexp("^On.*Output$");
local nCharsToStrip = 6;
foreach( key, val in table )
{

View File

@ -2694,6 +2694,18 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_PISTOL );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_SHOTGUN );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_SMG1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_AR2 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_PHYSGUN );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_GRENADE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_RPG );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_CROSSBOW );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_MELEE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_SLAM );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_REVOLVER );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_REVOLVER );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_REVOLVER );
@ -2702,6 +2714,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_REVOLVER );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_REVOLVER );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_REVOLVER );
#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES
@ -2713,6 +2726,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_AR1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_AR1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_AR1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_AR3 );
@ -2723,6 +2737,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_AR3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_AR3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_AR3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SMG2 );
@ -2733,6 +2748,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG2 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_SMG2 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_SMG2 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_SMG2 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SMG3 );
@ -2743,6 +2759,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_SMG3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_SMG3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_SMG3 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_HMG1 );
@ -2753,6 +2770,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_HMG1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_HMG1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_HMG1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_HMG1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_HMG1 );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SNIPER_RIFLE );
@ -2763,6 +2781,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_SNIPER_RIFLE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SNIPER_RIFLE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_SNIPER_RIFLE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_SNIPER_RIFLE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_SNIPER_RIFLE );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_DUAL_PISTOLS );
@ -2773,6 +2792,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_DUAL_PISTOLS );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_DUAL_PISTOLS );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_DUAL_PISTOLS );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELAX_DUAL_PISTOLS );
REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_DUAL_PISTOLS );
#endif

View File

@ -2598,6 +2598,18 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM,
ACT_HL2MP_GESTURE_RELAX,
ACT_HL2MP_GESTURE_RELAX_PISTOL,
ACT_HL2MP_GESTURE_RELAX_SHOTGUN,
ACT_HL2MP_GESTURE_RELAX_SMG1,
ACT_HL2MP_GESTURE_RELAX_AR2,
ACT_HL2MP_GESTURE_RELAX_PHYSGUN,
ACT_HL2MP_GESTURE_RELAX_GRENADE,
ACT_HL2MP_GESTURE_RELAX_RPG,
ACT_HL2MP_GESTURE_RELAX_CROSSBOW,
ACT_HL2MP_GESTURE_RELAX_MELEE,
ACT_HL2MP_GESTURE_RELAX_SLAM,
ACT_HL2MP_IDLE_REVOLVER,
ACT_HL2MP_RUN_REVOLVER,
ACT_HL2MP_WALK_REVOLVER,
@ -2606,6 +2618,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER,
ACT_HL2MP_GESTURE_RELOAD_REVOLVER,
ACT_HL2MP_GESTURE_RELAX_REVOLVER,
ACT_HL2MP_JUMP_REVOLVER,
#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES
@ -2618,6 +2631,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_AR1,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1,
ACT_HL2MP_GESTURE_RELOAD_AR1,
ACT_HL2MP_GESTURE_RELAX_AR1,
ACT_HL2MP_JUMP_AR1,
ACT_HL2MP_IDLE_AR3,
@ -2628,6 +2642,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_AR3,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR3,
ACT_HL2MP_GESTURE_RELOAD_AR3,
ACT_HL2MP_GESTURE_RELAX_AR3,
ACT_HL2MP_JUMP_AR3,
ACT_HL2MP_IDLE_SMG2,
@ -2638,6 +2653,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG2,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2,
ACT_HL2MP_GESTURE_RELOAD_SMG2,
ACT_HL2MP_GESTURE_RELAX_SMG2,
ACT_HL2MP_JUMP_SMG2,
ACT_HL2MP_IDLE_SMG3,
@ -2648,6 +2664,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG3,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG3,
ACT_HL2MP_GESTURE_RELOAD_SMG3,
ACT_HL2MP_GESTURE_RELAX_SMG3,
ACT_HL2MP_JUMP_SMG3,
ACT_HL2MP_IDLE_HMG1,
@ -2658,6 +2675,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_HMG1,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_HMG1,
ACT_HL2MP_GESTURE_RELOAD_HMG1,
ACT_HL2MP_GESTURE_RELAX_HMG1,
ACT_HL2MP_JUMP_HMG1,
ACT_HL2MP_IDLE_SNIPER_RIFLE,
@ -2668,6 +2686,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_SNIPER_RIFLE,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_SNIPER_RIFLE,
ACT_HL2MP_GESTURE_RELOAD_SNIPER_RIFLE,
ACT_HL2MP_GESTURE_RELAX_SNIPER_RIFLE,
ACT_HL2MP_JUMP_SNIPER_RIFLE,
ACT_HL2MP_IDLE_DUAL_PISTOLS,
@ -2678,6 +2697,7 @@ typedef enum
ACT_HL2MP_GESTURE_RANGE_ATTACK_DUAL_PISTOLS,
ACT_HL2MP_GESTURE_RANGE_ATTACK2_DUAL_PISTOLS,
ACT_HL2MP_GESTURE_RELOAD_DUAL_PISTOLS,
ACT_HL2MP_GESTURE_RELAX_DUAL_PISTOLS,
ACT_HL2MP_JUMP_DUAL_PISTOLS,
#endif

View File

@ -31,6 +31,9 @@
#ifdef GAME_DLL
#include "sceneentity.h"
#ifdef MAPBASE
#include "mapbase/choreosentence.h"
#endif
#endif
#include "networkstringtabledefs.h"
@ -492,6 +495,17 @@ void CGameResponseSystem::Precache()
CBaseEntity::PrecacheScriptSound( response.value );
}
break;
#ifdef MAPBASE
case RESPONSE_CHOREOSENTENCE:
{
const ChoreoSentence_t *pSentence = LookupChoreoSentence( NULL, response.value );
if (pSentence)
PrecacheChoreoSentence( *pSentence );
else
Msg( "Choreo scene '%s' not found\n", response.value );
}
break;
#endif
}
}
}

View File

@ -18,12 +18,12 @@
#include "c_baseplayer.h"
#include "engine/ivdebugoverlay.h"
ConVar cl_showanimstate( "cl_showanimstate", "-1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Show the (client) animation state for the specified entity (-1 for none)." );
ConVar showanimstate_log( "cl_showanimstate_log", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "1 to output cl_showanimstate to Msg(). 2 to store in AnimStateClient.log. 3 for both." );
ConVar cl_showanimstate( "cl_showanimstate", "-1", FCVAR_CHEAT /*| FCVAR_DEVELOPMENTONLY*/, "Show the (client) animation state for the specified entity (-1 for none)." );
ConVar showanimstate_log( "cl_showanimstate_log", "0", FCVAR_CHEAT /*| FCVAR_DEVELOPMENTONLY*/, "1 to output cl_showanimstate to Msg(). 2 to store in AnimStateClient.log. 3 for both." );
#else
#include "player.h"
ConVar sv_showanimstate( "sv_showanimstate", "-1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Show the (server) animation state for the specified entity (-1 for none)." );
ConVar showanimstate_log( "sv_showanimstate_log", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "1 to output sv_showanimstate to Msg(). 2 to store in AnimStateServer.log. 3 for both." );
ConVar sv_showanimstate( "sv_showanimstate", "-1", FCVAR_CHEAT /*| FCVAR_DEVELOPMENTONLY*/, "Show the (server) animation state for the specified entity (-1 for none)." );
ConVar showanimstate_log( "sv_showanimstate_log", "0", FCVAR_CHEAT /*| FCVAR_DEVELOPMENTONLY*/, "1 to output sv_showanimstate to Msg(). 2 to store in AnimStateServer.log. 3 for both." );
#endif
@ -654,9 +654,11 @@ void CBasePlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr )
if ( m_AnimConfig.m_LegAnimType == LEGANIM_9WAY )
{
#ifndef MAPBASE // This causes problems with entities that rely on the player having a pitch (TODO: gate behind virtual function?)
#ifndef CLIENT_DLL
//Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
GetOuter()->SetLocalAngles( QAngle( 0, m_flCurrentFeetYaw, 0 ) );
#endif
#endif
int iMoveX = GetOuter()->LookupPoseParameter( pStudioHdr, "move_x" );
@ -942,6 +944,15 @@ void CBasePlayerAnimState::GetOuterAbsVelocity( Vector& vel ) const
#else
vel = GetOuter()->GetAbsVelocity();
#endif
#ifdef MAPBASE
if (GetOuter()->IsPlayer())
{
CBasePlayer *pPlayer = ToBasePlayer( GetOuter() );
if (pPlayer->GetLaggedMovementValue() != 1.0f)
vel *= pPlayer->GetLaggedMovementValue();
}
#endif
}
@ -1024,9 +1035,15 @@ void CBasePlayerAnimState::DebugShowAnimState( int iStartLine )
(float)pLayer->m_flWeight );
}
#ifdef MAPBASE
for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ )
{
CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( i );
#else
for ( int i=0; i < m_pOuter->GetNumAnimOverlays()-1; i++ )
{
CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( AIMSEQUENCE_LAYER + i );
#endif
#ifdef CLIENT_DLL
AnimStatePrintf( iLine++, "%s(%d), weight: %.2f, cycle: %.2f, order (%d), aim (%d)",
!pLayer->IsActive() ? "-- ": (pLayer->m_nSequence == 0 ? "-- " : GetSequenceName( m_pOuter->GetModelPtr(), pLayer->m_nSequence ) ),

View File

@ -307,6 +307,10 @@ public:
virtual bool ShouldBlockPrimaryFire() { return false; }
#ifdef CLIENT_DLL
#ifdef MAPBASE
virtual bool DispatchMuzzleEffect( const char *options, bool isFirstPerson );
#endif
virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd, const QAngle &vecOldViewAngles ) {}
virtual int CalcOverrideModelIndex() OVERRIDE;
#endif

View File

@ -3033,7 +3033,7 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f
float nextthink = gpGlobals->curtime + flTime;
pf->m_hfnThink = hFunc;
pf->m_hfnThink = g_pScriptVM->CopyObject( hFunc );
pf->m_flNextThink = nextthink;
#ifdef GAME_DLL

View File

@ -255,7 +255,7 @@ inline HSCRIPT ToHScript(CBaseEntity* pEnt)
return (pEnt) ? pEnt->GetScriptInstance() : NULL;
}
template <> ScriptClassDesc_t* GetScriptDesc<CBaseEntity>(CBaseEntity*);
template <> ScriptClassDesc_t* GetScriptDesc<CBaseEntity>(CBaseEntity*, bool);
inline CBaseEntity* ToEnt(HSCRIPT hScript)
{
return (hScript) ? (CBaseEntity*)g_pScriptVM->GetInstanceValue(hScript, GetScriptDescForClass(CBaseEntity)) : NULL;

View File

@ -15,7 +15,7 @@
//=============================================================================//
#include "cbase.h"
#include "singleplayer_animstate.h"
#include "mapbase_playeranimstate.h"
#include "tier0/vprof.h"
#include "animation.h"
#include "studio.h"
@ -23,25 +23,33 @@
#include "utldict.h"
#include "filesystem.h"
#include "in_buttons.h"
#include "gamemovement.h"
#include "datacache/imdlcache.h"
#ifdef CLIENT_DLL
#include "input.h"
#endif
extern ConVar mp_facefronttime, mp_feetyawrate, mp_ik;
extern ConVar mp_facefronttime, mp_feetyawrate;
ConVar sv_playeranimstate_animtype( "sv_playeranimstate_animtype", "0", FCVAR_NONE, "The leg animation type used by the singleplayer animation state. 9way = 0, 8way = 1, GoldSrc = 2" );
ConVar sv_playeranimstate_bodyyaw( "sv_playeranimstate_bodyyaw", "45.0", FCVAR_NONE, "The maximum body yaw used by the singleplayer animation state." );
ConVar sv_playeranimstate_use_aim_sequences( "sv_playeranimstate_use_aim_sequences", "1", FCVAR_NONE, "Allows the singleplayer animation state to use aim sequences." );
ConVar sv_playeranimstate_animtype( "sv_playeranimstate_animtype", "0", FCVAR_NONE, "The leg animation type used by the Mapbase animation state. 9way = 0, 8way = 1, GoldSrc = 2" );
ConVar sv_playeranimstate_bodyyaw( "sv_playeranimstate_bodyyaw", "45.0", FCVAR_NONE, "The maximum body yaw used by the Mapbase animation state." );
ConVar sv_playeranimstate_use_aim_sequences( "sv_playeranimstate_use_aim_sequences", "0", FCVAR_NONE, "Allows the Mapbase animation state to use aim sequences." );
ConVar sv_playeranimstate_use_walk_anims( "sv_playeranimstate_use_walk_anims", "0", FCVAR_NONE, "Allows the Mapbase animation state to use walk animations when the player is walking." );
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f
#define WEAPON_RELAX_TIME 0.5f
#define FIRESEQUENCE_LAYER (AIMSEQUENCE_LAYER+NUM_AIMSEQUENCE_LAYERS)
#define RELOADSEQUENCE_LAYER (FIRESEQUENCE_LAYER + 1)
#define NUM_LAYERS_WANTED (RELOADSEQUENCE_LAYER + 1)
#define MISCSEQUENCE_LAYER (RELOADSEQUENCE_LAYER + 1)
#define NUM_LAYERS_WANTED (MISCSEQUENCE_LAYER + 1)
CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer )
CMapbasePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer )
{
MDLCACHE_CRITICAL_SECTION();
CSinglePlayerAnimState *pState = new CSinglePlayerAnimState( pPlayer );
CMapbasePlayerAnimState *pState = new CMapbasePlayerAnimState( pPlayer );
// Setup the movement data.
CModAnimConfig movementData;
@ -65,22 +73,25 @@ CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer )
extern ConVar sv_backspeed;
extern ConVar mp_feetyawrate;
extern ConVar mp_facefronttime;
extern ConVar mp_ik;
CSinglePlayerAnimState::CSinglePlayerAnimState( CBasePlayer *pPlayer ): m_pPlayer( pPlayer )
CMapbasePlayerAnimState::CMapbasePlayerAnimState( CBasePlayer *pPlayer ): m_pPlayer( pPlayer )
{
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Activity CSinglePlayerAnimState::CalcMainActivity()
Activity CMapbasePlayerAnimState::CalcMainActivity()
{
#ifdef CLIENT_DLL
return ACT_IDLE;
#else
float speed = GetOuter()->GetAbsVelocity().Length2D();
if (m_pPlayer->GetLaggedMovementValue() != 1.0f)
speed *= m_pPlayer->GetLaggedMovementValue();
// May not always be precise
if (speed < 0.01f)
speed = 0.0f;
if ( HandleJumping() )
{
return ACT_HL2MP_JUMP;
@ -95,7 +106,24 @@ Activity CSinglePlayerAnimState::CalcMainActivity()
}
else
{
if ( GetOuter()->GetFlags() & FL_DUCKING )
bool bDucking = (GetOuter()->GetFlags() & FL_DUCKING) ? true : false;
// (currently singleplayer-exclusive since clients can't read whether other players are holding down IN_DUCK)
if (m_pPlayer->m_Local.m_flDucktime > 0 && gpGlobals->maxClients == 1)
{
// Consider ducking if half-way through duck time
bDucking = (m_pPlayer->m_Local.m_flDucktime < (GAMEMOVEMENT_DUCK_TIME * 0.9f));
// Unducking
#ifdef CLIENT_DLL
if (!((m_pPlayer->IsLocalPlayer() ? input->GetButtonBits( 0 ) : m_pPlayer->GetCurrentUserCommand()->buttons) & IN_DUCK))
#else
if (!(m_pPlayer->m_nButtons & IN_DUCK))
#endif
bDucking = !bDucking;
}
if ( bDucking )
{
if ( speed > 0 )
{
@ -111,7 +139,7 @@ Activity CSinglePlayerAnimState::CalcMainActivity()
if ( speed > 0 )
{
#if EXPANDED_HL2DM_ACTIVITIES
if ( m_pPlayer->GetButtons() & IN_WALK )
if ( m_pPlayer->m_nButtons & IN_WALK && sv_playeranimstate_use_walk_anims.GetBool() )
{
idealActivity = ACT_HL2MP_WALK;
}
@ -132,19 +160,22 @@ Activity CSinglePlayerAnimState::CalcMainActivity()
}
//return m_pPlayer->GetActivity();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim )
void CMapbasePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim )
{
if ( playerAnim == PLAYER_ATTACK1 )
{
m_iFireSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RANGE_ATTACK ) );
m_bFiring = m_iFireSequence != -1;
m_flFireCycle = 0;
// Be sure to stop reloading
m_bReloading = false;
m_flReloadCycle = 0;
}
else if ( playerAnim == PLAYER_ATTACK2 )
{
@ -155,6 +186,10 @@ void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim )
#endif
m_bFiring = m_iFireSequence != -1;
m_flFireCycle = 0;
// Be sure to stop reloading
m_bReloading = false;
m_flReloadCycle = 0;
}
else if ( playerAnim == PLAYER_JUMP )
{
@ -162,6 +197,7 @@ void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim )
if (!m_bJumping)
{
m_bJumping = true;
m_bDuckJumping = (GetOuter()->GetFlags() & FL_DUCKING) ? true : false; //m_pPlayer->m_nButtons & IN_DUCK;
m_bFirstJumpFrame = true;
m_flJumpStartTime = gpGlobals->curtime;
}
@ -184,13 +220,13 @@ void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim )
if (m_iWeaponSwitchSequence != -1)
{
// clear other events that might be playing in our layer
m_bPlayingMisc = false;
//m_bPlayingMisc = false;
m_bReloading = false;
m_bWeaponSwitching = true;
m_flWeaponSwitchCycle = 0;
m_flMiscBlendOut = 0.1f;
m_flMiscBlendIn = 0.1f;
//m_flMiscBlendOut = 0.1f;
//m_flMiscBlendIn = 0.1f;
m_bMiscNoOverride = false;
}
}
@ -199,10 +235,10 @@ void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Activity CSinglePlayerAnimState::TranslateActivity( Activity actDesired )
Activity CMapbasePlayerAnimState::TranslateActivity( Activity actDesired )
{
#ifdef CLIENT_DLL
return actDesired;
#if defined(CLIENT_DLL) && !defined(MAPBASE_MP)
return actDesired;
#else
return m_pPlayer->Weapon_TranslateActivity( actDesired );
#endif
@ -211,7 +247,7 @@ Activity CSinglePlayerAnimState::TranslateActivity( Activity actDesired )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CSinglePlayerAnimState::HandleJumping()
bool CMapbasePlayerAnimState::HandleJumping()
{
if ( m_bJumping )
{
@ -230,6 +266,7 @@ bool CSinglePlayerAnimState::HandleJumping()
if ( m_pOuter->GetFlags() & FL_ONGROUND || GetOuter()->GetGroundEntity() != NULL)
{
m_bJumping = false;
m_bDuckJumping = false;
RestartMainSequence(); // Reset the animation.
}
}
@ -242,20 +279,21 @@ bool CSinglePlayerAnimState::HandleJumping()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr )
void CMapbasePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr )
{
CBasePlayerAnimState::ComputeSequences(pStudioHdr);
ComputeFireSequence();
ComputeMiscSequence();
ComputeReloadSequence();
ComputeWeaponSwitchSequence();
ComputeWeaponSwitchSequence();
ComputeRelaxSequence();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::AddMiscSequence( int iSequence, float flBlendIn, float flBlendOut, float flPlaybackRate, bool bHoldAtEnd, bool bOnlyWhenStill )
void CMapbasePlayerAnimState::AddMiscSequence( int iSequence, float flBlendIn, float flBlendOut, float flPlaybackRate, bool bHoldAtEnd, bool bOnlyWhenStill )
{
Assert( iSequence != -1 );
@ -265,7 +303,7 @@ void CSinglePlayerAnimState::AddMiscSequence( int iSequence, float flBlendIn, fl
m_bPlayingMisc = true;
m_bMiscHoldAtEnd = bHoldAtEnd;
m_bReloading = false;
//m_bReloading = false;
m_flMiscCycle = 0;
m_bMiscOnlyWhenStill = bOnlyWhenStill;
m_bMiscNoOverride = true;
@ -275,12 +313,36 @@ void CSinglePlayerAnimState::AddMiscSequence( int iSequence, float flBlendIn, fl
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ClearAnimationState()
void CMapbasePlayerAnimState::StartWeaponRelax()
{
if (m_bWeaponRelaxing)
return;
m_bWeaponRelaxing = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMapbasePlayerAnimState::StopWeaponRelax()
{
if (!m_bWeaponRelaxing)
return;
m_bWeaponRelaxing = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMapbasePlayerAnimState::ClearAnimationState()
{
m_bJumping = false;
m_bDuckJumping = false;
m_bFiring = false;
m_bReloading = false;
m_bWeaponSwitching = false;
m_bWeaponRelaxing = false;
m_bPlayingMisc = false;
m_flReloadBlendIn = 0.0f;
m_flReloadBlendOut = 0.0f;
@ -289,32 +351,42 @@ void CSinglePlayerAnimState::ClearAnimationState()
CBasePlayerAnimState::ClearAnimationState();
}
void CSinglePlayerAnimState::ClearAnimationLayers()
void CMapbasePlayerAnimState::ClearAnimationLayers()
{
VPROF( "CBasePlayerAnimState::ClearAnimationLayers" );
// In c_baseanimatingoverlay.cpp, this sometimes desyncs from the interpolated overlays and causes a crash in ResizeAnimationLayerCallback when the player dies. (pVec->Count() != pVecIV->Count())
// Is there a better way of getting around this issue?
#ifndef CLIENT_DLL
if ( !m_pOuter )
return;
m_pOuter->SetNumAnimOverlays( NUM_LAYERS_WANTED );
for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ )
{
// If we're not using aim sequences, leave the aim layers alone
// (allows them to be used outside of anim state)
if ( !m_AnimConfig.m_bUseAimSequences && i <= NUM_AIMSEQUENCE_LAYERS )
continue;
m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS );
#ifndef CLIENT_DLL
m_pOuter->GetAnimOverlay( i )->m_fFlags = 0;
#endif
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CSinglePlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle )
int CMapbasePlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle )
{
// TODO?
return m_pOuter->LookupSequence( "soldier_Aim_9_directions" );
}
void CSinglePlayerAnimState::UpdateLayerSequenceGeneric( int iLayer, bool &bEnabled,
void CMapbasePlayerAnimState::UpdateLayerSequenceGeneric( int iLayer, bool &bEnabled,
float &flCurCycle, int &iSequence, bool bWaitAtEnd,
float fBlendIn, float fBlendOut, bool bMoveBlend, float fPlaybackRate, bool bUpdateCycle /* = true */ )
{
@ -383,7 +455,7 @@ void CSinglePlayerAnimState::UpdateLayerSequenceGeneric( int iLayer, bool &bEnab
pLayer->m_flPlaybackRate = fPlaybackRate;
pLayer->m_flWeight = 1.0f;
if (iLayer == RELOADSEQUENCE_LAYER)
if (fBlendIn > 0.0f || fBlendOut > 0.0f)
{
// blend this layer in and out for smooth reloading
if (flCurCycle < fBlendIn && fBlendIn>0)
@ -418,25 +490,91 @@ void CSinglePlayerAnimState::UpdateLayerSequenceGeneric( int iLayer, bool &bEnab
pLayer->SetOrder( iLayer );
}
void CSinglePlayerAnimState::ComputeFireSequence()
void CMapbasePlayerAnimState::ComputeFireSequence()
{
UpdateLayerSequenceGeneric( FIRESEQUENCE_LAYER, m_bFiring, m_flFireCycle, m_iFireSequence, false );
}
void CSinglePlayerAnimState::ComputeReloadSequence()
void CMapbasePlayerAnimState::ComputeReloadSequence()
{
UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bReloading, m_flReloadCycle, m_iReloadSequence, false, m_flReloadBlendIn, m_flReloadBlendOut, false, m_fReloadPlaybackRate );
}
void CSinglePlayerAnimState::ComputeWeaponSwitchSequence()
void CMapbasePlayerAnimState::ComputeWeaponSwitchSequence()
{
UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bWeaponSwitching, m_flWeaponSwitchCycle, m_iWeaponSwitchSequence, false, 0, 0.5f );
}
// does misc gestures if we're not firing
void CSinglePlayerAnimState::ComputeMiscSequence()
void CMapbasePlayerAnimState::ComputeRelaxSequence()
{
UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bPlayingMisc, m_flMiscCycle, m_iMiscSequence, m_bMiscHoldAtEnd, m_flMiscBlendIn, m_flMiscBlendOut, m_bMiscOnlyWhenStill, m_fMiscPlaybackRate );
bool bRelaxing = m_bWeaponRelaxing;
float flRelaxSpeed = 0.05f;
if ((m_bFiring && m_flFireCycle < 1.0f) || m_bReloading)
{
// Keep weapon raised
bRelaxing = false;
flRelaxSpeed = 0.5f;
//GetOuter()->SetPoseParameter( GetOuter()->LookupPoseParameter( "weapon_lower" ), 0.0f );
}
if (bRelaxing ? m_flWeaponRelaxAmount != 1.0f : m_flWeaponRelaxAmount != 0.0f)
{
if (bRelaxing)
m_flWeaponRelaxAmount += flRelaxSpeed;
else
m_flWeaponRelaxAmount -= flRelaxSpeed;
m_flWeaponRelaxAmount = clamp( m_flWeaponRelaxAmount, 0.0f, 1.0f );
GetOuter()->SetPoseParameter( GetOuter()->LookupPoseParameter( "weapon_lower" ), m_flWeaponRelaxAmount );
/*int nPose = GetOuter()->LookupPoseParameter( "weapon_lower" );
if (nPose != -1)
{
float flValue = RemapValClamped( (m_flWeaponRelaxTime - gpGlobals->curtime), 0.0f, 0.5f, 0.0f, 1.0f );
if (flValue <= 0.0f)
{
// All done
m_flWeaponRelaxTime = FLT_MAX;
}
if (m_bWeaponRelaxing)
flValue = 1.0f - flValue;
GetOuter()->SetPoseParameter( nPose, SimpleSpline( flValue ) );
}*/
}
else if (bRelaxing)
{
GetOuter()->SetPoseParameter( GetOuter()->LookupPoseParameter( "weapon_lower" ), 1.0f );
}
/*bool bEnabled = m_bWeaponRelaxing;
bool bUpdateCycle = true;
if (bEnabled)
{
if (m_flWeaponRelaxCycle >= 0.5f)
{
// Pause at 0.5
m_flWeaponRelaxCycle = 0.5f;
bUpdateCycle = false;
}
}
else if (m_flWeaponRelaxCycle < 1.0f)
{
// Make sure we exit the relax
bEnabled = true;
}
UpdateLayerSequenceGeneric( AIMSEQUENCE_LAYER, bEnabled, m_flWeaponRelaxCycle, m_iWeaponRelaxSequence, false, 0.5f, 0.5f, false, 1.0f, bUpdateCycle );*/
}
// does misc gestures if we're not firing
void CMapbasePlayerAnimState::ComputeMiscSequence()
{
UpdateLayerSequenceGeneric( MISCSEQUENCE_LAYER, m_bPlayingMisc, m_flMiscCycle, m_iMiscSequence, m_bMiscHoldAtEnd, m_flMiscBlendIn, m_flMiscBlendOut, m_bMiscOnlyWhenStill, m_fMiscPlaybackRate );
}
//-----------------------------------------------------------------------------
@ -444,7 +582,7 @@ void CSinglePlayerAnimState::ComputeMiscSequence()
// Input : -
// Output : float
//-----------------------------------------------------------------------------
float CSinglePlayerAnimState::GetCurrentMaxGroundSpeed()
float CMapbasePlayerAnimState::GetCurrentMaxGroundSpeed()
{
CStudioHdr *pStudioHdr = GetOuter()->GetModelPtr();
@ -481,11 +619,42 @@ float CSinglePlayerAnimState::GetCurrentMaxGroundSpeed()
return speed;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline bool CMapbasePlayerAnimState::ShouldUseAimPoses( void ) const
{
return GetAimPoseBlend() > 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CMapbasePlayerAnimState::GetAimPoseBlend( void ) const
{
if (!GetOuter()->MyCombatCharacterPointer() || !GetOuter()->MyCombatCharacterPointer()->GetActiveWeapon()
|| GetOuter()->MyCombatCharacterPointer()->GetActiveWeapon()->IsEffectActive( EF_NODRAW ))
return 0.0f;
return 1.0f - m_flWeaponRelaxAmount;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CMapbasePlayerAnimState::SetOuterBodyYaw( float flValue )
{
float flAimPoseBlend = GetAimPoseBlend();
GetOuter()->SetPoseParameter( GetOuter()->LookupPoseParameter( "aim_yaw" ), flValue * flAimPoseBlend );
return CBasePlayerAnimState::SetOuterBodyYaw( flValue * (1.0f - flAimPoseBlend) );
}
//-----------------------------------------------------------------------------
// Purpose: Override for backpeddling
// Input : dt -
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void )
void CMapbasePlayerAnimState::ComputePoseParam_BodyYaw( void )
{
CBasePlayerAnimState::ComputePoseParam_BodyYaw();
@ -495,7 +664,7 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void )
void CMapbasePlayerAnimState::ComputePoseParam_BodyLookYaw( void )
{
// See if we even have a blender for pitch
int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" );
@ -632,7 +801,7 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
void CMapbasePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
{
// Get pitch from v_angle
float flPitch = m_flEyePitch;
@ -643,16 +812,19 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr
}
flPitch = clamp( flPitch, -90, 90 );
//float flAimPoseBlend = GetAimPoseBlend();
// See if we have a blender for pitch
GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch );
GetOuter()->SetPoseParameter( pStudioHdr, "head_pitch", flPitch );
ComputePoseParam_HeadPitch( pStudioHdr );
//ComputePoseParam_HeadPitch( pStudioHdr );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr )
void CMapbasePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr )
{
// Get pitch from v_angle
int iHeadPitch = GetOuter()->LookupPoseParameter("head_pitch");

View File

@ -14,8 +14,8 @@
//
//=============================================================================//
#ifndef SINGLEPLAYER_ANIMSTATE_H
#define SINGLEPLAYER_ANIMSTATE_H
#ifndef MAPBASE_PLAYERANIMSTATE_H
#define MAPBASE_PLAYERANIMSTATE_H
#ifdef _WIN32
#pragma once
#endif
@ -34,10 +34,10 @@
#define SP_ANIM_STATE 1
#endif
class CSinglePlayerAnimState : public CBasePlayerAnimState
class CMapbasePlayerAnimState : public CBasePlayerAnimState
{
public:
CSinglePlayerAnimState( CBasePlayer *pPlayer );
CMapbasePlayerAnimState( CBasePlayer *pPlayer );
Activity CalcMainActivity();
int CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle );
@ -49,10 +49,16 @@ public:
void ComputeSequences( CStudioHdr *pStudioHdr );
void AddMiscSequence( int iSequence, float flBlendIn = 0.0f, float flBlendOut = 0.0f, float flPlaybackRate = 1.0f, bool bHoldAtEnd = false, bool bOnlyWhenStill = false );
void StartWeaponRelax();
void StopWeaponRelax();
void ClearAnimationState();
void ClearAnimationLayers();
inline bool IsJumping() const { return m_bJumping; }
inline bool IsDuckJumping() const { return m_bDuckJumping; }
private:
bool HandleJumping();
@ -60,13 +66,19 @@ private:
void ComputeFireSequence();
void ComputeReloadSequence();
void ComputeWeaponSwitchSequence();
void ComputeRelaxSequence();
void ComputeMiscSequence();
void UpdateLayerSequenceGeneric( int iLayer, bool &bEnabled, float &flCurCycle,
int &iSequence, bool bWaitAtEnd,
float fBlendIn=0.15f, float fBlendOut=0.15f, bool bMoveBlend = false,
float fBlendIn=0.0f, float fBlendOut=0.0f, bool bMoveBlend = false,
float fPlaybackRate=1.0f, bool bUpdateCycle = true );
bool ShouldUseAimPoses() const;
float GetAimPoseBlend() const;
float SetOuterBodyYaw( float flValue );
void ComputePoseParam_BodyYaw( void );
void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr );
void ComputePoseParam_BodyLookYaw( void );
@ -76,6 +88,7 @@ private:
// Current state variables.
bool m_bJumping; // Set on a jump event.
bool m_bDuckJumping; // Jump started while ducking
float m_flJumpStartTime;
bool m_bFirstJumpFrame;
@ -90,6 +103,9 @@ private:
float m_flWeaponSwitchCycle;
int m_iWeaponSwitchSequence;
bool m_bWeaponRelaxing;
float m_flWeaponRelaxAmount;
bool m_bPlayingMisc;
float m_flMiscCycle, m_flMiscBlendOut, m_flMiscBlendIn;
int m_iMiscSequence;
@ -105,6 +121,6 @@ private:
float m_flFireCycle;
};
CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer );
CMapbasePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer );
#endif // SINGLEPLAYER_ANIMSTATE_H
#endif // MAPBASE_PLAYERANIMSTATE_H

View File

@ -29,6 +29,7 @@
#include "AI_ResponseSystem.h"
#include "mapbase/SystemConvarMod.h"
#include "gameinterface.h"
#include "mapbase/choreosentence.h"
#endif
#if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
#include "protagonist_system.h"
@ -88,6 +89,7 @@ char g_iszGameName[128];
#ifdef GAME_DLL
// Default player configuration
char g_szDefaultPlayerModel[MAX_PATH];
bool g_bDefaultPlayerLegs;
bool g_bDefaultPlayerDrawExternally;
char g_szDefaultHandsModel[MAX_PATH];
@ -115,7 +117,7 @@ enum
MANIFEST_HUDLAYOUT,
#else
MANIFEST_TALKER,
//MANIFEST_SENTENCES,
MANIFEST_CHOREOSENTENCES,
MANIFEST_ACTBUSY,
#endif
#ifdef MAPBASE_VSCRIPT
@ -158,7 +160,7 @@ static const ManifestType_t gm_szManifestFileStrings[MANIFEST_NUM_TYPES] = {
{ "hudlayout", "mapbase_load_hudlayout", "Should we load map-specific HUD layout overrides? e.g. \"maps/<mapname>_hudlayout.res\"" },
#else
{ "talker", "mapbase_load_talker", "Should we load map-specific talker files? e.g. \"maps/<mapname>_talker.txt\"" },
//{ "sentences", "mapbase_load_sentences", "Should we load map-specific sentences? e.g. \"maps/<mapname>_sentences.txt\"" },
{ "choreosentences", "mapbase_load_choreosentences", "Should we load map-specific choreo sentences? e.g. \"maps/<mapname>_choreosentences.txt\"" },
{ "actbusy", "mapbase_load_actbusy", "Should we load map-specific actbusy files? e.g. \"maps/<mapname>_actbusy.txt\"" },
#endif
#ifdef MAPBASE_VSCRIPT
@ -249,6 +251,7 @@ public:
#ifdef GAME_DLL
Q_strncpy( g_szDefaultPlayerModel, gameinfo->GetString( "player_default_model", "models/player.mdl" ), sizeof( g_szDefaultPlayerModel ) );
g_bDefaultPlayerLegs = gameinfo->GetBool( "player_default_legs", false );
g_bDefaultPlayerDrawExternally = gameinfo->GetBool( "player_default_draw_externally", false );
Q_strncpy( g_szDefaultHandsModel, gameinfo->GetString( "player_default_hands", "models/weapons/v_hands.mdl" ), sizeof( g_szDefaultHandsModel ) );
@ -483,7 +486,7 @@ public:
LoadResponseSystemFile(value); //PrecacheCustomResponseSystem( value );
} break;
//case MANIFEST_SOUNDSCAPES: { g_SoundscapeSystem.AddSoundscapeFile(value); } break;
//case MANIFEST_SENTENCES: { engine->PrecacheSentenceFile(value); } break;
case MANIFEST_CHOREOSENTENCES: { LoadChoreoSentenceFile(value); } break;
case MANIFEST_ACTBUSY: { ParseCustomActbusyFile(value); } break;
#endif
#ifdef MAPBASE_VSCRIPT
@ -631,6 +634,7 @@ public:
#else
void LoadCustomTalkerFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_TALKER, false ); }
void LoadCustomActbusyFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_ACTBUSY, false ); }
void LoadCustomChoreoSentenceFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_CHOREOSENTENCES, false ); }
#endif
const char *GetModName() { return g_iszGameName; }
@ -679,6 +683,7 @@ BEGIN_SCRIPTDESC_ROOT( CMapbaseSystem, SCRIPT_SINGLETON "All-purpose Mapbase sys
#else
DEFINE_SCRIPTFUNC( LoadCustomTalkerFile, "Loads a custom talker file." )
DEFINE_SCRIPTFUNC( LoadCustomActbusyFile, "Loads a custom actbusy file." )
DEFINE_SCRIPTFUNC( LoadCustomChoreoSentenceFile, "Loads a custom choreo sentence file." )
#endif
DEFINE_SCRIPTFUNC( GetModName, "Gets the name of the mod. This is the name which shows up on Steam, RPC, etc." )

View File

@ -14,6 +14,7 @@
#include "c_ai_basenpc.h"
#else
#include "ai_basenpc.h"
#include "ai_senses.h"
#include "globalstate.h"
#endif
@ -357,7 +358,8 @@ void RegisterSharedScriptConstants()
ScriptRegisterConstant( g_pScriptVM, ROPE_NO_GRAVITY, "Disable gravity on this rope. (for use in rope flags)" );
ScriptRegisterConstant( g_pScriptVM, ROPE_NUMFLAGS, "The number of rope flags recognized by the game." );
ScriptRegisterConstantNamed( g_pScriptVM, Vector( ROPE_GRAVITY ), "ROPE_GRAVITY", "Default rope gravity vector." );
static Vector vecRopeGravity( ROPE_GRAVITY );
ScriptRegisterConstantNamed( g_pScriptVM, vecRopeGravity, "ROPE_GRAVITY", "Default rope gravity vector." );
//
// Sounds
@ -427,8 +429,8 @@ void RegisterSharedScriptConstants()
#ifdef GAME_DLL
//
// AI Sounds
// (QueryHearSound hook can use these)
// AI Senses
// (NPC hooks can use these)
//
ScriptRegisterConstant( g_pScriptVM, SOUND_NONE, "Sound type used in QueryHearSound hooks, etc." );
ScriptRegisterConstant( g_pScriptVM, SOUND_COMBAT, "Sound type used in QueryHearSound hooks, etc." );
@ -481,6 +483,11 @@ void RegisterSharedScriptConstants()
ScriptRegisterConstantNamed( g_pScriptVM, (int)SOUNDENT_VOLUME_PISTOL, "SOUNDENT_VOLUME_PISTOL", "Sound volume preset for use in InsertAISound, etc." );
ScriptRegisterConstantNamed( g_pScriptVM, (int)SOUNDENT_VOLUME_EMPTY, "SOUNDENT_VOLUME_PISTOL", "Sound volume preset for use in InsertAISound, etc." );
ScriptRegisterConstantNamed( g_pScriptVM, (int)SEEN_ALL, "SEEN_ALL", "All NPC sight arrays. Used in GetFirstSeenEntity, etc." );
ScriptRegisterConstantNamed( g_pScriptVM, (int)SEEN_HIGH_PRIORITY, "SEEN_HIGH_PRIORITY", "NPC sight array for players. Used in GetFirstSeenEntity, etc." );
ScriptRegisterConstantNamed( g_pScriptVM, (int)SEEN_NPCS, "SEEN_NPCS", "NPC sight array for other NPCs. Used in GetFirstSeenEntity, etc." );
ScriptRegisterConstantNamed( g_pScriptVM, (int)SEEN_MISC, "SEEN_MISC", "NPC sight array for objects. Used in GetFirstSeenEntity, etc." );
//
// Capabilities
//

View File

@ -255,11 +255,10 @@ void ScriptDispatchSpawn( HSCRIPT hEntity )
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static HSCRIPT CreateDamageInfo( HSCRIPT hInflictor, HSCRIPT hAttacker, const Vector &vecForce, const Vector &vecDamagePos, float flDamage, int iDamageType )
static HSCRIPT_RC CreateDamageInfo( HSCRIPT hInflictor, HSCRIPT hAttacker, const Vector &vecForce, const Vector &vecDamagePos, float flDamage, int iDamageType )
{
// The script is responsible for deleting this via DestroyDamageInfo().
CTakeDamageInfo *damageInfo = new CTakeDamageInfo( ToEnt(hInflictor), ToEnt(hAttacker), flDamage, iDamageType );
HSCRIPT hScript = g_pScriptVM->RegisterInstance( damageInfo );
HSCRIPT hScript = g_pScriptVM->RegisterInstance( damageInfo, true );
damageInfo->SetDamagePosition( vecDamagePos );
damageInfo->SetDamageForce( vecForce );
@ -267,14 +266,8 @@ static HSCRIPT CreateDamageInfo( HSCRIPT hInflictor, HSCRIPT hAttacker, const Ve
return hScript;
}
static void DestroyDamageInfo( HSCRIPT hDamageInfo )
static void DestroyDamageInfo( HSCRIPT )
{
CTakeDamageInfo *pInfo = HScriptToClass< CTakeDamageInfo >( hDamageInfo );
if ( pInfo )
{
g_pScriptVM->RemoveInstance( hDamageInfo );
delete pInfo;
}
}
void ScriptCalculateExplosiveDamageForce( HSCRIPT info, const Vector &vecDir, const Vector &vecForceOrigin, float flScale )
@ -317,6 +310,8 @@ void ScriptGuessDamageForce( HSCRIPT info, const Vector &vecForceDir, const Vect
//
//-----------------------------------------------------------------------------
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptGameTrace, "CGameTrace", "trace_t" )
DEFINE_SCRIPT_REFCOUNTED_INSTANCE()
DEFINE_SCRIPTFUNC( DidHitWorld, "Returns whether the trace hit the world entity or not." )
DEFINE_SCRIPTFUNC( DidHitNonWorldEntity, "Returns whether the trace hit something other than the world entity." )
DEFINE_SCRIPTFUNC( GetEntityIndex, "Returns the index of whatever entity this trace hit." )
@ -347,7 +342,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptGameTrace, "CGameTrace", "trace_t" )
DEFINE_SCRIPTFUNC( Surface, "" )
DEFINE_SCRIPTFUNC( Plane, "" )
DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." )
DEFINE_SCRIPTFUNC( Destroy, SCRIPT_HIDE )
END_SCRIPTDESC();
BEGIN_SCRIPTDESC_ROOT_NAMED( scriptsurfacedata_t, "surfacedata_t", "" )
@ -376,37 +371,28 @@ END_SCRIPTDESC();
CPlaneTInstanceHelper g_PlaneTInstanceHelper;
BEGIN_SCRIPTDESC_ROOT( cplane_t, "" )
DEFINE_SCRIPT_INSTANCE_HELPER( &g_PlaneTInstanceHelper )
BEGIN_SCRIPTDESC_ROOT_WITH_HELPER( cplane_t, "", &g_PlaneTInstanceHelper )
END_SCRIPTDESC();
static HSCRIPT ScriptTraceLineComplex( const Vector &vecStart, const Vector &vecEnd, HSCRIPT entIgnore, int iMask, int iCollisionGroup )
static HSCRIPT_RC ScriptTraceLineComplex( const Vector &vecStart, const Vector &vecEnd, HSCRIPT entIgnore, int iMask, int iCollisionGroup )
{
// The script is responsible for deleting this via Destroy().
CScriptGameTrace *tr = new CScriptGameTrace();
CBaseEntity *pIgnore = ToEnt( entIgnore );
UTIL_TraceLine( vecStart, vecEnd, iMask, pIgnore, iCollisionGroup, tr );
tr->RegisterSurface();
tr->RegisterPlane();
return tr->GetScriptInstance();
return g_pScriptVM->RegisterInstance( tr, true );
}
static HSCRIPT ScriptTraceHullComplex( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, const Vector &hullMax,
static HSCRIPT_RC ScriptTraceHullComplex( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, const Vector &hullMax,
HSCRIPT entIgnore, int iMask, int iCollisionGroup )
{
// The script is responsible for deleting this via Destroy().
CScriptGameTrace *tr = new CScriptGameTrace();
CBaseEntity *pIgnore = ToEnt( entIgnore );
UTIL_TraceHull( vecStart, vecEnd, hullMin, hullMax, iMask, pIgnore, iCollisionGroup, tr );
tr->RegisterSurface();
tr->RegisterPlane();
return tr->GetScriptInstance();
return g_pScriptVM->RegisterInstance( tr, true );
}
//-----------------------------------------------------------------------------
@ -477,12 +463,11 @@ void FireBulletsInfo_t::ScriptSetAdditionalIgnoreEnt( HSCRIPT value )
m_pAdditionalIgnoreEnt = ToEnt( value );
}
static HSCRIPT CreateFireBulletsInfo( int cShots, const Vector &vecSrc, const Vector &vecDirShooting,
static HSCRIPT_RC CreateFireBulletsInfo( int cShots, const Vector &vecSrc, const Vector &vecDirShooting,
const Vector &vecSpread, float iDamage, HSCRIPT pAttacker )
{
// The script is responsible for deleting this via DestroyFireBulletsInfo().
FireBulletsInfo_t *info = new FireBulletsInfo_t();
HSCRIPT hScript = g_pScriptVM->RegisterInstance( info );
HSCRIPT hScript = g_pScriptVM->RegisterInstance( info, true );
info->SetShots( cShots );
info->SetSource( vecSrc );
@ -494,14 +479,8 @@ static HSCRIPT CreateFireBulletsInfo( int cShots, const Vector &vecSrc, const Ve
return hScript;
}
static void DestroyFireBulletsInfo( HSCRIPT hBulletsInfo )
static void DestroyFireBulletsInfo( HSCRIPT )
{
FireBulletsInfo_t *pInfo = HScriptToClass< FireBulletsInfo_t >( hBulletsInfo );
if ( pInfo )
{
g_pScriptVM->RemoveInstance( hBulletsInfo );
delete pInfo;
}
}
//-----------------------------------------------------------------------------
@ -509,9 +488,7 @@ static void DestroyFireBulletsInfo( HSCRIPT hBulletsInfo )
//-----------------------------------------------------------------------------
CAnimEventTInstanceHelper g_AnimEventTInstanceHelper;
BEGIN_SCRIPTDESC_ROOT( scriptanimevent_t, "" )
DEFINE_SCRIPT_INSTANCE_HELPER( &g_AnimEventTInstanceHelper )
BEGIN_SCRIPTDESC_ROOT_WITH_HELPER( scriptanimevent_t, "", &g_AnimEventTInstanceHelper )
DEFINE_SCRIPTFUNC( GetEvent, "" )
DEFINE_SCRIPTFUNC( SetEvent, "" )
@ -535,7 +512,7 @@ bool CAnimEventTInstanceHelper::Get( void *p, const char *pszKey, ScriptVariant_
{
DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey );
animevent_t *ani = ((animevent_t *)p);
animevent_t *ani = &((scriptanimevent_t *)p)->event;
if (FStrEq( pszKey, "event" ))
variant = ani->event;
else if (FStrEq( pszKey, "options" ))
@ -558,18 +535,28 @@ bool CAnimEventTInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_
{
DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey );
animevent_t *ani = ((animevent_t *)p);
scriptanimevent_t *script_ani = ((scriptanimevent_t *)p);
animevent_t *ani = &script_ani->event;
if (FStrEq( pszKey, "event" ))
ani->event = variant;
{
return variant.AssignTo( &ani->event );
}
else if (FStrEq( pszKey, "options" ))
ani->options = variant;
{
char *szOptions;
if (!variant.AssignTo( &szOptions ))
{
return false;
}
script_ani->SetOptions( szOptions );
}
else if (FStrEq( pszKey, "cycle" ))
ani->cycle = variant;
return variant.AssignTo( &ani->cycle );
else if (FStrEq( pszKey, "eventtime" ))
ani->eventtime = variant;
return variant.AssignTo( &ani->eventtime );
else if (FStrEq( pszKey, "type" ))
ani->type = variant;
else if (FStrEq( pszKey, "source" ))
return variant.AssignTo( &ani->type );
else if (FStrEq( pszKey, "source" ) && variant.m_type == FIELD_HSCRIPT)
{
CBaseEntity *pEnt = ToEnt( variant.m_hScript );
if (pEnt)
@ -1046,14 +1033,14 @@ void RegisterSharedScriptFunctions()
#endif
ScriptRegisterFunction( g_pScriptVM, CreateDamageInfo, "" );
ScriptRegisterFunction( g_pScriptVM, DestroyDamageInfo, "" );
ScriptRegisterFunction( g_pScriptVM, DestroyDamageInfo, SCRIPT_HIDE );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateExplosiveDamageForce, "CalculateExplosiveDamageForce", "Fill out a damage info handle with a damage force for an explosive." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateBulletDamageForce, "CalculateBulletDamageForce", "Fill out a damage info handle with a damage force for a bullet impact." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateMeleeDamageForce, "CalculateMeleeDamageForce", "Fill out a damage info handle with a damage force for a melee impact." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGuessDamageForce, "GuessDamageForce", "Try and guess the physics force to use." );
ScriptRegisterFunction( g_pScriptVM, CreateFireBulletsInfo, "" );
ScriptRegisterFunction( g_pScriptVM, DestroyFireBulletsInfo, "" );
ScriptRegisterFunction( g_pScriptVM, DestroyFireBulletsInfo, SCRIPT_HIDE );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceLineComplex, "TraceLineComplex", "Complex version of TraceLine which takes 2 points, an ent to ignore, a trace mask, and a collision group. Returns a handle which can access all trace info." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceHullComplex, "TraceHullComplex", "Takes 2 points, min/max hull bounds, an ent to ignore, a trace mask, and a collision group to trace to a point using a hull. Returns a handle which can access all trace info." );
@ -1071,10 +1058,10 @@ void RegisterSharedScriptFunctions()
//
// Precaching
//
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheModel, "PrecacheModel", "Precaches a model for later usage." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheModel, "DoPrecacheModel", SCRIPT_ALIAS( "PrecacheModel", "Precaches a model for later usage." ) );
ScriptRegisterFunction( g_pScriptVM, PrecacheMaterial, "Precaches a material for later usage." );
ScriptRegisterFunction( g_pScriptVM, PrecacheParticleSystem, "Precaches a particle system for later usage." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheOther, "PrecacheOther", "Precaches an entity class for later usage." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheOther, "DoPrecacheOther", SCRIPT_ALIAS( "PrecacheOther", "Precaches an entity class for later usage." ) );
//
// NPCs

View File

@ -46,12 +46,14 @@ public:
class CSurfaceScriptHelper
{
public:
// This class is owned by CScriptGameTrace, and cannot be accessed without being initialised in CScriptGameTrace::RegisterSurface()
//CSurfaceScriptHelper() : m_pSurface(NULL), m_hSurfaceData(NULL) {}
CSurfaceScriptHelper() : m_pSurface(NULL), m_hSurfaceData(NULL) {}
~CSurfaceScriptHelper()
{
g_pScriptVM->RemoveInstance( m_hSurfaceData );
if ( m_hSurfaceData )
{
g_pScriptVM->RemoveInstance( m_hSurfaceData );
}
}
void Init( csurface_t *surf )
@ -98,16 +100,10 @@ class CScriptGameTrace : public CGameTrace
public:
CScriptGameTrace() : m_surfaceAccessor(NULL), m_planeAccessor(NULL)
{
m_hScriptInstance = g_pScriptVM->RegisterInstance( this );
}
~CScriptGameTrace()
{
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
}
if ( m_surfaceAccessor )
{
g_pScriptVM->RemoveInstance( m_surfaceAccessor );
@ -119,22 +115,6 @@ public:
}
}
void RegisterSurface()
{
m_surfaceHelper.Init( &surface );
m_surfaceAccessor = g_pScriptVM->RegisterInstance( &m_surfaceHelper );
}
void RegisterPlane()
{
m_planeAccessor = g_pScriptVM->RegisterInstance( &plane );
}
HSCRIPT GetScriptInstance() const
{
return m_hScriptInstance;
}
public:
float FractionLeftSolid() const { return fractionleftsolid; }
int HitGroup() const { return hitgroup; }
@ -154,15 +134,30 @@ public:
bool AllSolid() const { return allsolid; }
bool StartSolid() const { return startsolid; }
HSCRIPT Surface() const { return m_surfaceAccessor; }
HSCRIPT Plane() const { return m_planeAccessor; }
HSCRIPT Surface()
{
if ( !m_surfaceAccessor )
{
m_surfaceHelper.Init( &surface );
m_surfaceAccessor = g_pScriptVM->RegisterInstance( &m_surfaceHelper );
}
void Destroy() { delete this; }
return m_surfaceAccessor;
}
HSCRIPT Plane()
{
if ( !m_planeAccessor )
m_planeAccessor = g_pScriptVM->RegisterInstance( &plane );
return m_planeAccessor;
}
void Destroy() {}
private:
HSCRIPT m_surfaceAccessor;
HSCRIPT m_planeAccessor;
HSCRIPT m_hScriptInstance;
CSurfaceScriptHelper m_surfaceHelper;
@ -172,30 +167,47 @@ private:
//-----------------------------------------------------------------------------
// Exposes animevent_t to VScript
//-----------------------------------------------------------------------------
struct scriptanimevent_t : public animevent_t
struct scriptanimevent_t
{
int GetEvent() { return event; }
void SetEvent( int nEvent ) { event = nEvent; }
friend class CAnimEventTInstanceHelper;
const char *GetOptions() { return options; }
void SetOptions( const char *pOptions ) { options = pOptions; }
public:
scriptanimevent_t( animevent_t &event ) : event( event ), options( NULL ) { }
~scriptanimevent_t( ) { delete[] options; }
float GetCycle() { return cycle; }
void SetCycle( float flCycle ) { cycle = flCycle; }
int GetEvent() { return event.event; }
void SetEvent( int nEvent ) { event.event = nEvent; }
float GetEventTime() { return eventtime; }
void SetEventTime( float flEventTime ) { eventtime = flEventTime; }
const char *GetOptions() { return event.options; }
void SetOptions( const char *pOptions )
{
size_t len = strlen( pOptions );
delete[] options;
event.options = options = new char[len + 1];
memcpy( options, pOptions, len + 1 );
}
int GetType() { return type; }
void SetType( int nType ) { eventtime = type; }
float GetCycle() { return event.cycle; }
void SetCycle( float flCycle ) { event.cycle = flCycle; }
HSCRIPT GetSource() { return ToHScript( pSource ); }
float GetEventTime() { return event.eventtime; }
void SetEventTime( float flEventTime ) { event.eventtime = flEventTime; }
int GetType() { return event.type; }
void SetType( int nType ) { event.type = nType; }
HSCRIPT GetSource() { return ToHScript( event.pSource ); }
void SetSource( HSCRIPT hSource )
{
CBaseEntity *pEnt = ToEnt( hSource );
if (pEnt)
pSource = pEnt->GetBaseAnimating();
event.pSource = pEnt->GetBaseAnimating();
}
private:
animevent_t &event;
// storage for ScriptVariant_t string, which may be temporary
char *options;
};
class CAnimEventTInstanceHelper : public IScriptInstanceHelper

View File

@ -2920,7 +2920,7 @@ int CScriptGameEventListener::ListenToGameEvent( const char* szEvent, HSCRIPT hF
if ( bValid )
{
m_iContextHash = HashContext( szContext );
m_hCallback = hFunc;
m_hCallback = g_pScriptVM->CopyObject( hFunc );
m_bActive = true;
s_Listeners.AddToTail( this );
@ -3247,7 +3247,7 @@ public:
// NOTE: These two functions are new with Mapbase and have no Valve equivalent
static bool KeyValuesWrite( const char *szFile, HSCRIPT hInput );
static HSCRIPT KeyValuesRead( const char *szFile );
static HSCRIPT_RC KeyValuesRead( const char *szFile );
void LevelShutdownPostEntity()
{
@ -3433,7 +3433,7 @@ bool CScriptReadWriteFile::KeyValuesWrite( const char *szFile, HSCRIPT hInput )
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
HSCRIPT CScriptReadWriteFile::KeyValuesRead( const char *szFile )
HSCRIPT_RC CScriptReadWriteFile::KeyValuesRead( const char *szFile )
{
char pszFullName[MAX_PATH];
V_snprintf( pszFullName, sizeof(pszFullName), SCRIPT_RW_FULL_PATH_FMT, szFile );
@ -3458,7 +3458,7 @@ HSCRIPT CScriptReadWriteFile::KeyValuesRead( const char *szFile )
return NULL;
}
HSCRIPT hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pKV, true ); // bAllowDestruct is supposed to automatically remove the involved KV
HSCRIPT hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pKV );
return hScript;
}
@ -4609,9 +4609,9 @@ public:
CScriptConCommand( const char *name, HSCRIPT fn, const char *helpString, int flags, ConCommand *pLinked = NULL )
: BaseClass( name, this, helpString, flags, 0 ),
m_pLinked(pLinked),
m_hCallback(fn),
m_hCompletionCallback(NULL)
{
m_hCallback = g_pScriptVM->CopyObject( fn );
m_nCmdNameLen = V_strlen(name) + 1;
Assert( m_nCmdNameLen - 1 <= 128 );
}
@ -4701,7 +4701,7 @@ public:
BaseClass::m_pCommandCompletionCallback = this;
BaseClass::m_bHasCompletionCallback = true;
m_hCompletionCallback = fn;
m_hCompletionCallback = g_pScriptVM->CopyObject( fn );
}
else
{
@ -4720,7 +4720,8 @@ public:
if ( m_hCallback )
g_pScriptVM->ReleaseScript( m_hCallback );
m_hCallback = fn;
m_hCallback = g_pScriptVM->CopyObject( fn );
}
else
{
@ -4781,7 +4782,7 @@ public:
if (fn)
{
m_hCallback = fn;
m_hCallback = g_pScriptVM->CopyObject( fn );
BaseClass::InstallChangeCallback( (FnChangeCallback_t)ScriptConVarCallback );
}
else

View File

@ -60,6 +60,7 @@ public:
bool IsPredicted( void ) const { return m_iszClientScripts[0] != '\0'; }
const char* GetWeaponScriptName() { return m_iszWeaponScriptName[0] != '\0' ? m_iszWeaponScriptName : BaseClass::GetWeaponScriptName(); }
const char* GetName() const { return m_iszWeaponScriptName[0] != '\0' ? STRING( m_iClassname ) : BaseClass::GetName(); }
// Weapon selection
bool HasAnyAmmo( void ); // Returns true is weapon has ammo

View File

@ -33,6 +33,8 @@ END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CTakeDamageInfo, "Damage information handler." )
DEFINE_SCRIPT_REFCOUNTED_INSTANCE()
DEFINE_SCRIPTFUNC_NAMED( ScriptGetInflictor, "GetInflictor", "Gets the inflictor." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetInflictor, "SetInflictor", "Sets the inflictor." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetWeapon, "GetWeapon", "Gets the weapon." )
@ -590,4 +592,4 @@ void CTakeDamageInfo::DebugGetDamageTypeString(unsigned int damageType, char *ou
#define DMG_BLAST_SURFACE (1<<27) // A blast on the surface of water that cannot harm things underwater
#define DMG_DIRECT (1<<28)
#define DMG_BUCKSHOT (1<<29) // not quite a bullet. Little, rounder, different.
*/
*/

View File

@ -37,6 +37,7 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
#ifdef MAPBASE_VSCRIPT
// This is to ensure a dependency exists between the vscript library and the game DLLs
extern int vscript_token;
extern int vscript_debugger_port;
int vscript_token_hack = vscript_token;
#endif
@ -390,12 +391,30 @@ CON_COMMAND_F( script_debug, "Connect the vscript VM to the script debugger", FC
if ( !IsCommandIssuedByServerAdmin() )
return;
#ifdef MAPBASE_VSCRIPT
#ifdef GAME_DLL
int port = 1212;
#else
int port = 1213;
#endif
#endif
if ( !g_pScriptVM )
{
#ifdef MAPBASE_VSCRIPT
vscript_debugger_port = port;
CGMsg( 0, CON_GROUP_VSCRIPT, "VScript VM is not running, waiting for it to attach the debugger to port %d...\n", port );
#else
CGWarning( 0, CON_GROUP_VSCRIPT, "Scripting disabled or no server running\n" );
#endif
return;
}
#ifdef MAPBASE_VSCRIPT
g_pScriptVM->ConnectDebugger( port );
#else
g_pScriptVM->ConnectDebugger();
#endif
}
#ifdef CLIENT_DLL
@ -507,7 +526,7 @@ void RunAutorunScripts()
//-----------------------------------------------------------------------------
static short VSCRIPT_SERVER_SAVE_RESTORE_VERSION = 2;
static short VSCRIPT_SERVER_SAVE_RESTORE_VERSION = 3;
//-----------------------------------------------------------------------------

View File

@ -21,12 +21,16 @@ inline bool VScriptRunScript( const char *pszScriptName, bool bWarnMissing = fal
#define DECLARE_ENT_SCRIPTDESC() ALLOW_SCRIPT_ACCESS(); virtual ScriptClassDesc_t *GetScriptDesc()
#define BEGIN_ENT_SCRIPTDESC( className, baseClass, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC( className, baseClass, description )
#define BEGIN_ENT_SCRIPTDESC_ROOT( className, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT( className, description )
#define BEGIN_ENT_SCRIPTDESC_NAMED( className, baseClass, scriptName, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_NAMED( className, baseClass, scriptName, description )
#define BEGIN_ENT_SCRIPTDESC_ROOT_NAMED( className, scriptName, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT_NAMED( className, scriptName, description )
#define BEGIN_ENT_SCRIPTDESC( className, baseClass, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC( className, baseClass, description )
#define BEGIN_ENT_SCRIPTDESC_WITH_HELPER( className, baseClass, description, helper ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_WITH_HELPER( className, baseClass, description, helper )
#define BEGIN_ENT_SCRIPTDESC_ROOT( className, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT( className, description )
#define BEGIN_ENT_SCRIPTDESC_ROOT_WITH_HELPER( className, description, helper ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT_WITH_HELPER( className, description, helper )
#define BEGIN_ENT_SCRIPTDESC_NAMED( className, baseClass, scriptName, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_NAMED( className, baseClass, scriptName, description )
#define BEGIN_ENT_SCRIPTDESC_NAMED_WITH_HELPER( className, baseClass, scriptName, description, helper ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_NAMED_WITH_HELPER( className, baseClass, scriptName, description, helper )
#define BEGIN_ENT_SCRIPTDESC_ROOT_NAMED( className, scriptName, description ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT_NAMED( className, scriptName, description )
#define BEGIN_ENT_SCRIPTDESC_ROOT_NAMED_WITH_HELPER( className, scriptName, description, helper ) _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ); BEGIN_SCRIPTDESC_ROOT_NAMED_WITH_HELPER( className, scriptName, description, helper )
#define _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ) template <> ScriptClassDesc_t * GetScriptDesc<className>( className * ); ScriptClassDesc_t *className::GetScriptDesc() { return ::GetScriptDesc( this ); }
#define _IMPLEMENT_ENT_SCRIPTDESC_ACCESSOR( className ) template <> ScriptClassDesc_t * GetScriptDesc<className>( className *, bool ); ScriptClassDesc_t *className::GetScriptDesc() { return ::GetScriptDesc( this ); }
// Only allow scripts to create entities during map initialization
bool IsEntityCreationAllowedInScripts( void );

View File

@ -767,16 +767,7 @@ void DrawSkin_DX9_Internal( CBaseVSShader *pShader, IMaterialVar** params, IShad
pShader->SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, info.m_nBaseTextureTransform );
#ifdef MAPBASE
// The original code makes it seem like we have the opportunity to support both $bumptransform and $detail at the same time,
// and that may or may not have been Valve's intention, but we'd need to add another texcoord for this and it's already
// a limitation with the non-skin shader anyway.
if ( bHasBump )
{
pShader->SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_4, info.m_nBumpTransform );
}
else
#else
#ifndef MAPBASE // See below
if( bHasBump )
{
pShader->SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, info.m_nBumpTransform );
@ -794,6 +785,15 @@ void DrawSkin_DX9_Internal( CBaseVSShader *pShader, IMaterialVar** params, IShad
info.m_nBaseTextureTransform,
info.m_nDetailScale );
}
#ifdef MAPBASE
// The original code makes it seem like we have the opportunity to support both $bumptransform and $detail at the same time,
// and that may or may not have been Valve's intention, but we'd need to add another texcoord for this and it's already
// a limitation with the non-skin shader anyway.
else if ( bHasBump )
{
pShader->SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_4, info.m_nBumpTransform );
}
#endif
pShader->SetModulationPixelShaderDynamicState_LinearColorSpace( 1 );
pShader->SetPixelShaderConstant_W( PSREG_SELFILLUMTINT, info.m_nSelfIllumTint, fBlendFactor );

View File

@ -49,6 +49,14 @@ BEGIN_VS_SHADER( SDK_Cable_DX9, "Help for SplineRope" )
{
bool bShaderSrgbRead = ( IsX360() && params[SHADERSRGBREAD360]->GetIntValue() );
bool bShadowDepth = ( params[SHADOWDEPTH]->GetIntValue() != 0 );
#ifdef MAPBASE
BlendType_t nBlendType = EvaluateBlendRequirements( BASETEXTURE, true );
bool bFullyOpaque = (nBlendType != BT_BLENDADD) && (nBlendType != BT_BLEND) && !IS_FLAG_SET( MATERIAL_VAR_ALPHATEST ); //dest alpha is free for special use
#else
bool bFullyOpaque = true;
#endif
SHADOW_STATE
{
// draw back-facing because of yaw spin
@ -65,8 +73,19 @@ BEGIN_VS_SHADER( SDK_Cable_DX9, "Help for SplineRope" )
}
else
{
#ifdef MAPBASE
if (IS_FLAG_SET( MATERIAL_VAR_TRANSLUCENT ))
{
pShaderShadow->EnableDepthWrites( false );
pShaderShadow->EnableBlending( true );
pShaderShadow->BlendFunc( SHADER_BLEND_SRC_ALPHA, SHADER_BLEND_ONE_MINUS_SRC_ALPHA );
}
pShaderShadow->EnableAlphaTest( IS_FLAG_SET( MATERIAL_VAR_ALPHATEST ) );
#endif
// We need to write to dest alpha for depth feathering.
pShaderShadow->EnableAlphaWrites( true );
pShaderShadow->EnableAlphaWrites( bFullyOpaque );
// base texture
pShaderShadow->EnableTexture( SHADER_SAMPLER0, true );
@ -150,7 +169,7 @@ BEGIN_VS_SHADER( SDK_Cable_DX9, "Help for SplineRope" )
if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
{
DECLARE_DYNAMIC_PIXEL_SHADER( sdk_splinerope_ps20b );
SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITE_DEPTH_TO_DESTALPHA, pShaderAPI->ShouldWriteDepthToDestAlpha() );
SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITE_DEPTH_TO_DESTALPHA, bFullyOpaque && pShaderAPI->ShouldWriteDepthToDestAlpha() );
//SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetSceneFogMode() == MATERIAL_FOG_LINEAR_BELOW_FOG_Z );
SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() );
SET_DYNAMIC_PIXEL_SHADER( sdk_splinerope_ps20b );

View File

@ -99,6 +99,7 @@ namespace ResponseRules
#ifdef MAPBASE
RESPONSE_VSCRIPT, // Run VScript code
RESPONSE_VSCRIPT_FILE, // Run a VScript file (bypasses ugliness and character limits when just using IncludeScript() with RESPONSE_VSCRIPT)
RESPONSE_CHOREOSENTENCE, // Sentences put together as VCDs, see choreosentence.h for more information
#endif
NUM_RESPONSES,

View File

@ -141,6 +141,20 @@ class KeyValues;
DECLARE_POINTER_HANDLE( HSCRIPT );
#define INVALID_HSCRIPT ((HSCRIPT)-1)
// Reference counted HSCRIPT return value
//
// This is an alias for HSCRIPT that is converted back to HSCRIPT on return
// from vscript function bindings; it signals the vscript implementation to
// release its hold and let the script control the lifetime
// of the registered instance.
struct HSCRIPT_RC
{
HSCRIPT val;
HSCRIPT_RC( HSCRIPT v ) { val = v; }
HSCRIPT operator=( HSCRIPT v ) { val = v; return val; }
operator HSCRIPT() { return val; }
};
typedef unsigned int HScriptRaw;
#endif
@ -162,7 +176,7 @@ public:
virtual void DestroyVM( IScriptVM * ) = 0;
#ifdef MAPBASE_VSCRIPT
virtual HSCRIPT CreateScriptKeyValues( IScriptVM *pVM, KeyValues *pKV, bool bAllowDestruct ) = 0;
virtual HSCRIPT CreateScriptKeyValues( IScriptVM *pVM, KeyValues *pKV, bool bBorrow = false ) = 0;
virtual KeyValues *GetKeyValuesFromScriptKV( IScriptVM *pVM, HSCRIPT hSKV ) = 0;
#endif
};
@ -177,6 +191,9 @@ enum ExtendedFieldType
FIELD_CSTRING,
FIELD_HSCRIPT,
FIELD_VARIANT,
#ifdef MAPBASE_VSCRIPT
FIELD_HSCRIPT_RC,
#endif
};
typedef int ScriptDataType_t;
@ -197,6 +214,7 @@ DECLARE_DEDUCE_FIELDTYPE( FIELD_CHARACTER, char );
DECLARE_DEDUCE_FIELDTYPE( FIELD_HSCRIPT, HSCRIPT );
DECLARE_DEDUCE_FIELDTYPE( FIELD_VARIANT, ScriptVariant_t );
#ifdef MAPBASE_VSCRIPT
DECLARE_DEDUCE_FIELDTYPE( FIELD_HSCRIPT_RC, HSCRIPT_RC );
DECLARE_DEDUCE_FIELDTYPE( FIELD_VECTOR, QAngle );
DECLARE_DEDUCE_FIELDTYPE( FIELD_VECTOR, const QAngle& );
#endif
@ -298,9 +316,13 @@ struct ScriptMemberDesc_t
enum ScriptFuncBindingFlags_t
{
SF_MEMBER_FUNC = 0x01,
#ifdef MAPBASE_VSCRIPT
SF_REFCOUNTED_RET = 0x02,
#endif
};
typedef bool (*ScriptBindingFunc_t)( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn );
union ScriptVariantTemporaryStorage_t;
typedef bool (*ScriptBindingFunc_t)( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage );
struct ScriptFunctionBinding_t
{
@ -321,11 +343,6 @@ public:
#ifdef MAPBASE_VSCRIPT
virtual bool Get( void *p, const char *pszKey, ScriptVariant_t &variant ) { return false; }
virtual bool Set( void *p, const char *pszKey, ScriptVariant_t &variant ) { return false; }
virtual ScriptVariant_t *Add( void *p, ScriptVariant_t &variant ) { return NULL; }
virtual ScriptVariant_t *Subtract( void *p, ScriptVariant_t &variant ) { return NULL; }
virtual ScriptVariant_t *Multiply( void *p, ScriptVariant_t &variant ) { return NULL; }
virtual ScriptVariant_t *Divide( void *p, ScriptVariant_t &variant ) { return NULL; }
#endif
};
@ -360,6 +377,7 @@ struct ScriptClassDesc_t
IScriptInstanceHelper * pHelper; // optional helper
#ifdef MAPBASE_VSCRIPT
public:
static CUtlVector<ScriptClassDesc_t*>& AllClassesDesc()
{
static CUtlVector<ScriptClassDesc_t*> classes;
@ -389,13 +407,17 @@ struct ScriptVariant_t
ScriptVariant_t( bool val ) : m_flags( 0 ), m_type( FIELD_BOOLEAN ) { m_bool = val; }
ScriptVariant_t( HSCRIPT val ) : m_flags( 0 ), m_type( FIELD_HSCRIPT ) { m_hScript = val; }
ScriptVariant_t( const Vector &val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pVector = &val; } else { m_pVector = new Vector( val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const Vector *val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pVector = val; } else { m_pVector = new Vector( *val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const char *val , bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_CSTRING ) { if ( !bCopy ) { m_pszString = val; } else { m_pszString = strdup( val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const Vector &val ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { m_pVector = &val; }
ScriptVariant_t( const Vector *val ) : ScriptVariant_t( *val ) { }
ScriptVariant_t( const char *val ) : m_flags( 0 ), m_type( FIELD_CSTRING ) { m_pszString = val; }
#ifdef MAPBASE_VSCRIPT
ScriptVariant_t( const QAngle &val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pAngle = &val; } else { m_pAngle = new QAngle( val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const QAngle *val, bool bCopy = false ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { if ( !bCopy ) { m_pAngle = val; } else { m_pAngle = new QAngle( *val ); m_flags |= SV_FREE; } }
ScriptVariant_t( const QAngle &val ) : m_flags( 0 ), m_type( FIELD_VECTOR ) { m_pAngle = &val; }
ScriptVariant_t( const QAngle *val ) : ScriptVariant_t( *val ) { }
ScriptVariant_t( Vector &&val ) = delete;
ScriptVariant_t( QAngle &&val ) = delete;
#endif
bool IsNull() const { return (m_type == FIELD_VOID ); }
@ -403,74 +425,41 @@ struct ScriptVariant_t
operator int() const { Assert( m_type == FIELD_INTEGER ); return m_int; }
operator float() const { Assert( m_type == FIELD_FLOAT ); return m_float; }
operator const char *() const { Assert( m_type == FIELD_CSTRING ); return ( m_pszString ) ? m_pszString : ""; }
operator const Vector &() const { Assert( m_type == FIELD_VECTOR ); static Vector vecNull(0, 0, 0); return (m_pVector) ? *m_pVector : vecNull; }
operator const Vector &() const { Assert( m_type == FIELD_VECTOR ); return (m_pVector) ? *m_pVector : vec3_origin; }
operator char() const { Assert( m_type == FIELD_CHARACTER ); return m_char; }
operator bool() const { Assert( m_type == FIELD_BOOLEAN ); return m_bool; }
operator HSCRIPT() const { Assert( m_type == FIELD_HSCRIPT ); return m_hScript; }
#ifdef MAPBASE_VSCRIPT
operator const QAngle &() const { Assert( m_type == FIELD_VECTOR ); static QAngle vecNull(0, 0, 0); return (m_pAngle) ? *m_pAngle : vecNull; }
operator const QAngle &() const { Assert( m_type == FIELD_VECTOR ); return (m_pAngle) ? *m_pAngle : vec3_angle; }
#endif
void operator=( int i ) { m_type = FIELD_INTEGER; m_int = i; }
void operator=( float f ) { m_type = FIELD_FLOAT; m_float = f; }
void operator=( double f ) { m_type = FIELD_FLOAT; m_float = (float)f; }
void operator=( const Vector &vec ) { m_type = FIELD_VECTOR; m_pVector = &vec; }
void operator=( const Vector *vec ) { m_type = FIELD_VECTOR; m_pVector = vec; }
void operator=( const char *psz ) { m_type = FIELD_CSTRING; m_pszString = psz; }
void operator=( char c ) { m_type = FIELD_CHARACTER; m_char = c; }
void operator=( bool b ) { m_type = FIELD_BOOLEAN; m_bool = b; }
void operator=( HSCRIPT h ) { m_type = FIELD_HSCRIPT; m_hScript = h; }
void operator=( int i ) { m_type = FIELD_INTEGER; m_flags = 0; m_int = i; }
void operator=( float f ) { m_type = FIELD_FLOAT; m_flags = 0; m_float = f; }
void operator=( double f ) { m_type = FIELD_FLOAT; m_flags = 0; m_float = (float)f; }
void operator=( const Vector &vec ) { m_type = FIELD_VECTOR; m_flags = 0; m_pVector = &vec; }
void operator=( const Vector *vec ) { m_type = FIELD_VECTOR; m_flags = 0; m_pVector = vec; }
void operator=( const char *psz ) { m_type = FIELD_CSTRING; m_flags = 0; m_pszString = psz; }
void operator=( char c ) { m_type = FIELD_CHARACTER; m_flags = 0; m_char = c; }
void operator=( bool b ) { m_type = FIELD_BOOLEAN; m_flags = 0; m_bool = b; }
void operator=( HSCRIPT h ) { m_type = FIELD_HSCRIPT; m_flags = 0; m_hScript = h; }
#ifdef MAPBASE_VSCRIPT
void operator=( const QAngle &vec ) { m_type = FIELD_VECTOR; m_pAngle = &vec; }
void operator=( const QAngle *vec ) { m_type = FIELD_VECTOR; m_pAngle = vec; }
void operator=( const QAngle &ang ) { m_type = FIELD_VECTOR; m_flags = 0; m_pAngle = &ang; }
void operator=( const QAngle *ang ) { m_type = FIELD_VECTOR; m_flags = 0; m_pAngle = ang; }
void operator=( Vector &&vec ) = delete;
void operator=( QAngle &&ang ) = delete;
#endif
void Free() { if ( ( m_flags & SV_FREE ) && ( m_type == FIELD_HSCRIPT || m_type == FIELD_VECTOR || m_type == FIELD_CSTRING ) ) delete m_pszString; } // Generally only needed for return results
template <typename T>
T Get()
void Free()
{
T value;
AssignTo( &value );
return value;
}
template <typename T>
bool AssignTo( T *pDest )
{
ScriptDataType_t destType = ScriptDeduceType( T );
if ( destType == FIELD_TYPEUNKNOWN )
// Generally only needed for return results
if ( ! ( m_flags & SV_FREE ) )
{
DevWarning( "Unable to convert script variant to unknown type\n" );
}
if ( destType == m_type )
{
*pDest = *this;
return true;
return;
}
if ( m_type != FIELD_VECTOR && m_type != FIELD_CSTRING && destType != FIELD_VECTOR && destType != FIELD_CSTRING )
{
switch ( m_type )
{
case FIELD_VOID: *pDest = 0; break;
case FIELD_INTEGER: *pDest = m_int; return true;
case FIELD_FLOAT: *pDest = m_float; return true;
case FIELD_CHARACTER: *pDest = m_char; return true;
case FIELD_BOOLEAN: *pDest = m_bool; return true;
case FIELD_HSCRIPT: *pDest = m_hScript; return true;
}
}
else
{
DevWarning( "No free conversion of %s script variant to %s right now\n",
ScriptFieldTypeName( m_type ), ScriptFieldTypeName<T>() );
if ( destType != FIELD_VECTOR )
{
*pDest = 0;
}
}
return false;
AssertMsg( m_type == FIELD_CSTRING || m_type == FIELD_VECTOR, "Don't know how to free script variant of type %d", m_type );
free( (void*)m_pszString );
}
bool AssignTo( float *pDest )
@ -525,25 +514,38 @@ struct ScriptVariant_t
bool AssignTo( ScriptVariant_t *pDest )
{
pDest->Free();
pDest->m_type = m_type;
if ( m_type == FIELD_VECTOR )
if ( m_flags & SV_FREE )
{
pDest->m_pVector = new Vector;
((Vector *)(pDest->m_pVector))->Init( m_pVector->x, m_pVector->y, m_pVector->z );
pDest->m_flags |= SV_FREE;
}
else if ( m_type == FIELD_CSTRING )
{
pDest->m_pszString = strdup( m_pszString );
pDest->m_flags |= SV_FREE;
if ( m_type == FIELD_VECTOR )
{
pDest->m_pVector = (Vector*)malloc( sizeof( Vector ) );
pDest->EmplaceAllocedVector( *m_pVector );
m_flags |= SV_FREE;
}
else if ( m_type == FIELD_CSTRING )
{
pDest->m_pszString = strdup( m_pszString );
pDest->m_flags |= SV_FREE;
}
else
{
Assert( false );
pDest->m_int = m_int;
pDest->m_flags &= ~SV_FREE;
}
}
else
{
pDest->m_int = m_int;
pDest->m_flags &= ~SV_FREE;
}
return false;
}
void EmplaceAllocedVector( const Vector &vec );
union
{
int m_int;
@ -565,8 +567,25 @@ struct ScriptVariant_t
private:
};
#include "tier0/memdbgoff.h"
inline void ScriptVariant_t::EmplaceAllocedVector( const Vector &vec )
{
new ( (Vector*)m_pVector ) Vector( vec );
}
#include "tier0/memdbgon.h"
#define SCRIPT_VARIANT_NULL ScriptVariant_t()
union ScriptVariantTemporaryStorage_t
{
// members must be initialized via placement-new
ScriptVariantTemporaryStorage_t() { }
// members must have trivial destructor, since no destructor will be invoked
Vector m_vec;
QAngle m_ang;
};
#ifdef MAPBASE_VSCRIPT
//---------------------------------------------------------
struct ScriptConstantBinding_t
@ -618,6 +637,15 @@ struct ScriptEnumDesc_t
#define ScriptInitMemberFunctionBindingNamed( pScriptFunction, class, func, scriptName ) ScriptInitMemberFunctionBinding_( pScriptFunction, class, func, scriptName )
#define ScriptInitMemberFunctionBinding_( pScriptFunction, class, func, scriptName ) do { ScriptInitMemberFuncDescriptor_( (&(pScriptFunction)->m_desc), class, func, scriptName ); (pScriptFunction)->m_pfnBinding = ScriptCreateBinding( ((class *)0), &class::func ); (pScriptFunction)->m_pFunction = ScriptConvertFuncPtrToVoid( &class::func ); (pScriptFunction)->m_flags = SF_MEMBER_FUNC; } while (0)
#ifdef MAPBASE_VSCRIPT
// Convert HSCRIPT_RC return type into HSCRIPT return with SF_REFCOUNTED_RET binding flag
#undef ScriptInitFunctionBindingNamed
#define ScriptInitFunctionBindingNamed( pScriptFunction, func, scriptName ) do { ScriptInitFuncDescriptorNamed( (&(pScriptFunction)->m_desc), func, scriptName ); (pScriptFunction)->m_pfnBinding = ScriptCreateBinding( &func ); (pScriptFunction)->m_pFunction = (void *)&func; if ( (pScriptFunction)->m_desc.m_ReturnType == FIELD_HSCRIPT_RC ) { (pScriptFunction)->m_desc.m_ReturnType = FIELD_HSCRIPT; (pScriptFunction)->m_flags |= SF_REFCOUNTED_RET; } } while (0)
#undef ScriptInitMemberFunctionBinding_
#define ScriptInitMemberFunctionBinding_( pScriptFunction, class, func, scriptName ) do { ScriptInitMemberFuncDescriptor_( (&(pScriptFunction)->m_desc), class, func, scriptName ); (pScriptFunction)->m_pfnBinding = ScriptCreateBinding( ((class *)0), &class::func ); (pScriptFunction)->m_pFunction = ScriptConvertFuncPtrToVoid( &class::func ); (pScriptFunction)->m_flags = SF_MEMBER_FUNC; if ( (pScriptFunction)->m_desc.m_ReturnType == FIELD_HSCRIPT_RC ) { (pScriptFunction)->m_desc.m_ReturnType = FIELD_HSCRIPT; (pScriptFunction)->m_flags |= SF_REFCOUNTED_RET; } } while (0)
#endif
#define ScriptInitClassDesc( pClassDesc, class, pBaseClassDesc ) ScriptInitClassDescNamed( pClassDesc, class, pBaseClassDesc, #class )
#define ScriptInitClassDescNamed( pClassDesc, class, pBaseClassDesc, scriptName ) ScriptInitClassDescNamed_( pClassDesc, class, pBaseClassDesc, scriptName )
#define ScriptInitClassDescNoBase( pClassDesc, class ) ScriptInitClassDescNoBaseNamed( pClassDesc, class, #class )
@ -659,7 +687,7 @@ static inline int ToConstantVariant(int value)
// This is used for registering variants (particularly vectors) not tied to existing variables.
// The principal difference is that m_data is initted with bCopy set to true.
#define ScriptRegisterConstantFromTemp( pVM, constant, description ) ScriptRegisterConstantFromTempNamed( pVM, constant, #constant, description )
#define ScriptRegisterConstantFromTempNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ScriptVariant_t( constant, true ); pVM->RegisterConstant( &binding ); } while (0)
#define ScriptRegisterConstantFromTempNamed( pVM, constant, scriptName, description ) do { static const auto constantStorage = constant; static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ScriptVariant_t( constantStorage ); pVM->RegisterConstant( &binding ); } while (0)
//-----------------------------------------------------------------------------
//
@ -697,37 +725,48 @@ static inline int ToConstantVariant(int value)
//
//-----------------------------------------------------------------------------
#define ALLOW_SCRIPT_ACCESS() template <typename T> friend ScriptClassDesc_t *GetScriptDesc(T *);
#define ALLOW_SCRIPT_ACCESS() template <typename T> friend ScriptClassDesc_t *GetScriptDesc(T *, bool);
#define BEGIN_SCRIPTDESC( className, baseClass, description ) BEGIN_SCRIPTDESC_NAMED( className, baseClass, #className, description )
#define BEGIN_SCRIPTDESC_ROOT( className, description ) BEGIN_SCRIPTDESC_ROOT_NAMED( className, #className, description )
#define BEGIN_SCRIPTDESC( className, baseClass, description ) BEGIN_SCRIPTDESC_WITH_HELPER( className, baseClass, description, NULL )
#define BEGIN_SCRIPTDESC_WITH_HELPER( className, baseClass, description, helper ) BEGIN_SCRIPTDESC_NAMED_WITH_HELPER( className, baseClass, #className, description, helper )
#define BEGIN_SCRIPTDESC_ROOT( className, description ) BEGIN_SCRIPTDESC_ROOT_WITH_HELPER( className, description, NULL )
#define BEGIN_SCRIPTDESC_ROOT_WITH_HELPER( className, description, helper ) BEGIN_SCRIPTDESC_ROOT_NAMED_WITH_HELPER( className, #className, description, helper )
#define BEGIN_SCRIPTDESC_NAMED( className, baseClass, scriptName, description ) \
template <> ScriptClassDesc_t* GetScriptDesc<baseClass>(baseClass*); \
template <> ScriptClassDesc_t* GetScriptDesc<className>(className*); \
ScriptClassDesc_t & g_##className##_ScriptDesc = *GetScriptDesc<className>(nullptr); \
template <> ScriptClassDesc_t* GetScriptDesc<className>(className*) \
#define BEGIN_SCRIPTDESC_NAMED_WITH_HELPER( className, baseClass, scriptName, description, helper ) \
template <> ScriptClassDesc_t* GetScriptDesc<baseClass>(baseClass*, bool); \
template <> ScriptClassDesc_t* GetScriptDesc<className>(className*, bool); \
ScriptClassDesc_t & g_##className##_ScriptDesc = *GetScriptDesc<className>(nullptr, true); \
template <> ScriptClassDesc_t* GetScriptDesc<className>(className*, bool init) \
{ \
static ScriptClassDesc_t g_##className##_ScriptDesc; \
typedef className _className; \
ScriptClassDesc_t *pDesc = &g_##className##_ScriptDesc; \
if (pDesc->m_pszClassname) return pDesc; \
pDesc->m_pszDescription = description; \
ScriptInitClassDescNamed( pDesc, className, GetScriptDescForClass( baseClass ), scriptName ); \
ScriptClassDesc_t *pInstanceHelperBase = pDesc->m_pBaseDesc; \
while ( pInstanceHelperBase ) \
if (!pDesc->m_pszClassname) \
{ \
if ( pInstanceHelperBase->pHelper ) \
pDesc->m_pszDescription = description; \
ScriptClassDesc_t *pBaseDesc = GetScriptDescForClass( baseClass ); \
ScriptInitClassDescNamed( pDesc, className, pBaseDesc, scriptName ); \
pDesc->pHelper = helper; \
if ( !pDesc->pHelper ) \
{ \
pDesc->pHelper = pInstanceHelperBase->pHelper; \
break; \
while ( pBaseDesc ) \
{ \
if ( pBaseDesc->pHelper ) \
{ \
pDesc->pHelper = pBaseDesc->pHelper; \
break; \
} \
pBaseDesc = pBaseDesc->m_pBaseDesc; \
} \
} \
pInstanceHelperBase = pInstanceHelperBase->m_pBaseDesc; \
}
} \
if (!init) return pDesc;
#define BEGIN_SCRIPTDESC_ROOT_NAMED( className, scriptName, description ) \
BEGIN_SCRIPTDESC_NAMED( className, ScriptNoBase_t, scriptName, description )
BEGIN_SCRIPTDESC_ROOT_NAMED_WITH_HELPER( className, scriptName, description, NULL )
#define BEGIN_SCRIPTDESC_ROOT_NAMED_WITH_HELPER( className, scriptName, description, helper ) \
BEGIN_SCRIPTDESC_NAMED_WITH_HELPER( className, ScriptNoBase_t, scriptName, description, helper )
#define END_SCRIPTDESC() \
return pDesc; \
@ -736,9 +775,13 @@ static inline int ToConstantVariant(int value)
#define DEFINE_SCRIPTFUNC( func, description ) DEFINE_SCRIPTFUNC_NAMED( func, #func, description )
#define DEFINE_SCRIPTFUNC_NAMED( func, scriptName, description ) ScriptAddFunctionToClassDescNamed( pDesc, _className, func, scriptName, description );
#define DEFINE_SCRIPT_CONSTRUCTOR() ScriptAddConstructorToClassDesc( pDesc, _className );
#define DEFINE_SCRIPT_INSTANCE_HELPER( p ) pDesc->pHelper = (p);
#define DEFINE_SCRIPT_INSTANCE_HELPER( p ) MUST_USE_BEGIN_SCRIPTDESC_WITH_HELPER_INSTEAD
#ifdef MAPBASE_VSCRIPT
// Allow instance to be deleted but not constructed
// Not needed if the class has a constructor
#define DEFINE_SCRIPT_REFCOUNTED_INSTANCE() do { pDesc->m_pfnDestruct = &CScriptConstructor<_className>::Destruct; } while (0);
// Use this for hooks which have no parameters
#define DEFINE_SIMPLE_SCRIPTHOOK( hook, hookName, returnType, description ) \
if (!hook.m_bDefined) \
@ -781,10 +824,10 @@ static inline int ToConstantVariant(int value)
do { ScriptMemberDesc_t *pBinding = &((pDesc)->m_Members[(pDesc)->m_Members.AddToTail()]); pBinding->m_pszScriptName = varName; pBinding->m_pszDescription = description; pBinding->m_ReturnType = returnType; } while (0);
#endif
template <typename T> ScriptClassDesc_t *GetScriptDesc(T *);
template <typename T> ScriptClassDesc_t *GetScriptDesc(T *, bool = false);
struct ScriptNoBase_t;
template <> inline ScriptClassDesc_t *GetScriptDesc<ScriptNoBase_t>( ScriptNoBase_t *) { return NULL; }
template <> inline ScriptClassDesc_t *GetScriptDesc<ScriptNoBase_t>( ScriptNoBase_t *, bool ) { return NULL; }
#define GetScriptDescForClass( className ) GetScriptDesc( ( className *)NULL )
@ -838,7 +881,11 @@ public:
virtual bool Init() = 0;
virtual void Shutdown() = 0;
#ifdef MAPBASE_VSCRIPT
virtual bool ConnectDebugger( int port = 0 ) = 0;
#else
virtual bool ConnectDebugger() = 0;
#endif
virtual void DisconnectDebugger() = 0;
virtual ScriptLanguage_t GetLanguage() = 0;
@ -927,14 +974,13 @@ public:
//--------------------------------------------------------
#ifdef MAPBASE_VSCRIPT
// When a RegisterInstance instance is deleted, VScript normally treats it as a strong reference and only deregisters the instance itself, preserving the registered data
// it points to so the game can continue to use it.
// bAllowDestruct is supposed to allow VScript to treat it as a weak reference created by the script, destructing the registered data automatically like any other type.
// This is useful for classes pretending to be primitive types.
virtual HSCRIPT RegisterInstance( ScriptClassDesc_t *pDesc, void *pInstance, bool bAllowDestruct = false ) = 0;
// if bRefCounted is true, pInstance memory will be deleted by the script,
// returning the result will then behave as if the instance was constructed in script.
// Functions that return the result of this need to return HSCRIPT_RC
virtual HSCRIPT RegisterInstance( ScriptClassDesc_t *pDesc, void *pInstance, bool bRefCounted = false ) = 0;
virtual void SetInstanceUniqeId( HSCRIPT hInstance, const char *pszId ) = 0;
template <typename T> HSCRIPT RegisterInstance( T *pInstance, bool bAllowDestruct = false ) { return RegisterInstance( GetScriptDesc( pInstance ), pInstance, bAllowDestruct ); }
template <typename T> HSCRIPT RegisterInstance( T *pInstance, const char *pszInstance, HSCRIPT hScope = NULL, bool bAllowDestruct = false) { HSCRIPT hInstance = RegisterInstance( GetScriptDesc( pInstance ), pInstance, bAllowDestruct ); SetValue( hScope, pszInstance, hInstance ); return hInstance; }
template <typename T> HSCRIPT RegisterInstance( T *pInstance, bool bRefCounted = false ) { return RegisterInstance( GetScriptDesc( pInstance ), pInstance, bRefCounted ); }
template <typename T> HSCRIPT RegisterInstance( T *pInstance, const char *pszInstance, HSCRIPT hScope = NULL, bool bRefCounted = false) { HSCRIPT hInstance = RegisterInstance( GetScriptDesc( pInstance ), pInstance, bRefCounted ); SetValue( hScope, pszInstance, hInstance ); return hInstance; }
#else
virtual HSCRIPT RegisterInstance( ScriptClassDesc_t *pDesc, void *pInstance ) = 0;
virtual void SetInstanceUniqeId( HSCRIPT hInstance, const char *pszId ) = 0;
@ -983,6 +1029,8 @@ public:
#ifdef MAPBASE_VSCRIPT
virtual void CreateArray(ScriptVariant_t &arr, int size = 0) = 0;
virtual bool ArrayAppend(HSCRIPT hArray, const ScriptVariant_t &val) = 0;
// To hold strong references to script objects
virtual HSCRIPT CopyObject(HSCRIPT obj) = 0;
#endif
//----------------------------------------------------------------------------

View File

@ -326,8 +326,8 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
class CNonMemberScriptBinding##N \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
{ \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( !pContext ); \
@ -337,17 +337,15 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
return false; \
} \
*pReturn = ((FUNC_TYPE)pFunction)( SCRIPT_BINDING_ARGS_##N ); \
if ( pReturn->m_type == FIELD_VECTOR ) \
pReturn->m_pVector = new Vector(*pReturn->m_pVector); \
return true; \
} \
return true; \
} \
}; \
\
template <typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CNonMemberScriptBinding##N<FUNC_TYPE, void FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( !pReturn ); \
@ -362,12 +360,52 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
} \
}; \
\
template <typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CNonMemberScriptBinding##N<FUNC_TYPE, Vector FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( !pContext ); \
\
if ( nArguments != N || !pReturn || pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_vec ) Vector( ((FUNC_TYPE)pFunction)( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_vec; \
return true; \
} \
}; \
\
template <typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CNonMemberScriptBinding##N<FUNC_TYPE, QAngle FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( !pContext ); \
\
if ( nArguments != N || !pReturn || pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_ang ) QAngle( ((FUNC_TYPE)pFunction)( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_ang; \
return true; \
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
{ \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( pContext ); \
@ -377,17 +415,15 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
return false; \
} \
*pReturn = (((OBJECT_TYPE_PTR)(pContext))->*ScriptConvertFuncPtrFromVoid<FUNC_TYPE>(pFunction))( SCRIPT_BINDING_ARGS_##N ); \
if ( pReturn->m_type == FIELD_VECTOR ) \
pReturn->m_pVector = new Vector(*pReturn->m_pVector); \
return true; \
} \
return true; \
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N<OBJECT_TYPE_PTR, FUNC_TYPE, void FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn ) \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( !pReturn ); \
@ -402,6 +438,46 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N<OBJECT_TYPE_PTR, FUNC_TYPE, Vector FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( pContext ); \
\
if ( nArguments != N || !pReturn || !pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_vec ) Vector( (((OBJECT_TYPE_PTR)(pContext))->*ScriptConvertFuncPtrFromVoid<FUNC_TYPE>(pFunction))( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_vec; \
return true; \
} \
}; \
\
template <class OBJECT_TYPE_PTR, typename FUNC_TYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
class CMemberScriptBinding##N<OBJECT_TYPE_PTR, FUNC_TYPE, QAngle FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N> \
{ \
public: \
static bool Call( void *pFunction, void *pContext, ScriptVariant_t *pArguments, int nArguments, ScriptVariant_t *pReturn, ScriptVariantTemporaryStorage_t &temporaryReturnStorage ) \
{ \
Assert( nArguments == N ); \
Assert( pReturn ); \
Assert( pContext ); \
\
if ( nArguments != N || !pReturn || !pContext ) \
{ \
return false; \
} \
new ( &temporaryReturnStorage.m_ang ) QAngle( (((OBJECT_TYPE_PTR)(pContext))->*ScriptConvertFuncPtrFromVoid<FUNC_TYPE>(pFunction))( SCRIPT_BINDING_ARGS_##N ) ); \
*pReturn = temporaryReturnStorage.m_ang; \
return true; \
} \
}; \
\
template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N> \
inline ScriptBindingFunc_t ScriptCreateBinding(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) ) \
{ \
@ -423,7 +499,11 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p )
return &CMemberScriptBinding##N<OBJECT_TYPE_PTR, Func_t, FUNCTION_RETTYPE FUNC_BASE_TEMPLATE_FUNC_PARAMS_PASSTHRU_##N>::Call; \
}
//note: no memory is actually allocated in the functions that get defined,
// it merely uses placement-new for which we need to disable this
#include "tier0/memdbgoff.h"
FUNC_GENERATE_ALL( DEFINE_SCRIPT_BINDINGS );
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//

View File

@ -1494,23 +1494,35 @@ void CResponseSystem::ParseInclude()
#ifdef MAPBASE
char scriptfile[256];
GetCurrentScript( scriptfile, sizeof( scriptfile ) );
V_RemoveDotSlashes( scriptfile );
const char *pScriptFile = scriptfile;
if (pScriptFile[0] == CORRECT_PATH_SEPARATOR || pScriptFile[0] == INCORRECT_PATH_SEPARATOR)
pScriptFile++;
// Gets first path
// (for example, an #include from a file in resource/script/resp will return resource)
size_t len = strlen(scriptfile)-1;
size_t len = strlen( pScriptFile )-1;
for (size_t i = 0; i < len; i++)
{
if (scriptfile[i] == CORRECT_PATH_SEPARATOR || scriptfile[i] == INCORRECT_PATH_SEPARATOR)
if (pScriptFile[i] == CORRECT_PATH_SEPARATOR || pScriptFile[i] == INCORRECT_PATH_SEPARATOR)
{
len = i;
}
}
Q_strncpy(includefile, scriptfile, len+1);
Q_strncpy(includefile, pScriptFile, len+1);
if (len+1 != strlen(scriptfile))
if (len+1 != strlen( pScriptFile ))
{
Q_strncat( includefile, "/", sizeof( includefile ) );
Q_strncat( includefile, token, sizeof( includefile ) );
if (!includefile[0])
{
CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "%s: Unable to parse first folder from parent script \"%s\", falling back to 'scripts/'\n", token, pScriptFile );
}
else
{
Q_strncat( includefile, CORRECT_PATH_SEPARATOR_S, sizeof( includefile ) );
Q_strncat( includefile, token, sizeof( includefile ) );
}
}
else
includefile[0] = '\0';
@ -1643,6 +1655,8 @@ inline ResponseType_t ComputeResponseType( const char *s )
return RESPONSE_VSCRIPT_FILE;
else
return RESPONSE_VSCRIPT;
case 'c':
return RESPONSE_CHOREOSENTENCE;
#endif
}

View File

@ -260,6 +260,8 @@ const char *CRR_Response::DescribeResponse( ResponseType_t type )
return "RESPONSE_VSCRIPT";
case ResponseRules::RESPONSE_VSCRIPT_FILE:
return "RESPONSE_VSCRIPT_FILE";
case ResponseRules::RESPONSE_CHOREOSENTENCE:
return "RESPONSE_CHOREOSENTENCE";
#endif
}

View File

@ -1354,6 +1354,15 @@ int RunVBSP( int argc, char **argv )
" -replacematerials : Substitute materials according to materialsub.txt in content\\maps\n"
" -FullMinidumps : Write large minidumps on crash.\n"
" -nohiddenmaps : Exclude manifest maps if they are currently hidden.\n"
#ifdef MAPBASE
" -defaultcubemap : Makes a dummy cubemap.\n"
" -skyboxcubemap : Makes a skybox cubemaps for LDR cubemaps. (HDR skybox cubemaps are not supported)\n"
" -defaultcubemapres : Sets the dummy cubemap resolution. (Default 32)\n"
" -defaultproppermodelsstatic : Inserts propper_model into the level.\n"
" -strippropperentities : Strip out any entities with 'propper_' in their classname, as they don't actually exist in-game.\n"
" -scripting : Vscript vbsp system.\n"
" -doc : Prints all the related documentation of vbsp Vscript.\n"
#endif
);
}

View File

@ -18,7 +18,7 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static HSCRIPT VMFKV_CreateBlank()
static HSCRIPT_RC VMFKV_CreateBlank()
{
KeyValues *pKV = new KeyValues("VMF");
@ -28,7 +28,7 @@ static HSCRIPT VMFKV_CreateBlank()
pWorld->SetString( "classname", "worldspawn" );
}
return scriptmanager->CreateScriptKeyValues( g_pScriptVM, pKV, true );
return scriptmanager->CreateScriptKeyValues( g_pScriptVM, pKV );
}
static bool VMFKV_SaveToFile( const char *szFile, HSCRIPT hKV )
@ -69,7 +69,7 @@ static bool VMFKV_SaveToFile( const char *szFile, HSCRIPT hKV )
return res;
}
static HSCRIPT VMFKV_LoadFromFile( const char *szFile )
static HSCRIPT_RC VMFKV_LoadFromFile( const char *szFile )
{
char pszFullName[MAX_PATH];
V_snprintf( pszFullName, sizeof(pszFullName), NULL, szFile );
@ -87,7 +87,7 @@ static HSCRIPT VMFKV_LoadFromFile( const char *szFile )
return NULL;
}
HSCRIPT hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pKV, true ); // bAllowDestruct is supposed to automatically remove the involved KV
HSCRIPT hScript = scriptmanager->CreateScriptKeyValues( g_pScriptVM, pKV );
return hScript;
}
@ -142,7 +142,7 @@ static HSCRIPT VMFKV_AddEntityFromTables( HSCRIPT hVMF, HSCRIPT hKV, HSCRIPT hIO
}
}
return scriptmanager->CreateScriptKeyValues( g_pScriptVM, pEnt, false );
return scriptmanager->CreateScriptKeyValues( g_pScriptVM, pEnt, true );
}
//-----------------------------------------------------------------------------

View File

@ -2471,6 +2471,15 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail )
{
do_fast = true;
}
#ifdef MAPBASE
else if(!Q_stricmp(argv[i], "-ultrafast"))
{
do_fast = true;
g_bFastAmbient = true;
do_extra = false;
numbounce = 1;
}
#endif
else if (!Q_stricmp(argv[i],"-noskyboxrecurse"))
{
g_bNoSkyRecurse = true;
@ -2491,6 +2500,26 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail )
return 1;
}
}
#ifdef MAPBASE
else if (!Q_stricmp(argv[i], "-extrapasses"))
{
if (++i < argc)
{
int extrapassesParam = atoi(argv[i]);
if (extrapassesParam < 0)
{
Warning("Error: expected non-negative value after '-extrapasses'\n");
return 1;
}
extrapasses = extrapassesParam;
}
else
{
Warning("Error: expected a value after '-extrapasses'\n");
return 1;
}
}
#endif
else if (!Q_stricmp(argv[i],"-centersamples"))
{
do_centersamples = true;
@ -2777,9 +2806,15 @@ void PrintUsage( int argc, char **argv )
" -v (or -verbose): Turn on verbose output (also shows more command\n"
" -bounce # : Set max number of bounces (default: 100).\n"
" -fast : Quick and dirty lighting.\n"
#ifdef MAPBASE
" -ultrafast : Very quick and dirty lighting, same as -fast -fastambient -noextra -bounce 1\n"
#endif
" -fastambient : Per-leaf ambient sampling is lower quality to save compute time.\n"
" -final : High quality processing. equivalent to -extrasky 16.\n"
" -extrasky n : trace N times as many rays for indirect light and sky ambient.\n"
" -extrasky # : trace # times as many rays for indirect light and sky ambient.\n"
#ifdef MAPBASE
" -extrapasses # : Lets you scale how many extra passes you want your map to go through (default 4), differences above this value are minimal.\n"
#endif
" -low : Run as an idle-priority process.\n"
" -mpi : Use VMPI to distribute computations.\n"
" -rederror : Show errors in red.\n"
@ -2813,7 +2848,7 @@ void PrintUsage( int argc, char **argv )
" -loghash : Log the sample hash table to samplehash.txt.\n"
" -onlydetail : Only light detail props and per-leaf lighting.\n"
" -maxdispsamplesize #: Set max displacement sample size (default: 512).\n"
" -softsun <n> : Treat the sun as an area light source of size <n> degrees."
" -softsun # : Treat the sun as an area light source of size # degrees."
" Produces soft shadows.\n"
" Recommended values are between 0 and 5. Default is 0.\n"
" -FullMinidumps : Write large minidumps on crash.\n"

View File

@ -847,34 +847,40 @@ void RichText::Paint()
// 3.
// Calculate the range of text to draw all at once
int iLim = m_TextStream.Count();
int iLim = m_TextStream.Count() - 1;
// Stop at the next line break
if ( m_LineBreaks.IsValidIndex( lineBreakIndexIndex ) && m_LineBreaks[lineBreakIndexIndex] <= iLim )
iLim = m_LineBreaks[lineBreakIndexIndex] - 1;
// Stop at the next format change
if ( m_FormatStream.IsValidIndex(renderState.formatStreamIndex) &&
m_FormatStream[renderState.formatStreamIndex].textStreamIndex < iLim &&
m_FormatStream[renderState.formatStreamIndex].textStreamIndex <= iLim &&
m_FormatStream[renderState.formatStreamIndex].textStreamIndex >= i &&
m_FormatStream[renderState.formatStreamIndex].textStreamIndex )
{
iLim = m_FormatStream[renderState.formatStreamIndex].textStreamIndex;
iLim = m_FormatStream[renderState.formatStreamIndex].textStreamIndex - 1;
}
// Stop at the next line break
if ( m_LineBreaks.IsValidIndex( lineBreakIndexIndex ) && m_LineBreaks[lineBreakIndexIndex] < iLim )
iLim = m_LineBreaks[lineBreakIndexIndex];
// Stop when entering or exiting the selected range
if ( i < selection0 && iLim >= selection0 )
iLim = selection0 - 1;
if ( i >= selection0 && i < selection1 && iLim >= selection1 )
iLim = selection1 - 1;
// Handle non-drawing characters specially
for ( int iT = i; iT < iLim; iT++ )
for ( int iT = i; iT <= iLim; iT++ )
{
if ( iswcntrl(m_TextStream[iT]) )
{
iLim = iT;
iLim = iT - 1;
break;
}
}
// 4.
// Draw the current text range
if ( iLim <= i )
if ( iLim < i )
{
if ( m_TextStream[i] == '\t' )
{
@ -887,8 +893,8 @@ void RichText::Paint()
}
else
{
renderState.x += DrawString(i, iLim - 1, renderState, hFontCurrent );
i = iLim;
renderState.x += DrawString(i, iLim, renderState, hFontCurrent );
i = iLim + 1;
}
}

View File

@ -12,6 +12,10 @@ $Conditional VS2017 "0" // Toggles Visual Studio 2017 (v141) toolset
$Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset
$Conditional VS2022 "0" // Toggles Visual Studio 2022 (v143) toolset
//
// WARNING: If you do not have Visual Studio 2013 installed and try to use VPC, it may produce an error about a missing RegKey.
// You can fix this without installing VS2013 by running newer_vs_toolsets_regkey_fix.reg, which is in the same directory as this file.
// This .reg file adds a registry key which is normally created by installing VS2013. You will only have to do this once per machine.
//
// VPC may still say "Generating for Visual Studio 2013" even when using one of the above toolsets. This message is irrelevant and can be ignored.
//

View File

@ -0,0 +1,7 @@
Windows Registry Editor Version 5.00
; https://github.com/ValveSoftware/source-sdk-2013/issues/72#issuecomment-326633328
; If you are running a 32-bit system, you may need to remove WOW6432Node from the path.
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\10.0\Projects\{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}]
"DefaultProjectExtension"="vcproj"

View File

@ -0,0 +1,70 @@
//-----------------------------------------------------------------------
// github.com/samisalreadytaken/sqdbg
//-----------------------------------------------------------------------
//
// Squirrel Debugger
//
#ifndef SQDBG_H
#define SQDBG_H
#include <squirrel.h>
#define SQDBG_SV_API_VER 1
#ifndef SQDBG_API
#ifdef SQDBG_DLL
#if defined(_WIN32)
#ifdef SQDBG_DLL_EXPORT
#define SQDBG_API __declspec(dllexport)
#else
#define SQDBG_API __declspec(dllimport)
#endif
#elif defined(__GNUC__)
#ifdef SQDBG_DLL_EXPORT
#define SQDBG_API __attribute__((visibility("default")))
#else
#define SQDBG_API extern
#endif
#else
#define SQDBG_API extern
#endif
#else
#define SQDBG_API extern
#endif
#endif
struct SQDebugServer;
typedef SQDebugServer* HSQDEBUGSERVER;
#ifdef __cplusplus
extern "C" {
#endif
// Create and attach a new debugger
// Memory is owned by the VM, it is freed when the VM dies or
// the debugger is disconnected via sqdbg_destroy_debugger()
SQDBG_API HSQDEBUGSERVER sqdbg_attach_debugger( HSQUIRRELVM vm );
// Detach and destroy the debugger attached to this VM
// Invalidates the handle returned from sqdbg_attach_debugger()
SQDBG_API void sqdbg_destroy_debugger( HSQUIRRELVM vm );
// Open specified port and allow client connections
// If port is 0, the system will choose a unique available port
// Returns 0 on success
SQDBG_API int sqdbg_listen_socket( HSQDEBUGSERVER dbg, unsigned short port );
// Process client connections and incoming messages
// Blocks on script breakpoints while a client is connected
SQDBG_API void sqdbg_frame( HSQDEBUGSERVER dbg );
// Copies the script to be able to source it to debugger clients
SQDBG_API void sqdbg_on_script_compile( HSQDEBUGSERVER dbg, const SQChar *script, SQInteger size,
const SQChar *sourcename, SQInteger sourcenamelen );
#ifdef __cplusplus
}
#endif
#endif // SQDBG_H

View File

@ -0,0 +1,131 @@
//-----------------------------------------------------------------------
// github.com/samisalreadytaken/sqdbg
//-----------------------------------------------------------------------
//
#ifndef SQDBG_DEBUG_H
#define SQDBG_DEBUG_H
#if 0
#ifdef _DEBUG
#ifdef _WIN32
#include <crtdbg.h>
bool __IsDebuggerPresent();
const char *GetModuleBaseName();
#define DebuggerBreak() do { if ( __IsDebuggerPresent() ) __debugbreak(); } while(0)
#define Assert( x ) \
do { \
__CAT( L, __LINE__ ): \
if ( !(x) && (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, GetModuleBaseName(), #x)) ) \
{ \
if ( !__IsDebuggerPresent() ) \
goto __CAT( L, __LINE__ ); \
__debugbreak(); \
} \
} while(0)
#define AssertMsg( x, msg ) \
do { \
__CAT( L, __LINE__ ): \
if ( !(x) && (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, GetModuleBaseName(), msg)) ) \
{ \
if ( !__IsDebuggerPresent() ) \
goto __CAT( L, __LINE__ ); \
__debugbreak(); \
} \
} while(0)
#define AssertMsg1( x, msg, a1 ) \
do { \
__CAT( L, __LINE__ ): \
if ( !(x) && (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, GetModuleBaseName(), msg, a1)) ) \
{ \
if ( !__IsDebuggerPresent() ) \
goto __CAT( L, __LINE__ ); \
__debugbreak(); \
} \
} while(0)
#define AssertMsg2( x, msg, a1, a2 ) \
do { \
__CAT( L, __LINE__ ): \
if ( !(x) && (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, GetModuleBaseName(), msg, a1, a2)) ) \
{ \
if ( !__IsDebuggerPresent() ) \
goto __CAT( L, __LINE__ ); \
__debugbreak(); \
} \
} while(0)
#else
extern "C" int printf(const char *, ...);
#define DebuggerBreak() asm("int3")
#define Assert( x ) \
do { \
if ( !(x) ) \
{ \
::printf("Assertion failed %s:%d: %s\n", __FILE__, __LINE__, #x); \
DebuggerBreak(); \
} \
} while(0)
#define AssertMsg( x, msg ) \
do { \
if ( !(x) ) \
{ \
::printf("Assertion failed %s:%d: %s\n", __FILE__, __LINE__, msg); \
DebuggerBreak(); \
} \
} while(0)
#define AssertMsg1( x, msg, a1 ) \
do { \
if ( !(x) ) \
{ \
::printf("Assertion failed %s:%d: ", __FILE__, __LINE__); \
::printf(msg, a1); \
::printf("\n"); \
DebuggerBreak(); \
} \
} while(0)
#define AssertMsg2( x, msg, a1, a2 ) \
do { \
if ( !(x) ) \
{ \
::printf("Assertion failed %s:%d: ", __FILE__, __LINE__); \
::printf(msg, a1, a2); \
::printf("\n"); \
DebuggerBreak(); \
} \
} while(0)
#endif
#define Verify( x ) Assert(x)
#else
#define DebuggerBreak() ((void)0)
#define Assert( x ) ((void)0)
#define AssertMsg( x, msg ) ((void)0)
#define AssertMsg1( x, msg, a1 ) ((void)0)
#define AssertMsg2( x, msg, a1, a2 ) ((void)0)
#define Verify( x ) x
#endif // _DEBUG
#endif
#include <tier0/dbg.h>
// Misdefined for GCC in platform.h
#undef UNREACHABLE
#ifdef _WIN32
#define UNREACHABLE() do { Assert(!"UNREACHABLE"); __assume(0); } while(0)
#else
#define UNREACHABLE() do { Assert(!"UNREACHABLE"); __builtin_unreachable(); } while(0)
#endif
#endif // SQDBG_DEBUG_H

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More