void CEnvProjectedTexture::Activate( void ) { m_bState = ( ( GetSpawnFlags() & ENV_PROJECTEDTEXTURE_STARTON ) != 0 ); m_bAlwaysUpdate = ( ( GetSpawnFlags() & ENV_PROJECTEDTEXTURE_ALWAYSUPDATE ) != 0 ); SetThink( &CEnvProjectedTexture::InitialThink ); SetNextThink( gpGlobals->curtime + 0.1f ); BaseClass::Activate(); }
// // Causes the door to "do its thing", i.e. start moving, and cascade activation. // int CBaseDoor::DoorActivate() { if( !UTIL_IsMasterTriggered( m_sMaster, m_hActivator ) ) return 0; if( GetSpawnFlags().Any( SF_DOOR_NO_AUTO_RETURN ) && m_toggle_state == TS_AT_TOP ) {// door should close DoorGoDown(); } else {// door should open if( m_hActivator != NULL && m_hActivator->IsPlayer() ) { // give health if player opened the door (medikit) m_hActivator->GiveHealth( m_bHealthValue, DMG_GENERIC ); } // play door unlock sounds PlayLockSounds( this, &m_ls, false, false ); DoorGoUp(); } return 1; }
// lookup a sequence name and setup the target monster to play it bool CCineMonster::StartSequence( CBaseMonster *pTarget, int iszSeq, const bool completeOnEmpty ) { if( !iszSeq && completeOnEmpty ) { SequenceDone( pTarget ); return false; } pTarget->SetSequence( pTarget->LookupSequence( STRING( iszSeq ) ) ); if( pTarget->GetSequence() == -1 ) { ALERT( at_error, "%s: unknown scripted sequence \"%s\"\n", pTarget->GetTargetname(), STRING( iszSeq ) ); pTarget->SetSequence( 0 ); // return false; } #if 0 char *s; if( GetSpawnFlags().Any( SF_SCRIPT_NOINTERRUPT ) ) s = "No"; else s = "Yes"; ALERT( at_console, "%s (%s): started \"%s\":INT:%s\n", pTarget->GetTargetname(), pTarget->GetClassname(), STRING( iszSeq ), s ); #endif pTarget->SetFrame( 0 ); pTarget->ResetSequenceInfo(); return true; }
bool CTalkMonster::FOkToSpeak() const { // if in the grip of a barnacle, don't speak if ( m_MonsterState == MONSTERSTATE_PRONE || m_IdealMonsterState == MONSTERSTATE_PRONE ) { return false; } // if not alive, certainly don't speak if ( GetDeadFlag() != DEAD_NO ) { return false; } // if someone else is talking, don't speak if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) return false; if ( GetSpawnFlags().Any( SF_MONSTER_GAG ) ) return false; // if player is not in pvs, don't speak if( !IsAlive() || !UTIL_FindClientInPVS( this ) ) return false; // don't talk if you're in combat if (m_hEnemy != NULL && FVisible( m_hEnemy )) return false; return true; }
// // Used by SUB_UseTargets, when a door is the target of a button. // void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { m_hActivator = pActivator; // if not ready to be used, ignore "use" command. if( m_toggle_state == TS_AT_BOTTOM || ( GetSpawnFlags().Any( SF_DOOR_NO_AUTO_RETURN ) && m_toggle_state == TS_AT_TOP ) ) DoorActivate(); }
//========================================================= // IdleHello // Try to greet player first time he's seen //========================================================= bool CTalkMonster::FIdleHello() { if (!FOkToSpeak()) return false; // if this is first time scientist has seen player, greet him if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) { // get a player CBaseEntity *pPlayer = FindNearestFriend(true); if (pPlayer) { if (FInViewCone(pPlayer) && FVisible(pPlayer)) { m_hTalkTarget = pPlayer; if ( GetSpawnFlags().Any( SF_MONSTER_PREDISASTER ) ) PlaySentence( m_szGrp[TLK_PHELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); else PlaySentence( m_szGrp[TLK_HELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); SetBits(m_bitsSaid, bit_saidHelloPlayer); return true; } } } return false; }
void CMultiSource::Register( void ) { m_iTotal = 0; memset( m_rgEntities, 0, MS_MAX_TARGETS * sizeof( EHANDLE ) ); SetThink( &CMultiSource::SUB_DoNothing ); // search for all entities which target this multisource (GetTargetname()) CBaseEntity* pTarget = nullptr; while( ( pTarget = UTIL_FindEntityByTarget( pTarget, GetTargetname() ) ) != nullptr && ( m_iTotal < MS_MAX_TARGETS ) ) { m_rgEntities[ m_iTotal++ ] = pTarget; } pTarget = nullptr; while( ( pTarget = UTIL_FindEntityByClassname( pTarget, "multi_manager" ) ) != nullptr && ( m_iTotal < MS_MAX_TARGETS ) ) { if( pTarget->HasTarget( GetTargetname() ) ) m_rgEntities[ m_iTotal++ ] = pTarget; } GetSpawnFlags().ClearFlags( SF_MULTI_INIT ); }
//========================================================= // StartMonster //========================================================= void CSquadMonster :: StartMonster( void ) { CBaseMonster :: StartMonster(); if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() ) { if ( HasNetName() ) { // if I have a groupname, I can only recruit if I'm flagged as leader if ( !GetSpawnFlags().Any( SF_SQUADMONSTER_LEADER ) ) { return; } } // try to form squads now. int iSquadSize = SquadRecruit( 1024, 4 ); if ( iSquadSize ) { ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, GetClassname() ); } if ( IsLeader() && ClassnameIs( "monster_human_grunt" ) ) { SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack SetSkin( 0 ); } } }
void CTalkMonster :: FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // Don't allow use during a scripted_sentence if ( m_useTime > gpGlobals->time ) return; if ( pCaller != NULL && pCaller->IsPlayer() ) { // Pre-disaster followers can't be used if ( GetSpawnFlags().Any( SF_MONSTER_PREDISASTER ) ) { DeclineFollowing(); } else if ( CanFollow() ) { LimitFollowers( pCaller , 1 ); if ( m_afMemory & bits_MEMORY_PROVOKED ) ALERT( at_console, "I'm not following you, you evil person!\n" ); else { StartFollowing( pCaller ); SetBits(m_bitsSaid, bit_saidHelloPlayer); // Don't say hi after you've started following } } else { StopFollowing( true ); } } }
void CCineMonster::Spawn( void ) { // SetSolidType( SOLID_TRIGGER ); // SetSize( Vector(-8, -8, -8), Vector(8, 8, 8)); SetSolidType( SOLID_NOT ); // REMOVE: The old side-effect #if 0 if( m_iszIdle ) m_fMoveTo = 4; #endif // if no targetname, start now if( !HasTargetname() || !FStringNull( m_iszIdle ) ) { SetThink( &CCineMonster::CineThink ); SetNextThink( gpGlobals->time + 1.0 ); // Wait to be used? if( HasTargetname() ) m_startTime = gpGlobals->time + 1E6; } if( GetSpawnFlags().Any( SF_SCRIPT_NOINTERRUPT ) ) m_interruptable = false; else m_interruptable = true; }
void CBaseDoor::Spawn() { Precache(); SetMovedir( this ); if( GetSkin() == 0 ) {//normal door if( GetSpawnFlags().Any( SF_DOOR_PASSABLE ) ) SetSolidType( SOLID_NOT ); else SetSolidType( SOLID_BSP ); } else {// special contents SetSolidType( SOLID_NOT ); GetSpawnFlags().AddFlags( SF_DOOR_SILENT ); // water is silent for now } SetMoveType( MOVETYPE_PUSH ); SetAbsOrigin( GetAbsOrigin() ); SetModel( GetModelName() ); if( GetSpeed() == 0 ) SetSpeed( 100 ); m_vecPosition1 = GetAbsOrigin(); // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big m_vecPosition2 = m_vecPosition1 + ( GetMoveDir() * ( fabs( GetMoveDir().x * ( GetBounds().x - 2 ) ) + fabs( GetMoveDir().y * ( GetBounds().y - 2 ) ) + fabs( GetMoveDir().z * ( GetBounds().z - 2 ) ) - m_flLip ) ); ASSERTSZ( m_vecPosition1 != m_vecPosition2, "door start/end positions are equal" ); if( GetSpawnFlags().Any( SF_DOOR_START_OPEN ) ) { // swap pos1 and pos2, put door at pos2 SetAbsOrigin( m_vecPosition2 ); m_vecPosition2 = m_vecPosition1; m_vecPosition1 = GetAbsOrigin(); } m_toggle_state = TS_AT_BOTTOM; // if the door is flagged for USE button activation only, use NULL touch function if( GetSpawnFlags().Any( SF_DOOR_USE_ONLY ) ) { SetTouch( NULL ); } else // touchable button SetTouch( &CBaseDoor::DoorTouch ); }
// // Starts the door going to its "up" position (simply ToggleData->vecPosition2). // void CBaseDoor::DoorGoUp( void ) { entvars_t *pevActivator; // It could be going-down, if blocked. ASSERT( m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN ); // emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't // filter them out and leave a client stuck with looping door sounds! if( !GetSpawnFlags().Any( SF_DOOR_SILENT ) ) { if( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN ) EMIT_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseMoving ), 1, ATTN_NORM ); } m_toggle_state = TS_GOING_UP; SetMoveDone( &CBaseDoor::DoorHitTop ); if( ClassnameIs( "func_door_rotating" ) ) // !!! BUGBUG Triggered doors don't work with this yet { float sign = 1.0; if( m_hActivator != NULL ) { pevActivator = m_hActivator->pev; if( !GetSpawnFlags().Any( SF_DOOR_ONEWAY ) && GetMoveDir().y ) // Y axis rotation, move away from the player { Vector vec = pevActivator->origin - GetAbsOrigin(); Vector angles = pevActivator->angles; angles.x = 0; angles.z = 0; UTIL_MakeVectors( angles ); // Vector vnext = (pevToucher->origin + (pevToucher->velocity * 10)) - GetAbsOrigin(); UTIL_MakeVectors( pevActivator->angles ); Vector vnext = ( pevActivator->origin + ( gpGlobals->v_forward * 10 ) ) - GetAbsOrigin(); if( ( vec.x*vnext.y - vec.y*vnext.x ) < 0 ) sign = -1.0; } } AngularMove( m_vecAngle2*sign, GetSpeed() ); } else LinearMove( m_vecPosition2, GetSpeed() ); }
void CMultiSource::Spawn() { // set up think for later registration SetSolidType( SOLID_NOT ); SetMoveType( MOVETYPE_NONE ); SetNextThink( gpGlobals->time + 0.1 ); GetSpawnFlags() |= SF_MULTI_INIT; // Until it's initialized SetThink( &CMultiSource::Register ); }
void CEnvProjectedTexture::Activate( void ) { if ( GetSpawnFlags() & ENV_PROJECTEDTEXTURE_STARTON ) { m_bState = true; } SetThink( &CEnvProjectedTexture::InitialThink ); SetNextThink( gpGlobals->curtime + 0.1f ); BaseClass::Activate(); }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CInfoGameEventProxy::Spawn() { BaseClass::Spawn(); m_flRange *= 12.0f; // Convert feet to inches if( GetSpawnFlags() & SF_GAME_EVENT_PROXY_AUTO_VISIBILITY ) { VisibilityMonitor_AddEntity( this, m_flRange, &CInfoGameEventProxy::GameEventProxyCallback, NULL ); } }
void CDeferredLightGlobal::Activate() { BaseClass::Activate(); SetSolid( SOLID_NONE ); SetMoveType( MOVETYPE_NONE ); AddEffects( EF_NODRAW ); m_iDefFlags = GetSpawnFlags(); m_vecColor_Diff.GetForModify() = stringColToVec( STRING( m_str_Diff ) ); m_vecColor_Ambient_High.GetForModify() = stringColToVec( STRING( m_str_Ambient_High ) ); m_vecColor_Ambient_Low.GetForModify() = stringColToVec( STRING( m_str_Ambient_Low ) ); }
// // The door has reached the "up" position. Either go back down, or wait for another activation. // void CBaseDoor::DoorHitTop( void ) { if( !GetSpawnFlags().Any( SF_DOOR_SILENT ) ) { STOP_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseMoving ) ); EMIT_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseArrived ), 1, ATTN_NORM ); } ASSERT( m_toggle_state == TS_GOING_UP ); m_toggle_state = TS_AT_TOP; // toggle-doors don't come down automatically, they wait for refire. if( GetSpawnFlags().Any( SF_DOOR_NO_AUTO_RETURN ) ) { // Re-instate touch method, movement is complete if( !GetSpawnFlags().Any( SF_DOOR_USE_ONLY ) ) SetTouch( &CBaseDoor::DoorTouch ); } else { // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open SetNextThink( GetLastThink() + m_flWait ); SetThink( &CBaseDoor::DoorGoDown ); if( m_flWait == -1 ) { SetNextThink( -1 ); } } // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target if( HasNetName() && GetSpawnFlags().Any( SF_DOOR_START_OPEN ) ) FireTargets( GetNetName(), m_hActivator, this, USE_TOGGLE, 0 ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished }
//----------------------------------------------------------------------------- // Purpose: Sets default member values when spawning. //----------------------------------------------------------------------------- void CASWEnvShake::Spawn( void ) { SetSolid( SOLID_NONE ); SetMoveType( MOVETYPE_NONE ); if ( GetSpawnFlags() & SF_ASW_SHAKE_EVERYONE ) { m_Radius = 0; } if ( HasSpawnFlags( SF_ASW_SHAKE_NO_VIEW ) && !HasSpawnFlags( SF_ASW_SHAKE_PHYSICS ) && !HasSpawnFlags( SF_ASW_SHAKE_ROPES ) ) { DevWarning( "env_shake %s with \"Don't shake view\" spawnflag set without \"Shake physics\" or \"Shake ropes\" spawnflags set.", GetDebugName() ); } }
void CDeferredLight::Activate() { BaseClass::Activate(); SetSolid( SOLID_NONE ); AddEffects( EF_NODRAW ); m_iDefFlags = GetSpawnFlags(); m_bShouldTransmit = GetParent() != NULL || Q_strlen( GetEntityNameAsCStr() ) > 0; SetMoveType( (GetParent() != NULL) ? MOVETYPE_PUSH : MOVETYPE_NONE ); DispatchUpdateTransmitState(); const char *pszCookie = STRING( m_str_CookieString ); if ( m_iDefFlags & DEFLIGHT_COOKIE_ENABLED && pszCookie != NULL && Q_strlen( pszCookie ) > 0 ) m_iCookieIndex = GetDeferredManager()->AddCookieTexture( pszCookie ); else m_iCookieIndex = 0; Assert( m_iCookieIndex >= 0 && m_iCookieIndex < MAX_COOKIE_TEXTURES ); m_vecColor_Diff.GetForModify() = stringColToVec( STRING( m_str_Diff ) ); m_vecColor_Ambient.GetForModify() = stringColToVec( STRING( m_str_Ambient ) ); if ( !m_bShouldTransmit ) { if ( m_iDefFlags & DEFLIGHT_ENABLED && ( m_vecColor_Diff.Get().LengthSqr() > 0 || m_vecColor_Ambient.Get().LengthSqr() > 0 ) && m_flSpotConeOuter > 0.01f && m_flRadius > 0 ) { GetDeferredManager()->AddWorldLight( this ); } else AssertMsg( 0, "I'm turned off and nobody can turn me on :(" ); UTIL_Remove( this ); } else { UpdateSize(); } }
// // Starts the door going to its "down" position (simply ToggleData->vecPosition1). // void CBaseDoor::DoorGoDown( void ) { if( !GetSpawnFlags().Any( SF_DOOR_SILENT ) ) { if( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN ) EMIT_SOUND( this, CHAN_STATIC, ( char* ) STRING( pev->noiseMoving ), 1, ATTN_NORM ); } #ifdef DOOR_ASSERT ASSERT( m_toggle_state == TS_AT_TOP ); #endif // DOOR_ASSERT m_toggle_state = TS_GOING_DOWN; SetMoveDone( &CBaseDoor::DoorHitBottom ); if( ClassnameIs( "func_door_rotating" ) )//rotating door AngularMove( m_vecAngle1, GetSpeed() ); else LinearMove( m_vecPosition1, GetSpeed() ); }
//========================================================= // SequenceDone - called when a scripted sequence animation // sequence is done playing ( or when an AI Scripted Sequence // doesn't supply an animation sequence to play ). Expects // the CBaseMonster pointer to the monster that the sequence // possesses. //========================================================= void CCineMonster::SequenceDone( CBaseMonster *pMonster ) { //ALERT( at_aiconsole, "Sequence %s finished\n", STRING( m_pCine->m_iszPlay ) ); if( !GetSpawnFlags().Any( SF_SCRIPT_REPEATABLE ) ) { SetThink( &CCineMonster::SUB_Remove ); SetNextThink( gpGlobals->time + 0.1 ); } // This is done so that another sequence can take over the monster when triggered by the first pMonster->CineCleanup(); FixScriptMonsterSchedule( pMonster ); // This may cause a sequence to attempt to grab this guy NOW, so we have to clear him out // of the existing sequence SUB_UseTargets( NULL, USE_TOGGLE, 0 ); }
void CTriggerPush::Spawn() { Vector vecAngles = GetAbsAngles(); if( vecAngles == g_vecZero ) { vecAngles.y = 360; SetAbsAngles( vecAngles ); } InitTrigger(); if( GetSpeed() == 0 ) SetSpeed( 100 ); if( GetSpawnFlags().Any( SF_TRIGGER_PUSH_START_OFF ) )// if flagged to Start Turned Off, make trigger nonsolid. SetSolidType( SOLID_NOT ); SetUse( &CTriggerPush::ToggleUse ); SetAbsOrigin( GetAbsOrigin() ); // Link into the list }
void CNPC_BaseTurret::Spawn() { Precache( ); SetNextThink( gpGlobals->curtime + 1 ); SetMoveType( MOVETYPE_FLY ); SetSequence( 0 ); SetCycle( 0 ); SetSolid( SOLID_BBOX ); AddSolidFlags( FSOLID_NOT_STANDABLE ); m_takedamage = DAMAGE_YES; AddFlag( FL_AIMTARGET ); AddFlag( FL_NPC ); SetUse( &CNPC_BaseTurret::TurretUse ); if (( m_spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) && !( m_spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) { m_iAutoStart = true; } ResetSequenceInfo( ); SetBoneController(0, 0); SetBoneController(1, 0); m_flFieldOfView = VIEW_FIELD_FULL; m_bloodColor = DONT_BLEED; m_flDamageTime = 0; if ( GetSpawnFlags() & SF_MONSTER_TURRET_STARTINACTIVE ) { SetTurretAnim( TURRET_ANIM_RETIRE ); SetCycle( 0.0f ); m_flPlaybackRate = 0.0f; } }
void CBubbling::Spawn( void ) { Precache(); SetModel( GetModelName() ); // Set size SetSolidType( SOLID_NOT ); // Remove model & collisions SetRenderAmount( 0 ); // The engine won't draw this model if this is set to 0 and blending is on SetRenderMode( kRenderTransTexture ); int speed = fabs( GetSpeed() ); // HACKHACK!!! - Speed in rendercolor SetRenderColor( Vector( speed >> 8, speed & 255, ( GetSpeed() < 0 ) ? 1 : 0 ) ); if( !GetSpawnFlags().Any( SF_BUBBLES_STARTOFF ) ) { SetThink( &CBubbling::FizzThink ); SetNextThink( gpGlobals->time + 2.0 ); m_state = true; } else m_state = false; }
void CTriggerPush::Touch( CBaseEntity *pOther ) { // UNDONE: Is there a better way than health to detect things that have physics? (clients/monsters) switch( pOther->GetMoveType() ) { case MOVETYPE_NONE: case MOVETYPE_PUSH: case MOVETYPE_NOCLIP: case MOVETYPE_FOLLOW: return; default: break; } if( pOther->GetSolidType() != SOLID_NOT && pOther->GetSolidType() != SOLID_BSP ) { // Instant trigger, just transfer velocity and remove if( GetSpawnFlags().Any( SF_TRIG_PUSH_ONCE ) ) { pOther->SetAbsVelocity( pOther->GetAbsVelocity() + ( GetSpeed() * GetMoveDir() ) ); if( pOther->GetAbsVelocity().z > 0 ) pOther->GetFlags().ClearFlags( FL_ONGROUND ); UTIL_Remove( this ); } else { // Push field, transfer to base velocity Vector vecPush = ( GetSpeed() * GetMoveDir() ); if( pOther->GetFlags().Any( FL_BASEVELOCITY ) ) vecPush = vecPush + pOther->GetBaseVelocity(); pOther->SetBaseVelocity( vecPush ); pOther->GetFlags() |= FL_BASEVELOCITY; // ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); } } }
bool CMultiSource::IsTriggered( const CBaseEntity* const ) const { // Is everything triggered? int i = 0; // Still initializing? if( GetSpawnFlags().Any( SF_MULTI_INIT ) ) return false; while( i < m_iTotal ) { if( m_rgTriggered[ i ] == 0 ) break; i++; } if( i == m_iTotal ) { if( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) return true; } return false; }
//========================================================= // SelectSchedule - Decides which type of schedule best suits // the monster's current state and conditions. Then calls // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= int CNPC_HL1Barney::SelectSchedule( void ) { if ( m_NPCState == NPC_STATE_COMBAT || GetEnemy() != NULL ) { // Priority action! if (!m_fGunDrawn ) return SCHED_ARM_WEAPON; } if ( GetFollowTarget() == NULL ) { if ( HasCondition( COND_PLAYER_PUSHING ) && !(GetSpawnFlags() & SF_NPC_PREDISASTER ) ) // Player wants me to move return SCHED_HL1TALKER_FOLLOW_MOVE_AWAY; } if ( BehaviorSelectSchedule() ) return BaseClass::SelectSchedule(); if ( HasCondition( COND_HEAR_DANGER ) ) { CSound *pSound; pSound = GetBestSound(); ASSERT( pSound != NULL ); if ( pSound && pSound->IsSoundType( SOUND_DANGER ) ) return SCHED_TAKE_COVER_FROM_BEST_SOUND; } if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToSpeak() ) { Speak( BA_KILL ); } switch( m_NPCState ) { case NPC_STATE_COMBAT: { // dead enemy if ( HasCondition( COND_ENEMY_DEAD ) ) return BaseClass::SelectSchedule(); // call base class, all code to handle dead enemies is centralized there. // always act surprized with a new enemy if ( HasCondition( COND_NEW_ENEMY ) && HasCondition( COND_LIGHT_DAMAGE) ) return SCHED_SMALL_FLINCH; if ( HasCondition( COND_HEAVY_DAMAGE ) ) return SCHED_TAKE_COVER_FROM_ENEMY; if ( !HasCondition(COND_SEE_ENEMY) ) { // we can't see the enemy if ( !HasCondition(COND_ENEMY_OCCLUDED) ) { // enemy is unseen, but not occluded! // turn to face enemy return SCHED_COMBAT_FACE; } else { return SCHED_CHASE_ENEMY; } } } break; case NPC_STATE_ALERT: case NPC_STATE_IDLE: if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) ) { // flinch if hurt return SCHED_SMALL_FLINCH; } if ( GetEnemy() == NULL && GetFollowTarget() ) { if ( !GetFollowTarget()->IsAlive() ) { // UNDONE: Comment about the recently dead player here? StopFollowing(); break; } else { return SCHED_TARGET_FACE; } } // try to say something about smells TrySmellTalk(); break; } return BaseClass::SelectSchedule(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CASWEnvShake::ApplyShake( ShakeCommand_t command ) { if ( !HasSpawnFlags( SF_ASW_SHAKE_NO_VIEW ) ) { bool air = (GetSpawnFlags() & SF_ASW_SHAKE_INAIR) ? true : false; UTIL_ASW_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_ROPES ) { CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(), Frequency() ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_PHYSICS ) { if ( !m_pShakeController ) { m_pShakeController = physenv->CreateMotionController( &m_shakeCallback ); } // do physics shake switch( command ) { case SHAKE_START: { m_stopTime = gpGlobals->curtime + Duration(); m_nextShake = 0; m_pShakeController->ClearObjects(); SetNextThink( gpGlobals->curtime ); m_currentAmp = Amplitude(); CBaseEntity *list[1024]; float radius = Radius(); // probably checked "Shake Everywhere" do a big radius if ( !radius ) { radius = MAX_COORD_INTEGER; } Vector extents = Vector(radius, radius, radius); Vector mins = GetAbsOrigin() - extents; Vector maxs = GetAbsOrigin() + extents; int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 ); for ( int i = 0; i < count; i++ ) { // // Only shake physics entities that players can see. This is one frame out of date // so it's possible that we could miss objects if a player changed PVS this frame. // if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) ) { IPhysicsObject *pPhys = list[i]->VPhysicsGetObject(); if ( pPhys && pPhys->IsMoveable() ) { m_pShakeController->AttachObject( pPhys, false ); pPhys->Wake(); } } } } break; case SHAKE_STOP: m_pShakeController->ClearObjects(); break; case SHAKE_AMPLITUDE: m_currentAmp = Amplitude(); case SHAKE_FREQUENCY: m_pShakeController->WakeObjects(); break; } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pMapData - //----------------------------------------------------------------------------- int CNodeEnt::Spawn( const char *pMapData ) { m_NodeData.strEntityName = GetEntityName(); m_NodeData.vecPosition = GetAbsOrigin(); m_NodeData.nNodeID = NO_NODE; if ( m_NodeData.minState == NPC_STATE_NONE ) m_NodeData.minState = NPC_STATE_IDLE; if ( m_NodeData.maxState == NPC_STATE_NONE ) m_NodeData.maxState = NPC_STATE_COMBAT; // --------------------------------------------------------------------------------- // If just a hint node (not used for navigation) just create a hint and bail // --------------------------------------------------------------------------------- if (FClassnameIs( this, "info_hint" )) { if (m_NodeData.nHintType) { CAI_HintManager::CreateHint( &m_NodeData, pMapData ); } else { Warning("info_hint (HammerID: %d, position (%.2f, %.2f, %.2f)) with no hint type.\n", m_NodeData.nWCNodeID, m_NodeData.vecPosition.x, m_NodeData.vecPosition.y, m_NodeData.vecPosition.z ); } UTIL_RemoveImmediate( this ); return -1; } // --------------------------------------------------------------------------------- // First check if this node has a hint. If so create a hint entity // --------------------------------------------------------------------------------- CAI_Hint *pHint = NULL; if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) ) { if ( m_NodeData.nHintType || m_NodeData.strGroup != NULL_STRING || m_NodeData.strEntityName != NULL_STRING ) { m_NodeData.nNodeID = m_nNodeCount; pHint = CAI_HintManager::CreateHint( &m_NodeData, pMapData ); pHint->AddSpawnFlags( GetSpawnFlags() ); } } // --------------------------------------------------------------------------------- // If we loaded from disk, we can discard all these node ents as soon as they spawn // unless we are in WC edited mode // --------------------------------------------------------------------------------- if ( g_pAINetworkManager->NetworksLoaded() && !engine->IsInEditMode()) { // If hint exists for this node, set it if (pHint) { CAI_Node *pNode = g_pBigAINet->GetNode(m_nNodeCount); if (pNode) pNode->SetHint( pHint ); else { DevMsg("AI node graph corrupt\n"); } } m_nNodeCount++; UTIL_RemoveImmediate( this ); return -1; } else { m_nNodeCount++; } // --------------------------------------------------------------------------------- // Add a new node to the network // --------------------------------------------------------------------------------- // For now just using one big AI network CAI_Node *new_node = g_pBigAINet->AddNode( GetAbsOrigin(), GetAbsAngles().y ); new_node->SetHint( pHint ); // ------------------------------------------------------------------------- // Update table of how each WC id relates to each engine ID // ------------------------------------------------------------------------- if (g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable) { g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[new_node->GetId()] = m_NodeData.nWCNodeID; } // Keep track of largest index used by WC if (g_pAINetworkManager->GetEditOps()->m_nNextWCIndex <= m_NodeData.nWCNodeID) { g_pAINetworkManager->GetEditOps()->m_nNextWCIndex = m_NodeData.nWCNodeID+1; } // ------------------------------------------------------------------------- // If in WC edit mode: // Remember the original positions of the nodes before // they drop so we can send the undropped positions to wc. // ------------------------------------------------------------------------- if (engine->IsInEditMode()) { if (g_pAINetworkManager->GetEditOps()->m_pWCPosition) { g_pAINetworkManager->GetEditOps()->m_pWCPosition[new_node->GetId()] = new_node->GetOrigin(); } } if (FClassnameIs( this, "info_node_air" ) || FClassnameIs( this, "info_node_air_hint" )) { new_node->SetType( NODE_AIR ); } else if (FClassnameIs( this, "info_node_climb" )) { new_node->SetType( NODE_CLIMB ); } else { new_node->SetType( NODE_GROUND ); } new_node->m_eNodeInfo = ( m_spawnflags << NODE_ENT_FLAGS_SHIFT ); // If changed as part of WC editing process note that network must be rebuilt if (m_debugOverlays & OVERLAY_WC_CHANGE_ENTITY) { g_pAINetworkManager->GetEditOps()->SetRebuildFlags(); new_node->m_eNodeInfo |= bits_NODE_WC_CHANGED; // Initialize the new nodes position. The graph may not be rebuild // right away but the node should at least be positioned correctly g_AINetworkBuilder.InitNodePosition( g_pBigAINet, new_node ); } UTIL_RemoveImmediate( this ); return -1; }
//========================================================= // FIdleSpeak // ask question of nearby friend, or make statement //========================================================= bool CTalkMonster::FIdleSpeak() { // try to start a conversation, or make statement const char *szIdleGroup; const char *szQuestionGroup; float duration; if (!FOkToSpeak()) return false; // set idle groups based on pre/post disaster if ( GetSpawnFlags().Any( SF_MONSTER_PREDISASTER ) ) { szIdleGroup = m_szGrp[TLK_PIDLE]; szQuestionGroup = m_szGrp[TLK_PQUESTION]; // set global min delay for next conversation duration = RANDOM_FLOAT(4.8, 5.2); } else { szIdleGroup = m_szGrp[TLK_IDLE]; szQuestionGroup = m_szGrp[TLK_QUESTION]; // set global min delay for next conversation duration = RANDOM_FLOAT(2.8, 3.2); } /*int pitch = */GetVoicePitch(); // player using this entity is alive and wounded? CBaseEntity *pTarget = m_hTargetEnt; if ( pTarget != NULL ) { if ( pTarget->IsPlayer() ) { if ( pTarget->IsAlive() ) { m_hTalkTarget = m_hTargetEnt; if (!FBitSet(m_bitsSaid, bit_saidDamageHeavy) && (m_hTargetEnt->GetHealth() <= m_hTargetEnt->GetMaxHealth() / 8)) { //EMIT_SOUND_DYN( this, CHAN_VOICE, m_szGrp[TLK_PLHURT3], 1.0, ATTN_IDLE, 0, pitch); PlaySentence( m_szGrp[TLK_PLHURT3], duration, VOL_NORM, ATTN_IDLE ); SetBits(m_bitsSaid, bit_saidDamageHeavy); return true; } else if (!FBitSet(m_bitsSaid, bit_saidDamageMedium) && (m_hTargetEnt->GetHealth() <= m_hTargetEnt->GetMaxHealth() / 4)) { //EMIT_SOUND_DYN( this, CHAN_VOICE, m_szGrp[TLK_PLHURT2], 1.0, ATTN_IDLE, 0, pitch); PlaySentence( m_szGrp[TLK_PLHURT2], duration, VOL_NORM, ATTN_IDLE ); SetBits(m_bitsSaid, bit_saidDamageMedium); return true; } else if (!FBitSet(m_bitsSaid, bit_saidDamageLight) && (m_hTargetEnt->GetHealth() <= m_hTargetEnt->GetMaxHealth() / 2)) { //EMIT_SOUND_DYN( this, CHAN_VOICE, m_szGrp[TLK_PLHURT1], 1.0, ATTN_IDLE, 0, pitch); PlaySentence( m_szGrp[TLK_PLHURT1], duration, VOL_NORM, ATTN_IDLE ); SetBits(m_bitsSaid, bit_saidDamageLight); return true; } } else { //!!!KELLY - here's a cool spot to have the talkmonster talk about the dead player if we want. // "Oh dear, Gordon Freeman is dead!" -Scientist // "Damn, I can't do this without you." -Barney } } } { // if there is a friend nearby to speak to, play sentence, set friend's response time, return CBaseEntity *pFriend = FindNearestFriend( false ); if( pFriend && !( pFriend->IsMoving() ) && ( RANDOM_LONG( 0, 99 ) < 75 ) ) { PlaySentence( szQuestionGroup, duration, VOL_NORM, ATTN_IDLE ); //SENTENCEG_PlayRndSz( this, szQuestionGroup, 1.0, ATTN_IDLE, 0, pitch ); // force friend to answer CTalkMonster *pTalkMonster = ( CTalkMonster * ) pFriend; m_hTalkTarget = pFriend; pTalkMonster->SetAnswerQuestion( this ); // UNDONE: This is EVIL!!! pTalkMonster->m_flStopTalkTime = m_flStopTalkTime; m_nSpeak++; return true; } } // otherwise, play an idle statement, try to face client when making a statement. if ( RANDOM_LONG(0,1) ) { //SENTENCEG_PlayRndSz( this, szIdleGroup, 1.0, ATTN_IDLE, 0, pitch ); CBaseEntity *pFriend = FindNearestFriend(true); if ( pFriend ) { m_hTalkTarget = pFriend; PlaySentence( szIdleGroup, duration, VOL_NORM, ATTN_IDLE ); m_nSpeak++; return true; } } // didn't speak Talk( 0 ); CTalkMonster::g_talkWaitTime = 0; return false; }