void NPC::SetUpPModel(void) { void *pModel = null; if (!FNullEnt(GetEntity())) pModel = GET_MODEL_PTR(GetEntity()); if (pModel == null) { for (int i = 0; i < AS_ALL; i++) { m_actionSequence[i] = -1; m_actionTime[i] = -1.0f; } m_gaitSequence[AS_IDLE] = -1; m_gaitSequence[AS_MOVE] = -1; } else if (pModel != m_pmodel) { for (int i = 0; i < AS_ALL; i++) { if (strcmp(m_ASName[i], "null") == 0) m_actionSequence[i] = -1; else m_actionSequence[i] = LookupSequence(pModel, m_ASName[i]); m_actionTime[i] = LookupActionTime(pModel, m_actionSequence[i]); } m_gaitSequence[AS_IDLE] = LookupActivity(m_pmodel, pev, m_actionSequence[AS_IDLE]); m_gaitSequence[AS_MOVE] = LookupActivity(m_pmodel, pev, m_actionSequence[AS_MOVE]); } m_pmodel = pModel; }
//========================================================= // SetTurnActivity - measures the difference between the way // the monster is facing and determines whether or not to // select one of the 180 turn animations. //========================================================= void CBaseMonster :: SetTurnActivity ( void ) { float flYD; flYD = FlYawDiff(); if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) {// big right turn m_IdealActivity = ACT_TURN_RIGHT; } else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) {// big left turn m_IdealActivity = ACT_TURN_LEFT; } }
//----------------------------------------------------------------------------- // Purpose: Looks up a sequence by sequence name first, then by activity name. // Input : label - The sequence name or activity name to look up. // Output : Returns the sequence index of the matching sequence, or ACT_INVALID. //----------------------------------------------------------------------------- int LookupSequence( CStudioHdr *pstudiohdr, const char *label ) { VPROF( "LookupSequence" ); if (! pstudiohdr) return 0; if (!pstudiohdr->SequencesAvailable()) return 0; // // Look up by sequence name. // for (int i = 0; i < pstudiohdr->GetNumSeq(); i++) { mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i ); if (stricmp( seqdesc.pszLabel(), label ) == 0) return i; } // // Not found, look up by activity name. // int nActivity = LookupActivity( pstudiohdr, label ); if (nActivity != ACT_INVALID ) { return SelectWeightedSequence( pstudiohdr, nActivity ); } return ACT_INVALID; }
MojErr DevelCategoryHandler::Evict(MojServiceMessage *msg, MojObject &payload) { ACTIVITY_SERVICEMETHOD_BEGIN(); LOG_AM_TRACE("Entering function %s", __FUNCTION__); LOG_AM_DEBUG("Evict: %s", MojoObjectJson(payload).c_str()); MojErr err = MojErrNone; bool evictAll = false; payload.get(_T("evictAll"), evictAll); if (evictAll) { LOG_AM_DEBUG("EVICTING ALL ACTIVITIES FROM BACKGROUND QUEUE"); m_am->EvictAllBackgroundActivities(); } else { boost::shared_ptr<Activity> act; err = LookupActivity(msg, payload, act); MojErrCheck(err); LOG_AM_DEBUG(" EVICTING [Activity %llu] FROM BACKGROUND QUEUE",act->GetId()); m_am->EvictBackgroundActivity(act); } err = msg->replySuccess(); MojErrCheck(err); ACTIVITY_SERVICEMETHOD_END(msg); return MojErrNone; }
void CTalkMonster :: SetActivity ( Activity newActivity ) { if (newActivity == ACT_IDLE && IsTalking() ) newActivity = ACT_SIGNAL3; if ( newActivity == ACT_SIGNAL3 && (LookupActivity ( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE)) newActivity = ACT_IDLE; CBaseMonster::SetActivity( newActivity ); }
void CActAnimating :: SetActivity( Activity act ) { int sequence = LookupActivity( act ); if ( sequence != ACTIVITY_NOT_AVAILABLE ) { pev->sequence = sequence; m_Activity = act; pev->frame = 0; ResetSequenceInfo( ); } }
void CScientist :: SetActivity ( Activity newActivity ) { int iSequence; iSequence = LookupActivity ( newActivity ); // Set to the desired anim, or default anim if the desired is not present if ( iSequence == ACTIVITY_NOT_AVAILABLE ) newActivity = ACT_IDLE; CTalkMonster::SetActivity( newActivity ); }
//========================================================= // GetSmallFlinchActivity - determines the best type of flinch // anim to play. //========================================================= Activity CBaseMonster :: GetSmallFlinchActivity ( void ) { Activity flinchActivity; BOOL fTriedDirection; float flDot; fTriedDirection = FALSE; UTIL_MakeVectors ( pev->angles ); flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); switch ( m_LastHitGroup ) { // pick a region-specific flinch case HITGROUP_HEAD: flinchActivity = ACT_FLINCH_HEAD; break; case HITGROUP_STOMACH: flinchActivity = ACT_FLINCH_STOMACH; break; case HITGROUP_LEFTARM: flinchActivity = ACT_FLINCH_LEFTARM; break; case HITGROUP_RIGHTARM: flinchActivity = ACT_FLINCH_RIGHTARM; break; case HITGROUP_LEFTLEG: flinchActivity = ACT_FLINCH_LEFTLEG; break; case HITGROUP_RIGHTLEG: flinchActivity = ACT_FLINCH_RIGHTLEG; break; case HITGROUP_GENERIC: default: // just get a generic flinch. flinchActivity = ACT_SMALL_FLINCH; break; } // do we have a sequence for the ideal activity? if ( LookupActivity ( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) { flinchActivity = ACT_SMALL_FLINCH; } return flinchActivity; }
MojErr TestCategoryHandler::Leak(MojServiceMessage *msg, MojObject &payload) { ACTIVITY_SERVICEMETHOD_BEGIN(); MojLogTrace(s_log); MojLogInfo(s_log, _T("Leak: %s"), MojoObjectJson(payload).c_str()); MojErr err = MojErrNone; bool freeAll = false; payload.get(_T("freeAll"), freeAll); if (freeAll) { MojLogCritical(s_log, _T("RELEASING REFERENCES TO ALL INTENTIONALLY " "LEAKED ACTIVITIES")); while (!m_leakedActivities.empty()) { boost::shared_ptr<Activity> act = m_leakedActivities.front(); m_leakedActivities.pop_front(); MojLogCritical(s_log, _T("RELEASING REFERENCE TO [Activity %llu]"), act->GetId()); } } else { boost::shared_ptr<Activity> act; err = LookupActivity(msg, payload, act); MojErrCheck(err); MojLogCritical(s_log, _T("INTENTIONALLY LEAKING [Activity %llu]!!"), act->GetId()); m_leakedActivities.push_back(act); } err = msg->replySuccess(); MojErrCheck(err); ACTIVITY_SERVICEMETHOD_END(msg); return MojErrNone; }
void CHostage::SetActivity(Activity activity) { if (m_Activity != activity) { int animDesired = LookupActivity(activity); if (animDesired != -1) { if (pev->sequence != animDesired) { if ((m_Activity != ACT_WALK && m_Activity != ACT_RUN) || (activity != ACT_WALK && activity != ACT_RUN)) pev->frame = 0; pev->sequence = animDesired; } m_Activity = activity; ResetSequenceInfo(); } } }
// Overridden to make BigMomma jump on command; the model doesn't support it otherwise. void CBigMomma :: SetActivity ( Activity NewActivity ) { int iSequence; if (NewActivity == ACT_HOP) { iSequence = LookupSequence( "jump" ); } else { iSequence = LookupActivity ( NewActivity ); } // Set to the desired anim, or default anim if the desired is not present if ( iSequence > ACTIVITY_NOT_AVAILABLE ) { if ( pev->sequence != iSequence || !m_fSequenceLoops ) { // don't reset frame between walk and run if ( !(m_Activity == ACT_WALK || m_Activity == ACT_RUN) || !(NewActivity == ACT_WALK || NewActivity == ACT_RUN)) pev->frame = 0; } pev->sequence = iSequence; // Set to the reset anim (if it's there) ResetSequenceInfo( ); SetYawSpeed(); } else { // Not available try to get default anim ALERT ( at_aiconsole, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); pev->sequence = 0; // Set to the reset anim (if it's there) } m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present // In case someone calls this with something other than the ideal activity m_IdealActivity = m_Activity; }
MojErr DevelCategoryHandler::Run(MojServiceMessage *msg, MojObject &payload) { ACTIVITY_SERVICEMETHOD_BEGIN(); MojLogTrace(s_log); MojLogInfo(s_log, _T("Run: %s"), MojoObjectJson(payload).c_str()); MojErr err = MojErrNone; bool runAll = false; payload.get(_T("runAll"), runAll); if (runAll) { MojLogCritical(s_log, _T("EVICTING ALL ACTIVITIES FROM BACKGROUND " "QUEUE")); m_am->RunAllReadyActivities(); } else { boost::shared_ptr<Activity> act; err = LookupActivity(msg, payload, act); MojErrCheck(err); MojLogCritical(s_log, _T("EVICTING [Activity %llu] FROM BACKGROUND " "QUEUE"), act->GetId()); m_am->RunReadyBackgroundActivity(act); } err = msg->replySuccess(); MojErrCheck(err); ACTIVITY_SERVICEMETHOD_END(msg); return MojErrNone; }
//========================================================= // ********** DeadGenericMonster SPAWN ********** //========================================================= void CDeadGenericMonster :: Spawn( void ) { Precache(); SET_MODEL(ENT(pev), STRING(pev->model)); pev->effects = 0; pev->yaw_speed = 8; //LRC -- what? pev->sequence = 0; if (pev->netname) { pev->sequence = LookupSequence( STRING(pev->netname) ); if (pev->sequence == -1) { ALERT ( at_debug, "Invalid sequence name \"%s\" in monster_generic_dead\n", STRING(pev->netname) ); } } else { pev->sequence = LookupActivity( pev->frags ); // if (pev->sequence == -1) // { // ALERT ( at_error, "monster_generic_dead - specify a sequence name or choose a different death type: model \"%s\" has no available death sequences.\n", STRING(pev->model) ); // } //...and if that doesn't work, forget it. } // Corpses have less health pev->health = 8; MonsterInitDead(); ResetSequenceInfo( ); pev->frame = 255; // pose at the _end_ of its death sequence. }
//========================================================= // GetDeathActivity - determines the best type of death // anim to play. //========================================================= Activity CBaseMonster :: GetDeathActivity ( void ) { Activity deathActivity; BOOL fTriedDirection; float flDot; TraceResult tr; Vector vecSrc; if ( pev->deadflag != DEAD_NO ) { // don't run this while dying. return m_IdealActivity; } vecSrc = Center(); fTriedDirection = FALSE; deathActivity = ACT_DIESIMPLE;// in case we can't find any special deaths to do. UTIL_MakeVectors ( pev->angles ); flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); switch ( m_LastHitGroup ) { // try to pick a region-specific death. case HITGROUP_HEAD: deathActivity = ACT_DIE_HEADSHOT; break; case HITGROUP_STOMACH: deathActivity = ACT_DIE_GUTSHOT; break; case HITGROUP_GENERIC: // try to pick a death based on attack direction fTriedDirection = TRUE; if ( flDot > 0.3 ) { deathActivity = ACT_DIEFORWARD; } else if ( flDot <= -0.3 ) { deathActivity = ACT_DIEBACKWARD; } break; default: // try to pick a death based on attack direction fTriedDirection = TRUE; if ( flDot > 0.3 ) { deathActivity = ACT_DIEFORWARD; } else if ( flDot <= -0.3 ) { deathActivity = ACT_DIEBACKWARD; } break; } // can we perform the prescribed death? if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) { // no! did we fail to perform a directional death? if ( fTriedDirection ) { // if yes, we're out of options. Go simple. deathActivity = ACT_DIESIMPLE; } else { // cannot perform the ideal region-specific death, so try a direction. if ( flDot > 0.3 ) { deathActivity = ACT_DIEFORWARD; } else if ( flDot <= -0.3 ) { deathActivity = ACT_DIEBACKWARD; } } } if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) { // if we're still invalid, simple is our only option. deathActivity = ACT_DIESIMPLE; } if ( deathActivity == ACT_DIEFORWARD ) { // make sure there's room to fall forward UTIL_TraceHull ( vecSrc, vecSrc + gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); if ( tr.flFraction != 1.0 ) { deathActivity = ACT_DIESIMPLE; } } if ( deathActivity == ACT_DIEBACKWARD ) { // make sure there's room to fall backward UTIL_TraceHull ( vecSrc, vecSrc - gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); if ( tr.flFraction != 1.0 ) { deathActivity = ACT_DIESIMPLE; } } return deathActivity; }
//========================================================= // RunTask //========================================================= void CController :: RunTask ( Task_t *pTask ) { if (m_flShootEnd > gpGlobals->time) { Vector vecHand, vecAngle; GetAttachment( 2, vecHand, vecAngle ); while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) { Vector vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); Vector vecDir; if (m_pCine != NULL || m_hEnemy != NULL) { if (m_pCine != NULL) // LRC- is this a script that's telling it to fire? { if (m_hTargetEnt != NULL && m_pCine->PreciseAttack()) { vecDir = (m_hTargetEnt->pev->origin - pev->origin).Normalize() * gSkillData.controllerSpeedBall; } else { UTIL_MakeVectors(pev->angles); vecDir = gpGlobals->v_forward * gSkillData.controllerSpeedBall; } } else if (m_hEnemy != NULL) { if (HasConditions( bits_COND_SEE_ENEMY )) { m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->pev->velocity * 0.5; } else { m_vecEstVelocity = m_vecEstVelocity * 0.8; } vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall ); } float delta = 0.03490; // +-2 degree vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.controllerSpeedBall; vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, edict() ); pBall->pev->velocity = vecDir; } m_flShootTime += 0.2; } if (m_flShootTime > m_flShootEnd) { m_iBall[0] = 64; m_iBallTime[0] = m_flShootEnd; m_iBall[1] = 64; m_iBallTime[1] = m_flShootEnd; m_fInCombat = FALSE; } } switch ( pTask->iTask ) { case TASK_WAIT_FOR_MOVEMENT: case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: case TASK_WAIT_PVS: MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( pev->yaw_speed ); if (m_fSequenceFinished) { m_fInCombat = FALSE; } CSquadMonster :: RunTask ( pTask ); if (!m_fInCombat) { if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 )) { pev->sequence = LookupActivity( ACT_RANGE_ATTACK1 ); pev->frame = 0; ResetSequenceInfo( ); m_fInCombat = TRUE; } else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 )) { pev->sequence = LookupActivity( ACT_RANGE_ATTACK2 ); pev->frame = 0; ResetSequenceInfo( ); m_fInCombat = TRUE; } else { int iFloat = LookupFloat( ); if (m_fSequenceFinished || iFloat != pev->sequence) { pev->sequence = iFloat; pev->frame = 0; ResetSequenceInfo( ); } } } break; default: CSquadMonster :: RunTask ( pTask ); break; } }
//========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the // schedule. //========================================================= void CBaseMonster :: StartTask ( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_TURN_RIGHT: { float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); SetTurnActivity(); break; } case TASK_TURN_LEFT: { float flCurrentYaw; flCurrentYaw = UTIL_AngleMod( pev->angles.y ); pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); SetTurnActivity(); break; } case TASK_REMEMBER: { Remember ( (int)pTask->flData ); TaskComplete(); break; } case TASK_FORGET: { Forget ( (int)pTask->flData ); TaskComplete(); break; } case TASK_FIND_HINTNODE: { m_iHintNode = FindHintNode(); if ( m_iHintNode != NO_NODE ) { TaskComplete(); } else { TaskFail(); } break; } case TASK_STORE_LASTPOSITION: { m_vecLastPosition = pev->origin; TaskComplete(); break; } case TASK_CLEAR_LASTPOSITION: { m_vecLastPosition = g_vecZero; TaskComplete(); break; } case TASK_CLEAR_HINTNODE: { m_iHintNode = NO_NODE; TaskComplete(); break; } case TASK_STOP_MOVING: { if ( m_IdealActivity == m_movementActivity ) { m_IdealActivity = GetStoppedActivity(); } RouteClear(); TaskComplete(); break; } case TASK_PLAY_SEQUENCE_FACE_ENEMY: case TASK_PLAY_SEQUENCE_FACE_TARGET: case TASK_PLAY_SEQUENCE: { m_IdealActivity = ( Activity )( int )pTask->flData; break; } case TASK_PLAY_ACTIVE_IDLE: { // monsters verify that they have a sequence for the node's activity BEFORE // moving towards the node, so it's ok to just set the activity without checking here. m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; break; } case TASK_SET_SCHEDULE: { Schedule_t *pNewSchedule; pNewSchedule = GetScheduleOfType( (int)pTask->flData ); if ( pNewSchedule ) { ChangeSchedule( pNewSchedule ); } else { TaskFail(); } break; } case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_NODE_COVER_FROM_ENEMY: { if ( m_hEnemy == NULL ) { TaskFail(); return; } if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) { // try for cover farther than the FLData from the schedule. TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_COVER_FROM_ENEMY: { entvars_t *pevCover; if ( m_hEnemy == NULL ) { // Find cover from self if no enemy available pevCover = pev; // TaskFail(); // return; } else pevCover = m_hEnemy->pev; if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) { // try lateral first m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no coverwhatsoever. TaskFail(); } break; } case TASK_FIND_COVER_FROM_ORIGIN: { if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no cover! TaskFail(); } } break; case TASK_FIND_COVER_FROM_BEST_SOUND: { CSound *pBestSound; pBestSound = PBestSound(); ASSERT( pBestSound != NULL ); /* if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) { // try lateral first m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } */ if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + pTask->flData; TaskComplete(); } else { // no coverwhatsoever. or no sound in list TaskFail(); } break; } case TASK_FACE_HINTNODE: { pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; SetTurnActivity(); break; } case TASK_FACE_LASTPOSITION: MakeIdealYaw ( m_vecLastPosition ); SetTurnActivity(); break; case TASK_FACE_TARGET: if ( m_hTargetEnt != NULL ) { MakeIdealYaw ( m_hTargetEnt->pev->origin ); SetTurnActivity(); } else TaskFail(); break; case TASK_FACE_ENEMY: { MakeIdealYaw ( m_vecEnemyLKP ); SetTurnActivity(); break; } case TASK_FACE_IDEAL: { SetTurnActivity(); break; } case TASK_FACE_ROUTE: { if (FRouteClear()) { ALERT(at_aiconsole, "No route to face!\n"); TaskFail(); } else { MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); SetTurnActivity(); } break; } case TASK_WAIT_PVS: case TASK_WAIT_INDEFINITE: { // don't do anything. break; } case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: {// set a future time that tells us when the wait is over. m_flWaitFinished = gpGlobals->time + pTask->flData; break; } case TASK_WAIT_RANDOM: {// set a future time that tells us when the wait is over. m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); break; } case TASK_MOVE_TO_TARGET_RANGE: { if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) TaskComplete(); else { m_vecMoveGoal = m_hTargetEnt->pev->origin; if ( !MoveToTarget( ACT_WALK, 2 ) ) TaskFail(); } break; } case TASK_RUN_TO_SCRIPT: case TASK_WALK_TO_SCRIPT: { Activity newActivity; if ( !m_pGoalEnt || (m_pGoalEnt->pev->origin - pev->origin).Length() < 1 ) TaskComplete(); else { if ( pTask->iTask == TASK_WALK_TO_SCRIPT ) newActivity = ACT_WALK; else newActivity = ACT_RUN; // This monster can't do this! if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) TaskComplete(); else { if ( m_pGoalEnt != NULL ) { Vector vecDest; vecDest = m_pGoalEnt->pev->origin; if ( !MoveToLocation( newActivity, 2, vecDest ) ) { TaskFail(); ALERT( at_aiconsole, "%s Failed to reach script!!!\n", STRING(pev->classname) ); RouteClear(); } } else { TaskFail(); ALERT( at_aiconsole, "%s: MoveTarget is missing!?!\n", STRING(pev->classname) ); RouteClear(); } } } TaskComplete(); break; } case TASK_CLEAR_MOVE_WAIT: { m_flMoveWaitFinished = gpGlobals->time; TaskComplete(); break; } case TASK_MELEE_ATTACK1_NOTURN: case TASK_MELEE_ATTACK1: { m_IdealActivity = ACT_MELEE_ATTACK1; break; } case TASK_MELEE_ATTACK2_NOTURN: case TASK_MELEE_ATTACK2: { m_IdealActivity = ACT_MELEE_ATTACK2; break; } case TASK_RANGE_ATTACK1_NOTURN: case TASK_RANGE_ATTACK1: { m_IdealActivity = ACT_RANGE_ATTACK1; break; } case TASK_RANGE_ATTACK2_NOTURN: case TASK_RANGE_ATTACK2: { m_IdealActivity = ACT_RANGE_ATTACK2; break; } case TASK_RELOAD_NOTURN: case TASK_RELOAD: { m_IdealActivity = ACT_RELOAD; break; } case TASK_SPECIAL_ATTACK1: { m_IdealActivity = ACT_SPECIAL_ATTACK1; break; } case TASK_SPECIAL_ATTACK2: { m_IdealActivity = ACT_SPECIAL_ATTACK2; break; } case TASK_SET_ACTIVITY: { m_IdealActivity = (Activity)(int)pTask->flData; TaskComplete(); break; } case TASK_GET_PATH_TO_ENEMY_LKP: { if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_ENEMY: { CBaseEntity *pEnemy = m_hEnemy; if ( pEnemy == NULL ) { TaskFail(); return; } if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) { TaskComplete(); } else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_ENEMY_CORPSE: { UTIL_MakeVectors( pev->angles ); if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) { TaskComplete(); } else { ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); TaskFail(); } } break; case TASK_GET_PATH_TO_SPOT: { CBaseEntity *pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_TARGET: { RouteClear(); if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_SCRIPT: { RouteClear(); if ( m_pCine != NULL && MoveToLocation( m_movementActivity, 1, m_pCine->pev->origin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_HINTNODE:// for active idles! { if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_LASTPOSITION: { m_vecMoveGoal = m_vecLastPosition; if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_BESTSOUND: { CSound *pSound; pSound = PBestSound(); if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); TaskFail(); } break; } case TASK_GET_PATH_TO_BESTSCENT: { CSound *pScent; pScent = PBestScent(); if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) { TaskComplete(); } else { // no way to get there =( ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); TaskFail(); } break; } case TASK_RUN_PATH: { // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_RUN; } else { m_movementActivity = ACT_WALK; } TaskComplete(); break; } case TASK_WALK_PATH: { if ( pev->movetype == MOVETYPE_FLY ) { m_movementActivity = ACT_FLY; } if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) { m_movementActivity = ACT_WALK; } else { m_movementActivity = ACT_RUN; } TaskComplete(); break; } case TASK_STRAFE_PATH: { Vector2D vec2DirToPoint; Vector2D vec2RightSide; // to start strafing, we have to first figure out if the target is on the left side or right side UTIL_MakeVectors ( pev->angles ); vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) { // strafe right m_movementActivity = ACT_STRAFE_RIGHT; } else { // strafe left m_movementActivity = ACT_STRAFE_LEFT; } TaskComplete(); break; } case TASK_WAIT_FOR_MOVEMENT: { if (FRouteClear()) { TaskComplete(); } break; } case TASK_EAT: { Eat( pTask->flData ); TaskComplete(); break; } case TASK_SMALL_FLINCH: { m_IdealActivity = GetSmallFlinchActivity(); break; } case TASK_DIE: { RouteClear(); m_IdealActivity = GetDeathActivity(); pev->deadflag = DEAD_DYING; break; } case TASK_SOUND_WAKE: { AlertSound(); TaskComplete(); break; } case TASK_SOUND_DIE: { DeathSound(); TaskComplete(); break; } case TASK_SOUND_IDLE: { IdleSound(); TaskComplete(); break; } case TASK_SOUND_PAIN: { PainSound(); TaskComplete(); break; } case TASK_SOUND_DEATH: { DeathSound(); TaskComplete(); break; } case TASK_SOUND_ANGRY: { // sounds are complete as soon as we get here, cause we've already played them. ALERT ( at_aiconsole, "SOUND\n" ); TaskComplete(); break; } case TASK_WAIT_FOR_SCRIPT: { if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) { TaskComplete(); //LRC - start playing immediately } else if (!m_pCine->IsAction() && m_pCine->m_iszIdle) { m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) { pev->framerate = 0; } } else m_IdealActivity = ACT_IDLE; break; } case TASK_PLAY_SCRIPT: { if (m_pCine->IsAction()) { //ALERT(at_console,"PlayScript: setting idealactivity %d\n",m_pCine->m_fAction); switch(m_pCine->m_fAction) { case 0: m_IdealActivity = ACT_RANGE_ATTACK1; break; case 1: m_IdealActivity = ACT_RANGE_ATTACK2; break; case 2: m_IdealActivity = ACT_MELEE_ATTACK1; break; case 3: m_IdealActivity = ACT_MELEE_ATTACK2; break; case 4: m_IdealActivity = ACT_SPECIAL_ATTACK1; break; case 5: m_IdealActivity = ACT_SPECIAL_ATTACK2; break; case 6: m_IdealActivity = ACT_RELOAD; break; case 7: m_IdealActivity = ACT_HOP; break; } pev->framerate = 1.0; // shouldn't be needed, but just in case pev->movetype = MOVETYPE_FLY; ClearBits(pev->flags, FL_ONGROUND); } else { m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); if ( m_fSequenceFinished ) ClearSchedule(); pev->framerate = 1.0; //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); } m_scriptState = SCRIPT_PLAYING; break; } case TASK_ENABLE_SCRIPT: { m_pCine->DelayStart( 0 ); TaskComplete(); break; } //LRC case TASK_END_SCRIPT: { m_pCine->SequenceDone( this ); TaskComplete(); break; } case TASK_PLANT_ON_SCRIPT: { if ( m_pCine != NULL ) { // Plant on script // LRC - if it's a teleport script, do the turn too if (m_pCine->m_fMoveTo == 4 || m_pCine->m_fMoveTo == 6) { if (m_pCine->m_fTurnType == 0) //LRC pev->angles.y = m_hTargetEnt->pev->angles.y; else if (m_pCine->m_fTurnType == 1) pev->angles.y = UTIL_VecToYaw(m_hTargetEnt->pev->origin - pev->origin); pev->ideal_yaw = pev->angles.y; pev->avelocity = Vector( 0, 0, 0 ); pev->velocity = Vector( 0, 0, 0 ); pev->effects |= EF_NOINTERP; } if (m_pCine->m_fMoveTo != 6) pev->origin = m_pGoalEnt->pev->origin; } TaskComplete(); break; } case TASK_FACE_SCRIPT: { if ( m_pCine != NULL && m_pCine->m_fMoveTo != 0) // movetype "no move" makes us ignore turntype { switch (m_pCine->m_fTurnType) { case 0: pev->ideal_yaw = UTIL_AngleMod( m_pCine->pev->angles.y ); break; case 1: // yes, this is inconsistent- turn to face uses the "target" and turn to angle uses the "cine". if (m_hTargetEnt) MakeIdealYaw ( m_hTargetEnt->pev->origin ); else MakeIdealYaw ( m_pCine->pev->origin ); break; // default: don't turn } } TaskComplete(); m_IdealActivity = ACT_IDLE; RouteClear(); break; } case TASK_SUGGEST_STATE: { m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; TaskComplete(); break; } case TASK_SET_FAIL_SCHEDULE: m_failSchedule = (int)pTask->flData; TaskComplete(); break; case TASK_CLEAR_FAIL_SCHEDULE: m_failSchedule = SCHED_NONE; TaskComplete(); break; default: { ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); break; } } }
void CController :: RunTask ( const Task_t& task ) { if (m_flShootEnd > gpGlobals->time) { Vector vecHand, vecAngle; GetAttachment( 2, vecHand, vecAngle ); while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) { Vector vecSrc = vecHand + GetAbsVelocity() * (m_flShootTime - gpGlobals->time); Vector vecDir; if (m_hEnemy != NULL) { if (HasConditions( bits_COND_SEE_ENEMY )) { m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->GetAbsVelocity() * 0.5; } else { m_vecEstVelocity = m_vecEstVelocity * 0.8; } vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( GetAbsOrigin() ), m_vecEstVelocity, gSkillData.GetControllerSpeedBall() ); float delta = 0.03490; // +-2 degree vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.GetControllerSpeedBall(); vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, GetAbsAngles(), edict() ); pBall->SetAbsVelocity( vecDir ); } m_flShootTime += 0.2; } if (m_flShootTime > m_flShootEnd) { m_iBall[0] = 64; m_iBallTime[0] = m_flShootEnd; m_iBall[1] = 64; m_iBallTime[1] = m_flShootEnd; m_fInCombat = false; } } switch ( task.iTask ) { case TASK_WAIT_FOR_MOVEMENT: case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: case TASK_WAIT_PVS: MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( GetYawSpeed() ); if (m_fSequenceFinished) { m_fInCombat = false; } CSquadMonster :: RunTask ( task ); if (!m_fInCombat) { if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 )) { SetSequence( LookupActivity( ACT_RANGE_ATTACK1 ) ); SetFrame( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 )) { SetSequence( LookupActivity( ACT_RANGE_ATTACK2 ) ); SetFrame( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else { int iFloat = LookupFloat( ); if (m_fSequenceFinished || iFloat != GetSequence() ) { SetSequence( iFloat ); SetFrame( 0 ); ResetSequenceInfo( ); } } } break; default: CSquadMonster :: RunTask ( task ); break; } }
//========================================================= // GetSchedule - 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. //========================================================= Schedule_t *CBaseMonster :: GetSchedule ( void ) { switch ( m_MonsterState ) { case MONSTERSTATE_PRONE: { return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); break; } case MONSTERSTATE_NONE: { ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); break; } case MONSTERSTATE_IDLE: { if ( HasConditions ( bits_COND_HEAR_SOUND ) ) { return GetScheduleOfType( SCHED_ALERT_FACE ); } else if ( FRouteClear() ) { // no valid route! return GetScheduleOfType( SCHED_IDLE_STAND ); } else { // valid route. Get moving return GetScheduleOfType( SCHED_IDLE_WALK ); } break; } case MONSTERSTATE_ALERT: { if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) { return GetScheduleOfType ( SCHED_VICTORY_DANCE ); } if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) { if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction { return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); } else { return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); } } else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) { return GetScheduleOfType( SCHED_ALERT_FACE ); } else { return GetScheduleOfType( SCHED_ALERT_STAND ); } break; } case MONSTERSTATE_COMBAT: { if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // clear the current (dead) enemy and try to find another. m_hEnemy = NULL; if ( GetEnemy() ) { ClearConditions( bits_COND_ENEMY_DEAD ); return GetSchedule(); } else { SetState( MONSTERSTATE_ALERT ); return GetSchedule(); } } if ( HasConditions(bits_COND_NEW_ENEMY) ) { return GetScheduleOfType ( SCHED_WAKE_ANGRY ); } else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) { return GetScheduleOfType( SCHED_SMALL_FLINCH ); } else if ( !HasConditions(bits_COND_SEE_ENEMY) ) { // we can't see the enemy if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) { // enemy is unseen, but not occluded! // turn to face enemy return GetScheduleOfType( SCHED_COMBAT_FACE ); } else { // chase! return GetScheduleOfType( SCHED_CHASE_ENEMY ); } } else { // we can see the enemy if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) { return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); } if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) { return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); } if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) { return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) { return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); } if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) { // if we can see enemy but can't use either attack type, we must need to get closer to enemy return GetScheduleOfType( SCHED_CHASE_ENEMY ); } else if ( !FacingIdeal() ) { //turn return GetScheduleOfType( SCHED_COMBAT_FACE ); } else { ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); } } break; } case MONSTERSTATE_DEAD: { return GetScheduleOfType( SCHED_DIE ); break; } case MONSTERSTATE_SCRIPT: { ASSERT( m_pCine != NULL ); if ( !m_pCine ) { ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); // ALERT( at_console, "Script failed for %s\n", STRING(pev->classname) ); CineCleanup(); return GetScheduleOfType( SCHED_IDLE_STAND ); } return GetScheduleOfType( SCHED_AISCRIPT ); } default: { ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); break; } } return &slError[ 0 ]; }
PRECACHE_MODEL((char *)STRING(pev->model)); PRECACHE_SOUND("hostage/hos1.wav"); PRECACHE_SOUND("hostage/hos2.wav"); PRECACHE_SOUND("hostage/hos3.wav"); PRECACHE_SOUND("hostage/hos4.wav"); PRECACHE_SOUND("hostage/hos5.wav"); PRECACHE_MODEL("sprites/smoke.spr"); } void CHostage::SetActivity(Activity activity) { BINTRACE if (m_Activity != activity) { int animDesired = LookupActivity(activity); if (animDesired != -1) { if (pev->sequence != animDesired) { if ((m_Activity != ACT_WALK && m_Activity != ACT_RUN) || (activity != ACT_WALK && activity != ACT_RUN)) pev->frame = 0; pev->sequence = animDesired; } m_Activity = activity; ResetSequenceInfo(); } }
// // TentacleThink // void CTentacle :: Cycle( void ) { // ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState ); pev->nextthink = gpGlobals-> time + 0.1; // ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health ); if (m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT) { pev->angles.y = m_flInitialYaw; pev->ideal_yaw = m_flInitialYaw; ClearConditions( IgnoreConditions() ); MonsterThink( ); m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; return; } DispatchAnimEvents( ); StudioFrameAdvance( ); ChangeYaw( pev->yaw_speed ); CSound *pSound; Listen( ); // Listen will set this if there's something in my sound list if ( HasConditions( bits_COND_HEAR_SOUND ) ) pSound = PBestSound(); else pSound = NULL; if ( pSound ) { Vector vecDir; if (gpGlobals->time - m_flPrevSoundTime < 0.5) { float dt = gpGlobals->time - m_flPrevSoundTime; vecDir = pSound->m_vecOrigin + (pSound->m_vecOrigin - m_vecPrevSound) / dt - pev->origin; } else { vecDir = pSound->m_vecOrigin - pev->origin; } m_flPrevSoundTime = gpGlobals->time; m_vecPrevSound = pSound->m_vecOrigin; m_flSoundYaw = UTIL_VecToYaw ( vecDir ) - m_flInitialYaw; m_iSoundLevel = Level( vecDir.z ); if (m_flSoundYaw < -180) m_flSoundYaw += 360; if (m_flSoundYaw > 180) m_flSoundYaw -= 360; // ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); if (m_flSoundTime < gpGlobals->time) { // play "I hear new something" sound char *sound; switch( RANDOM_LONG(0,1) ) { case 0: sound = "tentacle/te_alert1.wav"; break; case 1: sound = "tentacle/te_alert2.wav"; break; } // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); } m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 ); } // clip ideal_yaw float dy = m_flSoundYaw; switch( pev->sequence ) { case TENTACLE_ANIM_Floor_Rear: case TENTACLE_ANIM_Floor_Rear_Idle: case TENTACLE_ANIM_Lev1_Rear: case TENTACLE_ANIM_Lev1_Rear_Idle: case TENTACLE_ANIM_Lev2_Rear: case TENTACLE_ANIM_Lev2_Rear_Idle: case TENTACLE_ANIM_Lev3_Rear: case TENTACLE_ANIM_Lev3_Rear_Idle: if (dy < 0 && dy > -m_flMaxYaw) dy = -m_flMaxYaw; if (dy > 0 && dy < m_flMaxYaw) dy = m_flMaxYaw; break; default: if (dy < -m_flMaxYaw) dy = -m_flMaxYaw; if (dy > m_flMaxYaw) dy = m_flMaxYaw; } pev->ideal_yaw = m_flInitialYaw + dy; if (m_fSequenceFinished) { // ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim ); if (pev->health <= 1) { m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; if (pev->sequence == TENTACLE_ANIM_Pit_Idle) { pev->health = 75; } } else if ( m_flSoundTime > gpGlobals->time ) { if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30)) { // strike m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); } else if (m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2) { // tap m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); } else { // go into rear idle m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel ); } } else if (pev->sequence == TENTACLE_ANIM_Pit_Idle) { // stay in pit until hear noise m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; } else if (pev->sequence == m_iGoalAnim) { if (MyLevel() >= 0 && gpGlobals->time < m_flSoundTime) { if (RANDOM_LONG(0,9) < m_flSoundTime - gpGlobals->time) { // continue stike m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); } else { // tap m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); } } else if (MyLevel( ) < 0) { m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 ); } else { if (m_flNextSong < gpGlobals->time) { // play "I hear new something" sound char *sound; switch( RANDOM_LONG(0,1) ) { case 0: sound = "tentacle/te_sing1.wav"; break; case 1: sound = "tentacle/te_sing2.wav"; break; } EMIT_SOUND(ENT(pev), CHAN_VOICE, sound, 1.0, ATTN_NORM); m_flNextSong = gpGlobals->time + RANDOM_FLOAT( 10, 20 ); } if (RANDOM_LONG(0,15) == 0) { // idle on new level m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG(0,3) ); } else if (RANDOM_LONG(0,3) == 0) { // tap m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel( ) ); } else { // idle m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel( ) ); } } if (m_flSoundYaw < 0) m_flSoundYaw += RANDOM_FLOAT( 2, 8 ); else m_flSoundYaw -= RANDOM_FLOAT( 2, 8 ); } pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); if (m_iDir > 0) { pev->frame = 0; } else { m_iDir = -1; // just to safe pev->frame = 255; } ResetSequenceInfo( ); m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 ); pev->framerate = m_iDir * 1.0 + m_flFramerateAdj; switch( pev->sequence) { case TENTACLE_ANIM_Floor_Tap: case TENTACLE_ANIM_Lev1_Tap: case TENTACLE_ANIM_Lev2_Tap: case TENTACLE_ANIM_Lev3_Tap: { Vector vecSrc; UTIL_MakeVectors( pev->angles ); TraceResult tr1, tr2; vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4); UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr1 ); vecSrc = pev->origin + Vector( 0, 0, MyHeight() + 8); UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr2 ); // ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 ); m_flTapRadius = SetBlending( 0, RANDOM_FLOAT( tr1.flFraction * 512, tr2.flFraction * 512 ) ); } break; default: m_flTapRadius = 336; // 400 - 64 break; } pev->view_ofs.z = MyHeight( ); // ALERT( at_console, "seq %d\n", pev->sequence ); } if (m_flPrevSoundTime + 2.0 > gpGlobals->time) { // 1.5 normal speed if hears sounds pev->framerate = m_iDir * 1.5 + m_flFramerateAdj; } else if (m_flPrevSoundTime + 5.0 > gpGlobals->time) { // slowdown to normal pev->framerate = m_iDir + m_iDir * (5 - (gpGlobals->time - m_flPrevSoundTime)) / 2 + m_flFramerateAdj; } }
//========================================================= // SetActivity //========================================================= void CFriend :: SetActivity ( Activity NewActivity ) { int iSequence = ACTIVITY_NOT_AVAILABLE; void *pmodel = GET_MODEL_PTR( ENT(pev) ); switch ( NewActivity) { case ACT_RANGE_ATTACK1: // if (RANDOM_LONG(0,1)) // { // iSequence = LookupSequence( "throwgrenade" ); // } // else // { if (pev->frags) { iSequence = LookupSequence( "standing_shotgun" ); } else { iSequence = LookupSequence( "standing_mp5" ); } // } break; case ACT_RANGE_ATTACK2: // grunt is going to a secondary long range attack. This may be a thrown // grenade or fired grenade, we must determine which and pick proper sequence // get toss anim iSequence = LookupSequence( "throwgrenade" ); break; case ACT_RUN: if ( pev->health <= LIMP_HEALTH ) { // limp! iSequence = LookupActivity ( ACT_RUN_HURT ); } else { iSequence = LookupActivity ( NewActivity ); } break; case ACT_WALK: if ( pev->health <= LIMP_HEALTH ) { // limp! iSequence = LookupActivity ( ACT_WALK_HURT ); } else { iSequence = LookupActivity ( NewActivity ); } break; case ACT_IDLE: if ( m_MonsterState == MONSTERSTATE_COMBAT ) { NewActivity = ACT_IDLE_ANGRY; } iSequence = LookupActivity ( NewActivity ); break; default: iSequence = LookupActivity ( NewActivity ); break; } m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present // Set to the desired anim, or default anim if the desired is not present if ( iSequence > ACTIVITY_NOT_AVAILABLE ) { if ( pev->sequence != iSequence || !m_fSequenceLoops ) { pev->frame = 0; } pev->sequence = iSequence; // Set to the reset anim (if it's there) ResetSequenceInfo( ); SetYawSpeed(); } else { // Not available try to get default anim ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); pev->sequence = 0; // Set to the reset anim (if it's there) } }