void CASW_Parasite::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_RANGE_ATTACK1: case TASK_RANGE_ATTACK2: { if ( IsActivityFinished() ) { TaskComplete(); m_bMidJump = false; SetTouch( NULL ); SetThink( &CASW_Parasite::CallNPCThink ); SetIdealActivity( ACT_IDLE ); } break; } case TASK_PARASITE_JUMP_FROM_EGG: GetMotor()->UpdateYaw(); if ( FacingIdeal() ) { TaskComplete(); } break; default: BaseClass::RunTask( pTask ); break; } }
/* ============= ai_run_missile Turn in place until within an angle to launch a missile attack ============= */ void ai_run_missile(edict_t *self) { self->ideal_yaw = enemy_yaw; M_ChangeYaw (self); if (FacingIdeal(self)) { self->monsterinfo.attack (self); self->monsterinfo.attack_state = AS_STRAIGHT; } }
/* ============= ai_run_missile Turn in place until within an angle to launch a missile attack ============= */ void ai_run_missile() { self->s.v.ideal_yaw = enemy_yaw; changeyaw( self ); if ( FacingIdeal() ) { if ( self->th_missile ) self->th_missile(); self->attack_state = AS_STRAIGHT; } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CNPC_Bug_Builder::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_BBUG_FACE_DAWDLE: { GetMotor()->UpdateYaw(); if ( FacingIdeal() ) { TaskComplete(); } break; } default: BaseClass::RunTask( pTask ); break; } }
void hhHarvesterSimple::Event_ExitPassageway(hhAIPassageway *pn) { if(currPassageway == NULL) { gameLocal.Error("%s tried to EXIT a passageway but did NOT have a curr passageway!", (const char*)name); } HH_ASSERT(currPassageway != NULL); // Store this passageway so we don't jump right back into it. lastPassageway = idEntityPtr<idEntity> (pn); lastPassagewayTime = gameLocal.time; if(GetPhysics()) GetPhysics()->SetContents(CONTENTS_BODY); currPassageway = NULL; AI_ACTIVATED = true; // Sometimes this is NOT true?!?! StopSound(SND_CHANNEL_VOICE, true); // Teleport to new pos idAngles angs = pn->GetAxis().ToAngles(); idVec3 pos = pn->GetExitPos(); Teleport( pos, angs, pn ); Show(); current_yaw = angs.yaw; ideal_yaw = angs.yaw; turnVel = 0.0f; HH_ASSERT(FacingIdeal()); // Exit anim to play? idStr exitAnim = pn->spawnArgs.GetString("exit_anim"); if(exitAnim.Length() && GetAnimator()->HasAnim(exitAnim)) { GetAnimator()->ClearAllAnims(gameLocal.GetTime(), 0); torsoAnim.UpdateState(); legsAnim.UpdateState(); torsoAnim.PlayAnim( GetAnimator()->GetAnim( exitAnim ) ); legsAnim.PlayAnim( GetAnimator()->GetAnim( exitAnim ) ); } }
//========================================================= // RunTask //========================================================= void CBaseMonster :: RunTask ( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_TURN_RIGHT: case TASK_TURN_LEFT: { ChangeYaw( pev->yaw_speed ); if ( FacingIdeal() ) { TaskComplete(); } break; } case TASK_PLAY_SEQUENCE_FACE_ENEMY: case TASK_PLAY_SEQUENCE_FACE_TARGET: { CBaseEntity *pTarget; if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) pTarget = m_hTargetEnt; else pTarget = m_hEnemy; if ( pTarget ) { pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); ChangeYaw( pev->yaw_speed ); } if ( m_fSequenceFinished ) TaskComplete(); } break; case TASK_PLAY_SEQUENCE: case TASK_PLAY_ACTIVE_IDLE: { if ( m_fSequenceFinished ) { TaskComplete(); } break; } case TASK_FACE_ENEMY: { MakeIdealYaw( m_vecEnemyLKP ); ChangeYaw( pev->yaw_speed ); if ( FacingIdeal() ) { TaskComplete(); } break; } case TASK_FACE_HINTNODE: case TASK_FACE_LASTPOSITION: case TASK_FACE_TARGET: case TASK_FACE_IDEAL: case TASK_FACE_ROUTE: { ChangeYaw( pev->yaw_speed ); if ( FacingIdeal() ) { TaskComplete(); } break; } case TASK_WAIT_PVS: { if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) { TaskComplete(); } break; } case TASK_WAIT_INDEFINITE: { // don't do anything. break; } case TASK_WAIT: case TASK_WAIT_RANDOM: { if ( gpGlobals->time >= m_flWaitFinished ) { TaskComplete(); } break; } case TASK_WAIT_FACE_ENEMY: { MakeIdealYaw ( m_vecEnemyLKP ); ChangeYaw( pev->yaw_speed ); if ( gpGlobals->time >= m_flWaitFinished ) { TaskComplete(); } break; } case TASK_MOVE_TO_TARGET_RANGE: { float distance; if ( m_hTargetEnt == NULL ) TaskFail(); else { distance = ( m_vecMoveGoal - pev->origin ).Length2D(); // Re-evaluate when you think your finished, or the target has moved too far if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) { m_vecMoveGoal = m_hTargetEnt->pev->origin; distance = ( m_vecMoveGoal - pev->origin ).Length2D(); FRefreshRoute(); } // Set the appropriate activity based on an overlapping range // overlap the range to prevent oscillation if ( distance < pTask->flData ) { TaskComplete(); RouteClear(); // Stop moving } else if ( distance < 190 && m_movementActivity != ACT_WALK ) m_movementActivity = ACT_WALK; else if ( distance >= 270 && m_movementActivity != ACT_RUN ) m_movementActivity = ACT_RUN; } break; } case TASK_WAIT_FOR_MOVEMENT: { if (MovementIsComplete()) { TaskComplete(); RouteClear(); // Stop moving } break; } case TASK_DIE: { if ( m_fSequenceFinished && pev->frame >= 255 ) { pev->deadflag = DEAD_DEAD; SetThink ( NULL ); StopAnimation(); if ( !BBoxFlat() ) { // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will // block the player on a slope or stairs, the corpse is made nonsolid. // pev->solid = SOLID_NOT; UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); } else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); if ( ShouldFadeOnDeath() ) { // this monster was created by a monstermaker... fade the corpse out. SUB_StartFadeOut(); } else { // body is gonna be around for a while, so have it stink for a bit. CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); } } break; } case TASK_RANGE_ATTACK1_NOTURN: case TASK_MELEE_ATTACK1_NOTURN: case TASK_MELEE_ATTACK2_NOTURN: case TASK_RANGE_ATTACK2_NOTURN: case TASK_RELOAD_NOTURN: { if ( m_fSequenceFinished ) { m_Activity = ACT_RESET; TaskComplete(); } break; } case TASK_RANGE_ATTACK1: case TASK_MELEE_ATTACK1: case TASK_MELEE_ATTACK2: case TASK_RANGE_ATTACK2: case TASK_SPECIAL_ATTACK1: case TASK_SPECIAL_ATTACK2: case TASK_RELOAD: { MakeIdealYaw ( m_vecEnemyLKP ); ChangeYaw ( pev->yaw_speed ); if ( m_fSequenceFinished ) { m_Activity = ACT_RESET; TaskComplete(); } break; } case TASK_SMALL_FLINCH: { if ( m_fSequenceFinished ) { TaskComplete(); } } break; case TASK_WAIT_FOR_SCRIPT: { if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) { TaskComplete(); } break; } case TASK_PLAY_SCRIPT: { // ALERT(at_console, "Play Script\n"); if (m_fSequenceFinished) { // ALERT(at_console, "Anim Finished\n"); if (m_pCine->m_iRepeatsLeft > 0) { // ALERT(at_console, "Frame %f; Repeat %d from %f\n", pev->frame, m_pCine->m_iRepeatsLeft, m_pCine->m_fRepeatFrame); m_pCine->m_iRepeatsLeft--; pev->frame = m_pCine->m_fRepeatFrame; ResetSequenceInfo( ); } else { TaskComplete(); } } 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 ]; }
//========================================================= // RunTask //========================================================= void CNPC_Stalker::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_ANNOUNCE_ATTACK: { // Stop waiting if enemy facing me or lost enemy CBaseCombatCharacter* pBCC = GetEnemyCombatCharacterPointer(); if (!pBCC || pBCC->FInViewCone( this )) { TaskComplete(); } if ( IsWaitFinished() ) { TaskComplete(); } break; } case TASK_STALKER_ZIGZAG : { if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) { TaskComplete(); GetNavigator()->StopMoving(); // Stop moving } else if (!GetNavigator()->IsGoalActive()) { SetIdealActivity( GetStoppedActivity() ); } else if (ValidateNavGoal()) { SetIdealActivity( GetNavigator()->GetMovementActivity() ); AddZigZagToPath(); } break; } case TASK_RANGE_ATTACK1: UpdateAttackBeam(); if ( !TaskIsRunning() || HasCondition( COND_TASK_FAILED )) { KillAttackBeam(); } break; case TASK_FACE_ENEMY: { if ( GetEnemy() != NULL ) { BaseClass:: RunTask( pTask ); return; } GetMotor()->SetIdealYawToTargetAndUpdate( m_vLaserCurPos ); if ( FacingIdeal() ) { TaskComplete(); } break; } default: { BaseClass::RunTask( pTask ); break; } } }
/* ================ rvMonsterStroggMarine::State_Torso_RangedAttack ================ */ stateResult_t rvMonsterStroggMarine::State_Torso_RangedAttack ( const stateParms_t& parms ) { enum { STAGE_START, STAGE_START_WAIT, STAGE_SHOOT, STAGE_SHOOT_WAIT, STAGE_END, STAGE_END_WAIT, }; //TurnToward(enemy.lastKnownPosition); switch ( parms.stage ) { case STAGE_START: // If moving switch to the moving ranged attack (torso only) if ( move.fl.moving && move.fl.running && !actionRangedAttack.fl.overrideLegs && FacingIdeal() ) { PostAnimState ( ANIMCHANNEL_TORSO, "Torso_MovingRangedAttack", parms.blendFrames ); return SRESULT_DONE; } // Full body animations DisableAnimState ( ANIMCHANNEL_LEGS ); fireAnimNum = gameLocal.random.RandomInt(2)+1; CalculateShots(); shotsFired = 0; // Attack lead in animation? if ( HasAnim ( ANIMCHANNEL_TORSO, va("range_attack%d_start", fireAnimNum), true ) ) { PlayAnim ( ANIMCHANNEL_TORSO, va("range_attack%d_start", fireAnimNum), parms.blendFrames ); return SRESULT_STAGE ( STAGE_START_WAIT ); } return SRESULT_STAGE ( STAGE_SHOOT ); case STAGE_START_WAIT: // When the pre shooting animation is done head over to shooting if ( AnimDone ( ANIMCHANNEL_TORSO, 0 ) ) { return SRESULT_STAGE ( STAGE_SHOOT ); } return SRESULT_WAIT; case STAGE_SHOOT: PlayAnim ( ANIMCHANNEL_TORSO, va("range_attack%d_loop", fireAnimNum), 0 ); shots--; shotsFired++; return SRESULT_STAGE ( STAGE_SHOOT_WAIT ); case STAGE_SHOOT_WAIT: // When the shoot animation is done either play another shot animation // or finish up with post_shooting if ( AnimDone ( ANIMCHANNEL_TORSO, 0 ) ) { if ( shots <= 0 ) { return SRESULT_STAGE ( STAGE_END ); } // If our enemy is no longer in our fov we can stop shooting if ( !enemy.fl.inFov && shotsFired >= minShots ) { return SRESULT_STAGE ( STAGE_END ); } return SRESULT_STAGE ( STAGE_SHOOT); } return SRESULT_WAIT; case STAGE_END: // Attack lead in animation? if ( HasAnim ( ANIMCHANNEL_TORSO, va("range_attack%d_end", fireAnimNum), true ) ) { PlayAnim ( ANIMCHANNEL_TORSO, va("range_attack%d_end", fireAnimNum), parms.blendFrames ); return SRESULT_STAGE ( STAGE_END_WAIT ); } return SRESULT_DONE; case STAGE_END_WAIT: if ( AnimDone ( ANIMCHANNEL_TORSO, parms.blendFrames ) ) { return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; }