diff --git a/dlls/gearbox/nuclearbomb.cpp b/dlls/gearbox/nuclearbomb.cpp index 573534c7..5c482aff 100644 --- a/dlls/gearbox/nuclearbomb.cpp +++ b/dlls/gearbox/nuclearbomb.cpp @@ -22,322 +22,246 @@ #include "items.h" #include "gamerules.h" -#define SF_BUTTON_DONTMOVE 1 -#define SF_ROTBUTTON_NOTSOLID 1 -#define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated -#define SF_BUTTON_SPARK_IF_OFF 64 // button sparks in OFF state -#define SF_BUTTON_TOUCH_ONLY 256 // button only fires as a result of USE key. - //========================================================= // Nuclear bomb //========================================================= -#define NUKE_CLASSNAME_BUTTON "item_nuclearbomb_button" -#define NUKE_CLASSNAME_TIMER "item_nuclearbomb_timer" - -#define NUKE_MODEL_BUTTON "models/nuke_button.mdl" -#define NUKE_MODEL_CASE "models/nuke_case.mdl" -#define NUKE_MODEL_TIMER "models/nuke_timer.mdl" - -#define NUKE_MIN_HEAR_DIST 192 - -//---------------------------------------------- -// Nuke button -//---------------------------------------------- -class CNukeButton : public CBaseAnimating +class CNuclearBombTimer : public CBaseEntity { public: - void Spawn(void); - void Precache(void); + void Precache(); + void Spawn(); + void EXPORT NuclearBombTimerThink(); + void SetNuclearBombTimer(bool on); + int ObjectCaps() {return FCAP_DONT_SAVE;} + + BOOL bPlayBombSound; + BOOL bBombSoundPlaying; }; -LINK_ENTITY_TO_CLASS(item_nuclearbomb_button, CNukeButton); +LINK_ENTITY_TO_CLASS(item_nuclearbombtimer, CNuclearBombTimer) -void CNukeButton::Spawn(void) +void CNuclearBombTimer::Precache() { - Precache(); - SET_MODEL(ENT(pev), "models/nuke_button.mdl"); + PRECACHE_MODEL("models/nuke_timer.mdl"); + PRECACHE_SOUND("common/nuke_ticking.wav"); +} +void CNuclearBombTimer::Spawn() +{ + Precache(); + SET_MODEL(ENT(pev), "models/nuke_timer.mdl"); + pev->solid = SOLID_NOT; + UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,32)); + pev->movetype = MOVETYPE_NONE; UTIL_SetOrigin(pev, pev->origin); - UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); + if( DROP_TO_FLOOR(ENT( pev ) ) == 0 ) + { + ALERT(at_error, "Nuclear Bomb timer fell out of level at %f,%f,%f\n", pev->origin.x, pev->origin.y, pev->origin.z); + UTIL_Remove( this ); + return; + } + pev->skin = 0; + bPlayBombSound = FALSE; + bBombSoundPlaying = FALSE; } -void CNukeButton::Precache(void) +void CNuclearBombTimer::NuclearBombTimerThink() { - PRECACHE_MODEL("models/nuke_button.mdl"); + if (pev->skin <= 1) + pev->skin++; + else + pev->skin = 0; + if (bPlayBombSound) + { + EMIT_SOUND(ENT(pev), CHAN_BODY, "common/nuke_ticking.wav", 0.75, ATTN_IDLE); + bBombSoundPlaying = TRUE; + } + pev->nextthink = gpGlobals->time + 0.1; } -//---------------------------------------------- -// Nuke timer -//---------------------------------------------- +void CNuclearBombTimer::SetNuclearBombTimer(bool on) +{ + if (on) + { + SetThink(&CNuclearBombTimer::NuclearBombTimerThink); + pev->nextthink = gpGlobals->time; + bPlayBombSound = TRUE; + } + else + { + SetThink(NULL); + pev->nextthink = gpGlobals->time; + pev->skin = 3; + if (bBombSoundPlaying) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "common/nuke_ticking.wav", 0.0, 0.0, SND_STOP, PITCH_NORM); + bBombSoundPlaying = FALSE; + } + } +} -class CNukeTimer : public CBaseAnimating +class CNuclearBombButton : public CBaseEntity { public: - void Spawn(void); - void Precache(void); + void Precache(); + void Spawn(); + void SetNuclearBombButton(bool on); + int ObjectCaps() {return FCAP_DONT_SAVE;} }; -LINK_ENTITY_TO_CLASS(item_nuclearbomb_timer, CNukeTimer); +LINK_ENTITY_TO_CLASS(item_nuclearbombbutton, CNuclearBombButton) -void CNukeTimer::Spawn(void) +void CNuclearBombButton::Precache() { - Precache(); - SET_MODEL(ENT(pev), "models/nuke_timer.mdl"); + PRECACHE_MODEL("models/nuke_button.mdl"); +} +void CNuclearBombButton::Spawn() +{ + Precache(); + SET_MODEL(ENT(pev), "models/nuke_button.mdl"); + pev->solid = SOLID_NOT; + UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,32)); + pev->movetype = MOVETYPE_NONE; UTIL_SetOrigin(pev, pev->origin); - UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); + if( DROP_TO_FLOOR(ENT( pev ) ) == 0 ) + { + ALERT(at_error, "Nuclear Bomb button fell out of level at %f,%f,%f\n", pev->origin.x, pev->origin.y, pev->origin.z); + UTIL_Remove( this ); + return; + } + pev->skin = 0; } -void CNukeTimer::Precache(void) +void CNuclearBombButton::SetNuclearBombButton(bool on) { - PRECACHE_MODEL("models/nuke_timer.mdl"); + pev->skin = 1; } -//---------------------------------------------- -// Nuke case -//---------------------------------------------- -class CNukeCase : public CBaseButton +class CNuclearBomb : public CBaseToggle { public: - - virtual int Save(CSave &save); - virtual int Restore(CRestore &restore); - - static TYPEDESCRIPTION m_SaveData[]; - - void KeyValue(KeyValueData *pkvd); - - void Spawn(void); - void Precache(void); - - void EXPORT StartupThink(void); - void EXPORT CaseThink(void); - - void ButtonActivate(); - - int m_initialstate; - float m_flWait; - float m_flNextTickTime; - BOOL m_fCaseOn; - - EHANDLE m_hNukeButton; - EHANDLE m_hNukeTimer; - - - void TurnOn(void); - void TurnOff(void); + void Precache(); + void Spawn(); + void KeyValue(KeyValueData* pkvd); + void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + int ObjectCaps() {return FCAP_ACROSS_TRANSITION | FCAP_IMPULSE_USE;} + void UpdateOnRemove(); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + BOOL m_fOn; + float m_flLastPush; + int m_iPushCount; + CNuclearBombTimer* m_pTimer; + CNuclearBombButton* m_pButton; }; -LINK_ENTITY_TO_CLASS(item_nuclearbomb, CNukeCase); +LINK_ENTITY_TO_CLASS(item_nuclearbomb, CNuclearBomb) -TYPEDESCRIPTION CNukeCase::m_SaveData[] = +TYPEDESCRIPTION CNuclearBomb::m_SaveData[] = { - DEFINE_FIELD(CNukeCase, m_initialstate, FIELD_INTEGER), - DEFINE_FIELD(CNukeCase, m_flWait, FIELD_FLOAT), - - DEFINE_FIELD(CNukeCase, m_hNukeButton, FIELD_EHANDLE), - DEFINE_FIELD(CNukeCase, m_hNukeTimer, FIELD_EHANDLE), - DEFINE_FIELD(CNukeCase, m_flNextTickTime, FIELD_TIME), - DEFINE_FIELD(CNukeCase, m_fCaseOn, FIELD_BOOLEAN), - + DEFINE_FIELD(CNuclearBomb, m_fOn, FIELD_BOOLEAN), + DEFINE_FIELD(CNuclearBomb, m_flLastPush, FIELD_TIME), + DEFINE_FIELD(CNuclearBomb, m_iPushCount, FIELD_INTEGER), }; -IMPLEMENT_SAVERESTORE(CNukeCase, CBaseButton); +IMPLEMENT_SAVERESTORE(CNuclearBomb, CBaseToggle) -void CNukeCase::KeyValue(KeyValueData* pkvd) +void CNuclearBomb::Precache() { - if (FStrEq(pkvd->szKeyName, "initialstate")) - { - m_initialstate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue(pkvd); + PRECACHE_MODEL("models/nuke_case.mdl"); + UTIL_PrecacheOther("item_nuclearbombtimer"); + UTIL_PrecacheOther("item_nuclearbombbutton"); + PRECACHE_SOUND("buttons/button4.wav"); + PRECACHE_SOUND("buttons/button6.wav"); + + m_pTimer = (CNuclearBombTimer*)Create("item_nuclearbombtimer", pev->origin, pev->angles); + if (m_pTimer) + m_pTimer->SetNuclearBombTimer(m_fOn); + m_pButton = (CNuclearBombButton*)Create("item_nuclearbombbutton", pev->origin, pev->angles); + if (m_pButton) + m_pButton->SetNuclearBombButton(m_fOn); } -void CNukeCase::Spawn(void) +void CNuclearBomb::Spawn() { - // - // Remove touch button flag, so that it will correctly set - // the default "ButtonUse" function pointer in the - // CBaseButton::Spawn function. - // - pev->spawnflags &= ~SF_BUTTON_TOUCH_ONLY; - - // Set toggle spawn flag, to prevent the button - // from returning. - pev->spawnflags |= SF_BUTTON_TOGGLE; - - - // Make the button stay on place. - m_flWait = -1; - - // - // Set model name right now so that it will be precached - // from the CBaseButton::Precache and set from - // the CBaseButton::Spawn function. - // - pev->model = ALLOC_STRING(NUKE_MODEL_CASE); - - // Call CBaseButton (baseclass) spawn function. - CBaseButton::Spawn(); - - pev->movetype = MOVETYPE_FLY; + Precache(); + SET_MODEL(ENT(pev), "models/nuke_case.mdl"); pev->solid = SOLID_BBOX; - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize( pev, Vector(-16, -16, 0), Vector(16, 16, 36) ); - - // Change button sound. - pev->noise = ALLOC_STRING("buttons/button4.wav"); - - // Setup next tick time (to play tick sound). - m_flNextTickTime = gpGlobals->time; - - m_hNukeButton.Set(NULL); - m_hNukeTimer.Set(NULL); - - // Adjust angles. In level editor, the case is 90 degrees in - // counter clockwise (relative to PI). - pev->angles.y = -90; - - SetThink(&CNukeCase::StartupThink); - pev->nextthink = gpGlobals->time + 0.1f; -} - -void CNukeCase::Precache(void) -{ - CBaseButton::Precache(); - - PRECACHE_MODEL(STRING(pev->model)); - - PRECACHE_SOUND( "common/nuke_ticking.wav" ); - - UTIL_PrecacheOther( NUKE_CLASSNAME_BUTTON ); - UTIL_PrecacheOther( NUKE_CLASSNAME_TIMER ); + UTIL_SetOrigin(pev, pev->origin); + UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,32)); + pev->movetype = MOVETYPE_NONE; + if( DROP_TO_FLOOR(ENT( pev ) ) == 0 ) + { + ALERT(at_error, "Nuclear Bomb fell out of level at %f,%f,%f\n", pev->origin.x, pev->origin.y, pev->origin.z); + UTIL_Remove( this ); + return; + } + m_iPushCount = 0; + m_flLastPush = gpGlobals->time; } - -void CNukeCase::StartupThink(void) +void CNuclearBomb::KeyValue(KeyValueData *pkvd) { - pev->nextthink = gpGlobals->time + 0.1f; - - CBaseEntity* pPart = NULL; - - pPart = CBaseEntity::Create(NUKE_CLASSNAME_BUTTON, pev->origin, pev->angles); - - if (pPart) - { - m_hNukeButton = pPart; - - // Adjust angles. In level editor, the case is 90 degrees in - // counter clockwise (relative to PI). - m_hNukeButton->pev->angles.y = -90; - } - else + if( FStrEq( pkvd->szKeyName, "initialstate" ) ) { - ALERT(at_aiconsole, "ERROR: Failed to create entity with classname %s.\n", NUKE_CLASSNAME_BUTTON); + m_fOn = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; } - - pPart = CBaseEntity::Create(NUKE_CLASSNAME_TIMER, pev->origin, pev->angles); - - if (pPart) + else if( FStrEq( pkvd->szKeyName, "wait" ) ) { - m_hNukeTimer = pPart; - - // Adjust angles. In level editor, the case is 90 degrees in - // counter clockwise (relative to PI). - m_hNukeTimer->pev->angles.y = -90; + m_flWait = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; } else - { - ALERT(at_aiconsole, "ERROR: Failed to create entity with classname %s.\n", NUKE_CLASSNAME_TIMER); - } - - TurnOn(); - - SetThink(&CNukeCase::CaseThink); + CBaseToggle::KeyValue(pkvd); } -void CNukeCase::CaseThink(void) +void CNuclearBomb::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { - if (m_fCaseOn) + if ((m_flWait >= 0 || m_iPushCount <= 0) && m_flWait <= gpGlobals->time - m_flLastPush && ShouldToggle(useType, m_fOn)) { - if (m_flNextTickTime < gpGlobals->time) + const char* sound = NULL; + if (m_fOn) { - if ( m_hNukeTimer ) - m_hNukeTimer->pev->skin = ((m_hNukeTimer->pev->skin + 1) % 3); - - CBaseEntity* pPlayer = UTIL_PlayerByIndex( 1 ); - - ASSERT( pPlayer != NULL ); - float volume = 0.0f; - float flDist = (pPlayer->pev->origin - pev->origin).Length(); - - if (flDist <= NUKE_MIN_HEAR_DIST) - { - volume = 1.0f - (flDist / (float)NUKE_MIN_HEAR_DIST); - ALERT(at_console, "Nuclearbomb volume: %f.\n", volume); - } - - EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/nuke_ticking.wav", volume, ATTN_NONE); - m_flNextTickTime = gpGlobals->time + 0.05f; + m_fOn = FALSE; + sound = "buttons/button4.wav"; + } + else + { + m_fOn = TRUE; + sound = "buttons/button6.wav"; + } + EMIT_SOUND(ENT(pev), CHAN_VOICE, sound, VOL_NORM, ATTN_NORM); + SUB_UseTargets(pActivator, USE_TOGGLE, 0); + if (m_pButton) + { + m_pButton->SetNuclearBombButton(m_fOn); + } + if (m_pTimer) + { + m_pTimer->SetNuclearBombTimer(m_fOn); } + m_iPushCount++; + m_flLastPush = gpGlobals->time; } - - pev->nextthink = gpGlobals->time + 0.1f; -} - -void CNukeCase::TurnOn(void) -{ - if (m_hNukeButton) - m_hNukeButton->pev->skin = 1; - - if (m_hNukeTimer) - m_hNukeTimer->pev->skin = 0; - - m_toggle_state = TS_AT_BOTTOM; - - m_flNextTickTime = gpGlobals->time; - m_fCaseOn = TRUE; } -void CNukeCase::TurnOff(void) +void CNuclearBomb::UpdateOnRemove() { - if (m_hNukeButton) - m_hNukeButton->pev->skin = 0; - - if (m_hNukeTimer) - m_hNukeTimer->pev->skin = 3; - - m_toggle_state = TS_AT_TOP; - - m_flNextTickTime = 0.0f; - m_fCaseOn = FALSE; - - STOP_SOUND(ENT(pev), CHAN_ITEM, "common/nuke_ticking.wav"); -} - -// -// Starts the button moving "in/up". -// -void CNukeCase::ButtonActivate(void) -{ - ASSERT(m_toggle_state == TS_AT_BOTTOM); - m_toggle_state = TS_AT_TOP; - - EMIT_SOUND(ENT(pev), CHAN_VOICE, STRING(pev->noise), 1, ATTN_NORM); - - TurnOff(); - - SUB_UseTargets(m_hActivator, USE_TOGGLE, TS_AT_TOP); - - SetThink( NULL ); - SetUse( NULL ); + CBaseToggle::UpdateOnRemove(); + if (m_pTimer) + { + UTIL_Remove(m_pTimer); + m_pTimer = NULL; + } + if (m_pButton) + { + UTIL_Remove(m_pButton); + m_pButton = NULL; + } }