Created
December 2, 2022 12:51
-
-
Save FreeSlave/0480df7c9c1713f99523638fd79aae6b to your computer and use it in GitHub Desktop.
trigger_random (Sven Co-op like)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define TRIGGER_RANDOM_MAX_COUNT 16 | |
#define SF_TRIGGER_RANDOM_START_ON 1 | |
#define SF_TRIGGER_RANDOM_ONCE 2 | |
#define SF_TRIGGER_RANDOM_REUSABLE 4 | |
#define SF_TRIGGER_RANDOM_TIMED 8 | |
#define SF_TRIGGER_RANDOM_UNIQUE 16 | |
#define SF_TRIGGER_RANDOM_DONT_REPEAT 32 | |
class CTriggerRandom : public CPointEntity | |
{ | |
public: | |
void Spawn(); | |
void KeyValue( KeyValueData *pkvd ); | |
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); | |
void EXPORT TimedThink(); | |
virtual int Save( CSave &save ); | |
virtual int Restore( CRestore &restore ); | |
static TYPEDESCRIPTION m_SaveData[]; | |
string_t ChooseTarget(); | |
float GetRandomDelay(); | |
int TargetCount(); | |
int m_targetCount; | |
string_t m_targets[TRIGGER_RANDOM_MAX_COUNT]; | |
int m_uniqueTargetsLeft; | |
int m_triggerNumberLimit; | |
int m_triggerCounter; | |
float m_minDelay; | |
float m_maxDelay; | |
string_t m_lastTarget; | |
string_t m_triggerOnLimit; | |
inline bool IsActive() { return pev->spawnflags & SF_TRIGGER_RANDOM_START_ON; } | |
inline void SetActive(bool active) | |
{ | |
if (active) | |
{ | |
SetBits(pev->spawnflags, SF_TRIGGER_RANDOM_START_ON); | |
} | |
else | |
{ | |
ClearBits(pev->spawnflags, SF_TRIGGER_RANDOM_START_ON); | |
} | |
} | |
}; | |
LINK_ENTITY_TO_CLASS( trigger_random, CTriggerRandom ) | |
// Sven Co-op compatibility | |
LINK_ENTITY_TO_CLASS( trigger_random_time, CTriggerRandom ) | |
LINK_ENTITY_TO_CLASS( trigger_random_unique, CTriggerRandom ) | |
TYPEDESCRIPTION CTriggerRandom::m_SaveData[] = | |
{ | |
DEFINE_FIELD( CTriggerRandom, m_targetCount, FIELD_INTEGER ), | |
DEFINE_ARRAY( CTriggerRandom, m_targets, FIELD_STRING, TRIGGER_RANDOM_MAX_COUNT ), | |
DEFINE_FIELD( CTriggerRandom, m_uniqueTargetsLeft, FIELD_INTEGER ), | |
DEFINE_FIELD( CTriggerRandom, m_triggerNumberLimit, FIELD_INTEGER ), | |
DEFINE_FIELD( CTriggerRandom, m_triggerCounter, FIELD_INTEGER ), | |
DEFINE_FIELD( CTriggerRandom, m_minDelay, FIELD_FLOAT ), | |
DEFINE_FIELD( CTriggerRandom, m_maxDelay, FIELD_FLOAT ), | |
DEFINE_FIELD( CTriggerRandom, m_lastTarget, FIELD_STRING ), | |
DEFINE_FIELD( CTriggerRandom, m_triggerOnLimit, FIELD_STRING ), | |
}; | |
IMPLEMENT_SAVERESTORE( CTriggerRandom, CPointEntity ) | |
void CTriggerRandom::KeyValue( KeyValueData *pkvd ) | |
{ | |
if ( FStrEq( pkvd->szKeyName, "min_delay") ) { | |
m_minDelay = atof( pkvd->szValue ); | |
if (m_minDelay < 0) { | |
m_minDelay = 0; | |
} | |
pkvd->fHandled = TRUE; | |
} else if ( FStrEq( pkvd->szKeyName, "max_delay") ) { | |
m_maxDelay = atof( pkvd->szValue ); | |
if (m_maxDelay < 0) { | |
m_maxDelay = 0; | |
} | |
pkvd->fHandled = TRUE; | |
} else if ( FStrEq( pkvd->szKeyName, "trigger_number") ) { | |
m_triggerNumberLimit = atoi( pkvd->szValue ); | |
if (m_triggerNumberLimit < 0) { | |
m_triggerNumberLimit = 0; | |
} | |
pkvd->fHandled = TRUE; | |
} else if ( FStrEq( pkvd->szKeyName, "target_count" ) ) { // Sven Co-op compatibility | |
m_targetCount = atoi( pkvd->szValue ); | |
if (m_targetCount < 0) { | |
m_targetCount = 0; | |
} else if (m_targetCount > TRIGGER_RANDOM_MAX_COUNT) { | |
m_targetCount = TRIGGER_RANDOM_MAX_COUNT; | |
} | |
pkvd->fHandled = TRUE; | |
} else if ( strncmp(pkvd->szKeyName, "target", 6) == 0 && isdigit(pkvd->szKeyName[6])) { | |
const int num = atoi(pkvd->szKeyName+6); | |
if (num <= 0 || num > TRIGGER_RANDOM_MAX_COUNT) | |
return; | |
const int index = num - 1; | |
m_targets[index] = ALLOC_STRING( pkvd->szValue ); | |
pkvd->fHandled = TRUE; | |
} else if ( FStrEq( pkvd->szKeyName, "trigger_on_limit") ) { | |
m_triggerOnLimit = ALLOC_STRING( pkvd->szValue ); | |
pkvd->fHandled = TRUE; | |
} else { | |
CBaseEntity::KeyValue( pkvd ); | |
} | |
} | |
void CTriggerRandom::Spawn() | |
{ | |
// Sven Co-op compatibility | |
if (FClassnameIs(pev, "trigger_random_time")) | |
{ | |
SetBits(pev->spawnflags, SF_TRIGGER_RANDOM_TIMED); | |
} | |
if (FClassnameIs(pev, "trigger_random_unique")) | |
{ | |
SetBits(pev->spawnflags, SF_TRIGGER_RANDOM_UNIQUE); | |
if (FBitSet(pev->spawnflags, 1)) | |
{ | |
SetBits(pev->spawnflags, SF_TRIGGER_RANDOM_REUSABLE); | |
ClearBits(pev->spawnflags, 1); | |
} | |
} | |
m_triggerCounter = 0; | |
if (FBitSet(pev->spawnflags, SF_TRIGGER_RANDOM_UNIQUE)) { | |
m_uniqueTargetsLeft = TargetCount(); | |
} | |
if (FBitSet(pev->spawnflags, SF_TRIGGER_RANDOM_TIMED)) { | |
if (IsActive()) { | |
SetThink(&CTriggerRandom::TimedThink); | |
pev->nextthink = gpGlobals->time + GetRandomDelay() + 0.1; | |
} | |
} | |
} | |
void CTriggerRandom::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) | |
{ | |
if (pev->spawnflags & SF_TRIGGER_RANDOM_TIMED) { | |
SetActive(!IsActive()); | |
if (IsActive()) { | |
SetThink(&CTriggerRandom::TimedThink); | |
pev->nextthink = gpGlobals->time + GetRandomDelay(); | |
} else { | |
SetThink(NULL); | |
m_triggerCounter = 0; | |
} | |
} else { | |
const int chosenTarget = ChooseTarget(); | |
if (!FStringNull(chosenTarget)) { | |
FireTargets(STRING(chosenTarget), pActivator, this, USE_TOGGLE, value); | |
} | |
} | |
} | |
void CTriggerRandom::TimedThink() | |
{ | |
if (IsActive()) { | |
int chosenTarget = ChooseTarget(); | |
if (!FStringNull(chosenTarget)) { | |
FireTargets(STRING(chosenTarget), this, this, USE_TOGGLE, 0); | |
if (m_triggerNumberLimit) { | |
m_triggerCounter++; | |
if (m_triggerCounter >= m_triggerNumberLimit) { | |
SetActive(false); | |
m_triggerCounter = 0; | |
if (!FStringNull(m_triggerOnLimit)) | |
FireTargets(STRING(m_triggerOnLimit), this, this, USE_TOGGLE, 0.0f); | |
} | |
} | |
} | |
if (pev->spawnflags & SF_TRIGGER_RANDOM_ONCE) | |
SetActive(false); | |
if (IsActive()) { | |
pev->nextthink = gpGlobals->time + GetRandomDelay(); | |
} | |
} | |
} | |
string_t CTriggerRandom::ChooseTarget() | |
{ | |
int chosenTargetIndex = 0; | |
string_t chosenTarget = iStringNull; | |
if (pev->spawnflags & SF_TRIGGER_RANDOM_UNIQUE) { | |
if (m_uniqueTargetsLeft) { | |
chosenTargetIndex = RANDOM_LONG(0, m_uniqueTargetsLeft - 1); | |
chosenTarget = m_targets[chosenTargetIndex]; | |
if (chosenTarget == m_lastTarget && FBitSet(pev->spawnflags, SF_TRIGGER_RANDOM_DONT_REPEAT) && m_uniqueTargetsLeft > 1) | |
{ | |
chosenTargetIndex = (chosenTargetIndex+1) % m_uniqueTargetsLeft; | |
chosenTarget = m_targets[chosenTargetIndex]; | |
} | |
m_targets[chosenTargetIndex] = m_targets[m_uniqueTargetsLeft-1]; | |
m_targets[m_uniqueTargetsLeft-1] = chosenTarget; | |
m_uniqueTargetsLeft--; | |
if (!m_uniqueTargetsLeft && (pev->spawnflags & SF_TRIGGER_RANDOM_REUSABLE) ) { | |
m_uniqueTargetsLeft = TargetCount(); | |
} | |
m_lastTarget = chosenTarget; | |
return chosenTarget; | |
} | |
} else { | |
const int targetCount = TargetCount(); | |
if (targetCount) { | |
chosenTargetIndex = RANDOM_LONG(0, targetCount - 1); | |
chosenTarget = m_targets[chosenTargetIndex]; | |
if (chosenTarget == m_lastTarget && FBitSet(pev->spawnflags, SF_TRIGGER_RANDOM_DONT_REPEAT) && targetCount > 1) | |
{ | |
chosenTargetIndex = (chosenTargetIndex+1) % targetCount; | |
chosenTarget = m_targets[chosenTargetIndex]; | |
} | |
m_lastTarget = chosenTarget; | |
return chosenTarget; | |
} | |
} | |
return iStringNull; | |
} | |
float CTriggerRandom::GetRandomDelay() | |
{ | |
return RANDOM_FLOAT(m_minDelay, Q_max(m_maxDelay, m_minDelay)); | |
} | |
int CTriggerRandom::TargetCount() | |
{ | |
if (m_targetCount) { | |
return m_targetCount; | |
} else { | |
for (int i = ARRAYSIZE(m_targets) - 1; i>=0; --i ) { | |
if (!FStringNull(m_targets[i])) { | |
m_targetCount = i+1; | |
return m_targetCount; | |
} | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment