You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
9.3 KiB
355 lines
9.3 KiB
/*** |
|
* |
|
* 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)); |
|
} |
|
}
|
|
|