// // This think function will deploy the turret when something comes into range. This is for // automatically activated turrets. // void CBaseTurret::AutoSearchThink(void) { // ensure rethink StudioFrameAdvance( ); pev->nextthink = gpGlobals->time + 0.3; // If we have a target and we're still healthy if (m_hEnemy != NULL) { if (!m_hEnemy->IsAlive() ) m_hEnemy = NULL;// Dead enemy forces a search for new one } // Acquire Target if (m_hEnemy == NULL) { Look( TURRET_RANGE ); m_hEnemy = BestVisibleEnemy(); } if (m_hEnemy != NULL) { SetThink(&CBaseTurret::Deploy); EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); } }
// // This search function will sit with the turret deployed and look for a new target. // After a set amount of time, the barrel will spin down. After m_flMaxWait, the turret will // retact. // void CBaseTurret::SearchThink(void) { // ensure rethink SetTurretAnim(TURRET_ANIM_SPIN); StudioFrameAdvance( ); pev->nextthink = gpGlobals->time + 0.1; if (m_flSpinUpTime == 0 && m_flMaxSpin) m_flSpinUpTime = gpGlobals->time + m_flMaxSpin; Ping( ); // If we have a target and we're still healthy if (m_hEnemy != NULL) { if (!m_hEnemy->IsAlive() ) m_hEnemy = NULL;// Dead enemy forces a search for new one } // Acquire Target if (m_hEnemy == NULL) { Look(TURRET_RANGE); m_hEnemy = BestVisibleEnemy(); } // If we've found a target, spin up the barrel and start to attack if (m_hEnemy != NULL) { m_flLastSight = 0; m_flSpinUpTime = 0; SetThink(&CBaseTurret::ActiveThink); } else { // Are we out of time, do we need to retract? if (gpGlobals->time > m_flLastSight) { //Before we retrace, make sure that we are spun down. m_flLastSight = 0; m_flSpinUpTime = 0; SetThink(&CBaseTurret::Retire); } // should we stop the spin? else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) { SpinDownCall(); } // generic hunt for new victims m_vecGoalAngles.y = (m_vecGoalAngles.y + 0.1 * m_fTurnRate); if (m_vecGoalAngles.y >= 360) m_vecGoalAngles.y -= 360; MoveTurret(); } }
void CLeech::SwitchLeechState( void ) { m_stateTime = gpGlobals->time + RANDOM_FLOAT( 3, 6 ); if ( m_MonsterState == MONSTERSTATE_COMBAT ) { m_hEnemy = NULL; SetState( MONSTERSTATE_IDLE ); // We may be up against the player, so redo the side checks m_sideTime = 0; } else { Look( m_flDistLook ); CBaseEntity *pEnemy = BestVisibleEnemy(); if ( pEnemy && pEnemy->pev->waterlevel != 0 ) { m_hEnemy = pEnemy; SetState( MONSTERSTATE_COMBAT ); m_stateTime = gpGlobals->time + RANDOM_FLOAT( 18, 25 ); AlertSound(); } } }
//========================================================= // Hornet is flying, gently tracking target //========================================================= void CHornet :: TrackTarget ( void ) { Vector vecFlightDir; Vector vecDirToEnemy; float flDelta; StudioFrameAdvance( ); if (gpGlobals->time > m_flStopAttack) { SetTouch( NULL ); SetThink( SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; return; } // UNDONE: The player pointer should come back after returning from another level if ( m_hEnemy == NULL ) {// enemy is dead. Look( 512 ); m_hEnemy = BestVisibleEnemy( ); } if ( m_hEnemy != NULL && FVisible( m_hEnemy )) { m_vecEnemyLKP = m_hEnemy->BodyTarget( GetAbsOrigin() ); } else { m_vecEnemyLKP = m_vecEnemyLKP + GetAbsVelocity() * m_flFlySpeed * 0.1; } vecDirToEnemy = ( m_vecEnemyLKP - GetAbsOrigin() ).Normalize(); if (GetAbsVelocity().Length() < 0.1) vecFlightDir = vecDirToEnemy; else vecFlightDir = GetAbsVelocity().Normalize(); // measure how far the turn is, the wider the turn, the slow we'll go this time. flDelta = DotProduct ( vecFlightDir, vecDirToEnemy ); if ( flDelta < 0.5 ) {// hafta turn wide again. play sound switch (RANDOM_LONG(0,2)) { case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; } } if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED ) {// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. flDelta = 0.25; } SetAbsVelocity(( vecFlightDir + vecDirToEnemy).Normalize() ); if( pev->owner && ( pev->owner->v.flags & FL_MONSTER )) { // random pattern only applies to hornets fired by monsters, not players. Vector vecVelocity = GetAbsVelocity(); vecVelocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit. vecVelocity.y += RANDOM_FLOAT ( -0.10, 0.10 ); vecVelocity.z += RANDOM_FLOAT ( -0.10, 0.10 ); SetAbsVelocity( vecVelocity ); } switch ( m_iHornetType ) { case HORNET_TYPE_RED: SetAbsVelocity( GetAbsVelocity() * ( m_flFlySpeed * flDelta ));// scale the dir by the ( speed * width of turn ) pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); break; case HORNET_TYPE_ORANGE: SetAbsVelocity( GetAbsVelocity() * m_flFlySpeed ); // do not have to slow down to turn. pev->nextthink = gpGlobals->time + 0.1;// fixed think time break; } SetAbsAngles( UTIL_VecToAngles( GetAbsVelocity())); pev->solid = SOLID_BBOX; // if hornet is close to the enemy, jet in a straight line for a half second. // (only in the single player game) if ( m_hEnemy != NULL && !g_pGameRules->IsMultiplayer() ) { if ( flDelta >= 0.4 && ( GetAbsOrigin() - m_vecEnemyLKP ).Length() <= 300 ) { Vector vecOrigin = GetAbsOrigin(); MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); WRITE_BYTE( TE_SPRITE ); WRITE_COORD( vecOrigin.x ); // pos WRITE_COORD( vecOrigin.y ); WRITE_COORD( vecOrigin.z ); WRITE_SHORT( iHornetPuff ); // model // WRITE_BYTE( 0 ); // life * 10 WRITE_BYTE( 2 ); // size * 10 WRITE_BYTE( 128 ); // brightness MESSAGE_END(); switch( RANDOM_LONG( 0, 2 )) { case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM ); break; } SetAbsVelocity( GetAbsVelocity() * 2 ); pev->nextthink = gpGlobals->time + 1.0; // don't attack again m_flStopAttack = gpGlobals->time; } } }
void CNihilanth :: NextActivity( ) { UTIL_MakeAimVectors( pev->angles ); if (m_irritation >= 2) { if (m_pBall == NULL) { m_pBall = CSprite::SpriteCreate( "sprites/tele1.spr", pev->origin, TRUE ); if (m_pBall) { m_pBall->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); m_pBall->SetAttachment( edict(), 1 ); m_pBall->SetScale( 4.0 ); m_pBall->pev->framerate = 10.0; m_pBall->TurnOn( ); } } if (m_pBall) { MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_COORD( 256 ); // radius WRITE_BYTE( 255 ); // R WRITE_BYTE( 192 ); // G WRITE_BYTE( 64 ); // B WRITE_BYTE( 200 ); // life * 10 WRITE_COORD( 0 ); // decay MESSAGE_END(); } } if ((pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2) && m_hRecharger == NULL && m_iLevel <= 9) { char szName[64]; CBaseEntity *pEnt = NULL; CBaseEntity *pRecharger = NULL; float flDist = 8192; sprintf(szName, "%s%d", m_szRechargerTarget, m_iLevel ); while ((pEnt = UTIL_FindEntityByTargetname( pEnt, szName )) != NULL) { float flLocal = (pEnt->pev->origin - pev->origin).Length(); if (flLocal < flDist) { flDist = flLocal; pRecharger = pEnt; } } if (pRecharger) { m_hRecharger = pRecharger; m_posDesired = Vector( pev->origin.x, pev->origin.y, pRecharger->pev->origin.z ); m_vecDesired = (pRecharger->pev->origin - m_posDesired).Normalize( ); m_vecDesired.z = 0; m_vecDesired = m_vecDesired.Normalize(); } else { m_hRecharger = NULL; ALERT( at_aiconsole, "nihilanth can't find %s\n", szName ); m_iLevel++; if (m_iLevel > 9) m_irritation = 2; } } float flDist = (m_posDesired - pev->origin).Length(); float flDot = DotProduct( m_vecDesired, gpGlobals->v_forward ); if (m_hRecharger != NULL) { // at we at power up yet? if (flDist < 128.0) { int iseq = LookupSequence( "recharge" ); if (iseq != pev->sequence) { char szText[64]; sprintf( szText, "%s%d", m_szDrawUse, m_iLevel ); FireTargets( szText, this, this, USE_ON, 1.0 ); ALERT( at_console, "fireing %s\n", szText ); } pev->sequence = LookupSequence( "recharge" ); } else { FloatSequence( ); } return; } if (m_hEnemy != NULL && !m_hEnemy->IsAlive()) { m_hEnemy = NULL; } if (m_flLastSeen + 15 < gpGlobals->time) { m_hEnemy = NULL; } if (m_hEnemy == NULL) { Look( 4096 ); m_hEnemy = BestVisibleEnemy( ); } if (m_hEnemy != NULL && m_irritation != 0) { if (m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0) { if (m_irritation >= 2 && pev->health < gSkillData.nihilanthHealth / 2.0) { pev->sequence = LookupSequence( "attack1_open" ); } else { if (RANDOM_LONG(0, 1 ) == 0) { pev->sequence = LookupSequence( "attack1" ); // zap } else { char szText[64]; sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); if (pTrigger != NULL || pTouch != NULL) { pev->sequence = LookupSequence( "attack2" ); // teleport } else { m_iTeleport++; pev->sequence = LookupSequence( "attack1" ); // zap } } } return; } } FloatSequence( ); }
void CSqueakGrenade::HuntThink( void ) { // ALERT( at_console, "think\n" ); if (!IsInWorld()) { SetTouch( NULL ); UTIL_Remove( this ); return; } StudioFrameAdvance( ); pev->nextthink = gpGlobals->time + 0.1; // explode when ready if (gpGlobals->time >= m_flDie) { g_vecAttackDir = pev->velocity.Normalize( ); pev->health = -1; Killed( pev, 0 ); return; } // float if (pev->waterlevel != 0) { if (pev->movetype == MOVETYPE_BOUNCE) { pev->movetype = MOVETYPE_FLY; } pev->velocity = pev->velocity * 0.9; pev->velocity.z += 8.0; } else if (pev->movetype = MOVETYPE_FLY) { pev->movetype = MOVETYPE_BOUNCE; } // return if not time to hunt if (m_flNextHunt > gpGlobals->time) return; m_flNextHunt = gpGlobals->time + 2.0; CBaseEntity *pOther = NULL; Vector vecDir; TraceResult tr; Vector vecFlat = pev->velocity; vecFlat.z = 0; vecFlat = vecFlat.Normalize( ); UTIL_MakeVectors( pev->angles ); if (m_hEnemy == NULL || !m_hEnemy->IsAlive()) { // find target, bounce a bit towards it. Look( 512 ); m_hEnemy = BestVisibleEnemy( ); } // squeek if it's about time blow up if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) { EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F)); CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); } // higher pitch as squeeker gets closer to detonation time float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); if (flpitch < 80) flpitch = 80; if (m_hEnemy != NULL) { if (FVisible( m_hEnemy )) { vecDir = m_hEnemy->EyePosition() - pev->origin; m_vecTarget = vecDir.Normalize( ); } float flVel = pev->velocity.Length(); float flAdj = 50.0 / (flVel + 10.0); if (flAdj > 1.2) flAdj = 1.2; // ALERT( at_console, "think : enemy\n"); // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); pev->velocity = pev->velocity * flAdj + m_vecTarget * 300; } if (pev->flags & FL_ONGROUND) { pev->avelocity = Vector( 0, 0, 0 ); } else { if (pev->avelocity == Vector( 0, 0, 0)) { pev->avelocity.x = RANDOM_FLOAT( -100, 100 ); pev->avelocity.z = RANDOM_FLOAT( -100, 100 ); } } if ((pev->origin - m_posPrev).Length() < 1.0) { pev->velocity.x = RANDOM_FLOAT( -100, 100 ); pev->velocity.y = RANDOM_FLOAT( -100, 100 ); } m_posPrev = pev->origin; pev->angles = UTIL_VecToAngles( pev->velocity ); pev->angles.z = 0; pev->angles.x = 0; }
//========================================================= // Hornet is flying, gently tracking target //========================================================= void CMHornet :: TrackTarget ( void ) { Vector vecFlightDir; Vector vecDirToEnemy; float flDelta; StudioFrameAdvance( ); if (gpGlobals->time > m_flStopAttack) { SetTouch( NULL ); SetThink( SUB_Remove ); pev->nextthink = gpGlobals->time + 0.1; return; } // UNDONE: The player pointer should come back after returning from another level if ( m_hEnemy == NULL ) {// enemy is dead. Look( 512 ); m_hEnemy = BestVisibleEnemy( ); } if ( m_hEnemy != NULL && UTIL_FVisible( m_hEnemy, ENT(pev) )) { m_vecEnemyLKP = UTIL_BodyTarget( m_hEnemy, pev->origin ); } else { m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1; } vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize(); if (pev->velocity.Length() < 0.1) vecFlightDir = vecDirToEnemy; else vecFlightDir = pev->velocity.Normalize(); // measure how far the turn is, the wider the turn, the slow we'll go this time. flDelta = DotProduct ( vecFlightDir, vecDirToEnemy ); if ( flDelta < 0.5 ) {// hafta turn wide again. play sound switch (RANDOM_LONG(0,2)) { case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; } } if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED ) {// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. flDelta = 0.25; } pev->velocity = ( vecFlightDir + vecDirToEnemy).Normalize(); if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) ) { // random pattern only applies to hornets fired by monsters, not players. pev->velocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit. pev->velocity.y += RANDOM_FLOAT ( -0.10, 0.10 ); pev->velocity.z += RANDOM_FLOAT ( -0.10, 0.10 ); } switch ( m_iHornetType ) { case HORNET_TYPE_RED: pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn ) pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); break; case HORNET_TYPE_ORANGE: pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn. pev->nextthink = gpGlobals->time + 0.1;// fixed think time break; } pev->angles = UTIL_VecToAngles (pev->velocity); pev->solid = SOLID_BBOX; }
void CApache :: HuntThink( void ) { StudioFrameAdvance( ); SetNextThink( 0.1 ); ShowDamage( ); if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target { m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); if (m_pGoalEnt) { m_posDesired = m_pGoalEnt->pev->origin; UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); m_vecGoal = gpGlobals->v_forward; } } // if (m_hEnemy == NULL) { Look( 4092 ); m_hEnemy = BestVisibleEnemy( ); } // generic speed up if (m_flGoalSpeed < 800) m_flGoalSpeed += 5; if (m_hEnemy != NULL) { // ALERT( at_console, "%s\n", STRING( m_hEnemy->pev->classname ) ); if (FVisible( m_hEnemy )) { if (m_flLastSeen < gpGlobals->time - 5) m_flPrevSeen = gpGlobals->time; m_flLastSeen = gpGlobals->time; m_posTarget = m_hEnemy->Center( ); } else { m_hEnemy = NULL; } } m_vecTarget = (m_posTarget - pev->origin).Normalize(); float flLength = (pev->origin - m_posDesired).Length(); if (m_pGoalEnt) { // ALERT( at_console, "%.0f\n", flLength ); if (flLength < 128) { m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_pGoalEnt->pev->target ) ); if (m_pGoalEnt) { m_posDesired = m_pGoalEnt->pev->origin; UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); m_vecGoal = gpGlobals->v_forward; flLength = (pev->origin - m_posDesired).Length(); } } } else { m_posDesired = pev->origin; } if (flLength > 250) // 500 { // float flLength2 = (m_posTarget - pev->origin).Length() * (1.5 - DotProduct((m_posTarget - pev->origin).Normalize(), pev->velocity.Normalize() )); // if (flLength2 < flLength) if (m_flLastSeen + 90 > gpGlobals->time && DotProduct( (m_posTarget - pev->origin).Normalize(), (m_posDesired - pev->origin).Normalize( )) > 0.25) { m_vecDesired = (m_posTarget - pev->origin).Normalize( ); } else { m_vecDesired = (m_posDesired - pev->origin).Normalize( ); } } else { m_vecDesired = m_vecGoal; } Flight( ); // ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->time, m_flLastSeen, m_flPrevSeen ); if ((m_flLastSeen + 1 > gpGlobals->time) && (m_flPrevSeen + 2 < gpGlobals->time)) { if (FireGun( )) { // slow down if we're fireing if (m_flGoalSpeed > 400) m_flGoalSpeed = 400; } // don't fire rockets and gun on easy mode if (g_iSkillLevel == SKILL_EASY) m_flNextRocket = gpGlobals->time + 10.0; } UTIL_MakeAimVectors( pev->angles ); Vector vecEst = (gpGlobals->v_forward * 800 + pev->velocity).Normalize( ); // ALERT( at_console, "%d %d %d %4.2f\n", pev->angles.x < 0, DotProduct( pev->velocity, gpGlobals->v_forward ) > -100, m_flNextRocket < gpGlobals->time, DotProduct( m_vecTarget, vecEst ) ); if ((m_iRockets % 2) == 1) { FireRocket( ); m_flNextRocket = gpGlobals->time + 0.5; if (m_iRockets <= 0) { m_flNextRocket = gpGlobals->time + 10; m_iRockets = 10; } } else if (pev->angles.x < 0 && DotProduct( pev->velocity, gpGlobals->v_forward ) > -100 && m_flNextRocket < gpGlobals->time) { if (m_flLastSeen + 60 > gpGlobals->time) { if (m_hEnemy != NULL) { // make sure it's a good shot if (DotProduct( m_vecTarget, vecEst) > .965) { TraceResult tr; UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, ignore_monsters, edict(), &tr ); if ((tr.vecEndPos - m_posTarget).Length() < 512) FireRocket( ); } } else { TraceResult tr; UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, dont_ignore_monsters, edict(), &tr ); // just fire when close if ((tr.vecEndPos - m_posTarget).Length() < 512) FireRocket( ); } } } }