Make extra `onbuild` context backwards compatible

Instead of changing the type of the parameters, the extra context is passed as a new second argument to the `onbuild` callback. The new second argument is a table with the keys `type` that contains a `BuildableTypes` constant and `fusetime` that contains a number with the fusetime of the detpack that is trying to be built (or nil if it's not a detpack being built).

Doing it this way also makes it easy to add more context in the future in a backwards compatible way (just add more stuff to the table).

Example usage:

```
function nobuild:onbuild( player, buildable_info )
  -- only allow detpacks if they have a fuse time of exactly 20
  if buildable_info.type == BuildableTypes.kDetpack and buildable_info.fusetime == 20 then
    return EVENT_ALLOWED
  end
  return EVENT_DISALLOWED
end
```
This commit is contained in:
Ryan Liptak 2022-12-13 19:07:14 -08:00
parent 1ec85713c2
commit 6907da1329
9 changed files with 62 additions and 107 deletions

View File

@ -293,8 +293,7 @@ CFFDetpack *CFFDetpack::Create( const Vector &vecOrigin, const QAngle &vecAngles
pObject->VPhysicsInitNormal( SOLID_VPHYSICS, pObject->GetSolidFlags(), true );
// Spawn the object
//pObject->Spawn();
// commented out for better nobuild functions, will be spawned ONLY IF it's allowed to, from ff_player.cpp
pObject->Spawn( );
return pObject;
}

View File

@ -414,8 +414,7 @@ CFFDispenser *CFFDispenser::Create( const Vector &vecOrigin, const QAngle &vecAn
//pObject->VPhysicsInitNormal( SOLID_VPHYSICS, pObject->GetSolidFlags(), true );
// Spawn the object
//pObject->Spawn();
// commented out for better nobuild functions, will be spawned ONLY IF it's allowed to, from ff_player.cpp
pObject->Spawn();
return pObject;
}

View File

@ -17,6 +17,8 @@
#pragma once
#endif
class CFFLuaSC;
/////////////////////////////////////////////////////////////////////////////
// CFFEntitySystemHelper
/////////////////////////////////////////////////////////////////////////////
@ -52,6 +54,7 @@ private:
bool FFScriptRunPredicates( CBaseEntity *pEntity, const char *pszFunction, bool bExpectedVal );
bool FFScriptRunPredicates( CBaseEntity *pEntity, const char *pszFunction, bool bExpectedVal, Vector vecOrigin, Vector vecMins = Vector(-16,-16,-16), Vector vecMaxs = Vector(16,16,16) ); // UTIL_EntitiesInBox
bool FFScriptRunPredicates( CBaseEntity *pEntity, const char *pszFunction, bool bExpectedVal, Vector vecOrigin, float flRadius = 16 ); // UTIL_EntitiesInSphere
bool FFScriptRunPredicates( CFFLuaSC *pContext, const char *pszFunction, bool bExpectedVal, Vector vecOrigin, float flRadius = 16 ); // UTIL_EntitiesInSphere
/////////////////////////////////////////////////////////////////////////////
#endif // FF_ENTITY_SYSTEM_H

View File

@ -35,6 +35,15 @@ namespace FFLib
}
}
/////////////////////////////////////////////////////////////////////////////
// CFFBuildableObject_BuildableTypes
// Purpose: this is a fake class to expose "FF_BUILD_" constants to lua
/////////////////////////////////////////////////////////////////////////////
class CFFBuildableObject_BuildableTypes
{
public:
};
//---------------------------------------------------------------------------
void CFFLuaLib::InitBuildables(lua_State* L)
{
@ -82,6 +91,18 @@ void CFFLuaLib::InitBuildables(lua_State* L)
class_<CFFDetpack, CFFBuildableObject>("Detpack")
.def("GetFuseTime", &CFFDetpack::GetFuseTime)
.def("GetDetonateTime", &CFFDetpack::GetDetonateTime)
.def("LastFiveSeconds", &CFFDetpack::LastFiveSeconds)
.def("LastFiveSeconds", &CFFDetpack::LastFiveSeconds),
class_<CFFBuildableObject_BuildableTypes>("BuildableTypes")
.enum_("BuildableTypes")
[
value("kNone", FF_BUILD_NONE),
value("kDispenser", FF_BUILD_DISPENSER),
value("kSentryGun", FF_BUILD_SENTRYGUN),
value("kDetpack", FF_BUILD_DETPACK),
value("kJumpPad", FF_BUILD_MANCANNON),
// For consistency with other names, even though jump pad should be preferred everywhere
value("kManCannon", FF_BUILD_MANCANNON)
]
];
};

