mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2024-12-25 06:15:30 +03:00
commit
7f0aec4371
2
.github/workflows/mapbase_build-base.yml
vendored
2
.github/workflows/mapbase_build-base.yml
vendored
@ -51,7 +51,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
|
1
.github/workflows/mapbase_build-sp-games.yml
vendored
1
.github/workflows/mapbase_build-sp-games.yml
vendored
@ -13,6 +13,7 @@ on:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- '.github/workflows/mapbase_build-base.yml'
|
||||
- '.github/workflows/mapbase_build-sp-rel-games.yml'
|
||||
- 'sp/src/vpc_scripts/**'
|
||||
- 'sp/src/game/**'
|
||||
|
4
.github/workflows/mapbase_pr.yml
vendored
4
.github/workflows/mapbase_pr.yml
vendored
@ -6,12 +6,12 @@
|
||||
# https://github.com/actions/labeler
|
||||
|
||||
name: Pull Request Automation
|
||||
on: [pull_request]
|
||||
on: [pull_request] # pull_request_target
|
||||
|
||||
jobs:
|
||||
label:
|
||||
|
||||
if: github.repository_owner == 'mapbase-source'
|
||||
if: github.repository_owner == 'mapbase-source' # ${{ vars.MAPBASE_LABELS == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
14
README
14
README
@ -1,6 +1,6 @@
|
||||
//=========================================================================================================================
|
||||
|
||||
Mapbase v7.1 - Source 2013
|
||||
Mapbase v7.2 - Source 2013
|
||||
https://github.com/mapbase-source/source-sdk-2013
|
||||
https://www.moddb.com/mods/mapbase
|
||||
|
||||
@ -112,6 +112,12 @@ Direct contributions:
|
||||
- https://github.com/mapbase-source/source-sdk-2013/issues/201 (env_projectedtexture shadow filter keyvalue from celisej567)
|
||||
- https://github.com/mapbase-source/source-sdk-2013/pull/193 (RTB:R info_particle_system_coordinate by arbabf and Iridium77)
|
||||
- https://github.com/mapbase-source/source-sdk-2013/pull/193 (Infinite prop_interactable cooldown by arbabf)
|
||||
- https://github.com/mapbase-source/source-sdk-2013/pull/229 (Extended point_bugbait functionality by arbabf)
|
||||
- https://github.com/mapbase-source/source-sdk-2013/pull/236 (Toggleable prop sprinting by Crimson-X1)
|
||||
- https://github.com/mapbase-source/source-sdk-2013/pull/237 (Commander goal trace fix by Agrimar)
|
||||
- https://github.com/mapbase-source/source-sdk-2013/pull/245 (ViewPunch random fix by Mr0maks)
|
||||
- https://github.com/mapbase-source/source-sdk-2013/pull/248 (soundlevel_t conversation warning fix by Mechami)
|
||||
- https://github.com/mapbase-source/mapbase-game-src/pull/1 (Advanced video options duplicate field name fix by arbabf; This is asset-based and not reflected in the code)
|
||||
- Demo autorecord code provided by Klems
|
||||
- cc_emit crash fix provided by 1upD
|
||||
- Custom HL2 ammo crate models created by Rykah (Textures created by Blixibon; This is asset-based and, aside from the SLAM crate, not reflected in the code)
|
||||
@ -137,6 +143,9 @@ Direct contributions:
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/192 (VScript hook manager and fixes)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/206 (Fix CScriptNetMsgHelper::WriteEntity())
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/213 (VScript HUD visibility control, optimizations for 3D skybox angles/fake worldportals)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/229 (VScript VGUI HUD viewport parenting, game_text and vgui_text_display VScript font fallback)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/261 (Misc VScript additions)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/279 (weapon_custom_scripted fixes)
|
||||
|
||||
== Contributions from z33ky:
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes)
|
||||
@ -156,6 +165,9 @@ Direct contributions:
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/184 (Projected texture horizontal FOV shadow fix)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/185 (Fix enemyfinders becoming visible when they wake)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/186 (Fix for brightly glowing teeth)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/183 (Enhanced custom weapons support)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/230 (Caption fixes)
|
||||
=-- https://github.com/mapbase-source/source-sdk-2013/pull/231 (Sentence source bug fix)
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -208,7 +208,7 @@ void CWeaponAR2::DelayedAttack( void )
|
||||
|
||||
// pOwner->SnapEyeAngles( angles );
|
||||
|
||||
pOwner->ViewPunch( QAngle( SharedRandomInt( "ar2pax", -8, -12 ), SharedRandomInt( "ar2pay", 1, 2 ), 0 ) );
|
||||
pOwner->ViewPunch( QAngle( SharedRandomInt( "ar2pax", -12, -8 ), SharedRandomInt( "ar2pay", 1, 2 ), 0 ) );
|
||||
|
||||
// Decrease ammo
|
||||
pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
|
||||
|
@ -4042,6 +4042,92 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef MAPBASE // From Alien Swarm SDK
|
||||
case AE_CL_STOP_PARTICLE_EFFECT:
|
||||
{
|
||||
char token[256];
|
||||
char szParticleEffect[256];
|
||||
|
||||
// Get the particle effect name
|
||||
const char *p = options;
|
||||
p = nexttoken(token, p, ' ', sizeof(token));
|
||||
if ( token )
|
||||
{
|
||||
Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) );
|
||||
}
|
||||
|
||||
// Get the attachment point index
|
||||
p = nexttoken(token, p, ' ', sizeof(token));
|
||||
bool bStopInstantly = ( token && !Q_stricmp( token, "instantly" ) );
|
||||
|
||||
ParticleProp()->StopParticlesNamed( szParticleEffect, bStopInstantly );
|
||||
}
|
||||
break;
|
||||
|
||||
case AE_CL_ADD_PARTICLE_EFFECT_CP:
|
||||
{
|
||||
int iControlPoint = 1;
|
||||
int iAttachment = -1;
|
||||
int iAttachType = PATTACH_ABSORIGIN_FOLLOW;
|
||||
int iEffectIndex = -1;
|
||||
char token[256];
|
||||
char szParticleEffect[256];
|
||||
|
||||
// Get the particle effect name
|
||||
const char *p = options;
|
||||
p = nexttoken(token, p, ' ', sizeof(token));
|
||||
if ( token )
|
||||
{
|
||||
Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) );
|
||||
}
|
||||
|
||||
// Get the control point number
|
||||
p = nexttoken(token, p, ' ', sizeof(token));
|
||||
if ( token )
|
||||
{
|
||||
iControlPoint = atoi( token );
|
||||
}
|
||||
|
||||
// Get the attachment type
|
||||
p = nexttoken(token, p, ' ', sizeof(token));
|
||||
if ( token )
|
||||
{
|
||||
iAttachType = GetAttachTypeFromString( token );
|
||||
if ( iAttachType == -1 )
|
||||
{
|
||||
Warning("Invalid attach type specified for particle effect anim event. Trying to spawn effect '%s' with attach type of '%s'\n", szParticleEffect, token );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the attachment point index
|
||||
p = nexttoken(token, p, ' ', sizeof(token));
|
||||
if ( token )
|
||||
{
|
||||
iAttachment = atoi(token);
|
||||
|
||||
// See if we can find any attachment points matching the name
|
||||
if ( token[0] != '0' && iAttachment == 0 )
|
||||
{
|
||||
iAttachment = LookupAttachment( token );
|
||||
if ( iAttachment == -1 )
|
||||
{
|
||||
Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
iEffectIndex = ParticleProp()->FindEffect( szParticleEffect );
|
||||
if ( iEffectIndex == -1 )
|
||||
{
|
||||
Warning("Failed to find specified particle effect. Trying to add CP to '%s' on attachment named '%s'\n", szParticleEffect, token );
|
||||
return;
|
||||
}
|
||||
ParticleProp()->AddControlPoint( iEffectIndex, iControlPoint, this, (ParticleAttachment_t)iAttachType, iAttachment );
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case AE_CL_PLAYSOUND:
|
||||
{
|
||||
CLocalPlayerFilter filter;
|
||||
@ -4291,6 +4377,22 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef MAPBASE
|
||||
case AE_VSCRIPT_RUN:
|
||||
{
|
||||
if (!RunScript( options ))
|
||||
Warning( "%s failed to run AE_VSCRIPT_RUN on client with \"%s\"\n", GetDebugName(), options );
|
||||
}
|
||||
break;
|
||||
|
||||
case AE_VSCRIPT_RUN_FILE:
|
||||
{
|
||||
if (!RunScriptFile( options ))
|
||||
Warning( "%s failed to run AE_VSCRIPT_RUN_FILE on client with \"%s\"\n", GetDebugName(), options );
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ END_PREDICTION_DATA()
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
|
||||
BEGIN_ENT_SCRIPTDESC( C_BaseCombatCharacter, CBaseEntity, "" )
|
||||
BEGIN_ENT_SCRIPTDESC( C_BaseCombatCharacter, C_BaseAnimating, "" )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAmmoCount, "GetAmmoCount", "" )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetActiveWeapon, "GetActiveWeapon", "" )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetWeapon, "GetWeapon", "" )
|
||||
|
@ -502,6 +502,9 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities
|
||||
DEFINE_SCRIPTFUNC_NAMED( GetScriptOwnerEntity, "GetOwner", "Gets this entity's owner" )
|
||||
DEFINE_SCRIPTFUNC_NAMED( SetScriptOwnerEntity, "SetOwner", "Sets this entity's owner" )
|
||||
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetGroundEntity, "GetGroundEntity", "Get the entity we're standing on." )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptSetGroundEntity, "SetGroundEntity", "Set the entity we're standing on." )
|
||||
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetRenderColorVector", "Get the render color as a vector" )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetRenderColorR", "Get the render color's R value" )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetRenderColorG", "Get the render color's G value" )
|
||||
|
@ -288,6 +288,11 @@ public:
|
||||
HSCRIPT GetScriptOwnerEntity();
|
||||
virtual void SetScriptOwnerEntity(HSCRIPT pOwner);
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
HSCRIPT ScriptGetGroundEntity();
|
||||
void ScriptSetGroundEntity( HSCRIPT hGroundEnt );
|
||||
#endif
|
||||
|
||||
HSCRIPT GetScriptInstance();
|
||||
|
||||
HSCRIPT m_hScriptInstance;
|
||||
|
@ -69,6 +69,7 @@ $Project
|
||||
$File "mapbase\c_func_fake_worldportal.h"
|
||||
$File "mapbase\c_point_glow.cpp"
|
||||
$File "mapbase\c_vgui_text_display.cpp"
|
||||
$File "mapbase\c_weapon_custom_hl2.cpp"
|
||||
$File "mapbase\mapbase_autocubemap.cpp"
|
||||
}
|
||||
|
||||
|
@ -1496,9 +1496,23 @@ void CHudCloseCaption::Process( const wchar_t *stream, float duration, const cha
|
||||
|
||||
if ( m_Items.Count() > 0 )
|
||||
{
|
||||
#ifndef MAPBASE
|
||||
// Get the remaining life span of the last item
|
||||
CCloseCaptionItem *final = m_Items[ m_Items.Count() - 1 ];
|
||||
CCloseCaptionItem* final = m_Items[m_Items.Count() - 1];
|
||||
float prevlife = final->GetTimeToLive();
|
||||
#else
|
||||
float prevlife = 0.f;
|
||||
// Get the remaining life span of the last displayed item
|
||||
for (int i = m_Items.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_Items[i]->GetPreDisplayTime() > cc_predisplay_time.GetFloat())
|
||||
continue;
|
||||
|
||||
prevlife = m_Items[i]->GetTimeToLive();
|
||||
break;
|
||||
}
|
||||
#endif // !MAPBASE
|
||||
|
||||
|
||||
if ( prevlife > lifespan )
|
||||
{
|
||||
@ -1532,7 +1546,31 @@ void CHudCloseCaption::Process( const wchar_t *stream, float duration, const cha
|
||||
if ( wcslen( phrase ) > 0 )
|
||||
{
|
||||
CCloseCaptionItem *item = new CCloseCaptionItem( phrase, lifespan, addedlife, delay, valid, fromplayer );
|
||||
m_Items.AddToTail( item );
|
||||
#ifdef MAPBASE
|
||||
if (m_Items.Count())
|
||||
{
|
||||
// Add it where it will appear
|
||||
for (int i = m_Items.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_Items[i]->GetPreDisplayTime() > delay + cc_predisplay_time.GetFloat())
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
m_Items.AddToHead(item);
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
m_Items.InsertAfter(i, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // MAPBASE
|
||||
m_Items.AddToTail(item);
|
||||
|
||||
if ( StreamHasCommand( phrase, L"sfx" ) )
|
||||
{
|
||||
// SFX show up instantly.
|
||||
@ -1541,6 +1579,9 @@ void CHudCloseCaption::Process( const wchar_t *stream, float duration, const cha
|
||||
|
||||
if ( GetFloatCommandValue( phrase, L"len", override_duration ) )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
override_duration += cc_linger_time.GetFloat();
|
||||
#endif // MAPBASE
|
||||
item->SetTimeToLive( override_duration );
|
||||
}
|
||||
}
|
||||
@ -1569,7 +1610,30 @@ void CHudCloseCaption::Process( const wchar_t *stream, float duration, const cha
|
||||
if ( wcslen( phrase ) > 0 )
|
||||
{
|
||||
CCloseCaptionItem *item = new CCloseCaptionItem( phrase, lifespan, addedlife, delay, valid, fromplayer );
|
||||
m_Items.AddToTail( item );
|
||||
#ifdef MAPBASE
|
||||
if (m_Items.Count())
|
||||
{
|
||||
// Add it where it will appear
|
||||
for (int i = m_Items.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_Items[i]->GetPreDisplayTime() > delay + cc_predisplay_time.GetFloat())
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
m_Items.AddToHead(item);
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
m_Items.InsertAfter(i, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // MAPBASE
|
||||
m_Items.AddToTail(item);
|
||||
|
||||
if ( StreamHasCommand( phrase, L"sfx" ) )
|
||||
{
|
||||
@ -1579,6 +1643,10 @@ void CHudCloseCaption::Process( const wchar_t *stream, float duration, const cha
|
||||
|
||||
if ( GetFloatCommandValue( phrase, L"len", override_duration ) )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
override_duration += cc_linger_time.GetFloat();
|
||||
#endif // MAPBASE
|
||||
|
||||
item->SetTimeToLive( override_duration );
|
||||
item->SetInitialLifeSpan( override_duration );
|
||||
}
|
||||
@ -2614,8 +2682,14 @@ void CHudCloseCaption::InitCaptionDictionary( const char *dbfile )
|
||||
|
||||
g_AsyncCaptionResourceManager.Clear();
|
||||
|
||||
#ifdef MAPBASE
|
||||
int iBufferSize = filesystem->GetSearchPath("GAME", true, nullptr, 0);
|
||||
char* searchPaths = (char*)stackalloc(iBufferSize);
|
||||
filesystem->GetSearchPath("GAME", true, searchPaths, iBufferSize);
|
||||
#else
|
||||
char searchPaths[4096];
|
||||
filesystem->GetSearchPath( "GAME", true, searchPaths, sizeof( searchPaths ) );
|
||||
#endif
|
||||
|
||||
for ( char *path = strtok( searchPaths, ";" ); path; path = strtok( NULL, ";" ) )
|
||||
{
|
||||
@ -2626,8 +2700,13 @@ void CHudCloseCaption::InitCaptionDictionary( const char *dbfile )
|
||||
}
|
||||
|
||||
char fullpath[MAX_PATH];
|
||||
Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", path, dbfile );
|
||||
Q_FixSlashes( fullpath );
|
||||
#ifndef MAPBASE
|
||||
Q_snprintf(fullpath, sizeof(fullpath), "%s%s", path, dbfile);
|
||||
Q_FixSlashes(fullpath);
|
||||
#else
|
||||
V_ComposeFileName(path, dbfile, fullpath, sizeof(fullpath));
|
||||
#endif // !MAPBASE
|
||||
|
||||
|
||||
if ( IsX360() )
|
||||
{
|
||||
@ -2692,8 +2771,7 @@ void CHudCloseCaption::AddAdditionalCaptionDictionary( const char *dbfile, CUtlV
|
||||
}
|
||||
|
||||
char fullpath[MAX_PATH];
|
||||
Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", path, dbfile );
|
||||
Q_FixSlashes( fullpath );
|
||||
V_ComposeFileName(path, dbfile, fullpath, sizeof(fullpath));
|
||||
|
||||
if ( IsX360() )
|
||||
{
|
||||
|
@ -215,6 +215,13 @@ void C_TextDisplayPanel::UpdateText()
|
||||
if (pszFontName && pszFontName[0] != '\0')
|
||||
{
|
||||
HFont font = scheme()->GetIScheme( GetScheme() )->GetFont( pszFontName );
|
||||
|
||||
if ( !font )
|
||||
{
|
||||
extern HFont GetScriptFont( const char *, bool );
|
||||
font = GetScriptFont( pszFontName, false );
|
||||
}
|
||||
|
||||
m_pDisplayTextLabel->SetFont( font );
|
||||
}
|
||||
|
||||
|
91
sp/src/game/client/mapbase/c_weapon_custom_hl2.cpp
Normal file
91
sp/src/game/client/mapbase/c_weapon_custom_hl2.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
|
||||
//
|
||||
// Purpose: Client classes for Half-Life 2 based custom weapons.
|
||||
//
|
||||
// Author: Peter Covington (petercov@outlook.com)
|
||||
//
|
||||
//==================================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "c_weapon__stubs.h"
|
||||
#include "basehlcombatweapon_shared.h"
|
||||
#include "c_basehlcombatweapon.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class C_HLCustomWeaponMelee : public C_BaseHLBludgeonWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS(C_HLCustomWeaponMelee, C_BaseHLBludgeonWeapon);
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
C_HLCustomWeaponMelee();
|
||||
|
||||
void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
virtual const char* GetWeaponScriptName() { return m_iszWeaponScriptName; }
|
||||
private:
|
||||
char m_iszWeaponScriptName[128];
|
||||
};
|
||||
|
||||
STUB_WEAPON_CLASS_IMPLEMENT(weapon_hlcustommelee, C_HLCustomWeaponMelee);
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_HLCustomWeaponMelee, DT_HLCustomWeaponMelee, CHLCustomWeaponMelee)
|
||||
RecvPropString(RECVINFO(m_iszWeaponScriptName)),
|
||||
END_RECV_TABLE();
|
||||
|
||||
C_HLCustomWeaponMelee::C_HLCustomWeaponMelee()
|
||||
{
|
||||
m_iszWeaponScriptName[0] = '\0';
|
||||
}
|
||||
|
||||
void C_HLCustomWeaponMelee::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
if (updateType == DATA_UPDATE_CREATED)
|
||||
{
|
||||
Precache();
|
||||
}
|
||||
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
}
|
||||
|
||||
|
||||
|
||||
class C_HLCustomWeaponGun : public C_BaseHLCombatWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS(C_HLCustomWeaponGun, C_BaseHLCombatWeapon);
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
C_HLCustomWeaponGun();
|
||||
|
||||
void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
virtual const char* GetWeaponScriptName() { return m_iszWeaponScriptName; }
|
||||
private:
|
||||
char m_iszWeaponScriptName[128];
|
||||
};
|
||||
|
||||
STUB_WEAPON_CLASS_IMPLEMENT(weapon_hlcustomgun, C_HLCustomWeaponGun);
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_HLCustomWeaponGun, DT_HLCustomWeaponGun, CHLCustomWeaponGun)
|
||||
RecvPropString(RECVINFO(m_iszWeaponScriptName)),
|
||||
END_RECV_TABLE();
|
||||
|
||||
C_HLCustomWeaponGun::C_HLCustomWeaponGun()
|
||||
{
|
||||
m_iszWeaponScriptName[0] = '\0';
|
||||
}
|
||||
|
||||
void C_HLCustomWeaponGun::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
if (updateType == DATA_UPDATE_CREATED)
|
||||
{
|
||||
Precache();
|
||||
}
|
||||
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
}
|
@ -51,7 +51,7 @@
|
||||
|
||||
#include "view.h"
|
||||
#include "hudelement.h"
|
||||
//#include "iclientmode.h" // g_pClientMode->GetViewport()
|
||||
#include "iclientmode.h" // g_pClientMode->GetViewport()
|
||||
|
||||
#include "vscript_vgui.h"
|
||||
#include "vscript_vgui.nut"
|
||||
@ -92,10 +92,18 @@
|
||||
// Changing this is not backwards compatible, as existing top level script panel depth would then change relative to non-script panels.
|
||||
#define SCRIPT_ENGINE_ROOT_PANELS 1
|
||||
|
||||
// NOTE: causes rendering issues
|
||||
#define ALLOW_SCRIPT_HUD_VIEWPORT_ROOT_PANEL 0
|
||||
//
|
||||
// Options to restrict where script panels can be parented to.
|
||||
// The safest options any game can have are HUD viewport and clientdll.
|
||||
//
|
||||
|
||||
#define ALLOW_SCRIPT_GAMEUI_ROOT_PANEL 0
|
||||
#define ALLOW_ROOT_PANEL_PARENT 1
|
||||
|
||||
#define ALLOW_HUD_VIEWPORT_ROOT_PARENT 1
|
||||
|
||||
#define ALLOW_CLIENTDLL_ROOT_PARENT 1
|
||||
|
||||
#define ALLOW_GAMEUI_ROOT_PARENT 0
|
||||
|
||||
// On level transitions Restore is called up to 4 times in a row (due to .hl? client state files), each time
|
||||
// trying to restore script panels from pre and post transitions, failing every time because script panels are
|
||||
@ -353,8 +361,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if ALLOW_CLIENTDLL_ROOT_PARENT
|
||||
CScriptRootDLLPanel *g_pScriptClientDLLPanel = NULL;
|
||||
#if ALLOW_SCRIPT_GAMEUI_ROOT_PANEL
|
||||
#endif
|
||||
#if ALLOW_GAMEUI_ROOT_PARENT
|
||||
CScriptRootDLLPanel *g_pScriptGameUIDLLPanel = NULL;
|
||||
#endif
|
||||
#endif
|
||||
@ -367,12 +377,14 @@ void VGUI_DestroyScriptRootPanels()
|
||||
g_pScriptRootPanel = NULL;
|
||||
}
|
||||
#if SCRIPT_ENGINE_ROOT_PANELS
|
||||
#if ALLOW_CLIENTDLL_ROOT_PARENT
|
||||
if ( g_pScriptClientDLLPanel )
|
||||
{
|
||||
delete g_pScriptClientDLLPanel;
|
||||
g_pScriptClientDLLPanel = NULL;
|
||||
}
|
||||
#if ALLOW_SCRIPT_GAMEUI_ROOT_PANEL
|
||||
#endif
|
||||
#if ALLOW_GAMEUI_ROOT_PARENT
|
||||
if ( g_pScriptGameUIDLLPanel )
|
||||
{
|
||||
delete g_pScriptGameUIDLLPanel;
|
||||
@ -384,30 +396,29 @@ void VGUI_DestroyScriptRootPanels()
|
||||
|
||||
VPANEL VGUI_GetScriptRootPanel( VGuiPanel_t type )
|
||||
{
|
||||
#if !SCRIPT_ENGINE_ROOT_PANELS
|
||||
if ( !g_pScriptRootPanel )
|
||||
g_pScriptRootPanel = new CScriptRootPanel();
|
||||
|
||||
return enginevgui->GetPanel( type );
|
||||
#else
|
||||
#if SCRIPT_ENGINE_ROOT_PANELS
|
||||
switch ( type )
|
||||
{
|
||||
case PANEL_ROOT:
|
||||
#if ALLOW_ROOT_PANEL_PARENT
|
||||
{
|
||||
if ( !g_pScriptRootPanel )
|
||||
g_pScriptRootPanel = new CScriptRootPanel();
|
||||
|
||||
return g_pScriptRootPanel->GetVPanel();
|
||||
}
|
||||
#endif
|
||||
case PANEL_CLIENTDLL:
|
||||
#if ALLOW_CLIENTDLL_ROOT_PARENT
|
||||
{
|
||||
if ( !g_pScriptClientDLLPanel )
|
||||
g_pScriptClientDLLPanel = new CScriptRootDLLPanel( PANEL_CLIENTDLL, "VScriptClient" );
|
||||
|
||||
return g_pScriptClientDLLPanel->GetVPanel();
|
||||
}
|
||||
#if ALLOW_SCRIPT_GAMEUI_ROOT_PANEL
|
||||
#endif
|
||||
case PANEL_GAMEUIDLL:
|
||||
#if ALLOW_GAMEUI_ROOT_PARENT
|
||||
{
|
||||
if ( !g_pScriptGameUIDLLPanel )
|
||||
g_pScriptGameUIDLLPanel = new CScriptRootDLLPanel( PANEL_GAMEUIDLL, "VScriptGameUI" );
|
||||
@ -415,8 +426,10 @@ VPANEL VGUI_GetScriptRootPanel( VGuiPanel_t type )
|
||||
return g_pScriptGameUIDLLPanel->GetVPanel();
|
||||
}
|
||||
#endif
|
||||
default: return NULL;
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
return enginevgui->GetPanel(type);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -663,6 +676,11 @@ int CScriptSurface::GetCharacterWidth( int font, int ch )
|
||||
|
||||
void CScriptSurface::CreateFont( const char *customName, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int yresMin, int yresMax, bool proportional )
|
||||
{
|
||||
// Make sure font invalidation callback is established.
|
||||
// Not necessary if script fonts are reloaded in engine.
|
||||
if ( !g_pScriptRootPanel )
|
||||
g_pScriptRootPanel = new CScriptRootPanel();
|
||||
|
||||
if ( flags & ISurface::FONTFLAG_BITMAP )
|
||||
{
|
||||
AssertMsg( 0, "Bitmap fonts are not supported!" );
|
||||
@ -681,16 +699,41 @@ void CScriptSurface::CreateFont( const char *customName, const char *windowsFont
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool bProportionalFallbackFont = false;
|
||||
if ( proportional )
|
||||
{
|
||||
// Find if this is a resolution filtered font alias
|
||||
const char *fontAlias = GetFixedFontName( customName, false );
|
||||
int idx = g_ScriptFonts.Find( fontAlias );
|
||||
if ( idx != g_ScriptFonts.InvalidIndex() )
|
||||
{
|
||||
fontalias_t &alias = g_ScriptFonts[idx];
|
||||
for ( int i = 0; i < alias.Count(); ++i )
|
||||
{
|
||||
FontData_t &data = alias.Element(i);
|
||||
if ( data.yres_min && data.yres_max )
|
||||
{
|
||||
bProportionalFallbackFont = true;
|
||||
|
||||
// Save this proportional font in non-proportional alias
|
||||
proportional = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *fontAlias = GetFixedFontName( customName, proportional );
|
||||
|
||||
int idx = g_ScriptFonts.Find( fontAlias );
|
||||
if ( idx != g_ScriptFonts.InvalidIndex() )
|
||||
{
|
||||
fontalias_t &alias = g_ScriptFonts[idx];
|
||||
// TODO: One proportional font to fall back to amongst resolution filtered fonts.
|
||||
|
||||
#ifdef _DEBUG
|
||||
if ( !yresMin && !yresMax )
|
||||
if ( !yresMin && !yresMax /*&& !bProportionalFallbackFont*/ )
|
||||
{
|
||||
// There must be only one font registered.
|
||||
Assert( alias.Count() == 1 );
|
||||
@ -703,7 +746,7 @@ void CScriptSurface::CreateFont( const char *customName, const char *windowsFont
|
||||
// Font changes will not be applied.
|
||||
Assert( oldTall == newTall );
|
||||
if ( oldName ) // can be null
|
||||
Assert( !V_stricmp( oldName, windowsFontName ) );
|
||||
AssertMsg( !V_stricmp( oldName, windowsFontName ), "'%s' != '%s'", oldName, windowsFontName );
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -716,7 +759,10 @@ void CScriptSurface::CreateFont( const char *customName, const char *windowsFont
|
||||
if ( yresMin == data.yres_min && yresMax == data.yres_max )
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ( bProportionalFallbackFont )
|
||||
proportional = true;
|
||||
#endif
|
||||
DebugMsg( "Create font add '%s' [%d %d]\n", fontAlias, yresMin, yresMax );
|
||||
|
||||
FontData_t &newFont = alias.Element( alias.AddToTail() );
|
||||
@ -731,6 +777,22 @@ void CScriptSurface::CreateFont( const char *customName, const char *windowsFont
|
||||
newFont.yres_max = yresMax;
|
||||
newFont.proportional = proportional;
|
||||
|
||||
#if 0
|
||||
// Put the proportional font in the very end so that it is loaded only when no resolution is matched
|
||||
struct L
|
||||
{
|
||||
static int __cdecl F( const FontData_t* a, const FontData_t* b )
|
||||
{
|
||||
if ( !a->proportional && b->proportional )
|
||||
return -1;
|
||||
if ( a->proportional && !b->proportional )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
alias.Sort( L::F );
|
||||
#endif
|
||||
|
||||
LoadFont( newFont DBG_PARAM(, fontAlias) );
|
||||
}
|
||||
else
|
||||
@ -1067,7 +1129,7 @@ public:\
|
||||
class CScript_##panelClass : public panelClass\
|
||||
{\
|
||||
DECLARE_SCRIPTVGUI_CLASS( panelClass )\
|
||||
void Shutdown() {}\
|
||||
void ScriptShutdown() {}\
|
||||
\
|
||||
public:\
|
||||
CScript_##panelClass( Panel *parent, const char *name )\
|
||||
@ -1085,7 +1147,7 @@ public:\
|
||||
class CScript_##panelClass : public panelClass\
|
||||
{\
|
||||
DECLARE_SCRIPTVGUI_CLASS( panelClass )\
|
||||
void Shutdown() {}\
|
||||
void ScriptShutdown() {}\
|
||||
\
|
||||
public:\
|
||||
CScript_##panelClass( Panel *parent, const char *name, const char *text )\
|
||||
@ -1292,7 +1354,7 @@ public:
|
||||
if ( GetVPanel() )
|
||||
{
|
||||
DebugMsg( " Destroy panel '%s' %s\n", _base->GetName(), GetDebugName() );
|
||||
_base->Shutdown();
|
||||
_base->ScriptShutdown();
|
||||
ResolveChildren_r( _vpanel );
|
||||
_base->MarkForDeletion();
|
||||
}
|
||||
@ -1339,6 +1401,11 @@ public:
|
||||
}
|
||||
|
||||
AssertMsg( 0, "invalid parent" );
|
||||
|
||||
g_ScriptPanels.AddToTail( this );
|
||||
|
||||
// leave me parentless
|
||||
return;
|
||||
}
|
||||
|
||||
g_ScriptPanels.AddToTail( this );
|
||||
@ -1348,27 +1415,37 @@ public:
|
||||
//
|
||||
// This parameter is hidden in script, and is defined by the return value of dummy functions.
|
||||
VPANEL vparent = 0;
|
||||
|
||||
switch ( root )
|
||||
{
|
||||
#if ALLOW_ROOT_PANEL_PARENT
|
||||
case 0:
|
||||
vparent = VGUI_GetScriptRootPanel( PANEL_ROOT );
|
||||
break;
|
||||
#if ALLOW_SCRIPT_GAMEUI_ROOT_PANEL
|
||||
#endif
|
||||
#if ALLOW_GAMEUI_ROOT_PARENT
|
||||
case 1:
|
||||
vparent = VGUI_GetScriptRootPanel( PANEL_GAMEUIDLL );
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
#if ALLOW_CLIENTDLL_ROOT_PARENT
|
||||
case 2:
|
||||
vparent = VGUI_GetScriptRootPanel( PANEL_CLIENTDLL );
|
||||
break;
|
||||
#if ALLOW_SCRIPT_HUD_VIEWPORT_ROOT_PANEL
|
||||
// Hud viewport
|
||||
case 10:
|
||||
#endif
|
||||
#if ALLOW_HUD_VIEWPORT_ROOT_PARENT
|
||||
case 10: // Hud viewport
|
||||
Assert( g_pClientMode && g_pClientMode->GetViewport() );
|
||||
vparent = g_pClientMode->GetViewport()->GetVPanel();
|
||||
break;
|
||||
#endif
|
||||
default: UNREACHABLE(); // Invalid parent panel
|
||||
#endif
|
||||
default:
|
||||
#if SCRIPT_ENGINE_ROOT_PANELS
|
||||
UNREACHABLE(); // Invalid parent panel
|
||||
#else
|
||||
// Allow everything defined in vscript_vgui.nut
|
||||
vparent = VGUI_GetScriptRootPanel( (VGuiPanel_t)root );
|
||||
#endif
|
||||
}
|
||||
|
||||
_base->SetParent( vparent );
|
||||
@ -1400,6 +1477,11 @@ public:
|
||||
{
|
||||
ivgui()->AddTickSignal( this->GetVPanel(), i );
|
||||
}
|
||||
|
||||
void RemoveTickSignal()
|
||||
{
|
||||
ivgui()->RemoveTickSignal( this->GetVPanel() );
|
||||
}
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
void AddActionSignalTarget( HSCRIPT messageTarget )
|
||||
{
|
||||
@ -1434,10 +1516,12 @@ public:
|
||||
bool bRootParent = false;
|
||||
#if SCRIPT_ENGINE_ROOT_PANELS
|
||||
if ( ( parent == g_pScriptRootPanel->GetVPanel() )
|
||||
#if ALLOW_SCRIPT_GAMEUI_ROOT_PANEL
|
||||
#if ALLOW_GAMEUI_ROOT_PARENT
|
||||
|| ( g_pScriptGameUIDLLPanel && parent == g_pScriptGameUIDLLPanel->GetVPanel() )
|
||||
#endif
|
||||
#if ALLOW_CLIENTDLL_ROOT_PARENT
|
||||
|| ( g_pScriptClientDLLPanel && parent == g_pScriptClientDLLPanel->GetVPanel() )
|
||||
#endif
|
||||
)
|
||||
{
|
||||
bRootParent = true;
|
||||
@ -1452,7 +1536,7 @@ public:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if ALLOW_SCRIPT_HUD_VIEWPORT_ROOT_PANEL
|
||||
#if ALLOW_HUD_VIEWPORT_ROOT_PARENT
|
||||
if ( g_pClientMode && g_pClientMode->GetViewport() && ( parent == g_pClientMode->GetViewport()->GetVPanel() ) )
|
||||
bRootParent = true;
|
||||
#endif
|
||||
@ -1788,6 +1872,7 @@ public:
|
||||
DEFINE_SCRIPTFUNC( MakeReadyForUse, "" )\
|
||||
DEFINE_SCRIPTFUNC( GetName, "" )\
|
||||
DEFINE_SCRIPTFUNC( AddTickSignal, "" )\
|
||||
DEFINE_SCRIPTFUNC( RemoveTickSignal, "" )\
|
||||
\
|
||||
DEFINE_SCRIPTFUNC( GetParent, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetParent, "" )\
|
||||
@ -1829,10 +1914,12 @@ public:
|
||||
\
|
||||
DEFINE_SCRIPTFUNC( SetCursor, "" )\
|
||||
DEFINE_SCRIPTFUNC( IsCursorOver, "" )\
|
||||
\
|
||||
DEFINE_SCRIPTFUNC( HasFocus, "" )\
|
||||
DEFINE_SCRIPTFUNC( RequestFocus, "" )\
|
||||
DEFINE_SCRIPTFUNC( MakePopup, "" )\
|
||||
DEFINE_SCRIPTFUNC( MoveToFront, "" )\
|
||||
\
|
||||
DEFINE_SCRIPTFUNC( SetMouseInputEnabled, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetKeyBoardInputEnabled, "" )\
|
||||
\
|
||||
@ -1842,10 +1929,7 @@ public:
|
||||
//--------------------------------------------------------------
|
||||
//--------------------------------------------------------------
|
||||
// These need more testing.
|
||||
// TODO: IScript_Panel::FindChildByName()
|
||||
// TODO: DECLARE_BUILD_FACTORY_SCRIPT() to create overridable script panels from controls file
|
||||
// TODO: CScript_EditablePanel::ApplySchemeSettings() callback
|
||||
// (IScheme parameter can be passed as null until schemes are also tested)
|
||||
#if BUILD_GROUPS_ENABLED
|
||||
CLASS_HELPER_INTERFACE( EditablePanel, Panel )
|
||||
{
|
||||
@ -1855,11 +1939,27 @@ public:
|
||||
{
|
||||
__base()->LoadControlSettings( resName );
|
||||
}
|
||||
|
||||
HSCRIPT FindChildByName( const char *childName )
|
||||
{
|
||||
Panel *pPanel = __base()->FindChildByName( childName, false );
|
||||
if ( pPanel )
|
||||
{
|
||||
int i;
|
||||
IScriptVGUIObject* obj = FindInScriptPanels( child, i );
|
||||
if ( obj )
|
||||
{
|
||||
return obj->GetScriptInstance();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_VGUI_SCRIPTFUNC_EditablePanel()\
|
||||
DEFINE_VGUI_SCRIPTFUNC_Panel()\
|
||||
DEFINE_SCRIPTFUNC( LoadControlSettings, "" )
|
||||
DEFINE_SCRIPTFUNC( LoadControlSettings, "" )\
|
||||
DEFINE_SCRIPTFUNC( FindChildByName, "" )
|
||||
#endif
|
||||
//--------------------------------------------------------------
|
||||
//--------------------------------------------------------------
|
||||
@ -2106,6 +2206,16 @@ public:
|
||||
{
|
||||
__base()->SetShouldScaleImage( state );
|
||||
}
|
||||
|
||||
void SetRotation( int rotation )
|
||||
{
|
||||
Assert( rotation == ROTATED_UNROTATED ||
|
||||
rotation == ROTATED_CLOCKWISE_90 ||
|
||||
rotation == ROTATED_ANTICLOCKWISE_90 ||
|
||||
rotation == ROTATED_FLIPPED );
|
||||
|
||||
__base()->SetRotation( rotation );
|
||||
}
|
||||
#if 0
|
||||
void SetFrame( int nFrame )
|
||||
{
|
||||
@ -2120,6 +2230,7 @@ public:
|
||||
DEFINE_SCRIPTFUNC( SetDrawColor, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetTileImage, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetShouldScaleImage, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetRotation, "" )\
|
||||
|
||||
//--------------------------------------------------------------
|
||||
//--------------------------------------------------------------
|
||||
@ -2435,10 +2546,10 @@ public:
|
||||
//--------------------------------------------------------------
|
||||
//--------------------------------------------------------------
|
||||
#if VGUI_TGA_IMAGE_PANEL
|
||||
CLASS_HELPER_INTERFACE( TGAImagePanel, Panel )
|
||||
CLASS_HELPER_INTERFACE( TGAImage, Panel )
|
||||
{
|
||||
public:
|
||||
void SetTGAImage( const char *p )
|
||||
void SetImage( const char *p )
|
||||
{
|
||||
__base()->SetTGAImage( p );
|
||||
}
|
||||
@ -2454,9 +2565,37 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_VGUI_SCRIPTFUNC_TGAImagePanel()\
|
||||
#define DEFINE_VGUI_SCRIPTFUNC_TGAImage()\
|
||||
DEFINE_VGUI_SCRIPTFUNC_Panel()\
|
||||
DEFINE_SCRIPTFUNC( SetTGAImage, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetImage, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetDrawColor, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetShouldScaleImage, "" )
|
||||
#endif
|
||||
//--------------------------------------------------------------
|
||||
//--------------------------------------------------------------
|
||||
#if 0
|
||||
CLASS_HELPER_INTERFACE( PNGImage, Panel )
|
||||
{
|
||||
public:
|
||||
void SetImage( const char *p )
|
||||
{
|
||||
__base()->SetPNGImage( p );
|
||||
}
|
||||
|
||||
void SetDrawColor( int r, int g, int b, int a )
|
||||
{
|
||||
__base()->SetDrawColor( r, g, b, a );
|
||||
}
|
||||
|
||||
void SetShouldScaleImage( bool i )
|
||||
{
|
||||
__base()->SetShouldScaleImage( i );
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_VGUI_SCRIPTFUNC_PNGImage()\
|
||||
DEFINE_VGUI_SCRIPTFUNC_Panel()\
|
||||
DEFINE_SCRIPTFUNC( SetImage, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetDrawColor, "" )\
|
||||
DEFINE_SCRIPTFUNC( SetShouldScaleImage, "" )
|
||||
#endif
|
||||
@ -2479,7 +2618,7 @@ static inline void SetHScript( HSCRIPT &var, HSCRIPT val )
|
||||
}
|
||||
|
||||
#define CheckCallback(s)\
|
||||
if ( FStrEq( cb, #s ) )\
|
||||
if ( !V_strcmp( cb, #s ) )\
|
||||
{\
|
||||
SetHScript( m_hfn##s, fn );\
|
||||
return;\
|
||||
@ -2515,6 +2654,7 @@ private:
|
||||
HSCRIPT m_hfnOnKeyCodePressed;
|
||||
HSCRIPT m_hfnOnKeyCodeReleased;
|
||||
HSCRIPT m_hfnOnKeyCodeTyped;
|
||||
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
HSCRIPT m_hfnOnCommand;
|
||||
#endif
|
||||
@ -2530,7 +2670,9 @@ public:
|
||||
m_hfnPerformLayout(NULL),
|
||||
m_hfnOnTick(NULL),
|
||||
m_hfnOnScreenSizeChanged(NULL),
|
||||
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
m_hfnOnCommand(NULL),
|
||||
#endif
|
||||
m_hfnOnCursorEntered(NULL),
|
||||
m_hfnOnCursorExited(NULL),
|
||||
m_hfnOnCursorMoved(NULL),
|
||||
@ -2543,13 +2685,9 @@ public:
|
||||
m_hfnOnKeyCodePressed(NULL),
|
||||
m_hfnOnKeyCodeReleased(NULL),
|
||||
m_hfnOnKeyCodeTyped(NULL)
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
,
|
||||
m_hfnOnCommand(NULL)
|
||||
#endif
|
||||
{}
|
||||
|
||||
void Shutdown()
|
||||
void ScriptShutdown()
|
||||
{
|
||||
ivgui()->RemoveTickSignal( GetVPanel() );
|
||||
|
||||
@ -2573,6 +2711,7 @@ public:
|
||||
SetHScript( m_hfnOnKeyCodePressed, NULL );
|
||||
SetHScript( m_hfnOnKeyCodeReleased, NULL );
|
||||
SetHScript( m_hfnOnKeyCodeTyped, NULL );
|
||||
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
SetHScript( m_hfnOnCommand, NULL );
|
||||
#endif
|
||||
@ -2775,6 +2914,7 @@ public:
|
||||
CheckCallback( OnKeyCodePressed );
|
||||
CheckCallback( OnKeyCodeReleased );
|
||||
CheckCallback( OnKeyCodeTyped );
|
||||
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
CheckCallback( OnCommand );
|
||||
#endif
|
||||
@ -2810,6 +2950,7 @@ private:
|
||||
HSCRIPT m_hfnOnKeyCodePressed;
|
||||
HSCRIPT m_hfnOnKeyCodeReleased;
|
||||
HSCRIPT m_hfnOnKeyCodeTyped;
|
||||
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
HSCRIPT m_hfnOnCommand;
|
||||
#endif
|
||||
@ -2826,6 +2967,9 @@ public:
|
||||
m_hfnPerformLayout(NULL),
|
||||
m_hfnOnTick(NULL),
|
||||
m_hfnOnScreenSizeChanged(NULL),
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
m_hfnOnCommand(NULL),
|
||||
#endif
|
||||
|
||||
m_hfnOnCursorEntered(NULL),
|
||||
m_hfnOnCursorExited(NULL),
|
||||
@ -2839,15 +2983,11 @@ public:
|
||||
m_hfnOnKeyCodePressed(NULL),
|
||||
m_hfnOnKeyCodeReleased(NULL),
|
||||
m_hfnOnKeyCodeTyped(NULL)
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
,
|
||||
m_hfnOnCommand(NULL)
|
||||
#endif
|
||||
{
|
||||
SetFadeEffectDisableOverride( true );
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
void ScriptShutdown()
|
||||
{
|
||||
ivgui()->RemoveTickSignal( GetVPanel() );
|
||||
|
||||
@ -2866,6 +3006,7 @@ public:
|
||||
SetHScript( m_hfnOnKeyCodePressed, NULL );
|
||||
SetHScript( m_hfnOnKeyCodeReleased, NULL );
|
||||
SetHScript( m_hfnOnKeyCodeTyped, NULL );
|
||||
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
SetHScript( m_hfnOnCommand, NULL );
|
||||
#endif
|
||||
@ -2898,7 +3039,18 @@ public:
|
||||
g_pScriptVM->ExecuteFunction( m_hfnPerformLayout, NULL, 0, NULL, NULL, true );
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
void ApplySchemeSettings( IScheme *pScheme )
|
||||
{
|
||||
BaseClass::ApplySchemeSettings( pScheme );
|
||||
|
||||
if ( m_hfnApplySchemeSettings )
|
||||
{
|
||||
ScriptVariant_t arg;
|
||||
g_pScriptVM->ExecuteFunction( m_hfnApplySchemeSettings, &arg, 1, NULL, NULL, true );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void OnTick()
|
||||
{
|
||||
g_pScriptVM->ExecuteFunction( m_hfnOnTick, NULL, 0, NULL, NULL, true );
|
||||
@ -3072,6 +3224,7 @@ public:
|
||||
CheckCallback( OnKeyCodePressed );
|
||||
CheckCallback( OnKeyCodeReleased );
|
||||
CheckCallback( OnKeyCodeTyped );
|
||||
|
||||
#if SCRIPT_VGUI_SIGNAL_INTERFACE
|
||||
CheckCallback( OnCommand );
|
||||
#endif
|
||||
@ -3102,7 +3255,7 @@ public:
|
||||
m_hfnDoClick(NULL)
|
||||
{}
|
||||
|
||||
void Shutdown()
|
||||
void ScriptShutdown()
|
||||
{
|
||||
SetHScript( m_hfnPaint, NULL );
|
||||
SetHScript( m_hfnPaintBackground, NULL );
|
||||
@ -3173,7 +3326,7 @@ public:
|
||||
m_hfnTextChanged(NULL)
|
||||
{}
|
||||
|
||||
void Shutdown()
|
||||
void ScriptShutdown()
|
||||
{
|
||||
SetHScript( m_hfnTextChanged, NULL );
|
||||
}
|
||||
@ -3216,9 +3369,12 @@ public:
|
||||
SetShouldDrawFriendIcon( false );
|
||||
}
|
||||
|
||||
DEBUG_DESTRUCTOR( ~CScript_AvatarImage, CAvatarImagePanel )
|
||||
~CScript_AvatarImage()
|
||||
{
|
||||
DebugDestructor( CAvatarImagePanel );
|
||||
}
|
||||
|
||||
void Shutdown() {}
|
||||
void ScriptShutdown() {}
|
||||
};
|
||||
#endif
|
||||
//--------------------------------------------------------------
|
||||
@ -3229,7 +3385,7 @@ class CTGAImagePanel : public Panel
|
||||
DECLARE_SCRIPTVGUI_CLASS_EX( CTGAImagePanel, Panel );
|
||||
|
||||
private:
|
||||
int m_iTextureID;
|
||||
int m_iTexture;
|
||||
int m_nWidth;
|
||||
int m_nHeight;
|
||||
Color m_ImageColor;
|
||||
@ -3238,7 +3394,7 @@ private:
|
||||
public:
|
||||
CTGAImagePanel( Panel *parent, const char *name ) :
|
||||
BaseClass( parent, name ),
|
||||
m_iTextureID(-1),
|
||||
m_iTexture(-1),
|
||||
m_bScaleImage(0),
|
||||
m_ImageColor( 255, 255, 255, 255 )
|
||||
{
|
||||
@ -3249,21 +3405,21 @@ public:
|
||||
{
|
||||
DebugDestructor( CTGAImagePanel );
|
||||
|
||||
if ( m_iTextureID != -1 )
|
||||
if ( m_iTexture != -1 )
|
||||
{
|
||||
surface()->DestroyTextureID( m_iTextureID );
|
||||
surface()->DestroyTextureID( m_iTexture );
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown() {}
|
||||
void ScriptShutdown() {}
|
||||
|
||||
public:
|
||||
void Paint()
|
||||
{
|
||||
if ( m_iTextureID != -1 )
|
||||
if ( m_iTexture != -1 )
|
||||
{
|
||||
surface()->DrawSetColor( m_ImageColor );
|
||||
surface()->DrawSetTexture( m_iTextureID );
|
||||
surface()->DrawSetTexture( m_iTexture );
|
||||
|
||||
if ( m_bScaleImage )
|
||||
{
|
||||
@ -3288,19 +3444,21 @@ public:
|
||||
public:
|
||||
void SetTGAImage( const char *fileName )
|
||||
{
|
||||
if ( V_stricmp( V_GetFileExtension( fileName ), "tga" ) != 0 )
|
||||
const char *ext = V_GetFileExtension( fileName );
|
||||
|
||||
if ( ext && V_stricmp( ext, "tga" ) != 0 )
|
||||
return;
|
||||
|
||||
CUtlMemory< unsigned char > tga;
|
||||
|
||||
if ( TGALoader::LoadRGBA8888( fileName, tga, m_nWidth, m_nHeight ) )
|
||||
{
|
||||
if ( m_iTextureID == -1 )
|
||||
if ( m_iTexture == -1 )
|
||||
{
|
||||
m_iTextureID = surface()->CreateNewTextureID( true );
|
||||
m_iTexture = surface()->CreateNewTextureID( true );
|
||||
}
|
||||
|
||||
surface()->DrawSetTextureRGBA( m_iTextureID, tga.Base(), m_nWidth, m_nHeight, false, false );
|
||||
surface()->DrawSetTextureRGBA( m_iTexture, tga.Base(), m_nWidth, m_nHeight, false, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3393,10 +3551,19 @@ END_SCRIPTDESC()
|
||||
//--------------------------------------------------------------
|
||||
//--------------------------------------------------------------
|
||||
#if VGUI_TGA_IMAGE_PANEL
|
||||
BEGIN_VGUI_HELPER_EX( TGAImagePanel, CTGAImagePanel )
|
||||
BEGIN_VGUI_HELPER_EX( TGAImage, CTGAImagePanel )
|
||||
END_VGUI_HELPER()
|
||||
|
||||
BEGIN_SCRIPTDESC_VGUI( TGAImagePanel )
|
||||
BEGIN_SCRIPTDESC_VGUI( TGAImage )
|
||||
END_SCRIPTDESC()
|
||||
#endif
|
||||
//--------------------------------------------------------------
|
||||
//--------------------------------------------------------------
|
||||
#if 0
|
||||
BEGIN_VGUI_HELPER_EX( PNGImage, CPNGImagePanel )
|
||||
END_VGUI_HELPER()
|
||||
|
||||
BEGIN_SCRIPTDESC_VGUI( PNGImage )
|
||||
END_SCRIPTDESC()
|
||||
#endif
|
||||
//--------------------------------------------------------------
|
||||
@ -3448,7 +3615,7 @@ HSCRIPT CScriptVGUI::CreatePanel( const char* panelClass, HSCRIPT parent, const
|
||||
}
|
||||
|
||||
#define Check( _name )\
|
||||
if ( FStrEq( panelClass, #_name ) )\
|
||||
if ( !V_strcmp( panelClass, #_name ) )\
|
||||
{\
|
||||
CScript_##_name##_Helper *helper = AllocScriptPanel< CScript_##_name##_Helper >();\
|
||||
helper->CreateFromScript< CScript_##_name##_Helper >( (HSCRIPT)parent, panelName, root );\
|
||||
@ -3467,7 +3634,7 @@ HSCRIPT CScriptVGUI::CreatePanel( const char* panelClass, HSCRIPT parent, const
|
||||
Check( AvatarImage );
|
||||
#endif
|
||||
#if VGUI_TGA_IMAGE_PANEL
|
||||
Check( TGAImagePanel );
|
||||
Check( TGAImage );
|
||||
#endif
|
||||
|
||||
g_pScriptVM->RaiseException("invalid vgui class");
|
||||
@ -3480,25 +3647,33 @@ void CScriptVGUI::LevelShutdownPostEntity()
|
||||
{
|
||||
DebugMsg( "LevelShutdownPostEntity()\n" );
|
||||
|
||||
while ( g_ScriptPanels.Count() )
|
||||
if ( g_ScriptPanels.Count() )
|
||||
{
|
||||
Assert( g_ScriptPanels.Head() != g_ScriptPanels.InvalidIndex() );
|
||||
while ( g_ScriptPanels.Count() )
|
||||
{
|
||||
Assert( g_ScriptPanels.Head() != g_ScriptPanels.InvalidIndex() );
|
||||
|
||||
int head = g_ScriptPanels.Head();
|
||||
g_ScriptPanels[ head ]->Destroy( head );
|
||||
int head = g_ScriptPanels.Head();
|
||||
g_ScriptPanels[ head ]->Destroy( head );
|
||||
}
|
||||
|
||||
g_ScriptPanels.Purge();
|
||||
}
|
||||
g_ScriptPanels.Purge();
|
||||
|
||||
FOR_EACH_VEC( g_ScriptTextureIDs, i )
|
||||
if ( int i = g_ScriptTextureIDs.Count() )
|
||||
{
|
||||
while ( i-- )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
char tex[MAX_PATH];
|
||||
surface()->DrawGetTextureFile( g_ScriptTextureIDs[i], tex, sizeof(tex)-1 );
|
||||
DebugMsg( "Destroy texture [%i]%s\n", g_ScriptTextureIDs[i], tex );
|
||||
char tex[MAX_PATH];
|
||||
surface()->DrawGetTextureFile( g_ScriptTextureIDs[i], tex, sizeof(tex)-1 );
|
||||
DebugMsg( "Destroy texture [%i]%s\n", g_ScriptTextureIDs[i], tex );
|
||||
#endif
|
||||
surface()->DestroyTextureID( g_ScriptTextureIDs[i] );
|
||||
surface()->DestroyTextureID( g_ScriptTextureIDs[i] );
|
||||
}
|
||||
|
||||
g_ScriptTextureIDs.Purge();
|
||||
}
|
||||
g_ScriptTextureIDs.Purge();
|
||||
|
||||
//
|
||||
// Reset hud element visibility
|
||||
|
@ -1,6 +1,6 @@
|
||||
static const char* g_Script_vgui_init = R"script(
|
||||
local DoCreateFont = ISurface.CreateFont;
|
||||
ISurface.CreateFont <- function( name, props )
|
||||
function ISurface::CreateFont( name, props )
|
||||
{
|
||||
if ( !("name" in props) || typeof props.name != "string" )
|
||||
throw "invalid parameter 'name'";
|
||||
@ -86,12 +86,12 @@ ISurface.CreateFont <- function( name, props )
|
||||
return DoCreateFont( name, props.name, props.tall, props.weight, blur, scanlines, flags, yres_min, yres_max, proportional );
|
||||
}
|
||||
|
||||
local _Schemes = {}
|
||||
local _FontTall = {}
|
||||
local _Schemes = {}
|
||||
local DoGetFont = ISurface.DoGetFont <- ISurface.GetFont;
|
||||
local DoGetFontTall = ISurface.GetFontTall;
|
||||
|
||||
ISurface.GetFont <- function( name, proportional, sch = "" )
|
||||
function ISurface::GetFont( name, proportional, sch = "" )
|
||||
{
|
||||
if ( sch in _Schemes )
|
||||
{
|
||||
@ -151,33 +151,28 @@ ISurface.GetTextureID <- function( name )
|
||||
}
|
||||
|
||||
// Forward compatibility
|
||||
IVGui.GetRootPanel <- function() { return 1000 }
|
||||
//IVGui.GetGameUIRootPanel <- function() { return 1001 }
|
||||
IVGui.GetClientDLLRootPanel <- function() { return 1002 }
|
||||
//IVGui.GetHudViewportPanel <- function() { return 1010 }
|
||||
IVGui.GetRootPanel <- function() { return 0x8888 }
|
||||
//IVGui.GetGameUIRootPanel <- function() { return 0x8888+1 }
|
||||
IVGui.GetClientDLLRootPanel <- function() { return 0x8888+2 }
|
||||
IVGui.GetHudViewport <- function() { return 0x8888+10 }
|
||||
|
||||
local CreatePanel = IVGui.CreatePanel;
|
||||
IVGui.CreatePanel <- function( type, parent, name )
|
||||
function IVGui::CreatePanel( type, parent, name )
|
||||
{
|
||||
if ( !parent )
|
||||
throw "invalid parent";
|
||||
|
||||
local root = 0;
|
||||
|
||||
local root = -1;
|
||||
if ( typeof parent == "integer" )
|
||||
{
|
||||
switch ( parent )
|
||||
root = parent-0x8888;
|
||||
switch ( root )
|
||||
{
|
||||
case 1000:
|
||||
root = 0;
|
||||
case 0:
|
||||
case 2:
|
||||
case 10:
|
||||
break;
|
||||
|
||||
case 1002:
|
||||
root = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw "invalid parent";
|
||||
default: throw "invalid parent";
|
||||
}
|
||||
parent = null;
|
||||
}
|
||||
@ -390,5 +385,6 @@ if ( __Documentation.RegisterHelp != dummy )
|
||||
__Documentation.RegisterHelp( "IVGui::CreatePanel", "handle IVGui::CreatePanel(string, handle, string)", "" );
|
||||
__Documentation.RegisterHelp( "IVGui::GetRootPanel", "handle IVGui::GetRootPanel()", "" );
|
||||
__Documentation.RegisterHelp( "IVGui::GetClientDLLRootPanel", "handle IVGui::GetClientDLLRootPanel()", "" );
|
||||
__Documentation.RegisterHelp( "IVGui::GetHudViewport", "handle IVGui::GetHudViewport()", "" );
|
||||
}
|
||||
)script";
|
||||
|
@ -447,6 +447,8 @@ void CHudMessage::MessageScanStart( void )
|
||||
break;
|
||||
}
|
||||
|
||||
// Font was just set in MessageDrawScan()
|
||||
#ifndef MAPBASE
|
||||
m_parms.font = g_hFontTrebuchet24;
|
||||
|
||||
if ( m_parms.vguiFontName != NULL &&
|
||||
@ -455,6 +457,7 @@ void CHudMessage::MessageScanStart( void )
|
||||
|
||||
SetFont( vgui::scheme()->GetDefaultScheme(), m_parms.vguiFontName );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -497,7 +500,30 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time )
|
||||
m_parms.totalWidth = 0;
|
||||
m_parms.vguiFontName = pMessage->pVGuiSchemeFontName;
|
||||
|
||||
#ifdef MAPBASE
|
||||
if ( m_parms.vguiFontName != NULL &&
|
||||
m_parms.vguiFontName[ 0 ] )
|
||||
{
|
||||
SetFont( vgui::scheme()->GetDefaultScheme(), m_parms.vguiFontName );
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
if ( m_parms.font == vgui::INVALID_FONT )
|
||||
{
|
||||
extern vgui::HFont GetScriptFont( const char *, bool );
|
||||
|
||||
vgui::HFont font = GetScriptFont( m_parms.vguiFontName, IsProportional() );
|
||||
textmessage->SetFont( font );
|
||||
m_parms.font = font;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
m_parms.font = g_hFontTrebuchet24;
|
||||
}
|
||||
#else
|
||||
m_parms.font = g_hFontTrebuchet24;
|
||||
#endif
|
||||
|
||||
while ( *pText )
|
||||
{
|
||||
|
@ -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->GetName(), ucmd->weaponsubtype );
|
||||
player->SelectItem( weapon->GetClassname(), ucmd->weaponsubtype );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,6 @@ const Vector& CScriptMaterialProxy::GetVarVector( int i )
|
||||
if (m_MaterialVars[i]->GetType() != MATERIAL_VAR_TYPE_VECTOR)
|
||||
return vec3_origin;
|
||||
|
||||
// This is really bad. Too bad!
|
||||
return *(reinterpret_cast<const Vector*>(m_MaterialVars[i]->GetVecValue()));
|
||||
}
|
||||
|
||||
@ -761,6 +760,8 @@ public:
|
||||
virtual void LevelShutdownPostEntity( void )
|
||||
{
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
g_ScriptEntityIterator.DisableEntityListening();
|
||||
|
||||
g_ScriptNetMsg->LevelShutdownPreVM();
|
||||
|
||||
GetScriptHookManager().OnShutdown();
|
||||
|
@ -76,6 +76,23 @@ int CAI_BaseNPC::GetActivityID(const char* actName)
|
||||
return m_pActivitySR->GetStringID(actName);
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets an activity ID or registers a new private one if it doesn't exist
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAI_BaseNPC::GetOrRegisterActivity( const char *actName )
|
||||
{
|
||||
int actID = GetActivityID( actName );
|
||||
if (actID == ACT_INVALID)
|
||||
{
|
||||
actID = ActivityList_RegisterPrivateActivity( actName );
|
||||
AddActivityToSR( actName, actID );
|
||||
}
|
||||
|
||||
return actID;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ADD_ACTIVITY_TO_SR(activityname) AddActivityToSR(#activityname,activityname)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -671,13 +671,27 @@ void CAI_BaseNPC::Ignite( float flFlameLifetime, bool bNPCOnly, float flSize, bo
|
||||
{
|
||||
BaseClass::Ignite( flFlameLifetime, bNPCOnly, flSize, bCalledByLevelDesigner );
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Alyx's enemy ignited code from below can now be run on any NPC as long as
|
||||
// it's our current enemy.
|
||||
if ( GetEnemy() && GetEnemy()->IsNPC() )
|
||||
{
|
||||
GetEnemy()->MyNPCPointer()->EnemyIgnited( this );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HL2_EPISODIC
|
||||
CBasePlayer *pPlayer = AI_GetSinglePlayer();
|
||||
if ( pPlayer && pPlayer->IRelationType( this ) != D_LI )
|
||||
{
|
||||
CNPC_Alyx *alyx = CNPC_Alyx::GetAlyx();
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Alyx's code continues to run if Alyx was not this NPC's enemy.
|
||||
if ( alyx && alyx != GetEnemy() )
|
||||
#else
|
||||
if ( alyx )
|
||||
#endif
|
||||
{
|
||||
alyx->EnemyIgnited( this );
|
||||
}
|
||||
@ -3026,6 +3040,10 @@ void CAI_BaseNPC::PopulatePoseParameters( void )
|
||||
m_poseAim_Yaw = LookupPoseParameter( "aim_yaw" );
|
||||
m_poseMove_Yaw = LookupPoseParameter( "move_yaw" );
|
||||
|
||||
#ifdef MAPBASE
|
||||
m_poseInteractionRelativeYaw = LookupPoseParameter( "interaction_relative_yaw" );
|
||||
#endif
|
||||
|
||||
BaseClass::PopulatePoseParameters();
|
||||
}
|
||||
|
||||
@ -9526,6 +9544,12 @@ void CAI_BaseNPC::HandleAnimEvent( animevent_t *pEvent )
|
||||
{
|
||||
m_hCine->FireScriptEvent( atoi( pEvent->options ) );
|
||||
}
|
||||
#ifdef MAPBASE
|
||||
else if ( GetHintNode() )
|
||||
{
|
||||
GetHintNode()->FireScriptEvent( atoi( pEvent->options ) );
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
// FIXME: look so see if it's playing a vcd and fire those instead
|
||||
@ -12333,6 +12357,7 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC
|
||||
|
||||
DEFINE_SCRIPTFUNC( IsCommandable, "Check if the NPC is commandable." )
|
||||
DEFINE_SCRIPTFUNC( IsInPlayerSquad, "Check if the NPC is in the player's squad." )
|
||||
DEFINE_SCRIPTFUNC( IsMedic, "Returns true if this NPC is a medic." )
|
||||
|
||||
DEFINE_SCRIPTFUNC_NAMED( VScriptGetCine, "GetCine", "Get the NPC's currently running scripted sequence if it has one." )
|
||||
DEFINE_SCRIPTFUNC( GetScriptState, "Get the NPC's current scripted sequence state." )
|
||||
@ -12443,7 +12468,11 @@ BEGIN_SIMPLE_DATADESC( ScriptedNPCInteraction_t )
|
||||
DEFINE_FIELD( bValidOnCurrentEnemy, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( flNextAttemptTime, FIELD_TIME ),
|
||||
#ifdef MAPBASE
|
||||
DEFINE_FIELD( MiscCriteria, FIELD_STRING ),//DEFINE_UTLVECTOR( MiscCriteria, FIELD_EMBEDDED ),
|
||||
DEFINE_EMBEDDED_ARRAY( sTheirPhases, SNPCINT_NUM_PHASES ),
|
||||
DEFINE_FIELD( bHasSeparateSequenceNames, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( flMaxAngleDiff, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( iszRelatedInteractions, FIELD_STRING ),
|
||||
DEFINE_FIELD( MiscCriteria, FIELD_STRING ),
|
||||
#endif
|
||||
END_DATADESC()
|
||||
|
||||
@ -13200,17 +13229,14 @@ void CAI_BaseNPC::InputSetEnemyFilter( inputdata_t &inputdata )
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAI_BaseNPC::InputSetHealthFraction( inputdata_t &inputdata )
|
||||
{
|
||||
// npc_helicopter uses SetHealth() instead of the regular NPC practice of TakeHealth() and TakeDamage().
|
||||
// It also also uses 50, 75, etc. and scales it by 0.01 for some reason.
|
||||
// We're using the same model as InputSetHealth() and just letting npc_helicopter override it. No big deal.
|
||||
// We're also adding support for its "whole number * 0.01" thing too.
|
||||
// npc_helicopter uses an identically named input and scales down whole numbers instead of using fractions directly.
|
||||
// This function is overridden by npc_helicopter for other reasons, but support for its differing behavior is also available through this input.
|
||||
float flFactor = inputdata.value.Float();
|
||||
if ( flFactor > 1.0f )
|
||||
{
|
||||
flFactor *= 0.01f;
|
||||
}
|
||||
|
||||
// Excuse the complication...
|
||||
float flNewHealth = (GetMaxHealth() * flFactor);
|
||||
int iNewHealth = (int)flNewHealth;
|
||||
if (flNewHealth < (GetMaxHealth() / 2))
|
||||
@ -13510,6 +13536,10 @@ bool CAI_BaseNPC::CineCleanup()
|
||||
}
|
||||
|
||||
// Clear interaction partner, because we're not running a scripted sequence anymore
|
||||
#ifdef MAPBASE
|
||||
// We need the interaction partner for server ragdoll death cleanup, so don't clear if we're not alive
|
||||
if (IsAlive())
|
||||
#endif
|
||||
m_hInteractionPartner = NULL;
|
||||
CleanupForcedInteraction();
|
||||
}
|
||||
@ -14850,32 +14880,66 @@ void CAI_BaseNPC::ParseScriptedNPCInteractions(void)
|
||||
else if (!Q_strncmp(szName, "entry_sequence", 14))
|
||||
sInteraction.sPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szName, "entry_activity", 14))
|
||||
sInteraction.sPhases[SNPCINT_ENTRY].iActivity = GetActivityID(szValue);
|
||||
sInteraction.sPhases[SNPCINT_ENTRY].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "sequence", 8))
|
||||
sInteraction.sPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szName, "activity", 8))
|
||||
sInteraction.sPhases[SNPCINT_SEQUENCE].iActivity = GetActivityID(szValue);
|
||||
sInteraction.sPhases[SNPCINT_SEQUENCE].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "exit_sequence", 13))
|
||||
sInteraction.sPhases[SNPCINT_EXIT].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szName, "exit_activity", 13))
|
||||
sInteraction.sPhases[SNPCINT_EXIT].iActivity = GetActivityID(szValue);
|
||||
sInteraction.sPhases[SNPCINT_EXIT].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "their_", 6))
|
||||
{
|
||||
const char *szTheirName = szName + 6;
|
||||
sInteraction.bHasSeparateSequenceNames = true;
|
||||
|
||||
if (!Q_strncmp(szTheirName, "entry_sequence", 14))
|
||||
sInteraction.sTheirPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szTheirName, "entry_activity", 14))
|
||||
sInteraction.sTheirPhases[SNPCINT_ENTRY].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szTheirName, "sequence", 8))
|
||||
sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szTheirName, "activity", 8))
|
||||
sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szTheirName, "exit_sequence", 13))
|
||||
sInteraction.sTheirPhases[SNPCINT_EXIT].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szTheirName, "exit_activity", 13))
|
||||
sInteraction.sTheirPhases[SNPCINT_EXIT].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
// Add anything else to our miscellaneous criteria
|
||||
else
|
||||
{
|
||||
szCriteria = UTIL_VarArgs("%s,%s:%s", szCriteria, szName, szValue);
|
||||
}
|
||||
}
|
||||
|
||||
else if (!Q_strncmp(szName, "delay", 5))
|
||||
sInteraction.flDelay = atof(szValue);
|
||||
else if (!Q_strncmp(szName, "origin_max_delta", 16))
|
||||
sInteraction.flDistSqr = atof(szValue);
|
||||
else if (!Q_strncmp(szName, "angles_max_diff", 15))
|
||||
sInteraction.flMaxAngleDiff = atof(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "loop_in_action", 14) && !FStrEq(szValue, "0"))
|
||||
sInteraction.iFlags |= SCNPC_FLAG_LOOP_IN_ACTION;
|
||||
|
||||
else if (!Q_strncmp(szName, "dont_teleport_at_end", 20))
|
||||
{
|
||||
if (!Q_stricmp(szValue, "me") || !Q_stricmp(szValue, "both"))
|
||||
if (!Q_stricmp(szValue, "me"))
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_ME;
|
||||
else if (!Q_stricmp(szValue, "them") || !Q_stricmp(szValue, "both"))
|
||||
else if (!Q_stricmp(szValue, "them"))
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM;
|
||||
else if (!Q_stricmp( szValue, "both" ))
|
||||
{
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_ME;
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!Q_strncmp(szName, "needs_weapon", 12))
|
||||
@ -14902,6 +14966,11 @@ void CAI_BaseNPC::ParseScriptedNPCInteractions(void)
|
||||
sInteraction.iszTheirWeapon = AllocPooledString(szValue);
|
||||
}
|
||||
|
||||
else if (!Q_strncmp(szName, "related_interactions", 20))
|
||||
{
|
||||
sInteraction.iszRelatedInteractions = AllocPooledString(szValue);
|
||||
}
|
||||
|
||||
// Add anything else to our miscellaneous criteria
|
||||
else
|
||||
{
|
||||
@ -15133,8 +15202,23 @@ void CAI_BaseNPC::AddScriptedNPCInteraction( ScriptedNPCInteraction_t *pInteract
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CAI_BaseNPC::GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase )
|
||||
const char *CAI_BaseNPC::GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase, bool bOtherNPC )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if (bOtherNPC && pInteraction->bHasSeparateSequenceNames)
|
||||
{
|
||||
// Check unique phases
|
||||
if ( pInteraction->sTheirPhases[iPhase].iActivity != ACT_INVALID )
|
||||
{
|
||||
int iSequence = SelectWeightedSequence( (Activity)pInteraction->sTheirPhases[iPhase].iActivity );
|
||||
return GetSequenceName( iSequence );
|
||||
}
|
||||
|
||||
if ( pInteraction->sTheirPhases[iPhase].iszSequence != NULL_STRING )
|
||||
return STRING(pInteraction->sTheirPhases[iPhase].iszSequence);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( pInteraction->sPhases[iPhase].iActivity != ACT_INVALID )
|
||||
{
|
||||
int iSequence = SelectWeightedSequence( (Activity)pInteraction->sPhases[iPhase].iActivity );
|
||||
@ -15228,6 +15312,37 @@ void CAI_BaseNPC::StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedN
|
||||
|
||||
// Setup next attempt
|
||||
pInteraction->flNextAttemptTime = gpGlobals->curtime + pInteraction->flDelay + RandomFloat(-2,2);
|
||||
#ifdef MAPBASE
|
||||
if (pInteraction->iszRelatedInteractions != NULL_STRING)
|
||||
{
|
||||
// Delay related interactions as well
|
||||
char szRelatedInteractions[256];
|
||||
Q_strncpy( szRelatedInteractions, STRING( pInteraction->iszRelatedInteractions ), sizeof( szRelatedInteractions ) );
|
||||
|
||||
char *pszInteraction = strtok( szRelatedInteractions, "," );
|
||||
while (pszInteraction)
|
||||
{
|
||||
bool bWildCard = Matcher_ContainsWildcard( pszInteraction );
|
||||
|
||||
for ( int i = 0; i < m_ScriptedInteractions.Count(); i++ )
|
||||
{
|
||||
ScriptedNPCInteraction_t *pOtherInteraction = &m_ScriptedInteractions[i];
|
||||
|
||||
if ( Matcher_NamesMatch( pszInteraction, STRING( pOtherInteraction->iszInteractionName ) ) && pOtherInteraction != pInteraction )
|
||||
{
|
||||
if (pOtherInteraction->flNextAttemptTime < pInteraction->flNextAttemptTime)
|
||||
pOtherInteraction->flNextAttemptTime = pInteraction->flNextAttemptTime;
|
||||
|
||||
// Not looking for multiple
|
||||
if (!bWildCard)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pszInteraction = strtok( NULL, "," );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Spawn a scripted sequence for this NPC to play the interaction anim
|
||||
CAI_ScriptedSequence *pMySequence = (CAI_ScriptedSequence*)CreateEntityByName( "scripted_sequence" );
|
||||
@ -15259,6 +15374,15 @@ void CAI_BaseNPC::StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedN
|
||||
CAI_ScriptedSequence *pTheirSequence = NULL;
|
||||
if ( pOtherNPC )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if (pInteraction->bHasSeparateSequenceNames)
|
||||
{
|
||||
pszEntrySequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_ENTRY, true );
|
||||
pszSequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_SEQUENCE, true );
|
||||
pszExitSequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_EXIT, true );
|
||||
}
|
||||
#endif
|
||||
|
||||
pTheirSequence = (CAI_ScriptedSequence*)CreateEntityByName( "scripted_sequence" );
|
||||
pTheirSequence->KeyValue( "m_iszEntry", pszEntrySequence );
|
||||
pTheirSequence->KeyValue( "m_iszPlay", pszSequence );
|
||||
@ -15282,6 +15406,26 @@ void CAI_BaseNPC::StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedN
|
||||
|
||||
// Tell their sequence to keep their position relative to me
|
||||
pTheirSequence->SetupInteractionPosition( this, pInteraction->matDesiredLocalToWorld );
|
||||
|
||||
#ifdef MAPBASE
|
||||
if ( !(pInteraction->iFlags & SCNPC_FLAG_TEST_OTHER_ANGLES) )
|
||||
{
|
||||
// Set up interaction yaw pose if it exists
|
||||
float flYaw = AngleDistance( angDesired.y, angOtherAngles.y );
|
||||
|
||||
int nInteractionPose = LookupPoseInteractionRelativeYaw();
|
||||
if (nInteractionPose > -1)
|
||||
{
|
||||
SetPoseParameter( nInteractionPose, flYaw );
|
||||
}
|
||||
|
||||
nInteractionPose = pOtherNPC->LookupPoseInteractionRelativeYaw();
|
||||
if (nInteractionPose > -1)
|
||||
{
|
||||
pOtherNPC->SetPoseParameter( nInteractionPose, flYaw );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Spawn both sequences at once
|
||||
@ -15370,7 +15514,7 @@ bool CAI_BaseNPC::CanRunAScriptedNPCInteraction( bool bForced )
|
||||
return false;
|
||||
|
||||
// Default AI prevents interactions while melee attacking, but not ranged attacking
|
||||
if ( IsCurSchedule( SCHED_MELEE_ATTACK1 ) || IsCurSchedule( SCHED_MELEE_ATTACK2 ) )
|
||||
if ( ( IsCurSchedule( SCHED_MELEE_ATTACK1 ) || IsCurSchedule( SCHED_MELEE_ATTACK2 ) ) && !CanStartDynamicInteractionDuringMelee() )
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -15559,8 +15703,14 @@ void CAI_BaseNPC::CalculateValidEnemyInteractions( void )
|
||||
|
||||
if (bSame)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
// Resolve the activity or sequence, and make sure our enemy has it
|
||||
const char *pszSequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_SEQUENCE, true );
|
||||
if ( !pszSequence )
|
||||
continue;
|
||||
if ( pNPC->LookupSequence( pszSequence ) == -1 )
|
||||
continue;
|
||||
#else
|
||||
// Use sequence? or activity?
|
||||
if ( pInteraction->sPhases[SNPCINT_SEQUENCE].iActivity != ACT_INVALID )
|
||||
{
|
||||
@ -15576,53 +15726,6 @@ void CAI_BaseNPC::CalculateValidEnemyInteractions( void )
|
||||
if ( pNPC->LookupSequence( STRING(pInteraction->sPhases[SNPCINT_SEQUENCE].iszSequence) ) == -1 )
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
if (pInteraction->MiscCriteria != NULL_STRING)
|
||||
{
|
||||
// Test against response system criteria
|
||||
AI_CriteriaSet set;
|
||||
ModifyOrAppendCriteria( set );
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
if( pPlayer )
|
||||
pPlayer->ModifyOrAppendPlayerCriteria( set );
|
||||
ReAppendContextCriteria( set );
|
||||
|
||||
DevMsg("Testing %s misc criteria\n", STRING(pInteraction->MiscCriteria));
|
||||
|
||||
int index;
|
||||
const char *criteriavalue;
|
||||
char key[128];
|
||||
char value[128];
|
||||
const char *p = STRING(pInteraction->MiscCriteria);
|
||||
while ( p )
|
||||
{
|
||||
#ifdef NEW_RESPONSE_SYSTEM
|
||||
p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL, STRING(pInteraction->MiscCriteria) );
|
||||
#else
|
||||
p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL );
|
||||
#endif
|
||||
|
||||
index = set.FindCriterionIndex(key);
|
||||
if (index != -1)
|
||||
{
|
||||
criteriavalue = set.GetValue(index);
|
||||
if (!Matcher_Match(value, criteriavalue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test with empty string in case our criteria is != or something
|
||||
criteriavalue = "";
|
||||
if (!Matcher_Match(value, criteriavalue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pInteraction->bValidOnCurrentEnemy = true;
|
||||
@ -15792,7 +15895,95 @@ bool CAI_BaseNPC::InteractionIsAllowed( CAI_BaseNPC *pOtherNPC, ScriptedNPCInter
|
||||
return true;
|
||||
|
||||
// m_iDynamicInteractionsAllowed == TRS_FALSE case is already handled in CanRunAScriptedNPCInteraction().
|
||||
return !(pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE);
|
||||
if (pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE)
|
||||
return false;
|
||||
|
||||
// Test misc. criteria here since some of it may not have been valid on initial calculation, but could be now
|
||||
if (pInteraction->MiscCriteria != NULL_STRING)
|
||||
{
|
||||
// Test against response system criteria
|
||||
AI_CriteriaSet set;
|
||||
ModifyOrAppendCriteria( set );
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
if (pPlayer)
|
||||
pPlayer->ModifyOrAppendPlayerCriteria( set );
|
||||
|
||||
// Get criteria from target if we want it
|
||||
if ( V_strstr( STRING( pInteraction->MiscCriteria ), "their_" ) )
|
||||
{
|
||||
// Currently, in order to get everything which might be desired, we call the other NPC's ModifyOrAppendCriteria.
|
||||
// We put it in a separate criteria set, then assign a prefix and append it to the main set, similar to how contexts are appended.
|
||||
// This includes a few global criterions which we might not need, so we throw them out before they're merged.
|
||||
// This isn't a very efficient solution, but there are no better options available without rewriting parts of the response criteria system.
|
||||
AI_CriteriaSet theirSet;
|
||||
pOtherNPC->ModifyOrAppendCriteria( theirSet );
|
||||
|
||||
set.EnsureCapacity( (theirSet.GetCount()-2) + set.GetCount() ); // We know we'll be throwing out 2 global criterions
|
||||
|
||||
char sz[ 128 ];
|
||||
for ( int i = 0; i < theirSet.GetCount(); i++ )
|
||||
{
|
||||
const char *name = theirSet.GetName( i );
|
||||
const char *value = theirSet.GetValue( i );
|
||||
|
||||
if (FStrEq( name, "map" ) || FStrEq( name, "episodic" ) || FStrEq( name, "is_console" )
|
||||
|| FStrEq( name, "month" ) || FStrEq( name, "day" )
|
||||
|| FStrEq( name, "is_console" ) || FStrEq( name, "is_pc" )
|
||||
|| V_strnicmp( name, "world", 5 ) == 0)
|
||||
{
|
||||
// Global criterion, ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
Q_snprintf( sz, sizeof( sz ), "their_%s", name );
|
||||
|
||||
if (ai_debug_dyninteractions.GetInt() == 3)
|
||||
Msg( "%i: %s -> %s:%s\n", i, name, sz, value );
|
||||
|
||||
set.AppendCriteria( sz, value );
|
||||
}
|
||||
|
||||
// Append this afterwards because it has its own prefix system
|
||||
pOtherNPC->AppendContextToCriteria( set, "their_" );
|
||||
}
|
||||
|
||||
ReAppendContextCriteria( set );
|
||||
|
||||
int index;
|
||||
const char *criteriavalue;
|
||||
char key[128];
|
||||
char value[128];
|
||||
const char *p = STRING( pInteraction->MiscCriteria );
|
||||
while ( p )
|
||||
{
|
||||
#ifdef NEW_RESPONSE_SYSTEM
|
||||
p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL, STRING( pInteraction->MiscCriteria ) );
|
||||
#else
|
||||
p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL );
|
||||
#endif
|
||||
|
||||
index = set.FindCriterionIndex( key );
|
||||
if (index != -1)
|
||||
{
|
||||
criteriavalue = set.GetValue( index );
|
||||
if (!Matcher_Match( value, criteriavalue ))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test with empty string in case our criteria is != or something
|
||||
criteriavalue = "";
|
||||
if (!Matcher_Match( value, criteriavalue ))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -15830,6 +16021,11 @@ bool CAI_BaseNPC::InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInte
|
||||
{
|
||||
Msg(" %s distsqr: %0.2f (%0.2f %0.2f %0.2f), desired: <%0.2f (%0.2f %0.2f %0.2f)\n", GetDebugName(), flDistSqr,
|
||||
pOtherNPC->GetAbsOrigin().x, pOtherNPC->GetAbsOrigin().y, pOtherNPC->GetAbsOrigin().z, pInteraction->flDistSqr, vecOrigin.x, vecOrigin.y, vecOrigin.z );
|
||||
#ifdef MAPBASE
|
||||
Vector vecForward, vecRight;
|
||||
GetVectors( &vecForward, &vecRight, NULL );
|
||||
NDebugOverlay::Circle( vecOrigin + Vector(0,0,2), vecForward, vecRight, FastSqrt(pInteraction->flDistSqr), 255, 0, 0, 255, true, 0.1f );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15842,6 +16038,11 @@ bool CAI_BaseNPC::InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInte
|
||||
Msg(" %s is at: %0.2f %0.2f %0.2f\n", GetDebugName(), GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
|
||||
Msg(" %s distsqr: %0.2f (%0.2f %0.2f %0.2f), desired: (%0.2f %0.2f %0.2f)\n", GetDebugName(), flDistSqr,
|
||||
pOtherNPC->GetAbsOrigin().x, pOtherNPC->GetAbsOrigin().y, pOtherNPC->GetAbsOrigin().z, vecOrigin.x, vecOrigin.y, vecOrigin.z );
|
||||
#ifdef MAPBASE
|
||||
Vector vecForward, vecRight;
|
||||
GetVectors( &vecForward, &vecRight, NULL );
|
||||
NDebugOverlay::Circle( vecOrigin + Vector( 0, 0, 2 ), vecForward, vecRight, FastSqrt( pInteraction->flDistSqr ), 255, 0, 0, 255, true, 0.1f );
|
||||
#endif
|
||||
|
||||
if ( pOtherNPC )
|
||||
{
|
||||
@ -15858,14 +16059,28 @@ bool CAI_BaseNPC::InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInte
|
||||
for ( int ang = 0; ang < 3; ang++ )
|
||||
{
|
||||
float flAngDiff = AngleDiff( angEnemyAngles[ang], angAngles[ang] );
|
||||
#ifdef MAPBASE
|
||||
if ( fabs(flAngDiff) > pInteraction->flMaxAngleDiff )
|
||||
#else
|
||||
if ( fabs(flAngDiff) > DSS_MAX_ANGLE_DIFF )
|
||||
#endif
|
||||
{
|
||||
bMatches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bMatches )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if ( bDebug )
|
||||
{
|
||||
Msg(" %s angle not matched: (%0.2f %0.2f %0.2f), desired (%0.2f, %0.2f, %0.2f)\n", GetDebugName(),
|
||||
anglemod(angEnemyAngles.x), anglemod(angEnemyAngles.y), anglemod(angEnemyAngles.z), anglemod(angAngles.x), anglemod(angAngles.y), anglemod(angAngles.z) );
|
||||
Msg(" diff: (%0.2f, %0.2f, %0.2f)\n", AngleDiff( angEnemyAngles.x, angAngles.x ), AngleDiff( angEnemyAngles.y, angAngles.y ), AngleDiff( angEnemyAngles.z, angAngles.z ) );
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( bDebug )
|
||||
{
|
||||
@ -15873,6 +16088,13 @@ bool CAI_BaseNPC::InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInte
|
||||
anglemod(angEnemyAngles.x), anglemod(angEnemyAngles.y), anglemod(angEnemyAngles.z), anglemod(angAngles.x), anglemod(angAngles.y), anglemod(angAngles.z) );
|
||||
}
|
||||
}
|
||||
#ifdef MAPBASE
|
||||
else
|
||||
{
|
||||
// If we're not using angles, then use the NPC's current angles
|
||||
angAngles = pOtherNPC->GetAbsAngles();
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: Velocity check, if we're supposed to
|
||||
if ( pInteraction->iFlags & SCNPC_FLAG_TEST_OTHER_VELOCITY )
|
||||
@ -15952,6 +16174,7 @@ bool CAI_BaseNPC::InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInte
|
||||
if ( bDebug )
|
||||
{
|
||||
NDebugOverlay::Box( vecPos, GetHullMins(), GetHullMaxs(), 255,0,0, 100, 1.0 );
|
||||
NDebugOverlay::HorzArrow( GetAbsOrigin(), vecPos, 16.0f, 255, 0, 0, 255, true, 1.0f );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -15959,7 +16182,39 @@ bool CAI_BaseNPC::InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInte
|
||||
{
|
||||
//NDebugOverlay::Box( vecPos, GetHullMins(), GetHullMaxs(), 0,255,0, 100, 1.0 );
|
||||
|
||||
NDebugOverlay::Axis( vecPos, angAngles, 20, true, 10.0 );
|
||||
NDebugOverlay::Axis( vecPos, angAngles, 20, true, 1.0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Instead, make sure we fit into where the sequence movement ends at
|
||||
const char *pszSequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_SEQUENCE );
|
||||
int nSeq = LookupSequence( pszSequence );
|
||||
if ( pszSequence && nSeq != -1 )
|
||||
{
|
||||
Vector vecDeltaPos;
|
||||
QAngle angDeltaAngles;
|
||||
GetSequenceMovement( nSeq, 0.0f, 1.0f, vecDeltaPos, angDeltaAngles );
|
||||
if (!vecDeltaPos.IsZero())
|
||||
{
|
||||
QAngle angInteraction = GetAbsAngles();
|
||||
angInteraction[YAW] = m_flInteractionYaw;
|
||||
|
||||
Vector vecPos;
|
||||
VectorRotate( vecDeltaPos, angInteraction, vecPos );
|
||||
vecPos += GetAbsOrigin();
|
||||
|
||||
AI_TraceHull( vecPos, vecPos, GetHullMins(), GetHullMaxs(), MASK_SOLID, &traceFilter, &tr);
|
||||
if ( tr.fraction != 1.0 )
|
||||
{
|
||||
if ( bDebug )
|
||||
{
|
||||
NDebugOverlay::Box( vecPos, GetHullMins(), GetHullMaxs(), 255,0,0, 100, 1.0 );
|
||||
NDebugOverlay::HorzArrow( GetAbsOrigin(), vecPos, 16.0f, 255, 0, 0, 255, true, 1.0f );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -15983,6 +16238,25 @@ bool CAI_BaseNPC::HasInteractionCantDie( void )
|
||||
return ( m_bCannotDieDuringInteraction && IsRunningDynamicInteraction() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this NPC has valid interactions on the current enemy.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAI_BaseNPC::HasValidInteractionsOnCurrentEnemy( void )
|
||||
{
|
||||
if ( !GetEnemy() || !GetEnemy()->IsNPC() )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < m_ScriptedInteractions.Count(); i++ )
|
||||
{
|
||||
ScriptedNPCInteraction_t *pInteraction = &m_ScriptedInteractions[i];
|
||||
|
||||
if ( pInteraction->bValidOnCurrentEnemy )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &inputdata -
|
||||
@ -16216,6 +16490,21 @@ void CAI_BaseNPC::ModifyOrAppendEnemyCriteria( AI_CriteriaSet& set, CBaseEntity
|
||||
set.AppendCriteria( "enemyclass", g_pGameRules->AIClassText( pEnemy->Classify() ) ); // UTIL_VarArgs("%i", pEnemy->Classify())
|
||||
set.AppendCriteria( "distancetoenemy", UTIL_VarArgs( "%f", EnemyDistance(pEnemy) ) );
|
||||
set.AppendCriteria( "timesincecombat", "-1" );
|
||||
|
||||
CAI_BaseNPC *pNPC = pEnemy->MyNPCPointer();
|
||||
if (pNPC)
|
||||
{
|
||||
set.AppendCriteria("enemy_is_npc", "1");
|
||||
|
||||
set.AppendCriteria( "enemy_activity", CAI_BaseNPC::GetActivityName( pNPC->GetActivity() ) );
|
||||
set.AppendCriteria( "enemy_weapon", pNPC->GetActiveWeapon() ? pNPC->GetActiveWeapon()->GetClassname() : "0" );
|
||||
}
|
||||
else
|
||||
{
|
||||
set.AppendCriteria("enemy_is_npc", "0");
|
||||
}
|
||||
|
||||
pEnemy->AppendContextToCriteria( set, "enemy_" );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -425,6 +425,9 @@ struct ScriptedNPCInteraction_t
|
||||
iszTheirWeapon = NULL_STRING;
|
||||
#ifdef MAPBASE
|
||||
vecRelativeEndPos = vec3_origin;
|
||||
bHasSeparateSequenceNames = false;
|
||||
flMaxAngleDiff = DSS_MAX_ANGLE_DIFF;
|
||||
iszRelatedInteractions = NULL_STRING;
|
||||
MiscCriteria = NULL_STRING;
|
||||
#endif
|
||||
|
||||
@ -432,6 +435,10 @@ struct ScriptedNPCInteraction_t
|
||||
{
|
||||
sPhases[i].iszSequence = NULL_STRING;
|
||||
sPhases[i].iActivity = ACT_INVALID;
|
||||
#ifdef MAPBASE
|
||||
sTheirPhases[i].iszSequence = NULL_STRING;
|
||||
sTheirPhases[i].iActivity = ACT_INVALID;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,10 +466,14 @@ struct ScriptedNPCInteraction_t
|
||||
float flNextAttemptTime;
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Unrecognized keyvalues are tested against response criteria later.
|
||||
// This was originally a CUtlVector that carries response contexts, but I couldn't get it working due to some CUtlVector-struct shenanigans.
|
||||
// It works when we use a single string_t that's split and read each time the code runs, but feel free to improve on this.
|
||||
string_t MiscCriteria; // CUtlVector<ResponseContext_t>
|
||||
ScriptedNPCInteraction_Phases_t sTheirPhases[SNPCINT_NUM_PHASES]; // The animations played by the target NPC, if they are different
|
||||
bool bHasSeparateSequenceNames;
|
||||
|
||||
float flMaxAngleDiff;
|
||||
string_t iszRelatedInteractions; // These interactions will be delayed as well when this interaction is used.
|
||||
|
||||
// Unrecognized keyvalues which are tested against response criteria later.
|
||||
string_t MiscCriteria;
|
||||
#endif
|
||||
|
||||
DECLARE_SIMPLE_DATADESC();
|
||||
@ -838,6 +849,9 @@ protected: // pose parameters
|
||||
int m_poseAim_Pitch;
|
||||
int m_poseAim_Yaw;
|
||||
int m_poseMove_Yaw;
|
||||
#ifdef MAPBASE
|
||||
int m_poseInteractionRelativeYaw;
|
||||
#endif
|
||||
virtual void PopulatePoseParameters( void );
|
||||
|
||||
public:
|
||||
@ -845,6 +859,10 @@ public:
|
||||
|
||||
// Return the stored pose parameter for "move_yaw"
|
||||
inline int LookupPoseMoveYaw() { return m_poseMove_Yaw; }
|
||||
|
||||
#ifdef MAPBASE
|
||||
inline int LookupPoseInteractionRelativeYaw() { return m_poseInteractionRelativeYaw; }
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------
|
||||
@ -1304,10 +1322,14 @@ private:
|
||||
public:
|
||||
float GetInteractionYaw( void ) const { return m_flInteractionYaw; }
|
||||
|
||||
bool IsRunningDynamicInteraction( void ) { return (m_iInteractionState != NPCINT_NOT_RUNNING && (m_hCine != NULL)); }
|
||||
bool IsActiveDynamicInteraction( void ) { return (m_iInteractionState == NPCINT_RUNNING_ACTIVE && (m_hCine != NULL)); }
|
||||
CAI_BaseNPC *GetInteractionPartner( void );
|
||||
|
||||
protected:
|
||||
void ParseScriptedNPCInteractions( void );
|
||||
void AddScriptedNPCInteraction( ScriptedNPCInteraction_t *pInteraction );
|
||||
const char *GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase );
|
||||
const char *GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase, bool bOtherNPC = false );
|
||||
void StartRunningInteraction( CAI_BaseNPC *pOtherNPC, bool bActive );
|
||||
void StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedNPCInteraction_t *pInteraction, Vector vecOtherOrigin, QAngle angOtherAngles );
|
||||
void CheckForScriptedNPCInteractions( void );
|
||||
@ -1320,17 +1342,16 @@ protected:
|
||||
#endif
|
||||
bool InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInteraction_t *pInteraction, Vector &vecOrigin, QAngle &angAngles );
|
||||
virtual bool CanRunAScriptedNPCInteraction( bool bForced = false );
|
||||
bool IsRunningDynamicInteraction( void ) { return (m_iInteractionState != NPCINT_NOT_RUNNING && (m_hCine != NULL)); }
|
||||
bool IsActiveDynamicInteraction( void ) { return (m_iInteractionState == NPCINT_RUNNING_ACTIVE && (m_hCine != NULL)); }
|
||||
ScriptedNPCInteraction_t *GetRunningDynamicInteraction( void ) { return &(m_ScriptedInteractions[m_iInteractionPlaying]); }
|
||||
void SetInteractionCantDie( bool bCantDie ) { m_bCannotDieDuringInteraction = bCantDie; }
|
||||
bool HasInteractionCantDie( void );
|
||||
bool HasValidInteractionsOnCurrentEnemy( void );
|
||||
virtual bool CanStartDynamicInteractionDuringMelee() { return false; }
|
||||
|
||||
void InputForceInteractionWithNPC( inputdata_t &inputdata );
|
||||
void StartForcedInteraction( CAI_BaseNPC *pNPC, int iInteraction );
|
||||
void CleanupForcedInteraction( void );
|
||||
void CalculateForcedInteractionPosition( void );
|
||||
CAI_BaseNPC *GetInteractionPartner( void );
|
||||
|
||||
private:
|
||||
// Forced interactions
|
||||
@ -1974,6 +1995,9 @@ public:
|
||||
//---------------------------------
|
||||
|
||||
virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false );
|
||||
#ifdef MAPBASE
|
||||
virtual void EnemyIgnited( CAI_BaseNPC *pVictim ) {}
|
||||
#endif
|
||||
virtual bool PassesDamageFilter( const CTakeDamageInfo &info );
|
||||
|
||||
//---------------------------------
|
||||
@ -2228,6 +2252,9 @@ public:
|
||||
static const char* GetActivityName (int actID);
|
||||
|
||||
static void AddActivityToSR(const char *actName, int conID);
|
||||
#ifdef MAPBASE
|
||||
static int GetOrRegisterActivity( const char *actName );
|
||||
#endif
|
||||
|
||||
static void AddEventToSR(const char *eventName, int conID);
|
||||
static const char* GetEventName (int actID);
|
||||
|
@ -1610,6 +1610,12 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask )
|
||||
// as this should only run with the NPC "receiving" the interaction
|
||||
ScriptedNPCInteraction_t *pInteraction = m_hForcedInteractionPartner->GetRunningDynamicInteraction();
|
||||
|
||||
if ( !(pInteraction->iFlags & SCNPC_FLAG_TEST_OTHER_ANGLES) )
|
||||
{
|
||||
TaskComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get our target's origin
|
||||
Vector vecTarget = m_hForcedInteractionPartner->GetAbsOrigin();
|
||||
|
||||
@ -1617,7 +1623,7 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask )
|
||||
float angInteractionAngle = pInteraction->angRelativeAngles.y;
|
||||
angInteractionAngle += 180.0f;
|
||||
|
||||
GetMotor()->SetIdealYaw( CalcIdealYaw( vecTarget ) + angInteractionAngle );
|
||||
GetMotor()->SetIdealYaw( AngleNormalize( CalcIdealYaw( vecTarget ) + angInteractionAngle ) );
|
||||
|
||||
if (FacingIdeal())
|
||||
TaskComplete();
|
||||
@ -4113,6 +4119,15 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask )
|
||||
m_hCine->SynchronizeSequence( this );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
if ( IsRunningDynamicInteraction() && m_poseInteractionRelativeYaw > -1 )
|
||||
{
|
||||
// Animations in progress require pose parameters to be set every frame, so keep setting the interaction relative yaw pose.
|
||||
// The random value is added to help it pass server transmit checks.
|
||||
SetPoseParameter( m_poseInteractionRelativeYaw, GetPoseParameter( m_poseInteractionRelativeYaw ) + RandomFloat( -0.1f, 0.1f ) );
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -477,6 +477,20 @@ public:
|
||||
|
||||
AI_TraceHull( baseNPC->GetAbsOrigin(), vUpBit, baseNPC->GetHullMins(), baseNPC->GetHullMaxs(),
|
||||
MASK_NPCSOLID, baseNPC, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
// NEW: For vphysics/flying entities, do a second attempt which teleports based on bounding box
|
||||
if ( (baseNPC->GetMoveType() == MOVETYPE_VPHYSICS || baseNPC->CapabilitiesGet() & bits_CAP_MOVE_FLY) && (tr.startsolid || tr.fraction < 1.0) )
|
||||
{
|
||||
vUpBit.z += baseNPC->BoundingRadius();
|
||||
baseNPC->Teleport( &vUpBit, NULL, NULL );
|
||||
UTIL_DropToFloor( baseNPC, MASK_NPCSOLID );
|
||||
|
||||
Vector vUpBit2 = vUpBit;
|
||||
vUpBit2.z += 1;
|
||||
AI_TraceHull( vUpBit, vUpBit2, baseNPC->CollisionProp()->OBBMins(), baseNPC->CollisionProp()->OBBMaxs(),
|
||||
MASK_NPCSOLID, baseNPC, COLLISION_GROUP_NONE, &tr );
|
||||
}
|
||||
|
||||
if ( tr.startsolid || (tr.fraction < 1.0) )
|
||||
{
|
||||
baseNPC->SUB_Remove();
|
||||
|
@ -88,6 +88,15 @@ static void DispatchComeback( CAI_ExpresserWithFollowup *pExpress, CBaseEntity *
|
||||
// add in any provided contexts from the parameters onto the ones stored in the followup
|
||||
criteria.Merge( followup.followup_contexts );
|
||||
|
||||
#ifdef MAPBASE
|
||||
if (CAI_ExpresserSink *pSink = dynamic_cast<CAI_ExpresserSink *>(pRespondent))
|
||||
{
|
||||
criteria.AppendCriteria( "dist_from_issuer", UTIL_VarArgs( "%f", (pRespondent->GetAbsOrigin() - pSpeaker->GetAbsOrigin()).Length() ) );
|
||||
g_ResponseQueueManager.GetQueue()->AppendFollowupCriteria( followup.followup_concept, criteria, pSink->GetSinkExpresser(), pSink, pRespondent, pSpeaker, kDRT_SPECIFIC );
|
||||
|
||||
pSink->Speak( followup.followup_concept, &criteria );
|
||||
}
|
||||
#else
|
||||
// This is kludgy and needs to be fixed in class hierarchy, but for now, try to guess at the most likely
|
||||
// kinds of targets and dispatch to them.
|
||||
if (CBaseMultiplayerPlayer *pPlayer = dynamic_cast<CBaseMultiplayerPlayer *>(pRespondent))
|
||||
@ -99,6 +108,7 @@ static void DispatchComeback( CAI_ExpresserWithFollowup *pExpress, CBaseEntity *
|
||||
{
|
||||
pActor->Speak( followup.followup_concept, &criteria );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -902,6 +902,17 @@ BEGIN_DATADESC( CAI_Hint )
|
||||
DEFINE_OUTPUT( m_OnNPCStartedUsing, "OnNPCStartedUsing" ),
|
||||
DEFINE_OUTPUT( m_OnNPCStoppedUsing, "OnNPCStoppedUsing" ),
|
||||
|
||||
#ifdef MAPBASE
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[0], "OnScriptEvent01" ),
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[1], "OnScriptEvent02" ),
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[2], "OnScriptEvent03" ),
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[3], "OnScriptEvent04" ),
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[4], "OnScriptEvent05" ),
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[5], "OnScriptEvent06" ),
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[6], "OnScriptEvent07" ),
|
||||
DEFINE_OUTPUT( m_OnScriptEvent[7], "OnScriptEvent08" ),
|
||||
#endif
|
||||
|
||||
END_DATADESC( );
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
@ -1325,7 +1336,7 @@ bool CAI_Hint::HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hint
|
||||
|
||||
if ( distance > nRadius * nRadius )
|
||||
{
|
||||
REPORTFAILURE( "NPC is not within the node's radius." );
|
||||
REPORTFAILURE( "Not within the node's radius." );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1705,6 +1716,19 @@ void CAI_Hint::NPCStoppedUsing( CAI_BaseNPC *pNPC )
|
||||
m_OnNPCStoppedUsing.Set( pNPC, pNPC, this );
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAI_Hint::FireScriptEvent( int nEvent )
|
||||
{
|
||||
if ( ( nEvent >= 1 ) && ( nEvent <= 8 ) )
|
||||
{
|
||||
m_OnScriptEvent[nEvent - 1].FireOutput( m_hHintOwner, this );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
CON_COMMAND(ai_dump_hints, "")
|
||||
{
|
||||
@ -1794,6 +1818,11 @@ hinttypedescs_t g_pszHintDescriptions[] =
|
||||
{ HINT_HL1_WORLD_ALIEN_BLOOD, "HL1: World: Alien Blood" },
|
||||
|
||||
{ HINT_CSTRIKE_HOSTAGE_ESCAPE, "CS Port: Hostage Escape" },
|
||||
|
||||
#ifdef MAPBASE
|
||||
{ HINT_TACTICAL_COVER_CUSTOM, "Mapbase: Custom Cover" },
|
||||
{ HINT_TACTICAL_GRENADE_THROW, "Mapbase: Grenade Throw Hint" },
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -118,6 +118,7 @@ enum Hint_e
|
||||
// (these start at a high number to avoid potential conflicts with mod hints)
|
||||
|
||||
HINT_TACTICAL_COVER_CUSTOM = 10000, // Cover node with a custom hint activity (NPCs can take cover and reload here while playing said activity)
|
||||
HINT_TACTICAL_GRENADE_THROW, // Pre-determined position for NPCs to throw grenades at when their target in combat is near it
|
||||
#endif
|
||||
};
|
||||
const char *GetHintTypeDescription( Hint_e iHintType );
|
||||
@ -322,6 +323,9 @@ public:
|
||||
void FixupTargetNode();
|
||||
void NPCStartedUsing( CAI_BaseNPC *pNPC );
|
||||
void NPCStoppedUsing( CAI_BaseNPC *pNPC );
|
||||
#ifdef MAPBASE
|
||||
void FireScriptEvent( int nEvent );
|
||||
#endif
|
||||
|
||||
HintIgnoreFacing_t GetIgnoreFacing() const { return m_NodeData.fIgnoreFacing; }
|
||||
|
||||
@ -384,6 +388,10 @@ private:
|
||||
float m_nodeFOV;
|
||||
Vector m_vecForward;
|
||||
|
||||
#ifdef MAPBASE
|
||||
COutputEvent m_OnScriptEvent[8];
|
||||
#endif
|
||||
|
||||
// The next hint in list of all hints
|
||||
friend class CAI_HintManager;
|
||||
|
||||
|
@ -128,6 +128,12 @@ ConceptInfo_t g_ConceptInfos[] =
|
||||
|
||||
// Passenger behaviour
|
||||
{ TLK_PASSENGER_NEW_RADAR_CONTACT, SPEECH_IMPORTANT, -1, -1, -1, -1, -1, -1, AICF_DEFAULT, },
|
||||
|
||||
#ifdef MAPBASE
|
||||
{ TLK_TAKING_FIRE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, },
|
||||
{ TLK_NEW_ENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, },
|
||||
{ TLK_COMBAT_IDLE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, },
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1259,6 +1265,38 @@ void CAI_PlayerAlly::OnKilledNPC( CBaseCombatCharacter *pKilled )
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAI_PlayerAlly::OnEnemyRangeAttackedMe( CBaseEntity *pEnemy, const Vector &vecDir, const Vector &vecEnd )
|
||||
{
|
||||
BaseClass::OnEnemyRangeAttackedMe( pEnemy, vecDir, vecEnd );
|
||||
|
||||
if ( IRelationType( pEnemy ) <= D_FR )
|
||||
{
|
||||
AI_CriteriaSet modifiers;
|
||||
ModifyOrAppendEnemyCriteria( modifiers, pEnemy );
|
||||
|
||||
Vector vecEntDir = (pEnemy->EyePosition() - EyePosition());
|
||||
float flDot = DotProduct( vecEntDir.Normalized(), vecDir );
|
||||
modifiers.AppendCriteria( "shot_dot", CNumStr( flDot ) );
|
||||
|
||||
if (GetLastDamageTime() == gpGlobals->curtime)
|
||||
modifiers.AppendCriteria( "missed", "0" );
|
||||
else
|
||||
modifiers.AppendCriteria( "missed", "1" );
|
||||
|
||||
// Check if they're out of ammo
|
||||
if ( pEnemy->IsCombatCharacter() && pEnemy->MyCombatCharacterPointer()->GetActiveWeapon() && pEnemy->MyCombatCharacterPointer()->GetActiveWeapon()->Clip1() <= 0 )
|
||||
modifiers.AppendCriteria( "last_attack", "1" );
|
||||
else
|
||||
modifiers.AppendCriteria( "last_attack", "0" );
|
||||
|
||||
SpeakIfAllowed( TLK_TAKING_FIRE, modifiers );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAI_PlayerAlly::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
|
||||
{
|
||||
@ -1762,6 +1800,54 @@ bool CAI_PlayerAlly::IsAllowedToSpeak( AIConcept_t concept, bool bRespondingToPl
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Specifically for player allies handling followup responses.
|
||||
// Better-accounts for unknown concepts so that users are free in what they use.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAI_PlayerAlly::IsAllowedToSpeakFollowup( AIConcept_t concept, CBaseEntity *pIssuer, bool bSpecific )
|
||||
{
|
||||
CAI_AllySpeechManager * pSpeechManager = GetAllySpeechManager();
|
||||
ConceptInfo_t * pInfo = pSpeechManager->GetConceptInfo( concept );
|
||||
ConceptCategory_t category = SPEECH_PRIORITY; // Must be SPEECH_PRIORITY to get around semaphore
|
||||
|
||||
if ( !IsOkToSpeak( category, true ) )
|
||||
return false;
|
||||
|
||||
// If this followup is specifically targeted towards us, speak if we're not already speaking
|
||||
// If it's meant to be spoken by anyone, respect speech delay and semaphore
|
||||
if ( bSpecific )
|
||||
{
|
||||
if ( !GetExpresser()->CanSpeakAfterMyself() )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !GetExpresser()->CanSpeak() )
|
||||
return false;
|
||||
|
||||
CAI_TimedSemaphore *pSemaphore = GetExpresser()->GetMySpeechSemaphore( this );
|
||||
if ( pSemaphore && !pSemaphore->IsAvailable( this ) )
|
||||
{
|
||||
// Only if the semaphore holder isn't the one dispatching the followup
|
||||
if ( pSemaphore->GetOwner() != pIssuer )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !pSpeechManager->ConceptDelayExpired( concept ) )
|
||||
return false;
|
||||
|
||||
if ( ( pInfo && pInfo->flags & AICF_SPEAK_ONCE ) && GetExpresser()->SpokeConcept( concept ) )
|
||||
return false;
|
||||
|
||||
if ( !GetExpresser()->CanSpeakConcept( concept ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAI_PlayerAlly::SpeakIfAllowed( AIConcept_t concept, const char *modifiers, bool bRespondingToPlayer, char *pszOutResponseChosen, size_t bufsize )
|
||||
|
@ -132,6 +132,13 @@
|
||||
#define TLK_TGCATCHUP "TLK_TGCATCHUP"
|
||||
#define TLK_TGENDTOUR "TLK_TGENDTOUR"
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Additional concepts for companions in mods
|
||||
#define TLK_TAKING_FIRE "TLK_TAKING_FIRE" // Someone fired at me (regardless of whether I was hit)
|
||||
#define TLK_NEW_ENEMY "TLK_NEW_ENEMY" // A new enemy appeared while combat was already in progress
|
||||
#define TLK_COMBAT_IDLE "TLK_COMBAT_IDLE" // Similar to TLK_ATTACKING, but specifically for when *not* currently attacking (e.g. when in cover or reloading)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define TALKRANGE_MIN 500.0 // don't talk to anyone farther away than this
|
||||
@ -315,6 +322,10 @@ public:
|
||||
//---------------------------------
|
||||
void OnKilledNPC( CBaseCombatCharacter *pKilled );
|
||||
|
||||
#ifdef MAPBASE
|
||||
void OnEnemyRangeAttackedMe( CBaseEntity *pEnemy, const Vector &vecDir, const Vector &vecEnd );
|
||||
#endif
|
||||
|
||||
//---------------------------------
|
||||
// Damage handling
|
||||
//---------------------------------
|
||||
@ -392,6 +403,9 @@ public:
|
||||
|
||||
bool ShouldSpeakRandom( AIConcept_t concept, int iChance );
|
||||
bool IsAllowedToSpeak( AIConcept_t concept, bool bRespondingToPlayer = false );
|
||||
#ifdef MAPBASE
|
||||
bool IsAllowedToSpeakFollowup( AIConcept_t concept, CBaseEntity *pIssuer, bool bSpecific );
|
||||
#endif
|
||||
virtual bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 );
|
||||
#ifdef MAPBASE
|
||||
virtual bool SpeakIfAllowed( AIConcept_t concept, AI_CriteriaSet& modifiers, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 );
|
||||
|
@ -532,6 +532,7 @@ public:
|
||||
|
||||
// Must override CAI_Relationship
|
||||
void Spawn() { m_bIsActive = false; }
|
||||
void Activate();
|
||||
|
||||
bool KeyValue( const char *szKeyName, const char *szValue );
|
||||
|
||||
@ -557,6 +558,19 @@ BEGIN_DATADESC( CAI_ClassRelationship )
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
//---------------------------------------------------------
|
||||
//---------------------------------------------------------
|
||||
void CAI_ClassRelationship::Activate()
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
// Must re-apply every time a save is loaded
|
||||
if ( m_bIsActive )
|
||||
{
|
||||
ApplyRelationship();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Caches entity key values until spawn is called.
|
||||
// Input : szKeyName -
|
||||
@ -615,6 +629,9 @@ void CAI_ClassRelationship::ChangeRelationships( int disposition, int iReverting
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !CBaseCombatCharacter::DefaultRelationshipsLoaded() )
|
||||
return;
|
||||
|
||||
if ( m_iPreviousDisposition == -1 && iReverting == NOT_REVERTING )
|
||||
{
|
||||
// Set previous disposition.
|
||||
|
@ -126,6 +126,13 @@ public:
|
||||
virtual void OnSpokeConcept( AIConcept_t concept, AI_Response *response ) {};
|
||||
virtual void OnStartSpeaking() {}
|
||||
virtual bool UseSemaphore() { return true; }
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Works around issues with CAI_ExpresserHost<> class hierarchy
|
||||
virtual CAI_Expresser *GetSinkExpresser() { return NULL; }
|
||||
virtual bool IsAllowedToSpeakFollowup( AIConcept_t concept, CBaseEntity *pIssuer, bool bSpecific ) { return true; }
|
||||
virtual bool Speak( AIConcept_t concept, AI_CriteriaSet *pCriteria, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ) { return false; }
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ConceptHistory_t
|
||||
@ -244,9 +251,15 @@ public:
|
||||
static bool RunScriptResponse( CBaseEntity *pTarget, const char *response, AI_CriteriaSet *criteria, bool file );
|
||||
#endif
|
||||
|
||||
#ifdef MAPBASE
|
||||
public:
|
||||
#else
|
||||
protected:
|
||||
#endif
|
||||
CAI_TimedSemaphore *GetMySpeechSemaphore( CBaseEntity *pNpc );
|
||||
|
||||
protected:
|
||||
|
||||
bool SpeakRawScene( const char *pszScene, float delay, AI_Response *response, IRecipientFilter *filter = NULL );
|
||||
// This will create a fake .vcd/CChoreoScene to wrap the sound to be played
|
||||
#ifdef MAPBASE
|
||||
@ -311,11 +324,15 @@ private:
|
||||
//
|
||||
|
||||
template <class BASE_NPC>
|
||||
class CAI_ExpresserHost : public BASE_NPC, protected CAI_ExpresserSink
|
||||
class CAI_ExpresserHost : public BASE_NPC, public CAI_ExpresserSink
|
||||
{
|
||||
DECLARE_CLASS_NOFRIEND( CAI_ExpresserHost, BASE_NPC );
|
||||
|
||||
public:
|
||||
#ifdef MAPBASE
|
||||
CAI_Expresser *GetSinkExpresser() { return this->GetExpresser(); }
|
||||
#endif
|
||||
|
||||
virtual void NoteSpeaking( float duration, float delay );
|
||||
|
||||
virtual bool Speak( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "ai_baseactor.h"
|
||||
#include "ai_speech.h"
|
||||
//#include "flex_expresser.h"
|
||||
#ifdef MAPBASE
|
||||
#include "sceneentity.h"
|
||||
#endif
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
@ -170,15 +173,25 @@ void CResponseQueue::RemoveExpresserHost(CBaseEntity *host)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
/// Get the expresser for a base entity.
|
||||
static CAI_Expresser *InferExpresserFromBaseEntity(CBaseEntity * RESTRICT pEnt, CAI_ExpresserSink **ppSink = NULL)
|
||||
{
|
||||
if ( CAI_ExpresserSink *pSink = dynamic_cast<CAI_ExpresserSink *>(pEnt) )
|
||||
{
|
||||
if (ppSink)
|
||||
*ppSink = pSink;
|
||||
return pSink->GetSinkExpresser();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
/// Get the expresser for a base entity.
|
||||
/// TODO: Kind of an ugly hack until I get the class hierarchy straightened out.
|
||||
static CAI_Expresser *InferExpresserFromBaseEntity(CBaseEntity * RESTRICT pEnt)
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if ( CBasePlayer *pPlayer = ToBasePlayer(pEnt) )
|
||||
#else
|
||||
if ( CBaseMultiplayerPlayer *pPlayer = dynamic_cast<CBaseMultiplayerPlayer *>(pEnt) )
|
||||
#endif
|
||||
{
|
||||
return pPlayer->GetExpresser();
|
||||
}
|
||||
@ -197,6 +210,7 @@ static CAI_Expresser *InferExpresserFromBaseEntity(CBaseEntity * RESTRICT pEnt)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CResponseQueue::CDeferredResponse::Quash()
|
||||
@ -205,6 +219,23 @@ void CResponseQueue::CDeferredResponse::Quash()
|
||||
m_fDispatchTime = 0;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
void CResponseQueue::AppendFollowupCriteria( AIConcept_t concept, AI_CriteriaSet &set, CAI_Expresser *pEx,
|
||||
CAI_ExpresserSink *pSink, CBaseEntity *pTarget, CBaseEntity *pIssuer, DeferredResponseTarget_t nTargetType )
|
||||
{
|
||||
// Allows control over which followups interrupt speech routines
|
||||
set.AppendCriteria( "followup_allowed_to_speak", (pSink->IsAllowedToSpeakFollowup( concept, pIssuer, nTargetType == kDRT_SPECIFIC )) ? "1" : "0" );
|
||||
|
||||
set.AppendCriteria( "followup_target_type", UTIL_VarArgs( "%i", (int)nTargetType ) );
|
||||
|
||||
// NOTE: This assumes any expresser entity derived from CBaseFlex is also derived from CBaseCombatCharacter
|
||||
if (pTarget->IsCombatCharacter())
|
||||
set.AppendCriteria( "is_speaking", (pEx->IsSpeaking() || IsRunningScriptedSceneWithSpeechAndNotPaused( assert_cast<CBaseFlex*>(pTarget) )) ? "1" : "0" );
|
||||
else
|
||||
set.AppendCriteria( "is_speaking", "0" );
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CResponseQueue::DispatchOneResponse(CDeferredResponse &response)
|
||||
{
|
||||
// find the target.
|
||||
@ -272,9 +303,15 @@ bool CResponseQueue::DispatchOneResponse(CDeferredResponse &response)
|
||||
continue; // too far
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
CAI_ExpresserSink *pSink = NULL;
|
||||
pEx = InferExpresserFromBaseEntity( pTarget, &pSink );
|
||||
#else
|
||||
pEx = InferExpresserFromBaseEntity(pTarget);
|
||||
#endif
|
||||
if ( !pEx || pTarget == pIssuer )
|
||||
continue;
|
||||
|
||||
AI_CriteriaSet characterCriteria;
|
||||
pEx->GatherCriteria(&characterCriteria, response.m_concept, NULL);
|
||||
characterCriteria.Merge(&deferredCriteria);
|
||||
@ -282,6 +319,11 @@ bool CResponseQueue::DispatchOneResponse(CDeferredResponse &response)
|
||||
{
|
||||
characterCriteria.AppendCriteria( "dist_from_issuer", UTIL_VarArgs( "%f", sqrt(distIssuerToTargetSq) ) );
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
AppendFollowupCriteria( response.m_concept, characterCriteria, pEx, pSink, pTarget, pIssuer, kDRT_ALL );
|
||||
#endif
|
||||
|
||||
AI_Response prospectiveResponse;
|
||||
if ( pEx->FindResponse( prospectiveResponse, response.m_concept, &characterCriteria ) )
|
||||
{
|
||||
@ -304,14 +346,26 @@ bool CResponseQueue::DispatchOneResponse(CDeferredResponse &response)
|
||||
return false; // we're done right here.
|
||||
|
||||
// Get the expresser for the target.
|
||||
#ifdef MAPBASE
|
||||
CAI_ExpresserSink *pSink = NULL;
|
||||
pEx = InferExpresserFromBaseEntity( pTarget, &pSink );
|
||||
#else
|
||||
pEx = InferExpresserFromBaseEntity(pTarget);
|
||||
#endif
|
||||
if (!pEx)
|
||||
return false;
|
||||
|
||||
|
||||
AI_CriteriaSet characterCriteria;
|
||||
pEx->GatherCriteria(&characterCriteria, response.m_concept, NULL);
|
||||
characterCriteria.Merge(&deferredCriteria);
|
||||
#ifdef MAPBASE
|
||||
if ( pIssuer )
|
||||
{
|
||||
characterCriteria.AppendCriteria( "dist_from_issuer", UTIL_VarArgs( "%f", (pTarget->GetAbsOrigin() - pIssuer->GetAbsOrigin()).Length() ) );
|
||||
}
|
||||
|
||||
AppendFollowupCriteria( response.m_concept, characterCriteria, pEx, pSink, pTarget, pIssuer, kDRT_SPECIFIC );
|
||||
#endif
|
||||
pEx->Speak( response.m_concept, &characterCriteria );
|
||||
|
||||
return true;
|
||||
@ -364,7 +418,12 @@ bool CResponseQueue::DispatchOneResponse_ThenANY( CDeferredResponse &response, A
|
||||
continue; // too far
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
CAI_ExpresserSink *pSink = NULL;
|
||||
pEx = InferExpresserFromBaseEntity( pTarget, &pSink );
|
||||
#else
|
||||
pEx = InferExpresserFromBaseEntity(pTarget);
|
||||
#endif
|
||||
if ( !pEx )
|
||||
continue;
|
||||
|
||||
@ -376,6 +435,11 @@ bool CResponseQueue::DispatchOneResponse_ThenANY( CDeferredResponse &response, A
|
||||
{
|
||||
characterCriteria.AppendCriteria( "dist_from_issuer", UTIL_VarArgs( "%f", sqrt(distIssuerToTargetSq) ) );
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
AppendFollowupCriteria( response.m_concept, characterCriteria, pEx, pSink, pTarget, pIssuer, kDRT_ANY );
|
||||
#endif
|
||||
|
||||
AI_Response prospectiveResponse;
|
||||
|
||||
#ifdef MAPBASE
|
||||
|
@ -116,6 +116,11 @@ public:
|
||||
inline int GetNumExpresserTargets() const;
|
||||
inline CBaseEntity *GetExpresserHost(int which) const;
|
||||
|
||||
#ifdef MAPBASE
|
||||
void AppendFollowupCriteria( AIConcept_t concept, AI_CriteriaSet &set, CAI_Expresser *pEx,
|
||||
CAI_ExpresserSink *pSink, CBaseEntity *pTarget, CBaseEntity *pIssuer, DeferredResponseTarget_t nTargetType );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/// Actually send off one response to a consumer
|
||||
/// Return true if dispatch succeeded
|
||||
|
@ -335,6 +335,8 @@ BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" )
|
||||
DEFINE_SCRIPTFUNC( FindBodygroupByName, "Finds a bodygroup by name" )
|
||||
DEFINE_SCRIPTFUNC( GetBodygroupCount, "Gets the number of models in a bodygroup" )
|
||||
DEFINE_SCRIPTFUNC( GetNumBodyGroups, "Gets the number of bodygroups" )
|
||||
DEFINE_SCRIPTFUNC( GetModelScale, "Gets the model's scale" )
|
||||
DEFINE_SCRIPTFUNC( SetModelScale, "Sets the model's scale with the specified change duration" )
|
||||
|
||||
DEFINE_SCRIPTFUNC( Dissolve, "Use 'sprites/blueglow1.vmt' for the default material, Time() for the default start time, false for npcOnly if you don't want it to check if the entity is a NPC first, 0 for the default dissolve type, Vector(0,0,0) for the default dissolver origin, and 0 for the default magnitude." )
|
||||
DEFINE_SCRIPTFUNC( Ignite, "'NPCOnly' only lets this fall through if the entity is a NPC and 'CalledByLevelDesigner' determines whether to treat this like the Ignite input or just an internal ignition call." )
|
||||
@ -1331,7 +1333,7 @@ void CBaseAnimating::HandleAnimEvent( animevent_t *pEvent )
|
||||
#ifdef MAPBASE
|
||||
else if ( pEvent->event == AE_NPC_RESPONSE )
|
||||
{
|
||||
if (!MyNPCPointer()->GetExpresser()->IsSpeaking())
|
||||
if (MyNPCPointer() && MyNPCPointer()->GetExpresser() && !MyNPCPointer()->GetExpresser()->IsSpeaking())
|
||||
{
|
||||
DispatchResponse( pEvent->options );
|
||||
}
|
||||
@ -1342,6 +1344,18 @@ void CBaseAnimating::HandleAnimEvent( animevent_t *pEvent )
|
||||
DispatchResponse( pEvent->options );
|
||||
return;
|
||||
}
|
||||
else if ( pEvent->event == AE_VSCRIPT_RUN )
|
||||
{
|
||||
if (!RunScript( pEvent->options ))
|
||||
Warning( "%s failed to run AE_VSCRIPT_RUN on server with \"%s\"\n", GetDebugName(), pEvent->options );
|
||||
return;
|
||||
}
|
||||
else if ( pEvent->event == AE_VSCRIPT_RUN_FILE )
|
||||
{
|
||||
if (!RunScriptFile( pEvent->options ))
|
||||
Warning( "%s failed to run AE_VSCRIPT_RUN_FILE on server with \"%s\"\n", GetDebugName(), pEvent->options );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
else if ( pEvent->event == AE_RAGDOLL )
|
||||
{
|
||||
|
@ -28,6 +28,15 @@
|
||||
IMPLEMENT_SERVERCLASS_ST( CBaseHLBludgeonWeapon, DT_BaseHLBludgeonWeapon )
|
||||
END_SEND_TABLE()
|
||||
|
||||
#ifdef MAPBASE
|
||||
BEGIN_DATADESC(CBaseHLBludgeonWeapon)
|
||||
|
||||
DEFINE_FIELD(m_flDelayedFire, FIELD_TIME),
|
||||
DEFINE_FIELD(m_bShotDelayed, FIELD_BOOLEAN),
|
||||
|
||||
END_DATADESC()
|
||||
#endif // MAPBASE
|
||||
|
||||
#define BLUDGEON_HULL_DIM 16
|
||||
|
||||
static const Vector g_bludgeonMins(-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM);
|
||||
@ -39,6 +48,9 @@ static const Vector g_bludgeonMaxs(BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM,BLUDGEON_
|
||||
CBaseHLBludgeonWeapon::CBaseHLBludgeonWeapon()
|
||||
{
|
||||
m_bFiresUnderwater = true;
|
||||
#ifdef MAPBASE
|
||||
m_bShotDelayed = false;
|
||||
#endif // MAPBASE
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -96,11 +108,19 @@ void CBaseHLBludgeonWeapon::ItemPostFrame( void )
|
||||
#ifdef MAPBASE
|
||||
if (pOwner->HasSpawnFlags( SF_PLAYER_SUPPRESS_FIRING ))
|
||||
{
|
||||
m_bShotDelayed = false;
|
||||
WeaponIdle();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// See if we need to fire off our secondary round
|
||||
if (m_bShotDelayed)
|
||||
{
|
||||
if (gpGlobals->curtime > m_flDelayedFire)
|
||||
DelayedAttack();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
|
||||
{
|
||||
PrimaryAttack();
|
||||
@ -162,7 +182,12 @@ void CBaseHLBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity, bool
|
||||
pPlayer->EyeVectors( &hitDirection, NULL, NULL );
|
||||
VectorNormalize( hitDirection );
|
||||
|
||||
CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB );
|
||||
#ifdef MAPBASE
|
||||
CTakeDamageInfo info(GetOwner(), GetOwner(), GetDamageForActivity(nHitActivity), GetDamageType());
|
||||
#else
|
||||
CTakeDamageInfo info(GetOwner(), GetOwner(), GetDamageForActivity(nHitActivity), DMG_CLUB);
|
||||
#endif // MAPBASE
|
||||
|
||||
|
||||
if( pPlayer && pHitEntity->IsNPC() )
|
||||
{
|
||||
@ -234,7 +259,7 @@ Activity CBaseHLBludgeonWeapon::ChooseIntersectionPointAndActivity( trace_t &hit
|
||||
}
|
||||
|
||||
|
||||
return ACT_VM_HITCENTER;
|
||||
return GetPrimaryAttackActivity();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -292,7 +317,6 @@ void CBaseHLBludgeonWeapon::ImpactEffect( trace_t &traceHit )
|
||||
UTIL_ImpactTrace( &traceHit, DMG_CLUB );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Starts the swing of the weapon and determines the animation
|
||||
// Input : bIsSecondary - is this a secondary attack?
|
||||
@ -315,10 +339,14 @@ void CBaseHLBludgeonWeapon::Swing( int bIsSecondary )
|
||||
|
||||
Vector swingEnd = swingStart + forward * GetRange();
|
||||
UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit );
|
||||
Activity nHitActivity = ACT_VM_HITCENTER;
|
||||
Activity nHitActivity = GetPrimaryAttackActivity();
|
||||
|
||||
// Like bullets, bludgeon traces have to trace against triggers.
|
||||
CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB );
|
||||
#ifdef MAPBASE
|
||||
CTakeDamageInfo triggerInfo(GetOwner(), GetOwner(), GetDamageForActivity(nHitActivity), GetDamageType());
|
||||
#else
|
||||
CTakeDamageInfo triggerInfo(GetOwner(), GetOwner(), GetDamageForActivity(nHitActivity), DMG_CLUB);
|
||||
#endif // MAPBASE
|
||||
triggerInfo.SetDamagePosition( traceHit.startpos );
|
||||
triggerInfo.SetDamageForce( forward );
|
||||
TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, forward );
|
||||
@ -369,31 +397,20 @@ void CBaseHLBludgeonWeapon::Swing( int bIsSecondary )
|
||||
{
|
||||
nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER;
|
||||
|
||||
#ifndef MAPBASE
|
||||
// We want to test the first swing again
|
||||
Vector testEnd = swingStart + forward * GetRange();
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Sound has been moved here since we're using the other melee sounds now
|
||||
WeaponSound( SINGLE );
|
||||
#endif
|
||||
|
||||
// See if we happened to hit water
|
||||
ImpactWater( swingStart, testEnd );
|
||||
ImpactWater(swingStart, testEnd);
|
||||
#endif // !MAPBASE
|
||||
}
|
||||
#ifndef MAPBASE
|
||||
else
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
// Other melee sounds
|
||||
if (traceHit.m_pEnt && traceHit.m_pEnt->IsWorld())
|
||||
WeaponSound(MELEE_HIT_WORLD);
|
||||
else if (traceHit.m_pEnt && !traceHit.m_pEnt->PassesDamageFilter(triggerInfo))
|
||||
WeaponSound(MELEE_MISS);
|
||||
else
|
||||
WeaponSound(MELEE_HIT);
|
||||
#endif
|
||||
|
||||
Hit( traceHit, nHitActivity, bIsSecondary ? true : false );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send the anim
|
||||
SendWeaponAnim( nHitActivity );
|
||||
@ -409,5 +426,125 @@ void CBaseHLBludgeonWeapon::Swing( int bIsSecondary )
|
||||
|
||||
#ifdef MAPBASE
|
||||
pOwner->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
if (GetHitDelay() > 0.f)
|
||||
{
|
||||
//Play swing sound
|
||||
WeaponSound(SINGLE);
|
||||
|
||||
m_flDelayedFire = gpGlobals->curtime + GetHitDelay();
|
||||
m_bShotDelayed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (traceHit.fraction == 1.0f)
|
||||
{
|
||||
// We want to test the first swing again
|
||||
Vector testEnd = swingStart + forward * GetRange();
|
||||
|
||||
//Play swing sound
|
||||
WeaponSound(SINGLE);
|
||||
|
||||
// See if we happened to hit water
|
||||
ImpactWater(swingStart, testEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other melee sounds
|
||||
if (traceHit.m_pEnt && traceHit.m_pEnt->IsWorld())
|
||||
WeaponSound(MELEE_HIT_WORLD);
|
||||
else if (traceHit.m_pEnt && !traceHit.m_pEnt->PassesDamageFilter(triggerInfo))
|
||||
WeaponSound(MELEE_MISS);
|
||||
else
|
||||
WeaponSound(MELEE_HIT);
|
||||
|
||||
Hit(traceHit, nHitActivity, bIsSecondary ? true : false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
void CBaseHLBludgeonWeapon::DelayedAttack(void)
|
||||
{
|
||||
m_bShotDelayed = false;
|
||||
|
||||
trace_t traceHit;
|
||||
|
||||
// Try a ray
|
||||
CBasePlayer* pOwner = ToBasePlayer(GetOwner());
|
||||
if (!pOwner)
|
||||
return;
|
||||
|
||||
pOwner->RumbleEffect(RUMBLE_CROWBAR_SWING, 0, RUMBLE_FLAG_RESTART);
|
||||
|
||||
Vector swingStart = pOwner->Weapon_ShootPosition();
|
||||
Vector forward;
|
||||
|
||||
forward = pOwner->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT, GetRange());
|
||||
|
||||
Vector swingEnd = swingStart + forward * GetRange();
|
||||
UTIL_TraceLine(swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit);
|
||||
|
||||
if (traceHit.fraction == 1.0)
|
||||
{
|
||||
float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point
|
||||
|
||||
// Back off by hull "radius"
|
||||
swingEnd -= forward * bludgeonHullRadius;
|
||||
|
||||
UTIL_TraceHull(swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit);
|
||||
if (traceHit.fraction < 1.0 && traceHit.m_pEnt)
|
||||
{
|
||||
Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart;
|
||||
VectorNormalize(vecToTarget);
|
||||
|
||||
float dot = vecToTarget.Dot(forward);
|
||||
|
||||
// YWB: Make sure they are sort of facing the guy at least...
|
||||
if (dot < 0.70721f)
|
||||
{
|
||||
// Force amiss
|
||||
traceHit.fraction = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChooseIntersectionPointAndActivity(traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (traceHit.fraction == 1.0f)
|
||||
{
|
||||
// We want to test the first swing again
|
||||
Vector testEnd = swingStart + forward * GetRange();
|
||||
|
||||
// See if we happened to hit water
|
||||
ImpactWater(swingStart, testEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
CTakeDamageInfo triggerInfo(GetOwner(), GetOwner(), GetDamageForActivity(GetActivity()), GetDamageType());
|
||||
triggerInfo.SetDamagePosition(traceHit.startpos);
|
||||
triggerInfo.SetDamageForce(forward);
|
||||
|
||||
// Other melee sounds
|
||||
if (traceHit.m_pEnt && traceHit.m_pEnt->IsWorld())
|
||||
WeaponSound(MELEE_HIT_WORLD);
|
||||
else if (traceHit.m_pEnt && !traceHit.m_pEnt->PassesDamageFilter(triggerInfo))
|
||||
WeaponSound(MELEE_MISS);
|
||||
else
|
||||
WeaponSound(MELEE_HIT);
|
||||
|
||||
Hit(traceHit, GetActivity(), false);
|
||||
}
|
||||
}
|
||||
|
||||
bool CBaseHLBludgeonWeapon::CanHolster(void)
|
||||
{
|
||||
if (m_bShotDelayed)
|
||||
return false;
|
||||
|
||||
return BaseClass::CanHolster();
|
||||
}
|
||||
#endif // MAPBASE
|
||||
|
@ -23,6 +23,9 @@ public:
|
||||
CBaseHLBludgeonWeapon();
|
||||
|
||||
DECLARE_SERVERCLASS();
|
||||
#ifdef MAPBASE
|
||||
DECLARE_DATADESC();
|
||||
#endif // MAPBASE
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
@ -30,6 +33,9 @@ public:
|
||||
//Attack functions
|
||||
virtual void PrimaryAttack( void );
|
||||
virtual void SecondaryAttack( void );
|
||||
#ifdef MAPBASE
|
||||
void DelayedAttack(void);
|
||||
#endif // MAPBASE
|
||||
|
||||
virtual void ItemPostFrame( void );
|
||||
|
||||
@ -44,6 +50,12 @@ public:
|
||||
virtual int CapabilitiesGet( void );
|
||||
virtual int WeaponMeleeAttack1Condition( float flDot, float flDist );
|
||||
|
||||
#ifdef MAPBASE
|
||||
virtual int GetDamageType() { return DMG_CLUB; }
|
||||
virtual float GetHitDelay() { return 0.f; }
|
||||
virtual bool CanHolster(void);
|
||||
#endif // MAPBASE
|
||||
|
||||
protected:
|
||||
virtual void ImpactEffect( trace_t &trace );
|
||||
|
||||
@ -52,6 +64,11 @@ private:
|
||||
void Swing( int bIsSecondary );
|
||||
void Hit( trace_t &traceHit, Activity nHitActivity, bool bIsSecondary );
|
||||
Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner );
|
||||
|
||||
#ifdef MAPBASE
|
||||
float m_flDelayedFire;
|
||||
bool m_bShotDelayed;
|
||||
#endif // MAPBASE
|
||||
};
|
||||
|
||||
#endif
|
@ -175,6 +175,7 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptRelationType, "GetRelationship", "Get a character's relationship to a specific entity." )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptRelationPriority, "GetRelationPriority", "Get a character's relationship priority for a specific entity." )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptSetRelationship, "SetRelationship", "Set a character's relationship with a specific entity." )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptSetClassRelationship, "SetClassRelationship", "Set a character's relationship with a specific Classify() class." )
|
||||
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetVehicleEntity, "GetVehicleEntity", "Get the entity for a character's current vehicle if they're in one." )
|
||||
|
||||
@ -1264,6 +1265,11 @@ bool CTraceFilterMelee::ShouldHitEntity( IHandleEntity *pHandleEntity, int conte
|
||||
if ( pEntity->m_takedamage == DAMAGE_NO )
|
||||
return false;
|
||||
|
||||
#ifdef MAPBASE // Moved from CheckTraceHullAttack()
|
||||
if( m_pPassEnt && !pEntity->CanBeHitByMeleeAttack( const_cast<CBaseEntity*>(EntityFromEntityHandle( m_pPassEnt ) ) ) )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// FIXME: Do not translate this to the driver because the driver only accepts damage from the vehicle
|
||||
// Translate the vehicle into its driver for damage
|
||||
/*
|
||||
@ -1311,6 +1317,10 @@ bool CTraceFilterMelee::ShouldHitEntity( IHandleEntity *pHandleEntity, int conte
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
// Do not override an existing hit entity
|
||||
if (!m_pHit)
|
||||
#endif
|
||||
m_pHit = pEntity;
|
||||
|
||||
// Make sure if the player is holding this, he drops it
|
||||
@ -1386,11 +1396,13 @@ CBaseEntity *CBaseCombatCharacter::CheckTraceHullAttack( const Vector &vStart, c
|
||||
pEntity = traceFilter.m_pHit;
|
||||
}
|
||||
|
||||
#ifndef MAPBASE // Moved to CTraceFilterMelee
|
||||
if( pEntity && !pEntity->CanBeHitByMeleeAttack(this) )
|
||||
{
|
||||
// If we touched something, but it shouldn't be hit, return nothing.
|
||||
pEntity = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return pEntity;
|
||||
|
||||
@ -3239,6 +3251,16 @@ void CBaseCombatCharacter::SetDefaultRelationship(Class_T nClass, Class_T nClass
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Determine whether or not default relationships are loaded
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::DefaultRelationshipsLoaded()
|
||||
{
|
||||
return m_DefaultRelationship != NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fetch the default (ignore ai_relationship changes) relationship
|
||||
// Input :
|
||||
@ -3466,7 +3488,7 @@ void CBaseCombatCharacter::AddRelationship( const char *pszRelationship, CBaseEn
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MAPBASE // I know the extra #ifdef is pointless, but it's there so you know this is new
|
||||
// NEW: Classify class relationships
|
||||
if (!Q_strnicmp(entityString, "CLASS_", 5))
|
||||
{
|
||||
// Go through all of the classes and find which one this is
|
||||
@ -3487,8 +3509,7 @@ void CBaseCombatCharacter::AddRelationship( const char *pszRelationship, CBaseEn
|
||||
}
|
||||
|
||||
if (!bFoundEntity)
|
||||
#endif
|
||||
DevWarning( "Couldn't set relationship to unknown entity or class (%s)!\n", entityString );
|
||||
DevWarning( "Couldn't set relationship to unknown entity or class (%s)!\n", entityString );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3594,7 +3615,7 @@ CBaseEntity *CBaseCombatCharacter::Weapon_FindUsable( const Vector &range )
|
||||
else if (hl2_episodic.GetBool() && !GetActiveWeapon())
|
||||
{
|
||||
// Unarmed citizens are conservative in their weapon finding...in Episode One
|
||||
if (Classify() != CLASS_PLAYER_ALLY_VITAL && Q_strncmp(STRING(gpGlobals->mapname), "ep1_", 4))
|
||||
if (Classify() != CLASS_PLAYER_ALLY_VITAL && Q_strncmp(STRING(gpGlobals->mapname), "ep1_", 4) == 0)
|
||||
bConservative = true;
|
||||
}
|
||||
#endif
|
||||
@ -4643,6 +4664,13 @@ void CBaseCombatCharacter::ScriptSetRelationship( HSCRIPT pTarget, int dispositi
|
||||
AddEntityRelationship( ToEnt( pTarget ), (Disposition_t)disposition, priority );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::ScriptSetClassRelationship( int classify, int disposition, int priority )
|
||||
{
|
||||
AddClassRelationship( (Class_T)classify, (Disposition_t)disposition, priority);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
HSCRIPT CBaseCombatCharacter::ScriptGetVehicleEntity()
|
||||
|
@ -263,6 +263,10 @@ public:
|
||||
|
||||
virtual bool CanBecomeServerRagdoll( void ) { return true; }
|
||||
|
||||
#ifdef MAPBASE
|
||||
virtual void OnEnemyRangeAttackedMe( CBaseEntity *pEnemy, const Vector &vecDir, const Vector &vecEnd ) {}
|
||||
#endif
|
||||
|
||||
// -----------------------
|
||||
// Damage
|
||||
// -----------------------
|
||||
@ -440,6 +444,7 @@ public:
|
||||
int ScriptRelationType( HSCRIPT pTarget );
|
||||
int ScriptRelationPriority( HSCRIPT pTarget );
|
||||
void ScriptSetRelationship( HSCRIPT pTarget, int disposition, int priority );
|
||||
void ScriptSetClassRelationship( int classify, int disposition, int priority );
|
||||
|
||||
HSCRIPT ScriptGetVehicleEntity();
|
||||
|
||||
@ -462,6 +467,7 @@ public:
|
||||
static void AllocateDefaultRelationships( );
|
||||
static void SetDefaultRelationship( Class_T nClass, Class_T nClassTarget, Disposition_t nDisposition, int nPriority );
|
||||
#ifdef MAPBASE
|
||||
static bool DefaultRelationshipsLoaded();
|
||||
static Disposition_t GetDefaultRelationshipDisposition( Class_T nClassSource, Class_T nClassTarget );
|
||||
static int GetDefaultRelationshipPriority( Class_T nClassSource, Class_T nClassTarget );
|
||||
int GetDefaultRelationshipPriority( Class_T nClassTarget );
|
||||
|
@ -2378,6 +2378,9 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities"
|
||||
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" )
|
||||
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetGroundEntity, "GetGroundEntity", "Get the entity we're standing on." )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptSetGroundEntity, "SetGroundEntity", "Set the entity we're standing on." )
|
||||
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptFollowEntity, "FollowEntity", "Begin following the specified entity. This makes this entity non-solid, parents it to the target entity, and teleports it to the specified entity's origin. The second parameter is whether or not to use bonemerging while following." )
|
||||
DEFINE_SCRIPTFUNC( StopFollowingEntity, "Stops following an entity if we're following one." )
|
||||
@ -10297,8 +10300,9 @@ bool CBaseEntity::ScriptAddOutput( const char *pszOutputName, const char *pszTar
|
||||
const char *CBaseEntity::ScriptGetKeyValue( const char *pszKeyName )
|
||||
{
|
||||
static char szValue[128];
|
||||
GetKeyValue( pszKeyName, szValue, sizeof(szValue) );
|
||||
return szValue;
|
||||
if ( GetKeyValue( pszKeyName, szValue, sizeof(szValue) ) )
|
||||
return szValue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1445,6 +1445,11 @@ public:
|
||||
void SetGroundEntity( CBaseEntity *ground );
|
||||
CBaseEntity *GetGroundEntity( void );
|
||||
CBaseEntity *GetGroundEntity( void ) const { return const_cast<CBaseEntity *>(this)->GetGroundEntity(); }
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
HSCRIPT ScriptGetGroundEntity();
|
||||
void ScriptSetGroundEntity( HSCRIPT hGroundEnt );
|
||||
#endif
|
||||
|
||||
// Gets the velocity we impart to a player standing on us
|
||||
virtual void GetGroundVelocityToApply( Vector &vecGroundVel ) { vecGroundVel = vec3_origin; }
|
||||
@ -1575,7 +1580,7 @@ public:
|
||||
float flVolume, soundlevel_t iSoundlevel, int iFlags = 0, int iPitch = PITCH_NORM,
|
||||
const Vector *pOrigin = NULL, const Vector *pDirection = NULL, bool bUpdatePositions = true, float soundtime = 0.0f
|
||||
#ifdef MAPBASE
|
||||
, int iSpecialDSP = 0, int iSpeakerIndex = 0 // Needed for env_microphone
|
||||
, int iSpecialDSP = 0, int iSpeakerIndex = -1 // Needed for env_microphone
|
||||
#endif
|
||||
);
|
||||
|
||||
|
@ -736,6 +736,12 @@ CBaseEntity *CGlobalEntityList::FindEntityCustomProcedural( CBaseEntity *pStartE
|
||||
|
||||
g_pScriptVM->ExecuteFunction( g_CustomProcedurals[i].hFunc, args, 5, &functionReturn, NULL, true );
|
||||
|
||||
if (pStartEntity && ToEnt( functionReturn.m_hScript ) == pStartEntity)
|
||||
{
|
||||
Warning( "WARNING: Custom procedural %s returned entity identical to start entity (%s), returning null\n", g_CustomProcedurals[i].szName, pStartEntity->GetDebugName() );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ToEnt( functionReturn.m_hScript );
|
||||
}
|
||||
}
|
||||
|
@ -162,10 +162,10 @@ void CBaseFilter::InputSetField( inputdata_t& inputdata )
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
bool CBaseFilter::ScriptPassesFilter( HSCRIPT pCaller, HSCRIPT pEntity ) { return PassesFilter( ToEnt(pCaller), ToEnt(pEntity) ); }
|
||||
bool CBaseFilter::ScriptPassesDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesDamageFilter( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : NULL; }
|
||||
bool CBaseFilter::ScriptPassesFinalDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesFinalDamageFilter( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : NULL; }
|
||||
bool CBaseFilter::ScriptBloodAllowed( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? BloodAllowed( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : NULL; }
|
||||
bool CBaseFilter::ScriptDamageMod( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? DamageMod( ToEnt( pCaller ), *HScriptToClass<CTakeDamageInfo>( pInfo ) ) : NULL; }
|
||||
bool CBaseFilter::ScriptPassesDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesDamageFilter( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : false; }
|
||||
bool CBaseFilter::ScriptPassesFinalDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesFinalDamageFilter( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : false; }
|
||||
bool CBaseFilter::ScriptBloodAllowed( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? BloodAllowed( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : false; }
|
||||
bool CBaseFilter::ScriptDamageMod( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? DamageMod( ToEnt( pCaller ), *HScriptToClass<CTakeDamageInfo>( pInfo ) ) : false; }
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -190,6 +190,24 @@ int CAI_FuncTankBehavior::SelectSchedule()
|
||||
return SCHED_IDLE_STAND;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAI_FuncTankBehavior::ModifyOrAppendCriteria( AI_CriteriaSet &set )
|
||||
{
|
||||
BaseClass::ModifyOrAppendCriteria( set );
|
||||
|
||||
#ifdef MAPBASE
|
||||
set.AppendCriteria( "ft_mounted", m_bMounted ? "1" : "0" );
|
||||
|
||||
if (m_hFuncTank)
|
||||
{
|
||||
set.AppendCriteria( "ft_classname", m_hFuncTank->GetClassname() );
|
||||
m_hFuncTank->AppendContextToCriteria( set, "ft_" );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : activity -
|
||||
|
@ -55,6 +55,8 @@ public:
|
||||
bool CanManTank( CFuncTank *pTank, bool bForced );
|
||||
#endif
|
||||
|
||||
void ModifyOrAppendCriteria( AI_CriteriaSet &set );
|
||||
|
||||
Activity NPC_TranslateActivity( Activity activity );
|
||||
|
||||
// Conditions:
|
||||
|
@ -35,6 +35,9 @@ CBugBaitSensor* GetBugBaitSensorList()
|
||||
CBugBaitSensor::CBugBaitSensor( void )
|
||||
{
|
||||
g_BugBaitSensorList.Insert( this );
|
||||
#ifdef MAPBASE
|
||||
m_bUseRadius = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
CBugBaitSensor::~CBugBaitSensor( void )
|
||||
@ -50,10 +53,24 @@ BEGIN_DATADESC( CBugBaitSensor )
|
||||
DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "Enabled" ),
|
||||
DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
|
||||
|
||||
#ifdef MAPBASE
|
||||
DEFINE_KEYFIELD( m_bUseRadius, FIELD_BOOLEAN, "useradius" ),
|
||||
DEFINE_KEYFIELD( m_vecMins, FIELD_VECTOR, "bmins" ),
|
||||
DEFINE_KEYFIELD( m_vecMaxs, FIELD_VECTOR, "bmaxs" ),
|
||||
#endif
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
|
||||
|
||||
#ifdef MAPBASE
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "EnableRadius", InputEnableRadius ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "DisableRadius", InputDisableRadius ),
|
||||
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetRadius", InputSetRadius ),
|
||||
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetMins", InputSetMins ),
|
||||
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetMaxs", InputSetMaxs ),
|
||||
#endif
|
||||
|
||||
// Function Pointers
|
||||
DEFINE_OUTPUT( m_OnBaited, "OnBaited" ),
|
||||
|
||||
@ -267,18 +284,42 @@ bool CGrenadeBugBait::ActivateBugbaitTargets( CBaseEntity *pOwner, Vector vecOri
|
||||
continue;
|
||||
|
||||
//Make sure we're within range of the sensor
|
||||
if ( pSensor->GetRadius() > ( pSensor->GetAbsOrigin() - vecOrigin ).Length() )
|
||||
{
|
||||
//Tell the sensor it's been hit
|
||||
if ( pSensor->Baited( pOwner ) )
|
||||
#ifdef MAPBASE
|
||||
if ( pSensor->UsesRadius() ){
|
||||
#endif
|
||||
if ( pSensor->GetRadius() > (pSensor->GetAbsOrigin() - vecOrigin).Length() )
|
||||
{
|
||||
//If we're suppressing the call to antlions, then don't make a bugbait sound
|
||||
if ( pSensor->SuppressCall() )
|
||||
//Tell the sensor it's been hit
|
||||
if ( pSensor->Baited( pOwner ) )
|
||||
{
|
||||
suppressCall = true;
|
||||
//If we're suppressing the call to antlions, then don't make a bugbait sound
|
||||
if ( pSensor->SuppressCall() )
|
||||
{
|
||||
suppressCall = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef MAPBASE
|
||||
}
|
||||
else{
|
||||
Vector vMins = pSensor->GetAbsMins();
|
||||
Vector vMaxs = pSensor->GetAbsMaxs();
|
||||
bool inBox = ((vecOrigin.x >= vMins.x && vecOrigin.x <= vMaxs.x) &&
|
||||
(vecOrigin.y >= vMins.y && vecOrigin.y <= vMaxs.y) &&
|
||||
(vecOrigin.z >= vMins.z && vecOrigin.z <= vMaxs.z));
|
||||
if ( inBox ){
|
||||
//Tell the sensor it's been hit
|
||||
if ( pSensor->Baited( pOwner ) )
|
||||
{
|
||||
//If we're suppressing the call to antlions, then don't make a bugbait sound
|
||||
if ( pSensor->SuppressCall() )
|
||||
{
|
||||
suppressCall = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return suppressCall;
|
||||
|
@ -63,6 +63,28 @@ public:
|
||||
m_bEnabled = !m_bEnabled;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
void InputEnableRadius( inputdata_t &data ){
|
||||
m_bUseRadius = true;
|
||||
}
|
||||
|
||||
void InputDisableRadius( inputdata_t &data ){
|
||||
m_bUseRadius = false;
|
||||
}
|
||||
|
||||
void InputSetRadius( inputdata_t &data ){
|
||||
m_flRadius = data.value.Int();
|
||||
}
|
||||
|
||||
void InputSetMins( inputdata_t &data ){
|
||||
data.value.Vector3D( m_vecMins );
|
||||
}
|
||||
|
||||
void InputSetMaxs( inputdata_t &data ){
|
||||
data.value.Vector3D( m_vecMaxs );
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SuppressCall( void )
|
||||
{
|
||||
return ( HasSpawnFlags( SF_BUGBAIT_SUPPRESS_CALL ) );
|
||||
@ -91,10 +113,28 @@ public:
|
||||
return !m_bEnabled;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
bool UsesRadius( void ) const {
|
||||
return m_bUseRadius;
|
||||
}
|
||||
|
||||
Vector GetAbsMins( void ) const {
|
||||
return GetAbsOrigin() + m_vecMins;
|
||||
}
|
||||
Vector GetAbsMaxs( void ) const {
|
||||
return GetAbsOrigin() + m_vecMaxs;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
float m_flRadius;
|
||||
bool m_bEnabled;
|
||||
#ifdef MAPBASE
|
||||
bool m_bUseRadius;
|
||||
Vector m_vecMins;
|
||||
Vector m_vecMaxs;
|
||||
#endif
|
||||
COutputEvent m_OnBaited;
|
||||
|
||||
public:
|
||||
|
@ -1814,7 +1814,7 @@ bool CHL2_Player::CommanderFindGoal( commandgoal_t *pGoal )
|
||||
// Get either our +USE entity or the gravity gun entity
|
||||
CBaseEntity *pHeldEntity = GetPlayerHeldEntity(this);
|
||||
if ( !pHeldEntity )
|
||||
PhysCannonGetHeldEntity( GetActiveWeapon() );
|
||||
pHeldEntity = PhysCannonGetHeldEntity( GetActiveWeapon() );
|
||||
|
||||
CTraceFilterSkipTwoEntities filter( this, pHeldEntity, COLLISION_GROUP_INTERACTIVE_DEBRIS );
|
||||
#else
|
||||
|
@ -159,6 +159,10 @@ ConVar zombie_decaymax( "zombie_decaymax", "0.4" );
|
||||
|
||||
ConVar zombie_ambushdist( "zombie_ambushdist", "16000" );
|
||||
|
||||
#ifdef MAPBASE
|
||||
ConVar zombie_no_flinch_during_unique_anim( "zombie_no_flinch_during_unique_anim", "1", FCVAR_NONE, "Prevents zombies from flinching during actbusies and scripted sequences." );
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
// For a couple of reasons, we keep a running count of how
|
||||
// many zombies in the world are angry at any given time.
|
||||
@ -1745,7 +1749,11 @@ void CNPC_BaseZombie::HandleAnimEvent( animevent_t *pEvent )
|
||||
|
||||
dmgInfo.SetDamagePosition( vecHeadCrabPosition );
|
||||
|
||||
#ifdef MAPBASE
|
||||
ReleaseHeadcrab( vecHeadCrabPosition, vVelocity *iSpeed, true, false, true );
|
||||
#else
|
||||
ReleaseHeadcrab( EyePosition(), vVelocity * iSpeed, true, false, true );
|
||||
#endif
|
||||
|
||||
GuessDamageForce( &dmgInfo, vVelocity, vecHeadCrabPosition, 0.5f );
|
||||
TakeDamage( dmgInfo );
|
||||
@ -1927,6 +1935,31 @@ void CNPC_BaseZombie::OnScheduleChange( void )
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
//---------------------------------------------------------
|
||||
|
||||
bool CNPC_BaseZombie::CanFlinch( void )
|
||||
{
|
||||
if (!BaseClass::CanFlinch())
|
||||
return false;
|
||||
|
||||
#ifdef MAPBASE
|
||||
if (zombie_no_flinch_during_unique_anim.GetBool())
|
||||
{
|
||||
// Don't flinch if currently playing actbusy animation (navigating to or from one is fine)
|
||||
if (m_ActBusyBehavior.IsInsideActBusy())
|
||||
return false;
|
||||
|
||||
// Don't flinch if currently playing scripted sequence (navigating to or from one is fine)
|
||||
if (m_NPCState == NPC_STATE_SCRIPT && (IsCurSchedule( SCHED_SCRIPTED_WAIT, false ) || IsCurSchedule( SCHED_SCRIPTED_FACE, false )))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
//---------------------------------------------------------
|
||||
int CNPC_BaseZombie::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode )
|
||||
@ -2435,6 +2468,20 @@ void CNPC_BaseZombie::RemoveHead( void )
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
//---------------------------------------------------------
|
||||
void CNPC_BaseZombie::SetModel( const char *szModelName )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
// Zombies setting the same model again is a problem when they should maintain their current sequence (e.g. during dynamic interactions)
|
||||
if ( IsRunningDynamicInteraction() && GetModelIndex() != 0 && FStrEq( szModelName, STRING(GetModelName()) ) )
|
||||
return;
|
||||
#endif
|
||||
|
||||
BaseClass::SetModel( szModelName );
|
||||
}
|
||||
|
||||
|
||||
bool CNPC_BaseZombie::ShouldPlayFootstepMoan( void )
|
||||
{
|
||||
if( random->RandomInt( 1, zombie_stepfreq.GetInt() * s_iAngryZombies ) == 1 )
|
||||
@ -2450,9 +2497,15 @@ bool CNPC_BaseZombie::ShouldPlayFootstepMoan( void )
|
||||
#define CRAB_HULL_EXPAND 1.1f
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNPC_BaseZombie::HeadcrabFits( CBaseAnimating *pCrab )
|
||||
bool CNPC_BaseZombie::HeadcrabFits( CBaseAnimating *pCrab, const Vector *vecOrigin )
|
||||
{
|
||||
Vector vecSpawnLoc = pCrab->GetAbsOrigin();
|
||||
Vector vecSpawnLoc;
|
||||
#ifdef MAPBASE
|
||||
if (vecOrigin)
|
||||
vecSpawnLoc = *vecOrigin;
|
||||
else
|
||||
#endif
|
||||
vecSpawnLoc = pCrab->GetAbsOrigin();
|
||||
|
||||
CTraceFilterSimpleList traceFilter( COLLISION_GROUP_NONE );
|
||||
traceFilter.AddEntityToIgnore( pCrab );
|
||||
@ -2535,7 +2588,12 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve
|
||||
SetHeadcrabSpawnLocation( iCrabAttachment, pAnimatingGib );
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Server ragdolls don't have a valid origin on spawn, so we have to use the origin originally passed
|
||||
if( !HeadcrabFits( pAnimatingGib, m_bForceServerRagdoll ? &vecOrigin : NULL ) )
|
||||
#else
|
||||
if( !HeadcrabFits(pAnimatingGib) )
|
||||
#endif
|
||||
{
|
||||
UTIL_Remove(pGib);
|
||||
return;
|
||||
@ -2552,11 +2610,20 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve
|
||||
|
||||
if( UTIL_ShouldShowBlood(BLOOD_COLOR_YELLOW) )
|
||||
{
|
||||
UTIL_BloodImpact( pGib->WorldSpaceCenter(), Vector(0,0,1), BLOOD_COLOR_YELLOW, 1 );
|
||||
Vector vecGibCenter;
|
||||
#ifdef MAPBASE
|
||||
// Server ragdolls don't have a valid origin on spawn, so we have to use the origin originally passed
|
||||
if (m_bForceServerRagdoll)
|
||||
vecGibCenter = vecOrigin;
|
||||
else
|
||||
#endif
|
||||
vecGibCenter = pGib->WorldSpaceCenter();
|
||||
|
||||
UTIL_BloodImpact( vecGibCenter, Vector(0,0,1), BLOOD_COLOR_YELLOW, 1 );
|
||||
|
||||
for ( int i = 0 ; i < 3 ; i++ )
|
||||
{
|
||||
Vector vecSpot = pGib->WorldSpaceCenter();
|
||||
Vector vecSpot = vecGibCenter;
|
||||
|
||||
vecSpot.x += random->RandomFloat( -8, 8 );
|
||||
vecSpot.y += random->RandomFloat( -8, 8 );
|
||||
@ -2590,6 +2657,9 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve
|
||||
// Inherit some misc. properties
|
||||
pCrab->m_bForceServerRagdoll = m_bForceServerRagdoll;
|
||||
pCrab->m_iViewHideFlags = m_iViewHideFlags;
|
||||
|
||||
// Add response context for companion response (more reliable than checking for post-death zombie entity)
|
||||
pCrab->AddContext( "from_zombie", "1", 2.0f );
|
||||
#endif
|
||||
|
||||
// make me the crab's owner to avoid collision issues
|
||||
|
@ -151,6 +151,8 @@ public:
|
||||
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
|
||||
virtual float GetReactionDelay( CBaseEntity *pEnemy ) { return 0.0; }
|
||||
|
||||
bool CanFlinch( void );
|
||||
|
||||
virtual int SelectSchedule ( void );
|
||||
virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
|
||||
virtual void BuildScheduleTestBits( void );
|
||||
@ -186,9 +188,10 @@ public:
|
||||
// Headcrab releasing/breaking apart
|
||||
void RemoveHead( void );
|
||||
virtual void SetZombieModel( void ) { };
|
||||
virtual void SetModel( const char *szModelName );
|
||||
virtual void BecomeTorso( const Vector &vecTorsoForce, const Vector &vecLegsForce );
|
||||
virtual bool CanBecomeLiveTorso() { return false; }
|
||||
virtual bool HeadcrabFits( CBaseAnimating *pCrab );
|
||||
virtual bool HeadcrabFits( CBaseAnimating *pCrab, const Vector *vecOrigin = NULL );
|
||||
void ReleaseHeadcrab( const Vector &vecOrigin, const Vector &vecVelocity, bool fRemoveHead, bool fRagdollBody, bool fRagdollCrab = false );
|
||||
void SetHeadcrabSpawnLocation( int iCrabAttachment, CBaseAnimating *pCrab );
|
||||
|
||||
|
@ -1092,10 +1092,14 @@ void CNPC_Alyx::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Alyx::EnemyIgnited( CAI_BaseNPC *pVictim )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
BaseClass::EnemyIgnited( pVictim );
|
||||
#else
|
||||
if ( FVisible( pVictim ) )
|
||||
{
|
||||
SpeakIfAllowed( TLK_ENEMY_BURNING );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1252,6 +1256,7 @@ void CNPC_Alyx::DoCustomSpeechAI( void )
|
||||
|
||||
CBasePlayer *pPlayer = AI_GetSinglePlayer();
|
||||
|
||||
#ifndef MAPBASE // Ported to CNPC_PlayerCompanion
|
||||
if ( HasCondition(COND_NEW_ENEMY) && GetEnemy() )
|
||||
{
|
||||
if ( GetEnemy()->Classify() == CLASS_HEADCRAB )
|
||||
@ -1278,6 +1283,7 @@ void CNPC_Alyx::DoCustomSpeechAI( void )
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Darkness mode speech
|
||||
ClearCondition( COND_ALYX_IN_DARK );
|
||||
@ -1917,6 +1923,7 @@ int CNPC_Alyx::SelectSchedule( void )
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_Alyx::SelectScheduleDanger( void )
|
||||
{
|
||||
#ifndef MAPBASE
|
||||
if( HasCondition( COND_HEAR_DANGER ) )
|
||||
{
|
||||
CSound *pSound;
|
||||
@ -1929,6 +1936,7 @@ int CNPC_Alyx::SelectScheduleDanger( void )
|
||||
SpeakIfAllowed( TLK_DANGER_ZOMBINE_GRENADE );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return BaseClass::SelectScheduleDanger();
|
||||
}
|
||||
|
@ -412,7 +412,6 @@ ScriptHook_t CNPC_Citizen::g_Hook_SelectModel;
|
||||
|
||||
BEGIN_ENT_SCRIPTDESC( CNPC_Citizen, CAI_BaseActor, "npc_citizen from Half-Life 2" )
|
||||
|
||||
DEFINE_SCRIPTFUNC( IsMedic, "Returns true if this citizen is a medic." )
|
||||
DEFINE_SCRIPTFUNC( IsAmmoResupplier, "Returns true if this citizen is an ammo resupplier." )
|
||||
DEFINE_SCRIPTFUNC( CanHeal, "Returns true if this citizen is a medic or ammo resupplier currently able to heal/give ammo." )
|
||||
|
||||
|
@ -47,6 +47,8 @@ ConVar npc_combine_protected_run( "npc_combine_protected_run", "0", FCVAR_NONE,
|
||||
ConVar npc_combine_altfire_not_allies_only( "npc_combine_altfire_not_allies_only", "1", FCVAR_NONE, "Mapbase: Elites are normally only allowed to fire their alt-fire attack at the player and the player's allies; This allows elites to alt-fire at other enemies too." );
|
||||
|
||||
ConVar npc_combine_new_cover_behavior( "npc_combine_new_cover_behavior", "1", FCVAR_NONE, "Mapbase: Toggles small patches for parts of npc_combine AI related to soldiers failing to take cover. These patches are minimal and only change cases where npc_combine would otherwise look at an enemy without shooting or run up to the player to melee attack when they don't have to. Consult the Mapbase wiki for more information." );
|
||||
|
||||
ConVar npc_combine_fixed_shootpos( "npc_combine_fixed_shootpos", "0", FCVAR_NONE, "Mapbase: Toggles fixed Combine soldier shoot position." );
|
||||
#endif
|
||||
|
||||
#define COMBINE_SKIN_DEFAULT 0
|
||||
@ -2959,6 +2961,28 @@ Vector CNPC_Combine::Weapon_ShootPosition( )
|
||||
// FIXME: rename this "estimated" since it's not based on animation
|
||||
// FIXME: the orientation won't be correct when testing from arbitary positions for arbitary angles
|
||||
|
||||
#ifdef MAPBASE
|
||||
// HACKHACK: This weapon shoot position code does not work properly when in close range, causing the aim
|
||||
// to drift to the left as the enemy gets closer to it.
|
||||
// This problem is usually bearable for regular combat, but it causes dynamic interaction yaw to be offset
|
||||
// as well, preventing most from ever being triggered.
|
||||
// Ideally, this should be fixed from the root cause, but due to the sensitivity of such a change, this is
|
||||
// currently being tied to a cvar which is off by default.
|
||||
//
|
||||
// If the cvar is disabled but the soldier has valid interactions on its current enemy, then a separate hack
|
||||
// will still attempt to correct the drift as the enemy gets closer.
|
||||
if ( npc_combine_fixed_shootpos.GetBool() )
|
||||
{
|
||||
right *= 0.0f;
|
||||
}
|
||||
else if ( HasValidInteractionsOnCurrentEnemy() )
|
||||
{
|
||||
float flDistSqr = GetEnemy()->WorldSpaceCenter().DistToSqr( WorldSpaceCenter() );
|
||||
if (flDistSqr < Square( 128.0f ))
|
||||
right *= (flDistSqr / Square( 128.0f ));
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( bStanding )
|
||||
{
|
||||
if( HasShotgun() )
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "mapbase/GlobalStrings.h"
|
||||
#include "world.h"
|
||||
#include "vehicle_base.h"
|
||||
#include "npc_headcrab.h"
|
||||
#include "npc_BaseZombie.h"
|
||||
#endif
|
||||
|
||||
ConVar ai_debug_readiness("ai_debug_readiness", "0" );
|
||||
@ -640,6 +642,55 @@ void CNPC_PlayerCompanion::DoCustomSpeechAI( void )
|
||||
{
|
||||
SpeakIfAllowed( TLK_PLDEAD );
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Unique new enemy concepts ported from Alyx
|
||||
// The casts have been changed to dynamic_cast due to the risk of non-CBaseHeadcrab/CNPC_BaseZombie enemies using those classes
|
||||
if ( HasCondition(COND_NEW_ENEMY) && GetEnemy() )
|
||||
{
|
||||
int nClass = GetEnemy()->Classify();
|
||||
if ( nClass == CLASS_HEADCRAB )
|
||||
{
|
||||
CBaseHeadcrab *pHC = dynamic_cast<CBaseHeadcrab*>(GetEnemy());
|
||||
if ( pHC )
|
||||
{
|
||||
// If we see a headcrab for the first time as he's jumping at me, freak out!
|
||||
if ( ( GetEnemy()->GetEnemy() == this ) && pHC->IsJumping() && gpGlobals->curtime - GetEnemies()->FirstTimeSeen(GetEnemy()) < 0.5 )
|
||||
{
|
||||
SpeakIfAllowed( "TLK_SPOTTED_INCOMING_HEADCRAB" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we see a headcrab leaving a zombie that just died, mention it
|
||||
// (Note that this is now a response context since some death types remove the zombie instantly)
|
||||
int nContext = pHC->FindContextByName( "from_zombie" );
|
||||
if ( nContext > -1 && !ContextExpired( nContext ) ) // pHC->GetOwnerEntity() && ( pHC->GetOwnerEntity()->Classify() == CLASS_ZOMBIE ) && !pHC->GetOwnerEntity()->IsAlive()
|
||||
{
|
||||
SpeakIfAllowed( "TLK_SPOTTED_HEADCRAB_LEAVING_ZOMBIE" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( nClass == CLASS_ZOMBIE )
|
||||
{
|
||||
CNPC_BaseZombie *pZombie = dynamic_cast<CNPC_BaseZombie*>(GetEnemy());
|
||||
// If we see a zombie getting up, mention it
|
||||
if ( pZombie && pZombie->IsGettingUp() )
|
||||
{
|
||||
SpeakIfAllowed( "TLK_SPOTTED_ZOMBIE_WAKEUP" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( gpGlobals->curtime - GetEnemies()->TimeAtFirstHand( GetEnemy() ) <= 1.0f && nClass != CLASS_BULLSEYE )
|
||||
{
|
||||
// New concept which did not originate from Alyx, but is in the same category as the above concepts.
|
||||
// This is meant to be used when a new enemy enters the arena while combat is already in progress.
|
||||
// (Note that this can still trigger when combat begins, but unlike TLK_STARTCOMBAT, it has no delay
|
||||
// between combat engagements.)
|
||||
SpeakIfAllowed( TLK_NEW_ENEMY );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -910,8 +961,21 @@ int CNPC_PlayerCompanion::SelectScheduleDanger()
|
||||
|
||||
if ( pSound && (pSound->m_iType & SOUND_DANGER) )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if ( pSound->SoundChannel() == SOUNDENT_CHANNEL_ZOMBINE_GRENADE )
|
||||
{
|
||||
SetSpeechTarget( pSound->m_hOwner );
|
||||
SpeakIfAllowed( TLK_DANGER_ZOMBINE_GRENADE );
|
||||
}
|
||||
else if (!(pSound->SoundContext() & (SOUND_CONTEXT_MORTAR | SOUND_CONTEXT_FROM_SNIPER)) || IsOkToCombatSpeak())
|
||||
{
|
||||
SetSpeechTarget( pSound->m_hOwner );
|
||||
SpeakIfAllowed( TLK_DANGER );
|
||||
}
|
||||
#else
|
||||
if ( !(pSound->SoundContext() & (SOUND_CONTEXT_MORTAR|SOUND_CONTEXT_FROM_SNIPER)) || IsOkToCombatSpeak() )
|
||||
SpeakIfAllowed( TLK_DANGER );
|
||||
#endif
|
||||
|
||||
if ( HasCondition( COND_PC_SAFE_FROM_MORTAR ) )
|
||||
{
|
||||
@ -4309,6 +4373,20 @@ void CNPC_PlayerCompanion::Event_KilledOther( CBaseEntity *pVictim, const CTakeD
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called by enemy NPC's when they are ignited
|
||||
// Input : pVictim - entity that was ignited
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_PlayerCompanion::EnemyIgnited( CAI_BaseNPC *pVictim )
|
||||
{
|
||||
BaseClass::EnemyIgnited( pVictim );
|
||||
|
||||
if ( FVisible( pVictim ) )
|
||||
{
|
||||
SpeakIfAllowed( TLK_ENEMY_BURNING );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handles custom combat speech stuff ported from Alyx.
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -4376,6 +4454,21 @@ void CNPC_PlayerCompanion::DoCustomCombatAI( void )
|
||||
{
|
||||
SpeakIfAllowed( TLK_MANY_ENEMIES );
|
||||
}
|
||||
|
||||
// If we're not currently attacking or vulnerable, try speaking
|
||||
else if ( gpGlobals->curtime - GetLastAttackTime() > 1.0f && (!HasCondition( COND_SEE_ENEMY ) || IsCurSchedule( SCHED_RELOAD ) || IsCurSchedule( SCHED_HIDE_AND_RELOAD )) )
|
||||
{
|
||||
int chance = ( IsMoving() ) ? 20 : 3;
|
||||
if ( ShouldSpeakRandom( TLK_COMBAT_IDLE, chance ) )
|
||||
{
|
||||
AI_CriteriaSet modifiers;
|
||||
|
||||
modifiers.AppendCriteria( "in_cover", HasMemory( bits_MEMORY_INCOVER ) ? "1" : "0" );
|
||||
modifiers.AppendCriteria( "lastseenenemy", UTIL_VarArgs( "%f", gpGlobals->curtime - GetEnemyLastTimeSeen() ) );
|
||||
|
||||
SpeakIfAllowed( TLK_COMBAT_IDLE, modifiers );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -242,6 +242,7 @@ public:
|
||||
|
||||
virtual void Event_Killed( const CTakeDamageInfo &info );
|
||||
virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info );
|
||||
virtual void EnemyIgnited( CAI_BaseNPC *pVictim );
|
||||
virtual void DoCustomCombatAI( void );
|
||||
#endif
|
||||
|
||||
|
@ -121,6 +121,33 @@ acttable_t CWeaponAnnabelle::m_acttable[] =
|
||||
{ ACT_RELOAD_LOW, ACT_RELOAD_ANNABELLE_LOW, false },
|
||||
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_ANNABELLE, false },
|
||||
|
||||
// Readiness activities (not aiming)
|
||||
{ ACT_IDLE_RELAXED, ACT_IDLE_AR2_RELAXED, false },//never aims
|
||||
{ ACT_IDLE_STIMULATED, ACT_IDLE_AR2_STIMULATED, false },
|
||||
{ ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_AR2, false },//always aims
|
||||
|
||||
{ ACT_WALK_RELAXED, ACT_WALK_AR2_RELAXED, false },//never aims
|
||||
{ ACT_WALK_STIMULATED, ACT_WALK_AR2_STIMULATED, false },
|
||||
{ ACT_WALK_AGITATED, ACT_WALK_AIM_AR2, false },//always aims
|
||||
|
||||
{ ACT_RUN_RELAXED, ACT_RUN_AR2_RELAXED, false },//never aims
|
||||
{ ACT_RUN_STIMULATED, ACT_RUN_AR2_STIMULATED, false },
|
||||
{ ACT_RUN_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
|
||||
|
||||
// Readiness activities (aiming)
|
||||
{ ACT_IDLE_AIM_RELAXED, ACT_IDLE_AR2_RELAXED, false },//never aims
|
||||
{ ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_AR2_STIMULATED, false },
|
||||
{ ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_AR2, false },//always aims
|
||||
|
||||
{ ACT_WALK_AIM_RELAXED, ACT_WALK_AR2_RELAXED, false },//never aims
|
||||
{ ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_AR2_STIMULATED, false },
|
||||
{ ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_AR2, false },//always aims
|
||||
|
||||
{ ACT_RUN_AIM_RELAXED, ACT_RUN_AR2_RELAXED, false },//never aims
|
||||
{ ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_AR2_STIMULATED, false },
|
||||
{ ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
|
||||
//End readiness activities
|
||||
|
||||
{ ACT_ARM, ACT_ARM_RIFLE, true },
|
||||
{ ACT_DISARM, ACT_DISARM_RIFLE, true },
|
||||
#else
|
||||
@ -143,6 +170,13 @@ acttable_t CWeaponAnnabelle::m_acttable[] =
|
||||
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false },
|
||||
#endif
|
||||
|
||||
#if EXPANDED_HL2_COVER_ACTIVITIES
|
||||
{ ACT_COVER_WALL_R, ACT_COVER_WALL_R_RIFLE, false },
|
||||
{ ACT_COVER_WALL_L, ACT_COVER_WALL_L_RIFLE, false },
|
||||
{ ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, false },
|
||||
{ ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, false },
|
||||
#endif
|
||||
|
||||
#ifdef MAPBASE
|
||||
// HL2:DM activities (for third-person animations in SP)
|
||||
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false },
|
||||
@ -161,6 +195,18 @@ acttable_t CWeaponAnnabelle::m_acttable[] =
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponAnnabelle);
|
||||
|
||||
#ifdef MAPBASE
|
||||
acttable_t* GetAnnabelleActtable()
|
||||
{
|
||||
return CWeaponAnnabelle::m_acttable;
|
||||
}
|
||||
|
||||
int GetAnnabelleActtableCount()
|
||||
{
|
||||
return ARRAYSIZE(CWeaponAnnabelle::m_acttable);
|
||||
}
|
||||
#endif // MAPBASE
|
||||
|
||||
void CWeaponAnnabelle::Precache( void )
|
||||
{
|
||||
CBaseCombatWeapon::Precache();
|
||||
|
@ -346,7 +346,7 @@ void CWeaponAR2::DelayedAttack( void )
|
||||
|
||||
pOwner->SnapEyeAngles( angles );
|
||||
|
||||
pOwner->ViewPunch( QAngle( random->RandomInt( -8, -12 ), random->RandomInt( 1, 2 ), 0 ) );
|
||||
pOwner->ViewPunch( QAngle( random->RandomInt( -12, -8 ), random->RandomInt( 1, 2 ), 0 ) );
|
||||
|
||||
// Decrease ammo
|
||||
pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
|
||||
|
@ -762,6 +762,16 @@ acttable_t CWeaponCrossbow::m_acttable[] =
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTTABLE(CWeaponCrossbow);
|
||||
|
||||
acttable_t* GetCrossbowActtable()
|
||||
{
|
||||
return CWeaponCrossbow::m_acttable;
|
||||
}
|
||||
|
||||
int GetCrossbowActtableCount()
|
||||
{
|
||||
return ARRAYSIZE(CWeaponCrossbow::m_acttable);
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -68,6 +68,10 @@ ConVar player_throwforce( "player_throwforce", "1000" );
|
||||
ConVar physcannon_dmg_glass( "physcannon_dmg_glass", "15" );
|
||||
ConVar physcannon_right_turrets( "physcannon_right_turrets", "0" );
|
||||
|
||||
#ifdef MAPBASE
|
||||
ConVar sv_player_enable_propsprint("sv_player_enable_propsprint", "0", FCVAR_NONE, "If enabled, allows the player to sprint while holding a physics object" );
|
||||
ConVar sv_player_enable_gravgun_sprint("sv_player_enable_gravgun_sprint", "0", FCVAR_NONE, "Enables the player to sprint while holding a phys. object with the gravity gun" );
|
||||
#endif
|
||||
extern ConVar hl2_normspeed;
|
||||
extern ConVar hl2_walkspeed;
|
||||
|
||||
@ -1044,9 +1048,19 @@ void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject )
|
||||
CHL2_Player *pOwner = (CHL2_Player *)ToBasePlayer( pPlayer );
|
||||
if ( pOwner )
|
||||
{
|
||||
#ifndef MAPBASE
|
||||
pOwner->EnableSprint( false );
|
||||
#else
|
||||
if ( sv_player_enable_propsprint.GetBool() == false )
|
||||
{
|
||||
pOwner->EnableSprint( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
pOwner->EnableSprint( true );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// If the target is debris, convert it to non-debris
|
||||
if ( pObject->GetCollisionGroup() == COLLISION_GROUP_DEBRIS )
|
||||
{
|
||||
@ -1102,10 +1116,17 @@ void CPlayerPickupController::Shutdown( bool bThrown )
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
CHL2_Player *pOwner = (CHL2_Player *)ToBasePlayer( m_pPlayer );
|
||||
#ifndef MAPBASE
|
||||
if ( pOwner )
|
||||
{
|
||||
pOwner->EnableSprint( true );
|
||||
}
|
||||
#else
|
||||
if ( pOwner && sv_player_enable_propsprint.GetBool() == false )
|
||||
{
|
||||
pOwner->EnableSprint( true );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_pPlayer->SetUseEntity( NULL );
|
||||
if ( m_pPlayer->GetActiveWeapon() )
|
||||
@ -2497,6 +2518,7 @@ bool CWeaponPhysCannon::AttachObject( CBaseEntity *pObject, const Vector &vPosit
|
||||
// NVNT set the players constant force to simulate holding mass
|
||||
HapticSetConstantForce(pOwner,clamp(m_grabController.GetLoadWeight()*0.05,1,5)*Vector(0,-1,0));
|
||||
#endif
|
||||
#ifndef MAPBASE
|
||||
pOwner->EnableSprint( false );
|
||||
|
||||
float loadWeight = ( 1.0f - GetLoadPercentage() );
|
||||
@ -2504,6 +2526,22 @@ bool CWeaponPhysCannon::AttachObject( CBaseEntity *pObject, const Vector &vPosit
|
||||
|
||||
//Msg( "Load perc: %f -- Movement speed: %f/%f\n", loadWeight, maxSpeed, hl2_normspeed.GetFloat() );
|
||||
pOwner->SetMaxSpeed( maxSpeed );
|
||||
#else
|
||||
if ( sv_player_enable_gravgun_sprint.GetBool() == false )
|
||||
{
|
||||
pOwner->EnableSprint( false );
|
||||
|
||||
float loadWeight = ( 1.0f - GetLoadPercentage() );
|
||||
float maxSpeed = hl2_walkspeed.GetFloat() + ( ( hl2_normspeed.GetFloat() - hl2_walkspeed.GetFloat() ) * loadWeight );
|
||||
|
||||
//Msg( "Load perc: %f -- Movement speed: %f/%f\n", loadWeight, maxSpeed, hl2_normspeed.GetFloat() );
|
||||
pOwner->SetMaxSpeed( maxSpeed );
|
||||
}
|
||||
else
|
||||
{
|
||||
pOwner->EnableSprint( true );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Don't drop again for a slight delay, in case they were pulling objects near them
|
||||
@ -2950,9 +2988,17 @@ void CWeaponPhysCannon::DetachObject( bool playSound, bool wasLaunched )
|
||||
CHL2_Player *pOwner = (CHL2_Player *)ToBasePlayer( GetOwner() );
|
||||
if( pOwner != NULL )
|
||||
{
|
||||
#ifndef MAPBASE
|
||||
pOwner->EnableSprint( true );
|
||||
pOwner->SetMaxSpeed( hl2_normspeed.GetFloat() );
|
||||
|
||||
#else
|
||||
if (sv_player_enable_gravgun_sprint.GetBool() == false)
|
||||
{
|
||||
pOwner->EnableSprint( true );
|
||||
pOwner->SetMaxSpeed( hl2_normspeed.GetFloat() );
|
||||
}
|
||||
#endif
|
||||
if( wasLaunched )
|
||||
{
|
||||
pOwner->RumbleEffect( RUMBLE_357, 0, RUMBLE_FLAG_RESTART );
|
||||
|
@ -526,6 +526,10 @@ bool CWeaponPistol::Reload( void )
|
||||
return fRet;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
ConVar weapon_pistol_upwards_viewkick( "weapon_pistol_upwards_viewkick", "0" );
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -538,7 +542,11 @@ void CWeaponPistol::AddViewKick( void )
|
||||
|
||||
QAngle viewPunch;
|
||||
|
||||
#ifdef MAPBASE
|
||||
viewPunch.x = weapon_pistol_upwards_viewkick.GetBool() ? random->RandomFloat( -0.5f, -0.25f ) : random->RandomFloat( 0.25f, 0.5f );
|
||||
#else
|
||||
viewPunch.x = random->RandomFloat( 0.25f, 0.5f );
|
||||
#endif
|
||||
viewPunch.y = random->RandomFloat( -.6f, .6f );
|
||||
viewPunch.z = 0.0f;
|
||||
|
||||
|
@ -3112,7 +3112,7 @@ void CLogicBranch::UpdateOnRemove()
|
||||
CBaseEntity *pEntity = m_Listeners.Element( i ).Get();
|
||||
if ( pEntity )
|
||||
{
|
||||
g_EventQueue.AddEvent( this, "_OnLogicBranchRemoved", 0, this, this );
|
||||
g_EventQueue.AddEvent( pEntity, "_OnLogicBranchRemoved", 0, this, this );
|
||||
}
|
||||
}
|
||||
|
||||
@ -4059,7 +4059,7 @@ void CLogicFormat::FormatString(const char *szStringToFormat, char *szOutput, in
|
||||
curparam = atoi(szToken);
|
||||
if (curparam < MAX_LOGIC_FORMAT_PARAMETERS /*&& szParameters[curparam] != NULL*/) //if (curparam < MAX_FORMAT_PARAMETERS)
|
||||
{
|
||||
Q_snprintf(szFormatted, sizeof(szFormatted), "%s%s", szFormatted, szParameters[curparam]);
|
||||
Q_strncat(szFormatted, szParameters[curparam], sizeof(szFormatted));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4068,8 +4068,8 @@ void CLogicFormat::FormatString(const char *szStringToFormat, char *szOutput, in
|
||||
// This might not be the best way to do this, but
|
||||
// reaching it is supposed to be the result of a mistake anyway.
|
||||
m_iszBackupParameter != NULL_STRING ?
|
||||
Q_snprintf(szFormatted, sizeof(szFormatted), "%s%s", szFormatted, STRING(m_iszBackupParameter)) :
|
||||
Q_snprintf(szFormatted, sizeof(szFormatted), "%s<null>", szFormatted);
|
||||
Q_strncat( szFormatted, STRING(m_iszBackupParameter), sizeof( szFormatted ) ) :
|
||||
Q_strncat( szFormatted, "<null>", sizeof( szFormatted ) );
|
||||
}
|
||||
|
||||
inparam = false;
|
||||
@ -4077,7 +4077,7 @@ void CLogicFormat::FormatString(const char *szStringToFormat, char *szOutput, in
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintf(szFormatted, sizeof(szFormatted), "%s%s", szFormatted, szToken);
|
||||
Q_strncat( szFormatted, szToken, sizeof( szFormatted ) );
|
||||
|
||||
inparam = true;
|
||||
szToken = strtok(NULL, "}");
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "hl2_gamerules.h"
|
||||
#include "weapon_physcannon.h"
|
||||
#include "globalstate.h"
|
||||
#include "ai_hint.h"
|
||||
|
||||
#define COMBINE_AE_GREN_TOSS ( 7 )
|
||||
|
||||
@ -138,6 +139,8 @@ public:
|
||||
|
||||
void ClearAttackConditions( void );
|
||||
|
||||
bool FValidateHintType( CAI_Hint *pHint );
|
||||
|
||||
Vector GetAltFireTarget() { return m_vecAltFireTarget; }
|
||||
virtual bool CanAltFireEnemy( bool bUseFreeKnowledge );
|
||||
void DelayAltFireAttack( float flDelay );
|
||||
@ -558,6 +561,29 @@ bool CAI_GrenadeUser<BASE_NPC>::CanThrowGrenade( const Vector &vecTarget )
|
||||
}
|
||||
}
|
||||
|
||||
CHintCriteria hintCriteria;
|
||||
hintCriteria.SetHintType( HINT_TACTICAL_GRENADE_THROW );
|
||||
hintCriteria.SetFlag( bits_HINT_NPC_IN_NODE_FOV );
|
||||
hintCriteria.SetGroup( this->GetHintGroup() );
|
||||
hintCriteria.AddIncludePosition( this->GetAbsOrigin(), 1024 );
|
||||
|
||||
if (this->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
|
||||
hintCriteria.SetFlag( bits_HINT_NODE_REPORT_FAILURES );
|
||||
|
||||
// If there's a grenade throw hint nearby, try using it
|
||||
CAI_Hint *pHint = CAI_HintManager::FindHint( this, vecTarget, hintCriteria );
|
||||
if ( pHint )
|
||||
{
|
||||
if ( CheckCanThrowGrenade( pHint->GetAbsOrigin() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DevMsg( this, "Unable to throw grenade at hint %s\n", pHint->GetDebugName() );
|
||||
}
|
||||
}
|
||||
|
||||
return CheckCanThrowGrenade( vecTarget );
|
||||
}
|
||||
|
||||
@ -636,6 +662,18 @@ void CAI_GrenadeUser<BASE_NPC>::ClearAttackConditions()
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class BASE_NPC>
|
||||
bool CAI_GrenadeUser<BASE_NPC>::FValidateHintType( CAI_Hint *pHint )
|
||||
{
|
||||
if ( pHint->HintType() == HINT_TACTICAL_GRENADE_THROW )
|
||||
return true;
|
||||
|
||||
return BaseClass::FValidateHintType( pHint );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Drops grenades and alt-fire items on death. Based on code from npc_combines.cpp and npc_combine.cpp
|
||||
//-----------------------------------------------------------------------------
|
||||
|
208
sp/src/game/server/mapbase/custom_weapon_factory.cpp
Normal file
208
sp/src/game/server/mapbase/custom_weapon_factory.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
|
||||
//
|
||||
// Purpose: The central manager of the custom weapons system.
|
||||
//
|
||||
// Author: Peter Covington (petercov@outlook.com)
|
||||
//
|
||||
//==================================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "custom_weapon_factory.h"
|
||||
|
||||
#define GENERIC_MANIFEST_FILE "scripts/mapbase_default_manifest.txt"
|
||||
#define AUTOLOADED_MANIFEST_FILE UTIL_VarArgs("maps/%s_manifest.txt", STRING(gpGlobals->mapname))
|
||||
#define GLOBAL_WEAPONS_MANIFEST "scripts/custom_weapon_manifest.txt"
|
||||
|
||||
extern ConVar mapbase_load_default_manifest;
|
||||
|
||||
IMPLEMENT_PRIVATE_SYMBOLTYPE(CustomWeaponSymbol);
|
||||
|
||||
CCustomWeaponSystem::CCustomWeaponSystem() : CAutoGameSystem("CustomWeaponFactorySystem")
|
||||
{
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::LevelInitPreEntity()
|
||||
{
|
||||
LoadCustomWeaponsManifest(GLOBAL_WEAPONS_MANIFEST);
|
||||
|
||||
// Check for a generic "mapname_manifest.txt" file and load it.
|
||||
if (filesystem->FileExists(AUTOLOADED_MANIFEST_FILE, "GAME"))
|
||||
{
|
||||
AddManifestFile(AUTOLOADED_MANIFEST_FILE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load the generic script instead.
|
||||
ParseGenericManifest();
|
||||
}
|
||||
}
|
||||
|
||||
// Get a generic, hardcoded manifest with hardcoded names.
|
||||
void CCustomWeaponSystem::ParseGenericManifest()
|
||||
{
|
||||
if (!mapbase_load_default_manifest.GetBool())
|
||||
return;
|
||||
|
||||
KeyValues* pKV = new KeyValues("DefaultManifest");
|
||||
pKV->LoadFromFile(filesystem, GENERIC_MANIFEST_FILE);
|
||||
|
||||
AddManifestFile(pKV/*, true*/);
|
||||
|
||||
pKV->deleteThis();
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::AddManifestFile(const char* file)
|
||||
{
|
||||
KeyValues* pKV = new KeyValues(file);
|
||||
if (!pKV->LoadFromFile(filesystem, file))
|
||||
{
|
||||
Warning("Mapbase Manifest: \"%s\" is unreadable or missing (can't load KV, check for syntax errors)\n", file);
|
||||
pKV->deleteThis();
|
||||
return;
|
||||
}
|
||||
|
||||
CGMsg(1, CON_GROUP_MAPBASE_MISC, "===== Mapbase Manifest: Loading manifest file %s =====\n", file);
|
||||
|
||||
AddManifestFile(pKV, false);
|
||||
|
||||
CGMsg(1, CON_GROUP_MAPBASE_MISC, "==============================================================================\n");
|
||||
|
||||
pKV->deleteThis();
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::AddManifestFile(KeyValues* pKV, bool bDontWarn)
|
||||
{
|
||||
KeyValues* pKey = pKV->FindKey("weapons");
|
||||
|
||||
if (pKey)
|
||||
{
|
||||
char value[MAX_PATH];
|
||||
value[0] = '\0';
|
||||
|
||||
// Parse %mapname%, etc.
|
||||
bool inparam = false;
|
||||
CUtlStringList outStrings;
|
||||
V_SplitString(pKey->GetString(), "%", outStrings);
|
||||
for (int i = 0; i < outStrings.Count(); i++)
|
||||
{
|
||||
if (inparam)
|
||||
{
|
||||
if (FStrEq(outStrings[i], "mapname"))
|
||||
{
|
||||
Q_strncat(value, STRING(gpGlobals->mapname), sizeof(value));
|
||||
}
|
||||
else if (FStrEq(outStrings[i], "language"))
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
char uilanguage[64];
|
||||
engine->GetUILanguage(uilanguage, sizeof(uilanguage));
|
||||
Q_strncat(value, uilanguage, sizeof(value));
|
||||
#else
|
||||
// Give up, use English
|
||||
Q_strncat(value, "english", sizeof(value));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncat(value, outStrings[i], sizeof(value));
|
||||
}
|
||||
|
||||
inparam = !inparam;
|
||||
}
|
||||
|
||||
outStrings.PurgeAndDeleteElements();
|
||||
bDontWarn = pKV->GetBool("NoErrors", bDontWarn);
|
||||
|
||||
LoadCustomWeaponsManifest(value, bDontWarn);
|
||||
}
|
||||
}
|
||||
|
||||
#define Factory CustomWeaponsFactoryDictionary()
|
||||
void CCustomWeaponSystem::LoadCustomWeaponsManifest(const char* file, bool bDontWarn)
|
||||
{
|
||||
KeyValuesAD pKV("weapons_manifest");
|
||||
if (pKV->LoadFromFile(filesystem, file, "GAME"))
|
||||
{
|
||||
for (KeyValues *pkvWeapon = pKV->GetFirstValue(); pkvWeapon != nullptr; pkvWeapon = pkvWeapon->GetNextValue())
|
||||
{
|
||||
const char* pszClassname = pkvWeapon->GetName();
|
||||
KeyValuesAD pkvWeaponScript("WeaponData");
|
||||
if (pkvWeaponScript->LoadFromFile(filesystem, pkvWeapon->GetString(), "GAME"))
|
||||
{
|
||||
const char* pszFactory = pkvWeaponScript->GetString("custom_factory", nullptr);
|
||||
unsigned short FactoryIndex = Factory.Find(pszFactory);
|
||||
if (Factory.IsValidIndex(FactoryIndex))
|
||||
{
|
||||
auto* pFactory = Factory.Element(FactoryIndex);
|
||||
const void* pData = pFactory->ParseDataFromWeaponFile(pkvWeaponScript);
|
||||
if (!pData)
|
||||
continue;
|
||||
|
||||
unsigned short ClassIndex = m_ClassFactories.Find(pszClassname);
|
||||
if (!m_ClassFactories.IsValidIndex(ClassIndex))
|
||||
{
|
||||
ClassIndex = m_ClassFactories.Insert(pszClassname);
|
||||
m_ClassFactories[ClassIndex].pOldFactory = EntityFactoryDictionary()->FindFactory(pszClassname);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(m_ClassFactories[ClassIndex].pNewFactory);
|
||||
Assert(m_ClassFactories[ClassIndex].pData);
|
||||
|
||||
m_ClassFactories[ClassIndex].pNewFactory->ReleaseData(m_ClassFactories[ClassIndex].pData);
|
||||
}
|
||||
|
||||
m_ClassFactories[ClassIndex].sDataFile = pkvWeapon->GetString();
|
||||
m_ClassFactories[ClassIndex].pNewFactory = pFactory;
|
||||
m_ClassFactories[ClassIndex].pData = pData;
|
||||
EntityFactoryDictionary()->UninstallFactory(pszClassname);
|
||||
EntityFactoryDictionary()->InstallFactory(m_ClassFactories[ClassIndex].pNewFactory, pszClassname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef Factory
|
||||
|
||||
void CCustomWeaponSystem::LevelShutdownPostEntity()
|
||||
{
|
||||
for (unsigned short i = 0; i < m_ClassFactories.Count(); i++)
|
||||
{
|
||||
EntityFactoryDictionary()->UninstallFactory(m_ClassFactories.GetElementName(i));
|
||||
const CustomClassName_t& entry = m_ClassFactories.Element(i);
|
||||
if (entry.pOldFactory)
|
||||
EntityFactoryDictionary()->InstallFactory(entry.pOldFactory, m_ClassFactories.GetElementName(i));
|
||||
|
||||
Assert(entry.pData);
|
||||
entry.pNewFactory->ReleaseData(entry.pData);
|
||||
}
|
||||
|
||||
m_ClassFactories.Purge();
|
||||
g_CustomWeaponSymbolSymbolTable.RemoveAll();
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::ParseWeapon(CBaseCombatWeapon* pWeapon, const char* pClassName)
|
||||
{
|
||||
ICustomWeapon* pCustom = dynamic_cast<ICustomWeapon*> (pWeapon);
|
||||
if (!pCustom)
|
||||
return;
|
||||
|
||||
unsigned short i = m_ClassFactories.Find(pClassName);
|
||||
if (!m_ClassFactories.IsValidIndex(i))
|
||||
return;
|
||||
|
||||
pCustom->InitCustomWeaponFromData(m_ClassFactories[i].pData, m_ClassFactories[i].sDataFile.String());
|
||||
}
|
||||
|
||||
CUtlDict<ICustomWeaponDataLoader*, unsigned short>& CustomWeaponsFactoryDictionary()
|
||||
{
|
||||
static CUtlDict<ICustomWeaponDataLoader*, unsigned short> dict;
|
||||
return dict;
|
||||
}
|
||||
|
||||
static CCustomWeaponSystem g_CustomWeaponsSystem;
|
||||
CCustomWeaponSystem* CustomWeaponSystem()
|
||||
{
|
||||
return &g_CustomWeaponsSystem;
|
||||
}
|
117
sp/src/game/server/mapbase/custom_weapon_factory.h
Normal file
117
sp/src/game/server/mapbase/custom_weapon_factory.h
Normal file
@ -0,0 +1,117 @@
|
||||
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
|
||||
//
|
||||
// Purpose: See custom_weapon_factory.cpp
|
||||
//
|
||||
// Author: Peter Covington (petercov@outlook.com)
|
||||
//
|
||||
//==================================================================================//
|
||||
|
||||
#ifndef CUSTOM_WEAPON_FACTORY_H
|
||||
#define CUSTOM_WEAPON_FACTORY_H
|
||||
#pragma once
|
||||
#include "utldict.h"
|
||||
#include "utlsymbol.h"
|
||||
|
||||
DECLARE_PRIVATE_SYMBOLTYPE(CustomWeaponSymbol);
|
||||
|
||||
class ICustomWeaponDataLoader : public IEntityFactory
|
||||
{
|
||||
public:
|
||||
virtual const void* ParseDataFromWeaponFile(KeyValues* pKV) const = 0;
|
||||
virtual void ReleaseData(const void* pData) const = 0;
|
||||
};
|
||||
|
||||
class ICustomWeapon
|
||||
{
|
||||
public:
|
||||
virtual void InitCustomWeaponFromData(const void* pData, const char *pszWeaponScript) = 0;
|
||||
};
|
||||
|
||||
class CCustomWeaponSystem : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CCustomWeaponSystem();
|
||||
|
||||
// Level init, shutdown
|
||||
virtual void LevelInitPreEntity();
|
||||
virtual void LevelShutdownPostEntity();
|
||||
|
||||
void ParseWeapon(CBaseCombatWeapon* pWeapon, const char* pClassName);
|
||||
|
||||
private:
|
||||
void ParseGenericManifest();
|
||||
void AddManifestFile(const char* file);
|
||||
void AddManifestFile(KeyValues* pKV, bool bDontWarn = false);
|
||||
void LoadCustomWeaponsManifest(const char* file, bool bDontWarn = false);
|
||||
|
||||
typedef struct CustomClassName_s
|
||||
{
|
||||
CustomWeaponSymbol sDataFile;
|
||||
ICustomWeaponDataLoader* pNewFactory;
|
||||
IEntityFactory* pOldFactory;
|
||||
const void* pData;
|
||||
} CustomClassName_t;
|
||||
CUtlDict<CustomClassName_t, unsigned short> m_ClassFactories;
|
||||
};
|
||||
|
||||
CCustomWeaponSystem* CustomWeaponSystem();
|
||||
|
||||
CUtlDict< ICustomWeaponDataLoader*, unsigned short >& CustomWeaponsFactoryDictionary();
|
||||
|
||||
template <class T>
|
||||
class CCustomWeaponEntityFactoryBase : public ICustomWeaponDataLoader
|
||||
{
|
||||
public:
|
||||
CCustomWeaponEntityFactoryBase(const char* pFactoryClass)
|
||||
{
|
||||
CustomWeaponsFactoryDictionary().Insert(pFactoryClass, this);
|
||||
}
|
||||
|
||||
IServerNetworkable* Create(const char* pClassName)
|
||||
{
|
||||
T* pEnt = _CreateEntityTemplate((T*)NULL, pClassName);
|
||||
CustomWeaponSystem()->ParseWeapon(pEnt, pClassName);
|
||||
return pEnt->NetworkProp();
|
||||
}
|
||||
|
||||
void Destroy(IServerNetworkable* pNetworkable)
|
||||
{
|
||||
if (pNetworkable)
|
||||
{
|
||||
pNetworkable->Release();
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t GetEntitySize()
|
||||
{
|
||||
return sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Entity, class Data>
|
||||
class CDefaultCustomWeaponEntityFactory : public CCustomWeaponEntityFactoryBase<Entity>
|
||||
{
|
||||
public:
|
||||
CDefaultCustomWeaponEntityFactory(const char *pFactoryClass) : CCustomWeaponEntityFactoryBase<Entity>(pFactoryClass)
|
||||
{}
|
||||
|
||||
virtual const void* ParseDataFromWeaponFile(KeyValues* pKV) const
|
||||
{
|
||||
Data* pData = new Data;
|
||||
if (pData && pData->Parse(pKV))
|
||||
return pData;
|
||||
|
||||
delete pData;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void ReleaseData(const void* pData) const
|
||||
{
|
||||
delete pData;
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_CUSTOM_WEAPON_FACTORY(factoryName, DLLClassName, DataStruct) \
|
||||
static CDefaultCustomWeaponEntityFactory<DLLClassName, DataStruct> custom_weapon_##factoryName##_factory( #factoryName );
|
||||
|
||||
#endif // !CUSTOM_WEAPON_FACTORY_H
|
1546
sp/src/game/server/mapbase/weapon_custom_hl2.cpp
Normal file
1546
sp/src/game/server/mapbase/weapon_custom_hl2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -447,7 +447,8 @@ void CGameText::SetText( const char* pszStr )
|
||||
|
||||
for (int i = 1; i < vecLines.Count(); i++)
|
||||
{
|
||||
Q_snprintf( szMsg, sizeof( szMsg ), "%s\n%s", szMsg, vecLines[i] );
|
||||
Q_strncat( szMsg, "\n", sizeof( szMsg ) );
|
||||
Q_strncat( szMsg, vecLines[i], sizeof( szMsg ) );
|
||||
}
|
||||
m_iszMessage = AllocPooledString( szMsg );
|
||||
}
|
||||
|
@ -1557,6 +1557,16 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con
|
||||
pRagdoll->CollisionProp()->SetCollisionBounds( mins, maxs );
|
||||
|
||||
#ifdef MAPBASE
|
||||
// If this was a NPC running a dynamic interaction, disable collisions with the interaction partner
|
||||
if (pAnimating->IsNPC() /*&& pAnimating->MyNPCPointer()->IsRunningDynamicInteraction()*/)
|
||||
{
|
||||
CAI_BaseNPC *pNPC = pAnimating->MyNPCPointer();
|
||||
if (pNPC->GetInteractionPartner() && pNPC->GetInteractionPartner()->VPhysicsGetObject())
|
||||
{
|
||||
PhysDisableEntityCollisions( pRagdoll, pNPC->GetInteractionPartner() );
|
||||
}
|
||||
}
|
||||
|
||||
variant_t variant;
|
||||
variant.SetEntity(pRagdoll);
|
||||
pAnimating->FireNamedOutput("OnServerRagdoll", variant, pRagdoll, pAnimating);
|
||||
|
@ -7021,7 +7021,7 @@ bool CBasePlayer::BumpWeapon( CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
//Weapon_EquipAmmoOnly( pWeapon );
|
||||
|
||||
// I'm too lazy to make my own version of Weapon_EquipAmmoOnly that doesn't check if we already have the weapon first
|
||||
// Weapon_EquipAmmoOnly checks the array again, which isn't necessary here
|
||||
int primaryGiven = (pWeapon->UsesClipsForAmmo1()) ? pWeapon->m_iClip1 : pWeapon->GetPrimaryAmmoCount();
|
||||
int secondaryGiven = (pWeapon->UsesClipsForAmmo2()) ? pWeapon->m_iClip2 : pWeapon->GetSecondaryAmmoCount();
|
||||
|
||||
@ -7734,6 +7734,93 @@ void CBasePlayer::ResetAutoaim( void )
|
||||
m_fOnTarget = false;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
ConVar player_debug_probable_aim_target( "player_debug_probable_aim_target", "0", FCVAR_CHEAT, "" );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CBasePlayer::GetProbableAimTarget( const Vector &vecSrc, const Vector &vecDir )
|
||||
{
|
||||
trace_t tr;
|
||||
CBaseEntity *pIgnore = NULL;
|
||||
if (IsInAVehicle())
|
||||
pIgnore = GetVehicleEntity();
|
||||
|
||||
CTraceFilterSkipTwoEntities traceFilter( this, pIgnore, COLLISION_GROUP_NONE );
|
||||
|
||||
// Based on dot product and distance
|
||||
// If we aim directly at something, only return it if there's not a larger entity slightly off-center
|
||||
// Should be weighted based on whether an entity is a NPC, etc.
|
||||
CBaseEntity *pBestEnt = NULL;
|
||||
float flBestWeight = 0.0f;
|
||||
for (CBaseEntity *pEntity = UTIL_EntitiesInPVS( this, NULL ); pEntity; pEntity = UTIL_EntitiesInPVS( this, pEntity ))
|
||||
{
|
||||
// Combat characters can be unviewable if they just died
|
||||
if (!pEntity->IsViewable() && !pEntity->IsCombatCharacter())
|
||||
continue;
|
||||
|
||||
if (pEntity == this || pEntity->GetMoveParent() == this || pEntity == GetVehicleEntity())
|
||||
continue;
|
||||
|
||||
Vector vecEntDir = (pEntity->EyePosition() - vecSrc);
|
||||
float flDot = DotProduct( vecEntDir.Normalized(), vecDir);
|
||||
|
||||
if (flDot < m_flFieldOfView)
|
||||
continue;
|
||||
|
||||
// Make sure we can see it
|
||||
UTIL_TraceLine( vecSrc, pEntity->EyePosition(), MASK_SHOT, &traceFilter, &tr );
|
||||
if (tr.m_pEnt != pEntity)
|
||||
{
|
||||
if (pEntity->IsCombatCharacter())
|
||||
{
|
||||
// Trace between centers as well just in case our eyes are blocked
|
||||
UTIL_TraceLine( WorldSpaceCenter(), pEntity->WorldSpaceCenter(), MASK_SHOT, &traceFilter, &tr );
|
||||
if (tr.m_pEnt != pEntity)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
float flWeight = flDot - (vecEntDir.LengthSqr() / Square( 2048.0f ));
|
||||
|
||||
if (pEntity->IsCombatCharacter())
|
||||
{
|
||||
// Hostile NPCs are more likely targets
|
||||
if (IRelationType( pEntity ) <= D_FR)
|
||||
flWeight += 0.5f;
|
||||
}
|
||||
else if (pEntity->GetFlags() & FL_AIMTARGET)
|
||||
{
|
||||
// FL_AIMTARGET is often used for props like explosive barrels
|
||||
flWeight += 0.25f;
|
||||
}
|
||||
|
||||
if (player_debug_probable_aim_target.GetBool())
|
||||
{
|
||||
float flWeightClamped = 1.0f - RemapValClamped( flWeight, -2.0f, 2.0f, 0.0f, 1.0f );
|
||||
pEntity->EntityText( 0, UTIL_VarArgs( "%f", flWeight ), 2.0f, flWeightClamped * 255.0f, 255.0f, flWeightClamped * 255.0f, 255 );
|
||||
}
|
||||
|
||||
if (flWeight > flBestWeight)
|
||||
{
|
||||
pBestEnt = pEntity;
|
||||
flBestWeight = flWeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (player_debug_probable_aim_target.GetBool())
|
||||
{
|
||||
Msg( "Best probable aim target is %s\n", pBestEnt->GetDebugName() );
|
||||
NDebugOverlay::EntityBounds( pBestEnt, 255, 100, 0, 0, 2.0f );
|
||||
}
|
||||
|
||||
return pBestEnt;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ==========================================================================
|
||||
// > Weapon stuff
|
||||
// ==========================================================================
|
||||
|
@ -608,6 +608,11 @@ public:
|
||||
virtual bool ShouldAutoaim( void );
|
||||
void SetTargetInfo( Vector &vecSrc, float flDist );
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Tries to figure out what the player is trying to aim at
|
||||
CBaseEntity *GetProbableAimTarget( const Vector &vecSrc, const Vector &vecDir );
|
||||
#endif
|
||||
|
||||
void SetViewEntity( CBaseEntity *pEntity );
|
||||
CBaseEntity *GetViewEntity( void ) { return m_hViewEntity; }
|
||||
|
||||
|
@ -393,7 +393,7 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper
|
||||
if ( weapon )
|
||||
{
|
||||
VPROF( "player->SelectItem()" );
|
||||
player->SelectItem( weapon->GetName(), ucmd->weaponsubtype );
|
||||
player->SelectItem( weapon->GetClassname(), ucmd->weaponsubtype );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6308,14 +6308,12 @@ void CPropDoorRotating::Break( CBaseEntity *pBreaker, const CTakeDamageInfo &inf
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MAPBASE
|
||||
void CPropDoorRotating::InputSetSpeed(inputdata_t &inputdata)
|
||||
{
|
||||
AssertMsg1(inputdata.value.Float() > 0.0f, "InputSetSpeed on %s called with negative parameter!", GetDebugName() );
|
||||
m_flSpeed = inputdata.value.Float();
|
||||
DoorResume();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Debug sphere
|
||||
class CPhysSphere : public CPhysicsProp
|
||||
@ -6362,15 +6360,6 @@ BEGIN_DATADESC( CPhysSphere )
|
||||
END_DATADESC()
|
||||
#endif
|
||||
|
||||
#ifndef MAPBASE // Yes, all I'm doing is moving this up a few lines and I'm still using the preprocessor.
|
||||
void CPropDoorRotating::InputSetSpeed(inputdata_t &inputdata)
|
||||
{
|
||||
AssertMsg1(inputdata.value.Float() > 0.0f, "InputSetSpeed on %s called with negative parameter!", GetDebugName() );
|
||||
m_flSpeed = inputdata.value.Float();
|
||||
DoorResume();
|
||||
}
|
||||
#endif
|
||||
|
||||
LINK_ENTITY_TO_CLASS( prop_sphere, CPhysSphere );
|
||||
|
||||
|
||||
|
@ -1396,11 +1396,31 @@ void CAI_ScriptedSequence::ModifyScriptedAutoMovement( Vector *vecNewPos )
|
||||
}
|
||||
}
|
||||
|
||||
VMatrix matInteractionPosition = m_matInteractionPosition;
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Account for our own sequence movement
|
||||
pAnimating = m_hTargetEnt->GetBaseAnimating();
|
||||
if (pAnimating)
|
||||
{
|
||||
Vector vecDeltaPos;
|
||||
QAngle angDeltaAngles;
|
||||
|
||||
pAnimating->GetSequenceMovement( pAnimating->GetSequence(), 0.0f, pAnimating->GetCycle(), vecDeltaPos, angDeltaAngles );
|
||||
if (!vecDeltaPos.IsZero())
|
||||
{
|
||||
VMatrix matLocalMovement;
|
||||
matLocalMovement.SetupMatrixOrgAngles( vecDeltaPos, angDeltaAngles );
|
||||
MatrixMultiply( m_matInteractionPosition, matLocalMovement, matInteractionPosition );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// We've been asked to maintain a specific position relative to the other NPC
|
||||
// we're interacting with. Lerp towards the relative position.
|
||||
VMatrix matMeToWorld, matLocalToWorld;
|
||||
matMeToWorld.SetupMatrixOrgAngles( vecRelativeOrigin, angRelativeAngles );
|
||||
MatrixMultiply( matMeToWorld, m_matInteractionPosition, matLocalToWorld );
|
||||
MatrixMultiply( matMeToWorld, matInteractionPosition, matLocalToWorld );
|
||||
|
||||
// Get the desired NPC position in worldspace
|
||||
Vector vecOrigin;
|
||||
|
@ -63,6 +63,8 @@ $Project
|
||||
$File "mapbase\ai_grenade.h"
|
||||
$File "mapbase\ai_monitor.cpp"
|
||||
$File "mapbase\ai_weaponmodifier.cpp"
|
||||
$File "mapbase\custom_weapon_factory.cpp"
|
||||
$File "mapbase\custom_weapon_factory.h"
|
||||
$File "mapbase\closecaption_entity.cpp"
|
||||
$File "mapbase\datadesc_mod.cpp"
|
||||
$File "mapbase\datadesc_mod.h"
|
||||
@ -86,6 +88,7 @@ $Project
|
||||
$File "mapbase\SystemConvarMod.h"
|
||||
$File "mapbase\variant_tools.h"
|
||||
$File "mapbase\vgui_text_display.cpp"
|
||||
$File "mapbase\weapon_custom_hl2.cpp"
|
||||
|
||||
$File "mapbase\logic_eventlistener.cpp"
|
||||
$File "mapbase\logic_register_activator.cpp"
|
||||
|
@ -96,7 +96,7 @@ public:
|
||||
bool PointIsWithin( const Vector &vecPoint );
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
bool ScriptPassesTriggerFilters( HSCRIPT hOther ) { return ToEnt(hOther) ? PassesTriggerFilters( ToEnt(hOther) ) : NULL; }
|
||||
bool ScriptPassesTriggerFilters( HSCRIPT hOther ) { return ToEnt(hOther) ? PassesTriggerFilters( ToEnt(hOther) ) : false; }
|
||||
HSCRIPT ScriptGetTouchedEntityOfType( const char *sClassName ) { return ToHScript( GetTouchedEntityOfType(sClassName) ); }
|
||||
|
||||
void ScriptGetTouchingEntities( HSCRIPT hTable );
|
||||
|
@ -76,6 +76,10 @@ public:
|
||||
virtual const char *GetCannonicalName( const char *pClassName );
|
||||
void ReportEntitySizes();
|
||||
|
||||
#ifdef MAPBASE
|
||||
virtual void UninstallFactory(const char* pClassName);
|
||||
#endif // MAPBASE
|
||||
|
||||
private:
|
||||
IEntityFactory *FindFactory( const char *pClassName );
|
||||
public:
|
||||
@ -203,6 +207,11 @@ void CEntityFactoryDictionary::ReportEntitySizes()
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
void CEntityFactoryDictionary::UninstallFactory(const char* pClassName)
|
||||
{
|
||||
m_Factories.Remove(pClassName);
|
||||
}
|
||||
|
||||
int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 )
|
||||
{
|
||||
CEntityFactoryDictionary *pFactoryDict = (CEntityFactoryDictionary*)EntityFactoryDictionary();
|
||||
|
@ -100,6 +100,9 @@ public:
|
||||
virtual void Destroy( const char *pClassName, IServerNetworkable *pNetworkable ) = 0;
|
||||
virtual IEntityFactory *FindFactory( const char *pClassName ) = 0;
|
||||
virtual const char *GetCannonicalName( const char *pClassName ) = 0;
|
||||
#ifdef MAPBASE
|
||||
virtual void UninstallFactory(const char* pClassName) = 0;
|
||||
#endif // MAPBASE
|
||||
};
|
||||
|
||||
IEntityFactoryDictionary *EntityFactoryDictionary();
|
||||
@ -188,8 +191,7 @@ extern CGlobalVars *gpGlobals;
|
||||
inline bool FStrEq(const char *sz1, const char *sz2)
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
// V_stricmp() already checks if the pointers are equal, so having a pointer comparison here is pointless.
|
||||
// I'm not sure if this was already automatically phased out by the compiler, but if it wasn't, then this is a very good change.
|
||||
// V_stricmp() already checks if the pointers are equal, so having a pointer comparison here is unnecessary.
|
||||
return ( V_stricmp(sz1, sz2) == 0 );
|
||||
#else
|
||||
return ( sz1 == sz2 || V_stricmp(sz1, sz2) == 0 );
|
||||
|
@ -606,10 +606,10 @@ bool VScriptServerInit()
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
// MULTIPLAYER
|
||||
// NOTE: 'PlayerInstanceFromIndex' and 'GetPlayerFromUserID' are used in L4D2 and Source 2,
|
||||
// but the GetPlayerBy* names are more consistent.
|
||||
// ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PlayerByIndex, "GetPlayerByIndex", "PlayerInstanceFromIndex" );
|
||||
// ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PlayerByUserId, "GetPlayerByUserId", "GetPlayerFromUserID" );
|
||||
// ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PlayerByName, "GetPlayerByName", "" );
|
||||
// ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGetPlayerByNetworkID, "GetPlayerByNetworkID", "" );
|
||||
// ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PlayerByUserId, "GetPlayerByUserID", "GetPlayerFromUserID" );
|
||||
|
||||
ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_ShowMessageAll, "ShowMessage", "Print a hud message on all clients" );
|
||||
#else
|
||||
@ -841,6 +841,8 @@ public:
|
||||
virtual void LevelShutdownPostEntity( void )
|
||||
{
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
g_ScriptEntityIterator.DisableEntityListening();
|
||||
|
||||
g_ScriptNetMsg->LevelShutdownPreVM();
|
||||
|
||||
GetScriptHookManager().OnShutdown();
|
||||
|
@ -239,7 +239,7 @@ const unsigned char *CBaseCombatWeapon::GetEncryptionKey( void )
|
||||
void CBaseCombatWeapon::Precache( void )
|
||||
{
|
||||
#if defined( CLIENT_DLL )
|
||||
Assert( Q_strlen( GetClassname() ) > 0 );
|
||||
Assert( Q_strlen(GetWeaponScriptName() ) > 0 );
|
||||
// Msg( "Client got %s\n", GetClassname() );
|
||||
#endif
|
||||
m_iPrimaryAmmoType = m_iSecondaryAmmoType = -1;
|
||||
@ -321,7 +321,7 @@ void CBaseCombatWeapon::Precache( void )
|
||||
else
|
||||
{
|
||||
// Couldn't read data file, remove myself
|
||||
Warning( "Error reading weapon data file for: %s\n", GetClassname() );
|
||||
Warning( "Error reading weapon data file for: %s\n", GetWeaponScriptName() );
|
||||
// Remove( ); //don't remove, this gets released soon!
|
||||
}
|
||||
}
|
||||
@ -2886,6 +2886,15 @@ bool CBaseCombatWeapon::IsLocked( CBaseEntity *pAsker )
|
||||
return ( m_flUnlockTime > gpGlobals->curtime && m_hLocker != pAsker );
|
||||
}
|
||||
|
||||
bool CBaseCombatWeapon::CanBePickedUpByNPCs(void)
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
return GetWpnData().m_nWeaponRestriction != WPNRESTRICT_PLAYER_ONLY;
|
||||
#else
|
||||
return true;
|
||||
#endif // MAPBASE
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input :
|
||||
|
@ -390,7 +390,7 @@ public:
|
||||
bool IsLocked( CBaseEntity *pAsker );
|
||||
|
||||
//All weapons can be picked up by NPCs by default
|
||||
virtual bool CanBePickedUpByNPCs( void ) { return true; }
|
||||
virtual bool CanBePickedUpByNPCs(void);
|
||||
|
||||
virtual int GetSkinOverride() const { return -1; }
|
||||
|
||||
|
@ -83,6 +83,10 @@ ConVar ai_shot_bias_min( "ai_shot_bias_min", "-1.0", FCVAR_REPLICATED );
|
||||
ConVar ai_shot_bias_max( "ai_shot_bias_max", "1.0", FCVAR_REPLICATED );
|
||||
ConVar ai_debug_shoot_positions( "ai_debug_shoot_positions", "0", FCVAR_REPLICATED | FCVAR_CHEAT );
|
||||
|
||||
#if defined(MAPBASE) && defined(GAME_DLL)
|
||||
ConVar ai_shot_notify_targets( "ai_shot_notify_targets", "0", FCVAR_NONE, "Allows fired bullets to notify the NPCs and players they are targeting, regardless of whether they hit them or not. Can be used for custom AI and speech." );
|
||||
#endif
|
||||
|
||||
// Utility func to throttle rate at which the "reasonable position" spew goes out
|
||||
static double s_LastEntityReasonableEmitTime;
|
||||
bool CheckEmitReasonablePhysicsSpew()
|
||||
@ -2081,6 +2085,25 @@ void CBaseEntity::FireBullets( const FireBulletsInfo_t &info )
|
||||
CTakeDamageInfo dmgInfo( this, pAttacker, flCumulativeDamage, nDamageType );
|
||||
gamestats->Event_WeaponHit( pPlayer, info.m_bPrimaryAttack, pPlayer->GetActiveWeapon()->GetClassname(), dmgInfo );
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
if ( ai_shot_notify_targets.GetBool() )
|
||||
{
|
||||
if ( IsPlayer() )
|
||||
{
|
||||
// Look for probable target to notify of attack
|
||||
CBaseEntity *pAimTarget = static_cast<CBasePlayer*>(this)->GetProbableAimTarget( info.m_vecSrc, info.m_vecDirShooting );
|
||||
if ( pAimTarget && pAimTarget->IsCombatCharacter() )
|
||||
{
|
||||
pAimTarget->MyCombatCharacterPointer()->OnEnemyRangeAttackedMe( this, vecDir, vecEnd );
|
||||
}
|
||||
}
|
||||
else if ( GetEnemy() && GetEnemy()->IsCombatCharacter() )
|
||||
{
|
||||
GetEnemy()->MyCombatCharacterPointer()->OnEnemyRangeAttackedMe( this, vecDir, vecEnd );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2736,6 +2759,18 @@ void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner)
|
||||
SetOwnerEntity(ToEnt(pOwner));
|
||||
}
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
HSCRIPT CBaseEntity::ScriptGetGroundEntity()
|
||||
{
|
||||
return ToHScript( m_hGroundEntity.Get() );
|
||||
}
|
||||
|
||||
void CBaseEntity::ScriptSetGroundEntity( HSCRIPT hGroundEnt )
|
||||
{
|
||||
SetGroundEntity( ToEnt( hGroundEnt ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
const Vector& CBaseEntity::ScriptGetColorVector()
|
||||
|
@ -233,6 +233,11 @@ void EventList_RegisterSharedEvents( void )
|
||||
REGISTER_SHARED_ANIMEVENT( AE_SV_DUSTTRAIL, AE_TYPE_SERVER );
|
||||
|
||||
REGISTER_SHARED_ANIMEVENT( AE_CL_CREATE_PARTICLE_EFFECT, AE_TYPE_CLIENT );
|
||||
#ifdef MAPBASE // From Alien Swarm SDK
|
||||
REGISTER_SHARED_ANIMEVENT( AE_CL_STOP_PARTICLE_EFFECT, AE_TYPE_CLIENT );
|
||||
REGISTER_SHARED_ANIMEVENT( AE_CL_ADD_PARTICLE_EFFECT_CP, AE_TYPE_CLIENT );
|
||||
//REGISTER_SHARED_ANIMEVENT( AE_CL_CREATE_PARTICLE_BRASS, AE_TYPE_CLIENT );
|
||||
#endif
|
||||
|
||||
REGISTER_SHARED_ANIMEVENT( AE_RAGDOLL, AE_TYPE_SERVER );
|
||||
|
||||
@ -252,5 +257,8 @@ void EventList_RegisterSharedEvents( void )
|
||||
#ifdef MAPBASE
|
||||
REGISTER_SHARED_ANIMEVENT( AE_NPC_RESPONSE, AE_TYPE_SERVER );
|
||||
REGISTER_SHARED_ANIMEVENT( AE_NPC_RESPONSE_FORCED, AE_TYPE_SERVER );
|
||||
|
||||
REGISTER_SHARED_ANIMEVENT( AE_VSCRIPT_RUN, AE_TYPE_CLIENT | AE_TYPE_SERVER );
|
||||
REGISTER_SHARED_ANIMEVENT( AE_VSCRIPT_RUN_FILE, AE_TYPE_CLIENT | AE_TYPE_SERVER );
|
||||
#endif
|
||||
}
|
@ -69,6 +69,11 @@ typedef enum
|
||||
AE_SV_DUSTTRAIL,
|
||||
|
||||
AE_CL_CREATE_PARTICLE_EFFECT,
|
||||
#ifdef MAPBASE // From Alien Swarm SDK
|
||||
AE_CL_STOP_PARTICLE_EFFECT,
|
||||
AE_CL_ADD_PARTICLE_EFFECT_CP,
|
||||
//AE_CL_CREATE_PARTICLE_BRASS,
|
||||
#endif
|
||||
|
||||
AE_RAGDOLL,
|
||||
|
||||
@ -88,6 +93,9 @@ typedef enum
|
||||
#ifdef MAPBASE
|
||||
AE_NPC_RESPONSE, // Play a response system concept if we're not speaking
|
||||
AE_NPC_RESPONSE_FORCED, // Always play a response system concept
|
||||
|
||||
AE_VSCRIPT_RUN, // Run vscript code (server + client)
|
||||
AE_VSCRIPT_RUN_FILE, // Run vscript file (server + client)
|
||||
#endif
|
||||
|
||||
LAST_SHARED_ANIMEVENT,
|
||||
|
@ -208,7 +208,7 @@ void CWeaponAR2::DelayedAttack( void )
|
||||
|
||||
// pOwner->SnapEyeAngles( angles );
|
||||
|
||||
pOwner->ViewPunch( QAngle( SharedRandomInt( "ar2pax", -8, -12 ), SharedRandomInt( "ar2pay", 1, 2 ), 0 ) );
|
||||
pOwner->ViewPunch( QAngle( SharedRandomInt( "ar2pax", -12, -8 ), SharedRandomInt( "ar2pay", 1, 2 ), 0 ) );
|
||||
|
||||
// Decrease ammo
|
||||
pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
|
||||
|
@ -70,7 +70,7 @@ ConVar mapbase_version_client( "mapbase_version_client", MAPBASE_VERSION, FCVAR_
|
||||
// This is from the vgui_controls library
|
||||
extern vgui::HScheme g_iCustomClientSchemeOverride;
|
||||
|
||||
bool g_bUsingCustomHudAnimations = false;
|
||||
extern bool g_bUsingCustomHudAnimations;
|
||||
bool g_bUsingCustomHudLayout = false;
|
||||
#endif
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "filesystem.h"
|
||||
#include "igameevents.h"
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
#include "icommandline.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "IEffects.h"
|
||||
@ -1094,7 +1095,7 @@ const char *CScriptReadWriteFile::FileRead( const char *szFile )
|
||||
char pszFullName[MAX_PATH];
|
||||
V_snprintf( pszFullName, sizeof(pszFullName), SCRIPT_RW_FULL_PATH_FMT, szFile );
|
||||
|
||||
if ( !V_RemoveDotSlashes( pszFullName, CORRECT_PATH_SEPARATOR, true ) )
|
||||
if ( !CommandLine()->FindParm( "-script_dotslash_read" ) && !V_RemoveDotSlashes( pszFullName, CORRECT_PATH_SEPARATOR, true ) )
|
||||
{
|
||||
DevWarning( 2, "Invalid file location : %s\n", szFile );
|
||||
return NULL;
|
||||
@ -1143,7 +1144,7 @@ bool CScriptReadWriteFile::FileExists( const char *szFile )
|
||||
char pszFullName[MAX_PATH];
|
||||
V_snprintf( pszFullName, sizeof(pszFullName), SCRIPT_RW_FULL_PATH_FMT, szFile );
|
||||
|
||||
if ( !V_RemoveDotSlashes( pszFullName, CORRECT_PATH_SEPARATOR, true ) )
|
||||
if ( !CommandLine()->FindParm( "-script_dotslash_read" ) && !V_RemoveDotSlashes( pszFullName, CORRECT_PATH_SEPARATOR, true ) )
|
||||
{
|
||||
DevWarning( 2, "Invalid file location : %s\n", szFile );
|
||||
return NULL;
|
||||
@ -1224,7 +1225,7 @@ HSCRIPT CScriptReadWriteFile::KeyValuesRead( const char *szFile )
|
||||
char pszFullName[MAX_PATH];
|
||||
V_snprintf( pszFullName, sizeof(pszFullName), SCRIPT_RW_FULL_PATH_FMT, szFile );
|
||||
|
||||
if ( !V_RemoveDotSlashes( pszFullName, CORRECT_PATH_SEPARATOR, true ) )
|
||||
if ( !CommandLine()->FindParm( "-script_dotslash_read" ) && !V_RemoveDotSlashes( pszFullName, CORRECT_PATH_SEPARATOR, true ) )
|
||||
{
|
||||
DevWarning( 2, "Invalid file location : %s\n", szFile );
|
||||
return NULL;
|
||||
@ -1338,8 +1339,7 @@ static const char *HasNetMsgCollision( int hash, const char *ignore )
|
||||
|
||||
inline int CNetMsgScriptHelper::Hash( const char *key )
|
||||
{
|
||||
int hash = HashStringCaseless( key );
|
||||
Assert( hash < (1 << SCRIPT_NETMSG_HEADER_BITS) );
|
||||
int hash = CaselessStringHashFunctor()( key );
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -1445,7 +1445,7 @@ void CNetMsgScriptHelper::ReceiveMessage( bf_read &msg )
|
||||
while ( count-- )
|
||||
#endif
|
||||
{
|
||||
int hash = m_MsgIn_()ReadWord();
|
||||
int hash = m_MsgIn_()ReadUBitLong( SCRIPT_NETMSG_HEADER_BITS );
|
||||
|
||||
#ifdef _DEBUG
|
||||
const char *msgName = GetNetMsgName( hash );
|
||||
@ -1514,7 +1514,7 @@ void CNetMsgScriptHelper::Start( const char *msg )
|
||||
Reset();
|
||||
#endif
|
||||
|
||||
m_MsgOut.WriteWord( Hash( msg ) );
|
||||
m_MsgOut.WriteUBitLong( Hash( msg ), SCRIPT_NETMSG_HEADER_BITS );
|
||||
}
|
||||
|
||||
#ifdef GAME_DLL
|
||||
@ -1923,7 +1923,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N
|
||||
DEFINE_SCRIPTFUNC( Receive, "Set custom network message callback" )
|
||||
DEFINE_SCRIPTFUNC_NAMED( Receive, "Recieve", SCRIPT_HIDE ) // This was a typo until v6.3
|
||||
#ifdef GAME_DLL
|
||||
DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the server to the client (max 252 bytes)" )
|
||||
DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the server to the client (max 251 bytes)" )
|
||||
#else
|
||||
DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the client to the server (max 2044 bytes)" )
|
||||
#endif
|
||||
@ -2742,6 +2742,11 @@ public:
|
||||
|
||||
void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const char *helpString, int flags )
|
||||
{
|
||||
#if CLIENT_DLL
|
||||
// FIXME: This crashes in engine when used as a hook (dispatched from CScriptConCommand::CommandCallback())
|
||||
Assert( V_stricmp( name, "load" ) != 0 );
|
||||
#endif
|
||||
|
||||
unsigned int hash = Hash(name);
|
||||
int idx = g_ScriptConCommands.Find(hash);
|
||||
if ( idx == g_ScriptConCommands.InvalidIndex() )
|
||||
|
@ -24,7 +24,7 @@ void RegisterScriptSingletons();
|
||||
#endif
|
||||
|
||||
#define SCRIPT_NETMSG_QUEUE_BITS 3 // determines the number of custom messages client can write to a usercmd
|
||||
#define SCRIPT_NETMSG_HEADER_BITS (sizeof(word) << 3)
|
||||
#define SCRIPT_NETMSG_HEADER_BITS (sizeof(unsigned int) << 3)
|
||||
#define SCRIPT_NETMSG_STRING_SIZE 512
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "cbase.h"
|
||||
#include "tier1/fmtstr.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "weapon_custom_scripted.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
@ -179,7 +180,7 @@ bool CWeaponCustomScripted::RunWeaponHook( ScriptHook_t &hook, HSCRIPT &cached,
|
||||
{
|
||||
if ( !cached )
|
||||
{
|
||||
if ( hook.CanRunInScope( m_ScriptScope ) )
|
||||
if ( m_ScriptScope.IsInitialized() && hook.CanRunInScope( m_ScriptScope ) )
|
||||
{
|
||||
cached = hook.m_hFunc;
|
||||
}
|
||||
@ -187,6 +188,7 @@ bool CWeaponCustomScripted::RunWeaponHook( ScriptHook_t &hook, HSCRIPT &cached,
|
||||
|
||||
if (cached)
|
||||
{
|
||||
hook.m_hFunc = cached;
|
||||
return hook.Call( m_ScriptScope, retVal, pArgs, false );
|
||||
}
|
||||
|
||||
@ -198,13 +200,6 @@ bool CWeaponCustomScripted::RunWeaponHook( ScriptHook_t &hook, HSCRIPT &cached,
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWeaponCustomScripted::Spawn( void )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
if (m_iszClientScripts[0] != '\0' && ValidateScriptScope())
|
||||
{
|
||||
RunScriptFile( m_iszClientScripts );
|
||||
}
|
||||
#endif
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
@ -334,7 +329,7 @@ void CWeaponCustomScripted::ItemPreFrame( void )
|
||||
{
|
||||
SIMPLE_VOID_OVERRIDE( ItemPreFrame, NULL );
|
||||
|
||||
BaseClass::ItemPostFrame();
|
||||
BaseClass::ItemPreFrame();
|
||||
}
|
||||
|
||||
void CWeaponCustomScripted::ItemPostFrame( void )
|
||||
@ -432,7 +427,7 @@ void CWeaponCustomScripted::SecondaryAttack( void )
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
#define ACTIVITY_FUNC_OVERRIDE( name ) ScriptVariant_t retVal; \
|
||||
if (RunWeaponHook( g_Hook_##name, m_Func_##name, &retVal ) && retVal.m_bool == false) \
|
||||
if (RunWeaponHook( g_Hook_##name, m_Func_##name, &retVal ) && !retVal.IsNull()) \
|
||||
{ \
|
||||
if (retVal.m_type == FIELD_INTEGER) \
|
||||
{ \
|
||||
@ -586,6 +581,36 @@ int CWeaponCustomScripted::WeaponMeleeAttack2Condition( float flDot, float flDis
|
||||
|
||||
return BaseClass::WeaponMeleeAttack2Condition( flDot, flDist );
|
||||
}
|
||||
|
||||
struct VScriptWeaponCustomData_s
|
||||
{
|
||||
char cScripts[256];
|
||||
|
||||
bool Parse(KeyValues* pKVWeapon)
|
||||
{
|
||||
Q_strncpy(cScripts, pKVWeapon->GetString("vscript_file"), 256);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
DEFINE_CUSTOM_WEAPON_FACTORY(vscript, CWeaponCustomScripted, VScriptWeaponCustomData_s);
|
||||
void CWeaponCustomScripted::InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript)
|
||||
{
|
||||
Q_FileBase(pszWeaponScript, m_iszWeaponScriptName.GetForModify(), 256);
|
||||
Q_strncpy(m_iszClientScripts.GetForModify(), static_cast<const VScriptWeaponCustomData_s *> (pData)->cScripts, 256);
|
||||
}
|
||||
|
||||
extern ConVar sv_script_think_interval;
|
||||
#else
|
||||
void CWeaponCustomScripted::OnDataChanged(DataUpdateType_t type)
|
||||
{
|
||||
BaseClass::OnDataChanged(type);
|
||||
|
||||
if (!m_ScriptScope.IsInitialized())
|
||||
{
|
||||
RunVScripts();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -604,3 +629,96 @@ int CWeaponCustomScripted::ActivityListCount( void )
|
||||
|
||||
return BaseClass::ActivityListCount();
|
||||
}
|
||||
|
||||
void CWeaponCustomScripted::RunVScripts()
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
if (m_iszClientScripts[0] != '\0' && ValidateScriptScope())
|
||||
{
|
||||
RunScriptFile(m_iszClientScripts);
|
||||
}
|
||||
#else
|
||||
if (m_iszVScripts == NULL_STRING && m_iszClientScripts[0] == '\0')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
if (g_pScriptVM == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ValidateScriptScope();
|
||||
|
||||
// All functions we want to have call chained instead of overwritten
|
||||
// by other scripts in this entities list.
|
||||
static const char* sCallChainFunctions[] =
|
||||
{
|
||||
"OnPostSpawn",
|
||||
"Precache"
|
||||
};
|
||||
|
||||
ScriptLanguage_t language = g_pScriptVM->GetLanguage();
|
||||
|
||||
// Make a call chainer for each in this entities scope
|
||||
for (int j = 0; j < ARRAYSIZE(sCallChainFunctions); ++j)
|
||||
{
|
||||
|
||||
if (language == SL_PYTHON)
|
||||
{
|
||||
// UNDONE - handle call chaining in python
|
||||
;
|
||||
}
|
||||
else if (language == SL_SQUIRREL)
|
||||
{
|
||||
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter
|
||||
HSCRIPT hCreateChainScript = g_pScriptVM->CompileScript(CFmtStr("%sCallChain <- CSimpleCallChainer(\"%s\", self.GetScriptScope(), true)", sCallChainFunctions[j], sCallChainFunctions[j]));
|
||||
g_pScriptVM->Run(hCreateChainScript, (HSCRIPT)m_ScriptScope);
|
||||
}
|
||||
}
|
||||
|
||||
CUtlStringList szScripts;
|
||||
if (m_iszVScripts != NULL_STRING)
|
||||
{
|
||||
V_SplitString(STRING(m_iszVScripts), " ", szScripts);
|
||||
}
|
||||
|
||||
if (m_iszClientScripts[0] != '\0')
|
||||
{
|
||||
szScripts.AddToHead(strdup(m_iszClientScripts.Get()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < szScripts.Count(); i++)
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
CGMsg(0, CON_GROUP_VSCRIPT, "%s executing script: %s\n", GetDebugName(), szScripts[i]);
|
||||
#else
|
||||
Log("%s executing script: %s\n", GetDebugName(), szScripts[i]);
|
||||
#endif
|
||||
|
||||
RunScriptFile(szScripts[i], IsWorld());
|
||||
|
||||
for (int j = 0; j < ARRAYSIZE(sCallChainFunctions); ++j)
|
||||
{
|
||||
if (language == SL_PYTHON)
|
||||
{
|
||||
// UNDONE - handle call chaining in python
|
||||
;
|
||||
}
|
||||
else if (language == SL_SQUIRREL)
|
||||
{
|
||||
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter.
|
||||
HSCRIPT hRunPostScriptExecute = g_pScriptVM->CompileScript(CFmtStr("%sCallChain.PostScriptExecute()", sCallChainFunctions[j]));
|
||||
g_pScriptVM->Run(hRunPostScriptExecute, (HSCRIPT)m_ScriptScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_iszScriptThinkFunction != NULL_STRING)
|
||||
{
|
||||
SetContextThink(&CBaseEntity::ScriptThink, gpGlobals->curtime + sv_script_think_interval.GetFloat(), "ScriptThink");
|
||||
}
|
||||
#endif
|
||||
}
|
@ -14,6 +14,8 @@
|
||||
#include "basecombatweapon_shared.h"
|
||||
#ifdef CLIENT_DLL
|
||||
#include "vscript_client.h"
|
||||
#else
|
||||
#include "mapbase/custom_weapon_factory.h"
|
||||
#endif
|
||||
|
||||
// The base class of the scripted weapon is game-specific.
|
||||
@ -32,6 +34,9 @@
|
||||
HSCRIPT m_Func_##name;
|
||||
|
||||
class CWeaponCustomScripted : public SCRIPTED_WEAPON_DERIVED_FROM
|
||||
#ifndef CLIENT_DLL
|
||||
, public ICustomWeapon
|
||||
#endif // !CLIENT_DLL
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponCustomScripted, SCRIPTED_WEAPON_DERIVED_FROM );
|
||||
@ -45,6 +50,8 @@ public:
|
||||
bool KeyValue( const char *szKeyName, const char *szValue );
|
||||
bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen );
|
||||
|
||||
void RunVScripts();
|
||||
|
||||
// Base script has a function for this
|
||||
//void Precache( void );
|
||||
|
||||
@ -106,6 +113,11 @@ public:
|
||||
int WeaponRangeAttack2Condition( float flDot, float flDist );
|
||||
int WeaponMeleeAttack1Condition( float flDot, float flDist );
|
||||
int WeaponMeleeAttack2Condition( float flDot, float flDist );
|
||||
|
||||
// Inherited via ICustomWeapon
|
||||
virtual void InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript);
|
||||
#else
|
||||
void OnDataChanged(DataUpdateType_t type);
|
||||
#endif
|
||||
|
||||
ALLOW_SCRIPT_ACCESS();
|
||||
|
@ -453,8 +453,7 @@ void RunAddonScripts()
|
||||
|
||||
// mapspawn_addon
|
||||
char fullpath[MAX_PATH];
|
||||
Q_snprintf( fullpath, sizeof( fullpath ), "%sscripts/vscripts/mapspawn_addon", path );
|
||||
Q_FixSlashes( fullpath );
|
||||
Q_ComposeFileName( path, "scripts/vscripts/mapspawn_addon", fullpath, sizeof( fullpath ) );
|
||||
|
||||
VScriptRunScriptAbsolute( fullpath, NULL, false, folderName );
|
||||
}
|
||||
|
@ -408,6 +408,7 @@ FileWeaponInfo_t::FileWeaponInfo_t()
|
||||
m_flSwaySpeedScale = 1.0f;
|
||||
szDroppedModel[0] = 0;
|
||||
m_bUsesHands = false;
|
||||
m_nWeaponRestriction = WPNRESTRICT_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -415,6 +416,14 @@ FileWeaponInfo_t::FileWeaponInfo_t()
|
||||
extern ConVar hud_fastswitch;
|
||||
#endif
|
||||
|
||||
#ifdef MAPBASE
|
||||
const char* pWeaponRestrictions[NUM_WEAPON_RESTRICTION_TYPES] = {
|
||||
"none",
|
||||
"player_only",
|
||||
"npc_only",
|
||||
};
|
||||
#endif // MAPBASE
|
||||
|
||||
void FileWeaponInfo_t::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
|
||||
{
|
||||
// Okay, we tried at least once to look this up...
|
||||
@ -483,6 +492,19 @@ void FileWeaponInfo_t::Parse( KeyValues *pKeyValuesData, const char *szWeaponNam
|
||||
Q_strncpy( szDroppedModel, pKeyValuesData->GetString( "droppedmodel" ), MAX_WEAPON_STRING );
|
||||
|
||||
m_bUsesHands = ( pKeyValuesData->GetInt( "uses_hands", 0 ) != 0 ) ? true : false;
|
||||
|
||||
const char* pszRestrictString = pKeyValuesData->GetString("usage_restriction", nullptr);
|
||||
if (pszRestrictString)
|
||||
{
|
||||
for (int i = 0; i < NUM_WEAPON_RESTRICTION_TYPES; i++)
|
||||
{
|
||||
if (V_stricmp(pszRestrictString, pWeaponRestrictions[i]) == 0)
|
||||
{
|
||||
m_nWeaponRestriction = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MAPBASE // Mapbase makes weapons in the same slot & position swap each other out, which is a feature mods can intentionally use.
|
||||
|
@ -58,6 +58,17 @@ int GetWeaponSoundFromString( const char *pszString );
|
||||
class CHudTexture;
|
||||
class KeyValues;
|
||||
|
||||
#ifdef MAPBASE
|
||||
enum WeaponUsageRestricions_e
|
||||
{
|
||||
WPNRESTRICT_NONE = 0,
|
||||
WPNRESTRICT_PLAYER_ONLY,
|
||||
WPNRESTRICT_NPCS_ONLY,
|
||||
|
||||
NUM_WEAPON_RESTRICTION_TYPES
|
||||
};
|
||||
#endif // MAPBASE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Contains the data read from the weapon's script file.
|
||||
// It's cached so we only read each weapon's script file once.
|
||||
@ -125,6 +136,8 @@ public:
|
||||
char szDroppedModel[MAX_WEAPON_STRING]; // Model of this weapon when dropped on the ground
|
||||
|
||||
bool m_bUsesHands;
|
||||
|
||||
int m_nWeaponRestriction;
|
||||
#endif
|
||||
|
||||
// CLIENT DLL
|
||||
|
@ -102,8 +102,22 @@ enum soundlevel_t
|
||||
#define MAX_SNDLVL_VALUE ((1<<MAX_SNDLVL_BITS)-1)
|
||||
|
||||
|
||||
#define ATTN_TO_SNDLVL( a ) (soundlevel_t)(int)((a) ? (50 + 20 / ((float)a)) : 0 )
|
||||
#define SNDLVL_TO_ATTN( a ) ((a > 50) ? (20.0f / (float)(a - 50)) : 4.0 )
|
||||
inline soundlevel_t ATTN_TO_SNDLVL(float a)
|
||||
{
|
||||
soundlevel_t sndlvl = soundlevel_t::SNDLVL_NONE;
|
||||
|
||||
if (a >= 0.0f)
|
||||
{
|
||||
sndlvl = soundlevel_t(float(soundlevel_t::SNDLVL_50dB) + float(soundlevel_t::SNDLVL_20dB) / a);
|
||||
}
|
||||
|
||||
return sndlvl;
|
||||
}
|
||||
|
||||
inline float SNDLVL_TO_ATTN(soundlevel_t s)
|
||||
{
|
||||
return (s > soundlevel_t::SNDLVL_50dB)? (20.0f / float(s - soundlevel_t::SNDLVL_50dB)) : 4.0f;
|
||||
}
|
||||
|
||||
// This is a limit due to network encoding.
|
||||
// It encodes attenuation * 64 in 8 bits, so the maximum is (255 / 64)
|
||||
|
@ -1281,8 +1281,8 @@ PLATFORM_INTERFACE bool Is64BitOS();
|
||||
//-----------------------------------------------------------------------------
|
||||
// General Mapbase version constants compiled into projects for versioning purposes
|
||||
//-----------------------------------------------------------------------------
|
||||
#define MAPBASE_VERSION "7.1"
|
||||
#define MAPBASE_VER_INT 7100 // For use in #if in a similar fashion to macros like _MSC_VER
|
||||
#define MAPBASE_VERSION "7.2"
|
||||
#define MAPBASE_VER_INT 7200 // For use in #if in a similar fashion to macros like _MSC_VER
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -61,7 +61,11 @@ public:
|
||||
int GetNumFrames();
|
||||
void SetFrame( int nFrame );
|
||||
|
||||
#ifdef MAPBASE
|
||||
void SetRotation( int iRotation );
|
||||
#else
|
||||
void SetRotation( int iRotation ) { m_iRotation = iRotation; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void PaintBackground();
|
||||
|
@ -33,7 +33,7 @@ static CUtlSymbolTable g_ScriptSymbols(0, 128, true);
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Allows animation sequences to be overridden by map-specific files
|
||||
extern bool g_bUsingCustomHudAnimations;
|
||||
bool g_bUsingCustomHudAnimations = false;
|
||||
#endif
|
||||
|
||||
// singleton accessor for animation controller for use by the vgui controls
|
||||
|
@ -73,6 +73,13 @@ void ImagePanel::OnSizeChanged(int newWide, int newTall)
|
||||
//-----------------------------------------------------------------------------
|
||||
void ImagePanel::SetImage(IImage *image)
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if ( image )
|
||||
{
|
||||
image->SetRotation( m_iRotation );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_pImage = image;
|
||||
Repaint();
|
||||
}
|
||||
@ -471,3 +478,15 @@ void ImagePanel::SetFrame( int nFrame )
|
||||
|
||||
return m_pImage->SetFrame( nFrame );
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
void ImagePanel::SetRotation( int iRotation )
|
||||
{
|
||||
m_iRotation = iRotation;
|
||||
|
||||
if ( m_pImage )
|
||||
{
|
||||
m_pImage->SetRotation( m_iRotation );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -206,19 +206,28 @@ void CScriptKeyValues::ScriptReleaseKeyValues( )
|
||||
m_pKeyValues = NULL;
|
||||
}
|
||||
|
||||
void CScriptKeyValues::TableToSubKeys( HSCRIPT hTable )
|
||||
void KeyValues_TableToSubKeys( HSCRIPT hTable, KeyValues *pKV )
|
||||
{
|
||||
int nIterator = -1;
|
||||
ScriptVariant_t varKey, varValue;
|
||||
while ((nIterator = g_pScriptVM->GetKeyValue( hTable, nIterator, &varKey, &varValue )) != -1)
|
||||
{
|
||||
switch (varValue.m_type)
|
||||
if ( varKey.m_type == FIELD_CSTRING )
|
||||
{
|
||||
case FIELD_CSTRING: m_pKeyValues->SetString( varKey.m_pszString, varValue.m_pszString ); break;
|
||||
case FIELD_INTEGER: m_pKeyValues->SetInt( varKey.m_pszString, varValue.m_int ); break;
|
||||
case FIELD_FLOAT: m_pKeyValues->SetFloat( varKey.m_pszString, varValue.m_float ); break;
|
||||
case FIELD_BOOLEAN: m_pKeyValues->SetBool( varKey.m_pszString, varValue.m_bool ); break;
|
||||
case FIELD_VECTOR: m_pKeyValues->SetString( varKey.m_pszString, CFmtStr( "%f %f %f", varValue.m_pVector->x, varValue.m_pVector->y, varValue.m_pVector->z ) ); break;
|
||||
switch ( varValue.m_type )
|
||||
{
|
||||
case FIELD_CSTRING: pKV->SetString( varKey.m_pszString, varValue.m_pszString ); break;
|
||||
case FIELD_INTEGER: pKV->SetInt( varKey.m_pszString, varValue.m_int ); break;
|
||||
case FIELD_FLOAT: pKV->SetFloat( varKey.m_pszString, varValue.m_float ); break;
|
||||
case FIELD_BOOLEAN: pKV->SetBool( varKey.m_pszString, varValue.m_bool ); break;
|
||||
case FIELD_VECTOR: pKV->SetString( varKey.m_pszString, CFmtStr( "%f %f %f", varValue.m_pVector->x, varValue.m_pVector->y, varValue.m_pVector->z ) ); break;
|
||||
case FIELD_HSCRIPT:
|
||||
{
|
||||
KeyValues *subKey = pKV->FindKey( varKey.m_pszString, true );
|
||||
KeyValues_TableToSubKeys( varValue, subKey );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_pScriptVM->ReleaseValue( varKey );
|
||||
@ -226,19 +235,38 @@ void CScriptKeyValues::TableToSubKeys( HSCRIPT hTable )
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptKeyValues::SubKeysToTable( HSCRIPT hTable )
|
||||
void KeyValues_SubKeysToTable( KeyValues *pKV, HSCRIPT hTable )
|
||||
{
|
||||
FOR_EACH_SUBKEY( m_pKeyValues, key )
|
||||
FOR_EACH_SUBKEY( pKV, key )
|
||||
{
|
||||
switch ( key->GetDataType() )
|
||||
{
|
||||
case KeyValues::TYPE_STRING: g_pScriptVM->SetValue( hTable, key->GetName(), key->GetString() ); break;
|
||||
case KeyValues::TYPE_INT: g_pScriptVM->SetValue( hTable, key->GetName(), key->GetInt() ); break;
|
||||
case KeyValues::TYPE_FLOAT: g_pScriptVM->SetValue( hTable, key->GetName(), key->GetFloat() ); break;
|
||||
case KeyValues::TYPE_NONE:
|
||||
{
|
||||
ScriptVariant_t subTable;
|
||||
g_pScriptVM->CreateTable( subTable );
|
||||
g_pScriptVM->SetValue( hTable, key->GetName(), subTable );
|
||||
KeyValues_SubKeysToTable( key, subTable );
|
||||
g_pScriptVM->ReleaseValue( subTable );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptKeyValues::TableToSubKeys( HSCRIPT hTable )
|
||||
{
|
||||
KeyValues_TableToSubKeys( hTable, m_pKeyValues );
|
||||
}
|
||||
|
||||
void CScriptKeyValues::SubKeysToTable( HSCRIPT hTable )
|
||||
{
|
||||
KeyValues_SubKeysToTable( m_pKeyValues, hTable );
|
||||
}
|
||||
|
||||
HSCRIPT CScriptKeyValues::ScriptFindOrCreateKey( const char *pszName )
|
||||
{
|
||||
KeyValues *pKeyValues = m_pKeyValues->FindKey(pszName, true);
|
||||
|
@ -118,15 +118,14 @@ class CSimpleCallChainer
|
||||
|
||||
function PostScriptExecute()
|
||||
{
|
||||
local func;
|
||||
try {
|
||||
func = scope[prefix];
|
||||
} catch(e) {
|
||||
return;
|
||||
if ( prefix in scope )
|
||||
{
|
||||
local func = scope[prefix];
|
||||
if ( typeof func == "function" )
|
||||
{
|
||||
chain.push(func);
|
||||
}
|
||||
}
|
||||
if (typeof(func) != "function")
|
||||
return;
|
||||
chain.push(func);
|
||||
}
|
||||
|
||||
function Call()
|
||||
@ -569,4 +568,4 @@ if (developer)
|
||||
__Documentation.RegisterHelp( "Lerp", "float Lerp(float, float, float)", "" );
|
||||
__Documentation.RegisterHelp( "SimpleSpline", "float SimpleSpline(float)", "" );
|
||||
}
|
||||
)vscript";
|
||||
)vscript";
|
||||
|
Loading…
Reference in New Issue
Block a user