mirror of
https://github.com/FWGS/hlsdk-xash3d
synced 2024-11-10 20:29:35 +01:00
356 lines
9.3 KiB
C++
356 lines
9.3 KiB
C++
/***
|
|
*
|
|
* NEW file for the Mod "Spirit of Half-Life", by Laurie R. Cheers. (LRC)
|
|
* Created 19/11/00
|
|
*
|
|
***/
|
|
/*
|
|
|
|
===== alias.cpp ========================================================
|
|
|
|
Alias entities, replace the less powerful and (IMHO) less intuitive
|
|
trigger_changetarget entity.
|
|
|
|
*/
|
|
|
|
#include "extdll.h"
|
|
#include "util.h"
|
|
#include "cbase.h"
|
|
|
|
TYPEDESCRIPTION CBaseAlias::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CBaseAlias, m_pNextAlias, FIELD_CLASSPTR ),
|
|
};
|
|
IMPLEMENT_SAVERESTORE( CBaseAlias, CPointEntity )
|
|
|
|
/*********************
|
|
* Worldcraft entity: info_alias
|
|
*
|
|
* targetname- alias name
|
|
* target- alias destination while ON
|
|
* netname- alias destination while OFF
|
|
**********************/
|
|
|
|
#define SF_ALIAS_OFF 1
|
|
#define SF_ALIAS_DEBUG 2
|
|
|
|
class CInfoAlias : public CBaseAlias
|
|
{
|
|
public:
|
|
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
|
|
void Spawn( void );
|
|
STATE GetState() { return (pev->spawnflags & SF_ALIAS_OFF)?STATE_OFF:STATE_ON; }
|
|
|
|
CBaseEntity *FollowAlias( CBaseEntity *pFrom );
|
|
void ChangeValue( int iszValue );
|
|
void FlushChanges( void );
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS( info_alias, CInfoAlias )
|
|
|
|
void CInfoAlias::Spawn( void )
|
|
{
|
|
if (pev->spawnflags & SF_ALIAS_OFF)
|
|
pev->message = pev->netname;
|
|
else
|
|
pev->message = pev->target;
|
|
}
|
|
|
|
void CInfoAlias::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
if (pev->spawnflags & SF_ALIAS_OFF)
|
|
{
|
|
if (pev->spawnflags & SF_ALIAS_DEBUG)
|
|
ALERT(at_console,"DEBUG: info_alias %s turns on\n",STRING(pev->targetname));
|
|
pev->spawnflags &= ~SF_ALIAS_OFF;
|
|
pev->noise = pev->target;
|
|
}
|
|
else
|
|
{
|
|
if (pev->spawnflags & SF_ALIAS_DEBUG)
|
|
ALERT(at_console,"DEBUG: info_alias %s turns off\n",STRING(pev->targetname));
|
|
pev->spawnflags |= SF_ALIAS_OFF;
|
|
pev->noise = pev->netname;
|
|
}
|
|
UTIL_AddToAliasList( this );
|
|
}
|
|
|
|
CBaseEntity *CInfoAlias::FollowAlias( CBaseEntity *pFrom )
|
|
{
|
|
return UTIL_FindEntityByTargetname( pFrom, STRING(pev->message) );
|
|
}
|
|
|
|
void CInfoAlias::ChangeValue( int iszValue )
|
|
{
|
|
pev->noise = iszValue;
|
|
UTIL_AddToAliasList( this );
|
|
}
|
|
|
|
void CInfoAlias::FlushChanges( void )
|
|
{
|
|
pev->message = pev->noise;
|
|
if (pev->spawnflags & SF_ALIAS_DEBUG)
|
|
ALERT(at_console,"DEBUG: info_alias %s now refers to \"%s\"\n", STRING(pev->targetname), STRING(pev->message));
|
|
}
|
|
|
|
/*********************
|
|
* Worldcraft entity: info_group
|
|
*
|
|
* targetname- name
|
|
* target- alias entity to affect
|
|
* other values are handled in a multi_manager-like way.
|
|
**********************/
|
|
// definition in cbase.h
|
|
|
|
#define SF_GROUP_DEBUG 2
|
|
|
|
LINK_ENTITY_TO_CLASS( info_group, CInfoGroup );
|
|
|
|
TYPEDESCRIPTION CInfoGroup::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CInfoGroup, m_cMembers, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( CInfoGroup, m_iszMemberName, FIELD_STRING, MAX_MULTI_TARGETS ),
|
|
DEFINE_ARRAY( CInfoGroup, m_iszMemberValue, FIELD_STRING, MAX_MULTI_TARGETS ),
|
|
DEFINE_FIELD( CInfoGroup, m_iszDefaultMember, FIELD_STRING ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE(CInfoGroup,CBaseEntity);
|
|
|
|
void CInfoGroup :: KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "defaultmember"))
|
|
{
|
|
m_iszDefaultMember = ALLOC_STRING(pkvd->szValue);
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
// this assumes that additional fields are targetnames and their values are delay values.
|
|
else if ( m_cMembers < MAX_MULTI_TARGETS )
|
|
{
|
|
char tmp[128];
|
|
UTIL_StripToken( pkvd->szKeyName, tmp );
|
|
m_iszMemberName [ m_cMembers ] = ALLOC_STRING( tmp );
|
|
m_iszMemberValue [ m_cMembers ] = ALLOC_STRING (pkvd->szValue);
|
|
m_cMembers++;
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ALERT(at_error,"Too many members for info_group %s (limit is %d)\n",STRING(pev->targetname),MAX_MULTI_TARGETS);
|
|
}
|
|
}
|
|
|
|
void CInfoGroup::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
CBaseEntity *pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) );
|
|
|
|
if (pTarget && pTarget->IsAlias())
|
|
{
|
|
if (pev->spawnflags & SF_GROUP_DEBUG)
|
|
ALERT(at_console, "DEBUG: info_group %s changes the contents of %s \"%s\"\n",STRING(pev->targetname), STRING(pTarget->pev->classname), STRING(pTarget->pev->targetname));
|
|
((CBaseAlias*)pTarget)->ChangeValue(this);
|
|
}
|
|
else if (pev->target)
|
|
{
|
|
ALERT(at_console, "info_group \"%s\": alias \"%s\" was not found or not an alias!", STRING(pev->targetname), STRING(pev->target));
|
|
}
|
|
}
|
|
|
|
int CInfoGroup::GetMember( const char* szMemberName )
|
|
{
|
|
if (!szMemberName)
|
|
{
|
|
ALERT(at_console,"info_group: GetMember called with null szMemberName!?\n");
|
|
return 0;
|
|
}
|
|
for (int i = 0; i < m_cMembers; i++)
|
|
{
|
|
if (FStrEq(szMemberName, STRING(m_iszMemberName[i])))
|
|
{
|
|
// ALERT(at_console,"getMember: found member\n");
|
|
return m_iszMemberValue[i];
|
|
}
|
|
}
|
|
|
|
if (m_iszDefaultMember)
|
|
{
|
|
static char szBuffer[128];
|
|
strcpy(szBuffer, STRING(m_iszDefaultMember));
|
|
strcat(szBuffer, szMemberName);
|
|
return MAKE_STRING(szBuffer);
|
|
// this is a messy way to do it... but currently, only one
|
|
// GetMember gets performed at a time, so it works.
|
|
}
|
|
|
|
ALERT(at_console,"info_group \"%s\" has no member called \"%s\".\n",STRING(pev->targetname),szMemberName);
|
|
// ALERT(at_console,"getMember: fail\n");
|
|
return 0;
|
|
}
|
|
|
|
/*********************
|
|
* Worldcraft entity: multi_alias
|
|
*
|
|
* targetname- name
|
|
* other values are handled in a multi_manager-like way.
|
|
**********************/
|
|
// definition in cbase.h
|
|
|
|
LINK_ENTITY_TO_CLASS( multi_alias, CMultiAlias );
|
|
|
|
TYPEDESCRIPTION CMultiAlias::m_SaveData[] =
|
|
{
|
|
DEFINE_FIELD( CMultiAlias, m_cTargets, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( CMultiAlias, m_iszTargets, FIELD_STRING, MAX_MULTI_TARGETS ),
|
|
DEFINE_FIELD( CMultiAlias, m_iTotalValue, FIELD_INTEGER ),
|
|
DEFINE_ARRAY( CMultiAlias, m_iValues, FIELD_INTEGER, MAX_MULTI_TARGETS ),
|
|
DEFINE_FIELD( CMultiAlias, m_iMode, FIELD_INTEGER ),
|
|
};
|
|
|
|
IMPLEMENT_SAVERESTORE(CMultiAlias,CBaseAlias);
|
|
|
|
void CMultiAlias :: KeyValue( KeyValueData *pkvd )
|
|
{
|
|
if (FStrEq(pkvd->szKeyName, "m_iMode"))
|
|
{
|
|
m_iMode = atoi( pkvd->szValue );
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
// this assumes that additional fields are targetnames and their values are probability values.
|
|
else if ( m_cTargets < MAX_MULTI_TARGETS )
|
|
{
|
|
char tmp[128];
|
|
UTIL_StripToken( pkvd->szKeyName, tmp );
|
|
|
|
m_iszTargets [ m_cTargets ] = ALLOC_STRING( tmp );
|
|
m_iValues [ m_cTargets ] = atoi( pkvd->szValue );
|
|
|
|
m_iTotalValue += m_iValues [ m_cTargets ];
|
|
m_cTargets++;
|
|
|
|
pkvd->fHandled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ALERT(at_error,"Too many targets for multi_alias %s (limit is %d)\n",STRING(pev->targetname), MAX_MULTI_TARGETS);
|
|
}
|
|
}
|
|
|
|
CBaseEntity *CMultiAlias::FollowAlias( CBaseEntity *pStartEntity )
|
|
{
|
|
CBaseEntity* pBestEntity = NULL; // the entity we're currently planning to return.
|
|
int iBestOffset = -1; // the offset of that entity.
|
|
CBaseEntity* pTempEntity;
|
|
int iTempOffset;
|
|
|
|
int i = 0;
|
|
if (m_iMode)
|
|
{
|
|
// During any given 'game moment', this code may be called more than once. It must use the
|
|
// same random values each time (because otherwise it gets really messy). I'm using srand
|
|
// to arrange this.
|
|
srand( (int)(gpGlobals->time * 100) );
|
|
rand(); // throw away the first result - it's just the seed value
|
|
if (m_iMode == 1) // 'choose one' mode
|
|
{
|
|
int iRandom = 1 + (rand() % m_iTotalValue);
|
|
for (i = 0; i < m_cTargets; i++)
|
|
{
|
|
iRandom -= m_iValues[i];
|
|
if (iRandom <= 0)
|
|
break;
|
|
}
|
|
}
|
|
else // 'percent chance' mode
|
|
{
|
|
for (i = 0; i < m_cTargets; i++)
|
|
{
|
|
if (m_iValues[i] >= rand() % 100)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (i < m_cTargets)
|
|
{
|
|
pTempEntity = UTIL_FindEntityByTargetname(pStartEntity,STRING(m_iszTargets[i]));
|
|
if ( pTempEntity )
|
|
{
|
|
// We've found an entity; only use it if its offset is lower than the offset we've currently got.
|
|
iTempOffset = OFFSET(pTempEntity->pev);
|
|
if (iBestOffset == -1 || iTempOffset < iBestOffset)
|
|
{
|
|
iBestOffset = iTempOffset;
|
|
pBestEntity = pTempEntity;
|
|
}
|
|
}
|
|
if (m_iMode == 1)
|
|
break; // if it's in "pick one" mode, stop after the first.
|
|
else if (m_iMode == 2)
|
|
{
|
|
i++;
|
|
// if it's in "percent chance" mode, try to find another one to fire.
|
|
while (i < m_cTargets)
|
|
{
|
|
if (m_iValues[i] > rand() % 100)
|
|
break;
|
|
i++;
|
|
}
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
|
|
return pBestEntity;
|
|
}
|
|
|
|
/*********************
|
|
* Worldcraft entity: trigger_changealias
|
|
*
|
|
* target- alias entity to affect
|
|
* netname- value to change the alias to
|
|
**********************/
|
|
|
|
#define SF_CHANGEALIAS_RESOLVE 1
|
|
#define SF_CHANGEALIAS_DEBUG 2
|
|
|
|
class CTriggerChangeAlias : public CBaseEntity
|
|
{
|
|
public:
|
|
void Spawn( void );
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
|
};
|
|
LINK_ENTITY_TO_CLASS( trigger_changealias, CTriggerChangeAlias )
|
|
|
|
void CTriggerChangeAlias::Spawn( void )
|
|
{
|
|
}
|
|
|
|
void CTriggerChangeAlias::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
CBaseEntity *pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ), pActivator );
|
|
|
|
if (pTarget && pTarget->IsAlias())
|
|
{
|
|
CBaseEntity *pValue = NULL;
|
|
|
|
if (FStrEq(STRING(pev->netname), "*locus"))
|
|
{
|
|
pValue = pActivator;
|
|
}
|
|
else if (pev->spawnflags & SF_CHANGEALIAS_RESOLVE)
|
|
{
|
|
pValue = UTIL_FollowReference(NULL, STRING(pev->netname));
|
|
}
|
|
|
|
if (pValue)
|
|
((CBaseAlias*)pTarget)->ChangeValue(pValue);
|
|
else
|
|
((CBaseAlias*)pTarget)->ChangeValue(pev->netname);
|
|
}
|
|
else
|
|
{
|
|
ALERT(at_error, "trigger_changealias %s: alias \"%s\" was not found or not an alias!", STRING(pev->targetname), STRING(pev->target));
|
|
}
|
|
}
|