View File

@ -228,8 +228,7 @@ CFFManCannon *CFFManCannon::Create( const Vector& vecOrigin, const QAngle& vecAn
pObject->m_hOwner.GetForModify() = pentOwner;
pObject->VPhysicsInitNormal( SOLID_VPHYSICS, pObject->GetSolidFlags(), true );
//pObject->Spawn();
// commented out for better nobuild functions, will be spawned ONLY IF it's allowed to, from ff_player.cpp
pObject->Spawn();
return pObject;
}

View File

@ -32,6 +32,7 @@
#include "ff_projectile_pipebomb.h"
#include "ff_grenade_emp.h"
#include "ff_lualib_constants.h"
#include "luabind/luabind.hpp"
#include "client.h"
#include "gib.h"
@ -3221,12 +3222,12 @@ void CFFPlayer::PreBuildGenericThink( void )
// Store the player's current origin
m_vecBuildOrigin = GetAbsOrigin();
// Our neat buildable info container
CFFBuildableInfo hBuildInfo( this, m_iWantBuild );
// See if player is in a no build area first
// TODO: need to check where the SG is being built, NOT where player is? - AfterShock
// Status: Complete
/*if( IsInNoBuild() && ( (m_iWantBuild == FF_BUILD_DISPENSER) || (m_iWantBuild == FF_BUILD_SENTRYGUN) || (m_iWantBuild == FF_BUILD_MANCANNON) ) )
if( IsInNoBuild(hBuildInfo) )
{
Omnibot::Notify_Build_CantBuild(this, m_iWantBuild);
@ -3239,7 +3240,7 @@ void CFFPlayer::PreBuildGenericThink( void )
ClientPrint( this, HUD_PRINTCENTER, "#FF_BUILDERROR_NOBUILD" );
return;
}*/
}
/*
DevMsg( "[Building] Not currently building so lets try to build a: %s" );
@ -3335,9 +3336,6 @@ void CFFPlayer::PreBuildGenericThink( void )
return;
}
// Our neat buildable info container
CFFBuildableInfo hBuildInfo( this, m_iWantBuild );
// Will we be able to build here?
if( hBuildInfo.BuildResult() == BUILD_ALLOWED )
{
@ -3362,24 +3360,6 @@ void CFFPlayer::PreBuildGenericThink( void )
pDispenser->SetGroundOrigin( hBuildInfo.GetBuildOrigin() );
pDispenser->SetGroundAngles( hBuildInfo.GetBuildAngles() );
// Send info to "trigger:onbuild()" lua function after setting buildable info, see if it's allowed
if( IsInNoBuild( pDispenser ) ) {
pDispenser->Cancel();
pDispenser->Remove(); // prevent leaving model in any case
pDispenser = NULL; // not sure if this is needed, added it anyway
// Re-initialize
m_iCurBuild = FF_BUILD_NONE;
m_iWantBuild = FF_BUILD_NONE;
m_bBuilding = false;
m_bStaticBuilding = false;
ClientPrint( this, HUD_PRINTCENTER, "#FF_BUILDERROR_NOBUILD" );
return;
} else {
pDispenser->Spawn();
}
// Set network var
m_hDispenser = pDispenser;
@ -3431,24 +3411,6 @@ void CFFPlayer::PreBuildGenericThink( void )
pSentryGun->SetGroundOrigin( hBuildInfo.GetBuildOrigin() );
pSentryGun->SetGroundAngles( hBuildInfo.GetBuildAngles() );
// Send info to "trigger:onbuild()" lua function after setting buildable info, see if it's allowed
if( IsInNoBuild( pSentryGun ) ) {
pSentryGun->Cancel();
pSentryGun->Remove(); // prevent leaving model in any case
pSentryGun = NULL; // not sure if this is needed, added it anyway
// Re-initialize
m_iCurBuild = FF_BUILD_NONE;
m_iWantBuild = FF_BUILD_NONE;
m_bBuilding = false;
m_bStaticBuilding = false;
ClientPrint( this, HUD_PRINTCENTER, "#FF_BUILDERROR_NOBUILD" );
return;
} else {
pSentryGun->Spawn();
}
// Set network var
m_hSentryGun = pSentryGun;
@ -3470,33 +3432,15 @@ void CFFPlayer::PreBuildGenericThink( void )
// Changed to building straight on ground (Bug #0000191: Engy "imagines" SG placement, then lifts SG, then back to imagined position.)
CFFDetpack *pDetpack = CFFDetpack::Create( hBuildInfo.GetBuildOrigin(), hBuildInfo.GetBuildAngles(), this );
pDetpack->SetLocation(g_pGameRules->GetChatLocation(true, this));
// Set the fuse time
pDetpack->m_iFuseTime = m_iDetpackTime;
pDetpack->SetLocation(g_pGameRules->GetChatLocation(true, this));
// Mirv: Store future ground location + orientation
pDetpack->SetGroundOrigin( hBuildInfo.GetBuildOrigin() );
pDetpack->SetGroundAngles( hBuildInfo.GetBuildAngles() );
// Send info to "trigger:onbuild()" lua function after setting buildable info, see if it's allowed
if( IsInNoBuild( pDetpack ) ) {
pDetpack->Cancel();
pDetpack->Remove(); // prevent leaving model in any case
pDetpack = NULL; // not sure if this is needed, added it anyway
// Re-initialize
m_iCurBuild = FF_BUILD_NONE;
m_iWantBuild = FF_BUILD_NONE;
m_bBuilding = false;
m_bStaticBuilding = false;
ClientPrint( this, HUD_PRINTCENTER, "#FF_BUILDERROR_NOBUILD" );
return;
} else {
pDetpack->Spawn();
}
// Set network var
m_hDetpack = pDetpack;
@ -3515,24 +3459,6 @@ void CFFPlayer::PreBuildGenericThink( void )
pManCannon->SetGroundOrigin( hBuildInfo.GetBuildOrigin() );
pManCannon->SetGroundAngles( hBuildInfo.GetBuildAngles() );
// Send info to "trigger:onbuild()" lua function after setting buildable info, see if it's allowed
if( IsInNoBuild( pManCannon ) ) {
pManCannon->Cancel();
pManCannon->Remove(); // prevent leaving model in any case
pManCannon = NULL; // not sure if this is needed, added it anyway
// Re-initialize
m_iCurBuild = FF_BUILD_NONE;
m_iWantBuild = FF_BUILD_NONE;
m_bBuilding = false;
m_bStaticBuilding = false;
ClientPrint( this, HUD_PRINTCENTER, "#FF_BUILDERROR_NOBUILD" );
return;
} else {
pManCannon->Spawn();
}
m_hManCannon = pManCannon;
m_flBuildTime = gpGlobals->curtime + 3.5f; // 3.5 seconds to build?
@ -6943,13 +6869,9 @@ bool CFFPlayer::HasItem(const char* itemname) const
}
//-----------------------------------------------------------------------------
bool CFFPlayer::IsInNoBuild( CBaseEntity *pEntity )
bool CFFPlayer::IsInNoBuild(const CFFBuildableInfo &hBuildInfo)
{
Vector vecForward;
EyeVectors(&vecForward);
vecForward.z = 0;
VectorNormalize( vecForward );
Vector vecOrigin = GetAbsOrigin() + (vecForward * 88.0f);
Vector vecOrigin = hBuildInfo.GetBuildOrigin();
#ifdef _DEBUG
if( !engine->IsDedicatedServer() )
@ -6959,7 +6881,15 @@ bool CFFPlayer::IsInNoBuild( CBaseEntity *pEntity )
}
#endif
return !FFScriptRunPredicates( pEntity, "onbuild", true, vecOrigin, 40.0f );
luabind::adl::object luatblInfo = luabind::newtable(_scriptman.GetLuaState());
luatblInfo["type"] = m_iWantBuild;
if (m_iWantBuild == FF_BUILD_DETPACK) {
luatblInfo["fusetime"] = m_iDetpackTime;
}
// CFFLuaSC constructor assumes all args are CBaseEntity*, so push the table separately
CFFLuaSC hContext = CFFLuaSC(1, (CBaseEntity*)this);
hContext.Push(luatblInfo);
return !FFScriptRunPredicates( &hContext, "onbuild", true, vecOrigin, 40.0f );
}

View File

@ -32,6 +32,7 @@ class CFFDetpack;
class CFFDispenser;
class CFFSentryGun;
class CFFManCannon;
class CFFBuildableInfo;
class CFFGrenadeBase;
@ -311,7 +312,7 @@ public:
// <-- Mirv: Damage & force stuff
bool HasItem(const char* szItemName) const;
bool IsInNoBuild( CBaseEntity *pEntity );
bool IsInNoBuild(const CFFBuildableInfo &hBuildInfo);
bool IsUnderWater() const { return (GetWaterLevel() == WL_Eyes); }
bool IsWaistDeepInWater() const { return (GetWaterLevel() == WL_Waist); }
bool IsFeetDeepInWater() const { return (GetWaterLevel() == WL_Feet); }

View File

@ -646,10 +646,17 @@ bool FFScriptRunPredicates( CBaseEntity *pObject, const char *pszFunction, bool
// same as above, but uses a separate sphere
bool FFScriptRunPredicates( CBaseEntity *pObject, const char *pszFunction, bool bExpectedVal, Vector vecOrigin, float flRadius )
{
CFFLuaSC hOutput( 1, pObject );
return FFScriptRunPredicates(&hOutput, pszFunction, bExpectedVal, vecOrigin, flRadius);
}
// same as above, but takes a CFFLuaSC
bool FFScriptRunPredicates( CFFLuaSC *pContext, const char *pszFunction, bool bExpectedVal, Vector vecOrigin, float flRadius )
{
VPROF_BUDGET( "FFScriptRunPredicates", VPROF_BUDGETGROUP_FF_LUA );
if( pObject && pszFunction )
if( pContext && pszFunction )
{
CBaseEntity *pList[ 128 ];
int count = UTIL_EntitiesInSphere( pList, 128, vecOrigin, flRadius, 0 );
@ -675,11 +682,8 @@ bool FFScriptRunPredicates( CBaseEntity *pObject, const char *pszFunction, bool
continue;
bool bEntSys = bExpectedVal;
//CFFLuaObjectWrapper hOutput;
CFFLuaSC hOutput( 1, pObject );
//bool bEntSys = entsys.RunPredicates_LUA( pEntity, pObject, pszFunction ) > 0;
if( _scriptman.RunPredicates_LUA( pEntity, &hOutput, pszFunction ) )
bEntSys = hOutput.GetBool();
if( _scriptman.RunPredicates_LUA( pEntity, pContext, pszFunction ) )
bEntSys = pContext->GetBool();
if( bEntSys != bExpectedVal )
return !bExpectedVal;

View File

@ -1773,8 +1773,7 @@ CFFSentryGun *CFFSentryGun::Create( const Vector &vecOrigin, const QAngle &vecAn
//pObject->VPhysicsInitNormal( SOLID_VPHYSICS, pObject->GetSolidFlags(), true );
// Spawn the object
//pObject->Spawn();
// commented out for better nobuild functions, will be spawned ONLY IF it's allowed to, from ff_player.cpp
pObject->Spawn();
return pObject;
}