Handle entvar keyvalues.

This commit is contained in:
Giegue
2023-03-06 20:02:04 -03:00
parent 73f240ddb1
commit bd9fe1f487
9 changed files with 274 additions and 6 deletions

View File

@@ -158,8 +158,6 @@ I'm aware that the plugin is far from perfect, and there are a few things that n
- Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing. Cause of bug unknown. - Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing. Cause of bug unknown.
- Entvars are not recognized, so anything that is a pevfield that is not used by monstermod is unusable.
There are probably more issues that aren't listed here, I'll attempt to fix them as I find them. Of course, any bug report is welcome. If reporting a bug, try to explain step by step how the bug ocurred. The easier it is to replicate a bug, the easier it is to locate it and fix it. There are probably more issues that aren't listed here, I'll attempt to fix them as I find them. Of course, any bug report is welcome. If reporting a bug, try to explain step by step how the bug ocurred. The easier it is to replicate a bug, the easier it is to locate it and fix it.
## Milestones ## Milestones

View File

@@ -4,4 +4,6 @@ This folder contains auxiliary tools used to enhance the compatibility and/or in
As these are auxiliary, they aren't needed to enjoy MonsterMod. If you want an extra boost, feel free to install these. As these are auxiliary, they aren't needed to enjoy MonsterMod. If you want an extra boost, feel free to install these.
Plugins from the `base` folder should come first, then the ones from the appropiate mod folder.
Once all milestones are completed, the possibility of removing the need for external plugins will be considered. Until then, this has to stay. Once all milestones are completed, the possibility of removing the need for external plugins will be considered. Until then, this has to stay.

25
extra/base/README.md Normal file
View File

@@ -0,0 +1,25 @@
## Base Plugins (All Mods)
Auxiliary Tools to use MonsterMod in any GoldSrc game.
These are base plugins that should be installed first before adding any mod-specific plugin.
### AMX Mod X Plugins
#### -A note about AMXX plugins-
All plugins in this section require AMXX 1.9.0 or greater, they will not work on 1.8.2 or older.
Compiled plugins are provided in the `bin` folder for your convenience. However, if you prefer to build the plugins yourself, the source code of all AMXX plugins are located in the `src` folder for compilation.
#### GoldSrc --> MonsterMod Use Dispatcher
Because MonsterMod entities are, -quite literally-, just a func_wall with its own logic, trying to trigger any MonsterMod entity from the outside will fail, as it will attempt to use the logic of game's "func_wall" instead of our own.
To add salt to injury, Metamod is incapable of hooking use functions, as the pfnUse/DispatchUse methods provided by the API has been deprecated, and no longer work. Leaving AMXX's HamSandwich as the only module that can hook an entity's Use() function.
In normal circunstances, you do not need this plugin. But let's say you have a turret monster, disabled by default, and you gave it a targetname. Even with a name, triggering this turret regardless of the method used will not activate it.
This plugin redirects the game's func_wall Use() function to MonsterMod, connecting the missing piece and allowing you to trigger MonsterMod entities with your shiny func_button.
I can't believe I've done this. *incomprehensible screams*

Binary file not shown.

View File

@@ -0,0 +1,24 @@
#pragma semicolon 1
#include <amxmodx>
#include <engine>
#include <hamsandwich>
public plugin_init()
{
register_plugin( "GAME-MONSTER: Use Dispatcher", "1.0", "Giegue" );
RegisterHam( Ham_Use, "func_wall", "DispatchUse" );
}
public DispatchUse( entity, caller, activator, useType, Float:value )
{
// all monstermod entities have this set
if ( entity_get_edict( entity, EV_ENT_euser4 ) )
{
server_cmd( "_use %i %i %i %i %f", entity, caller, activator, useType, value );
return HAM_SUPERCEDE;
}
return HAM_IGNORED;
}

View File

@@ -17,6 +17,8 @@
#include "cmbase.h" #include "cmbase.h"
#include "decals.h" #include "decals.h"
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd );
extern Vector VecBModelOrigin( entvars_t* pevBModel ); extern Vector VecBModelOrigin( entvars_t* pevBModel );
extern DLL_GLOBAL Vector g_vecAttackDir; extern DLL_GLOBAL Vector g_vecAttackDir;
@@ -103,6 +105,19 @@ edict_t *CMBaseEntity::CreateEntity(char *classname)
return pent; return pent;
} }
// process entvar keyvalue
void CMBaseEntity :: KeyValue( KeyValueData* pkvd )
{
if ( !pev || !pkvd )
return;
if ( pkvd->fHandled )
{
// only handled data contain readable strings
EntvarsKeyvalue( pev, pkvd );
}
}
// give health // give health
int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
{ {

View File

@@ -134,7 +134,7 @@ public:
// initialization functions // initialization functions
virtual void Spawn( void ) { return; } virtual void Spawn( void ) { return; }
virtual void Precache( void ) { return; } virtual void Precache( void ) { return; }
virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; } virtual void KeyValue( KeyValueData* pkvd );
virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; } virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; }
virtual void Activate( void ) {} virtual void Activate( void ) {}

View File

@@ -1327,6 +1327,46 @@ void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther )
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);
} }
// pfnUse has been deprecated so the only way to trigger a monstermod
// entity from the outside is to do it manually. ARRGHH! -Giegue
void mmDispatchUse( void )
{
if ( CMD_ARGC() >= 6 ) // the command itself is an argument, we need 5. so argc == 6
{
edict_t *entity = INDEXENT( atoi( CMD_ARGV( 1 ) ) );
edict_t *caller = INDEXENT( atoi( CMD_ARGV( 2 ) ) );
edict_t *activator = INDEXENT( atoi( CMD_ARGV( 3 ) ) );
USE_TYPE useType = USE_TYPE( atoi( CMD_ARGV( 4 ) ) );
float flValue = atof( CMD_ARGV( 5 ) );
// nevermind the unoptimization that this brings... >C
for (int index=0; index < monster_ents_used; index++)
{
if ((entity != NULL) && (entity == monsters[index].monster_pent))
{
if ( FNullEnt( caller ) ) caller = NULL;
if ( FNullEnt( activator ) ) activator = NULL;
monsters[index].pMonster->Use( caller, activator, useType, flValue );
return;
}
}
}
}
void mmDispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd )
{
for (int index=0; index < monster_ents_used; index++)
{
if ((pentKeyvalue != NULL) && (pentKeyvalue == monsters[index].monster_pent))
{
monsters[index].pMonster->KeyValue( pkvd );
RETURN_META(MRES_SUPERCEDE);
}
}
RETURN_META(MRES_IGNORED);
}
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
{ {
@@ -1371,6 +1411,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
(g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand); (g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand);
(g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand); (g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand);
(g_engfuncs.pfnAddServerCommand)("_use", mmDispatchUse);
for (index = 0; monster_types[index].name[0]; index++) for (index = 0; monster_types[index].name[0]; index++)
{ {
@@ -1531,10 +1572,10 @@ static DLL_FUNCTIONS gFunctionTable =
mmGameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll) mmGameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll)
mmDispatchSpawn, //! pfnSpawn() mmDispatchSpawn, //! pfnSpawn()
mmDispatchThink, //! pfnThink mmDispatchThink, //! pfnThink
NULL, // pfnUse NULL, // pfnUse [DEPRECATED]
mmDispatchTouch, //! pfnTouch mmDispatchTouch, //! pfnTouch
NULL, // pfnBlocked NULL, // pfnBlocked
NULL, // pfnKeyValue mmDispatchKeyValue, //! pfnKeyValue
NULL, // pfnSave NULL, // pfnSave
NULL, // pfnRestore NULL, // pfnRestore
NULL, // pfnSetAbsBox NULL, // pfnSetAbsBox
@@ -1631,7 +1672,7 @@ static DLL_FUNCTIONS gFunctionTable_Post =
NULL, // pfnGameInit() Initialize the game (one-time call after loading of game .dll) NULL, // pfnGameInit() Initialize the game (one-time call after loading of game .dll)
NULL, // pfnSpawn() NULL, // pfnSpawn()
mmDispatchThink_Post, //! pfnThink mmDispatchThink_Post, //! pfnThink
NULL, // pfnUse NULL, // pfnUse [DEPRECATED]
NULL, // pfnTouch NULL, // pfnTouch
NULL, // pfnBlocked NULL, // pfnBlocked
NULL, // pfnKeyValue NULL, // pfnKeyValue

View File

@@ -226,6 +226,120 @@ UTIL_GroupTrace::~UTIL_GroupTrace( void )
} }
TYPEDESCRIPTION gEntvarsDescription[] =
{
DEFINE_ENTITY_FIELD( classname, FIELD_STRING ),
DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ),
DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ),
DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ),
DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ),
// Having these fields be local to the individual levels makes it easier to test those levels individually.
DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ),
DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( netname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( message, FIELD_STRING ),
DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ),
DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ),
DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ),
};
#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0]))
#ifdef DEBUG #ifdef DEBUG
edict_t *DBG_EntOfVars( const entvars_t *pev ) edict_t *DBG_EntOfVars( const entvars_t *pev )
{ {
@@ -1512,6 +1626,55 @@ void UTIL_StripToken( const char *pKey, char *pDest )
} }
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd )
{
int i;
TYPEDESCRIPTION *pField;
for ( i = 0; i < ENTVARS_COUNT; i++ )
{
pField = &gEntvarsDescription[i];
if ( !stricmp( pField->fieldName, pkvd->szKeyName ) )
{
switch( pField->fieldType )
{
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
(*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue );
break;
case FIELD_TIME:
case FIELD_FLOAT:
(*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue );
break;
case FIELD_INTEGER:
(*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue );
break;
case FIELD_POSITION_VECTOR:
case FIELD_VECTOR:
UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue );
break;
default:
case FIELD_EVARS:
case FIELD_CLASSPTR:
case FIELD_EDICT:
case FIELD_ENTITY:
case FIELD_POINTER:
ALERT( at_error, "Bad field in entity!!\n" );
break;
}
pkvd->fHandled = TRUE;
return;
}
}
}
Vector VecBModelOrigin( entvars_t* pevBModel ) Vector VecBModelOrigin( entvars_t* pevBModel )
{ {
return pevBModel->absmin + ( pevBModel->size * 0.5 ); return pevBModel->absmin + ( pevBModel->size * 0.5 );