This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/server/ents/baselogic.cpp

533 lines
16 KiB
C++
Raw Blame History

//=======================================================================
// Copyright (C) Shambler Team 2004
// logicentity.cpp - all entities with prefix "logic_"
// additional entities for smart system
//=======================================================================
#include "extdll.h"
#include "utils.h"
#include "cbase.h"
#include "defaults.h"
// Use CBaseDelay as main function (renamed as CBaseLogic, see declaration in cbase.h).
//=======================================================================
// main functions ()
//=======================================================================
void CBaseLogic :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "delay") || FStrEq(pkvd->szKeyName, "MaxDelay"))
{
m_flDelay = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "wait") || FStrEq(pkvd->szKeyName, "MaxWait"))
{
m_flWait = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "master"))
{
m_sMaster = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "killtarget"))
{
m_iszKillTarget = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "globalstate"))
{
m_globalstate = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseEntity::KeyValue( pkvd );
}
void CBaseLogic :: FireTargets( USE_TYPE useType, float value )
{
//fire our targets
UTIL_FireTargets( pev->target, m_hActivator, this, useType, value );
UTIL_FireTargets( m_iszKillTarget, m_hActivator, this, USE_REMOVE );
}
BOOL CBaseLogic :: IsLockedByMaster( void )
{
if (UTIL_IsMasterTriggered(m_sMaster, m_hActivator))
return FALSE;
return TRUE;
}
BOOL CBaseLogic :: IsLockedByMaster( CBaseEntity *pActivator )
{
if (UTIL_IsMasterTriggered(m_sMaster, pActivator))
return FALSE;
return TRUE;
}
BOOL CBaseLogic :: IsLockedByMaster( USE_TYPE useType )
{
if (UTIL_IsMasterTriggered(m_sMaster, m_hActivator))
return FALSE;
else if (useType == USE_SHOWINFO) return FALSE;//pass to debug info
return TRUE;
}
TYPEDESCRIPTION CBaseLogic::m_SaveData[] =
{
DEFINE_FIELD( CBaseLogic, m_flDelay, FIELD_FLOAT ),
DEFINE_FIELD( CBaseLogic, m_hActivator, FIELD_EHANDLE ),
DEFINE_FIELD( CBaseLogic, m_hTarget, FIELD_EHANDLE ),
DEFINE_FIELD( CBaseLogic, m_iState, FIELD_INTEGER ),
DEFINE_FIELD( CBaseLogic, m_sMaster, FIELD_STRING),
DEFINE_FIELD( CBaseLogic, m_iszKillTarget, FIELD_STRING ),
DEFINE_FIELD( CBaseLogic, m_sSet, FIELD_STRING),
DEFINE_FIELD( CBaseLogic, m_sReset, FIELD_STRING),
DEFINE_FIELD( CBaseLogic, m_flWait, FIELD_FLOAT ),
DEFINE_FIELD( CBaseLogic, m_globalstate, FIELD_STRING ),
};IMPLEMENT_SAVERESTORE( CBaseLogic, CBaseEntity );
//=======================================================================
// Logic_generator
//=======================================================================
#define NORMAL_MODE 0
#define RANDOM_MODE 1
#define RANDOM_MODE_WITH_DEC 2
class CGenerator : public CBaseLogic
{
public:
void KeyValue( KeyValueData *pkvd );
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void Think (void);
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
private:
int m_iFireCount;
int m_iMaxFireCount;
};
LINK_ENTITY_TO_CLASS( logic_generator, CGenerator );
void CGenerator :: Spawn()
{
if(pev->button == RANDOM_MODE || pev->button == RANDOM_MODE_WITH_DEC)
{ //set delay with decceleration
if (!m_flDelay || pev->button == RANDOM_MODE_WITH_DEC) m_flDelay = 0.005;
//generate max count automaticallly, if not set on map
if (!m_iMaxFireCount) m_iMaxFireCount = RANDOM_LONG(100, 200);
}
else
{
//Smart Field System <20>
if (!m_iMaxFireCount) m_iMaxFireCount = -1;//disable counting for normal mode
}
if(pev->spawnflags & SF_START_ON)
{
m_iState = STATE_ON;//initialy off in random mode
SetNextThink(m_flDelay);
}
}
TYPEDESCRIPTION CGenerator :: m_SaveData[] =
{
DEFINE_FIELD( CGenerator, m_iMaxFireCount, FIELD_INTEGER ),
DEFINE_FIELD( CGenerator, m_iFireCount, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CGenerator, CBaseLogic );
void CGenerator :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "maxcount"))
{
m_iMaxFireCount = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
if (FStrEq(pkvd->szKeyName, "mode"))
{
pev->button = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void CGenerator :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_TOGGLE)
{
if(m_iState) useType = USE_OFF;
else useType = USE_ON;
}
if (useType == USE_ON)
{
if(pev->button == RANDOM_MODE || pev->button == RANDOM_MODE_WITH_DEC)
{
if(pev->button == RANDOM_MODE_WITH_DEC) m_flDelay = 0.005;
m_iFireCount = RANDOM_LONG(0, m_iMaxFireCount/2);
}
m_iState = STATE_ON;
SetNextThink( 0 );//immediately start firing targets
}
else if (useType == USE_OFF)
{
m_iState = STATE_OFF;
DontThink();
}
else if (useType == USE_SET) //set max count of impulses
m_iMaxFireCount = value;
else if (useType == USE_RESET) //immediately reset
m_iFireCount = 0;
else if (useType == USE_SHOWINFO)
{
ALERT(at_console, "======/Xash Debug System/======\n");
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
ALERT(at_console, "State: %s, Delay time %f\n", GetStringForState( GetState()), m_flDelay);
ALERT(at_console, "FireCount: %d, Max FireCount: %d\n", m_iFireCount, m_iMaxFireCount);
}
}
void CGenerator :: Think( void )
{
if(m_iFireCount != -1)//if counter enabled
{
if(m_iFireCount == m_iMaxFireCount)
{
m_iFireCount = NULL;
DontThink();
m_iState = STATE_OFF;
return;
}
else m_iFireCount++;
}
if(pev->button == RANDOM_MODE_WITH_DEC)
{ //deceleration for random mode
if(m_iMaxFireCount - m_iFireCount < 40) m_flDelay += 0.005;
}
UTIL_FireTargets( pev->target, this, this, USE_TOGGLE );
SetNextThink(m_flDelay);
}
//=======================================================================
// Logic_switcher
//=======================================================================
#define MODE_INCREMENT 0
#define MODE_DECREMENT 1
#define MODE_RANDOM_VALUE 2
class CSwitcher : public CBaseLogic
{
public:
void KeyValue( KeyValueData *pkvd );
void Spawn ( void );
void Think ( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
int m_cTargets;// the total number of targets in this manager's fire list.
int m_index; // Current target
int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array
};
LINK_ENTITY_TO_CLASS( logic_switcher, CSwitcher );
// Global Savedata for switcher
TYPEDESCRIPTION CSwitcher::m_SaveData[] =
{ DEFINE_FIELD( CSwitcher, m_cTargets, FIELD_INTEGER ),
DEFINE_FIELD( CSwitcher, m_index, FIELD_INTEGER ),
DEFINE_ARRAY( CSwitcher, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ),
};IMPLEMENT_SAVERESTORE(CSwitcher, CBaseLogic);
void CSwitcher :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "mode"))
{
pev->button = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if ( m_cTargets < MAX_MULTI_TARGETS )
{
// add this field to the target list
// this assumes that additional fields are targetnames and their values are delay values.
char tmp[128];
UTIL_StripToken( pkvd->szKeyName, tmp );
m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp );
m_cTargets++;
pkvd->fHandled = TRUE;
}
}
void CSwitcher :: Spawn( void )
{
int r_index = 0;
int w_index = m_cTargets - 1;
while(r_index < w_index)
{
//we store target with right index in tempname
int name = m_iTargetName [r_index];
//target with right name is free, record new value from wrong name
m_iTargetName [r_index] = m_iTargetName [w_index];
//ok, we can swap targets
m_iTargetName [w_index] = name;
r_index++;
w_index--;
}
m_iState = STATE_OFF;
m_index = 0;
if(pev->spawnflags & SF_START_ON)
{
m_iState = STATE_ON;
SetNextThink (m_flDelay);
}
}
void CSwitcher :: Think ( void )
{
if(pev->button == MODE_INCREMENT)//increase target number
{
m_index++;
if(m_index >= m_cTargets) m_index = 0;
}
else if(pev->button == MODE_DECREMENT)
{
m_index--;
if(m_index < 0) m_index = m_cTargets - 1;
}
else if(pev->button == MODE_RANDOM_VALUE)
{
m_index = RANDOM_LONG (0, m_cTargets - 1);
}
SetNextThink (m_flDelay);
}
void CSwitcher :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_hActivator = pActivator;
if(IsLockedByMaster( useType )) return;
if (useType == USE_SET)//set new target for activate (direct choose or increment\decrement)
{
if(pev->spawnflags & SF_START_ON)
{
m_iState = STATE_ON;
SetNextThink (m_flDelay);
return;
}
//set maximum priority for direct choose
if(value)
{
m_index = (value - 1);
if(m_index >= m_cTargets) m_index = -1;
return;
}
if(pev->button == MODE_INCREMENT)
{
m_index++;
if(m_index >= m_cTargets) m_index = 0;
}
else if(pev->button == MODE_DECREMENT)//increase target number
{
m_index--;
if(m_index < 0) m_index = m_cTargets - 1;
}
else if(pev->button == MODE_RANDOM_VALUE)
{
m_index = RANDOM_LONG (0, m_cTargets - 1);
}
}
else if (useType == USE_RESET)
{
//reset switcher
m_iState = STATE_OFF;
DontThink();
m_index = 0;
return;
}
else if (useType == USE_SHOWINFO)
{
ALERT(at_console, "======/Xash Debug System/======\n");
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
ALERT(at_console, "State: %s, number of targets %d\n", GetStringForState( GetState()), m_cTargets - 1);
ALERT(at_console, "Current target %s, target number %d\n", STRING(m_iTargetName[ m_index ]), m_index );
}
else if(m_index != -1)//fire any other USE_TYPE and right index
{
UTIL_FireTargets( m_iTargetName[ m_index ], m_hActivator, this, useType, value );
}
}
//=======================================================================
// Logic_counter
//=======================================================================
class CLogicCounter : public CBaseLogic
{
public:
void Spawn( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void KeyValue( KeyValueData *pkvd );
};
LINK_ENTITY_TO_CLASS( logic_counter, CLogicCounter );
void CLogicCounter :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "count"))
{
pev->frags = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
if (FStrEq(pkvd->szKeyName, "maxcount"))
{
pev->body = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void CLogicCounter :: Spawn( void )
{
//Smart Field System <20>
if (pev->frags == 0) pev->frags = 2;
if (pev->body == 0) pev->body = 100;
if (pev->frags == -1) pev->frags = RANDOM_LONG (1, pev->body);
//save number of impulses
pev->impulse = pev->frags;
m_iState = STATE_OFF;//always disable
}
void CLogicCounter :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_SET)
{
if(value) pev->impulse = pev->frags = value; //write new value
else pev->impulse = pev->frags = RANDOM_LONG (1, pev->body);//write random value
}
else if (useType == USE_RESET) pev->frags = pev->impulse; //restore counter to default
else if (useType == USE_SHOWINFO)
{
ALERT(at_console, "======/Xash Debug System/======\n");
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
ALERT(at_console, "start count %d, current count %.f\n",pev->impulse , pev->impulse - pev->frags );
ALERT(at_console, "left activates: %.f\n", pev->frags);
}
else //any other useType
{
pev->frags--;
if(pev->frags > 0) return;
pev->frags = 0; //don't reset counter in negative value
UTIL_FireTargets( pev->target, pActivator, this, useType, value ); //activate target
}
}
//=======================================================================
// Logic_usetype - sorting different usetypes
//=======================================================================
class CLogicUseType : public CBaseLogic
{
public:
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS( logic_usetype, CLogicUseType );
void CLogicUseType::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "toggle"))
{
pev->target = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "enable"))
{
pev->message = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "disable"))
{
pev->netname = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "set"))
{
m_sSet = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "reset"))
{
m_sReset = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void CLogicUseType::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if(IsLockedByMaster( useType )) return;
if(useType == USE_TOGGLE) UTIL_FireTargets(pev->target, pActivator, this, useType, value );
else if (useType == USE_ON) UTIL_FireTargets(pev->message, pActivator, this, useType, value );
else if (useType == USE_OFF) UTIL_FireTargets(pev->netname, pActivator, this, useType, value );
else if (useType == USE_SET) UTIL_FireTargets(m_sSet, pActivator, this, useType, value );
else if (useType == USE_RESET)UTIL_FireTargets(m_sReset, pActivator, this, useType, value );
else if (useType == USE_SHOWINFO)
{
ALERT(at_console, "======/Xash Debug System/======\n");
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
ALERT(at_console, "This entity don't displayed settings!\n" );
SHIFT;
}
}
//=======================================================================
// Logic_scale - apply scale for value
//=======================================================================
class CLogicScale : public CBaseLogic
{
public:
void KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "mode"))
{
pev->impulse = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else CBaseLogic::KeyValue( pkvd );
}
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if (useType == USE_SHOWINFO)
{
DEBUGHEAD;
ALERT(at_console, "Mode %s. Scale %.3f.\n", pev->impulse ? "Bool" : "Float", pev->scale);
SHIFT;
}
else
{
if(pev->impulse == 0)//bool logic
{
if(value >= 0.99)UTIL_FireTargets(pev->target, pActivator, this, USE_ON, 1 );
if(value <= 0.01)UTIL_FireTargets(pev->target, pActivator, this, USE_OFF,0 );
}
if(pev->impulse == 1)//direct scale
UTIL_FireTargets(pev->target, pActivator, this, USE_SET, value * pev->scale );
if(pev->impulse == 2)//inverse sacle
UTIL_FireTargets(pev->target, pActivator, this, USE_SET, pev->scale * (1-value));
}
}
};
LINK_ENTITY_TO_CLASS( logic_scale, CLogicScale);