#include maps\mp\agents\_scriptedAgents; main() { //IPrintLnBold ("Alien entering IDLE state"); self.animSubstate = "none"; self SetTimeOfNextSound(); self.timeOfNextSound += 2000; self.bIdleHitReaction = false; self ScrAgentSetGoalPos( self.origin ); self ScrAgentSetOrientMode( "face angle abs", self.angles ); self ScrAgentSetAnimMode( "anim deltas" ); self ScrAgentSetPhysicsMode( "gravity" ); self UpdateState(); } end_script() { if ( IsDefined( self.prevTurnRate ) ) { self ScrAgentSetMaxTurnSpeed( self.prevTurnRate ); self.prevTurnRate = undefined; } } UpdateState() { self endon( "killanimscript" ); self endon( "cancelidleloop" ); while ( true ) { prevState = self.animSubstate; nextState = self DetermineState(); if ( nextState != self.animSubstate ) self EnterState( nextState ); self UpdateAngle(); switch ( self.animSubstate ) { case "idle_combat": wait( 0.2 ); break; case "idle_noncombat": if ( prevState == "none" ) { if ( self.moveMode == "run" || self.moveMode == "sprint" ) self PlaySoundOnMovingEnt( "alien_minion_idle" ); else self PlaySoundOnMovingEnt( "alien_minion_idle" ); } else { if ( GetTime() > self.timeOfNextSound ) { if ( RandomInt(10) < 4 ) self PlaySoundOnMovingEnt( "alien_minion_idle" ); else self PlaySoundOnMovingEnt( "alien_minion_idle" ); self SetTimeOfNextSound(); } } wait ( 0.5 ); break; default: assertmsg( "unknown dog stop state " + self.animSubstate ); wait( 1 ); break; } } } DetermineState() { if ( ShouldAttackIdle() ) return "idle_combat"; else return "idle_noncombat"; } EnterState( state ) { self ExitState( self.animSubstate ); self.animSubstate = state; PlayIdleAnim(); } ExitState( prevState ) { if ( IsDefined( self.prevTurnRate ) ) { self ScrAgentSetMaxTurnSpeed( self.prevTurnRate ); self.prevTurnRate = undefined; } } PlayIdleAnim() { if ( self.animSubstate == "idle_combat" ) self SetAnimState( "attack_idle" ); else self SetAnimState( "casual_idle" ); } UpdateAngle() { faceTarget = undefined; if ( IsDefined( self.enemy ) && DistanceSquared( self.enemy.origin, self.origin ) < 1024 * 1024 ) faceTarget = self.enemy; else if ( IsDefined( self.owner ) ) faceTarget = self.owner; if ( IsDefined( faceTarget ) ) { meToTarget = faceTarget.origin - self.origin; meToTargetAngles = VectorToAngles( meToTarget ); if ( abs( AngleClamp180( meToTargetAngles[1] - self.angles[1] ) ) > 1 ) self TurnToAngle( meToTargetAngles[1] ); } } ShouldAttackIdle() { return isdefined( self.enemy ) && maps\mp\_utility::IsReallyAlive( self.enemy ) && distanceSquared( self.origin, self.enemy.origin ) < 1000000; //&& self SeeRecently( self.enemy, 5 ); } GetTurnAnimState( angleDiff ) { if ( self ShouldAttackIdle() ) { if ( angleDiff < -135 || angleDiff > 135 ) return "attack_turn_180"; else if ( angleDiff < 0 ) return "attack_turn_right_90"; else return "attack_turn_left_90"; } else { if ( angleDiff < -135 || angleDiff > 135 ) return "casual_turn_180"; else if ( angleDiff < 0 ) return "casual_turn_right_90"; else return "casual_turn_left_90"; } } TurnToAngle( desiredAngle ) { currentAngle = self.angles[1]; angleDiff = AngleClamp180( desiredAngle - currentAngle ); if ( -0.5 < angleDiff && angleDiff < 0.5 ) return; if ( -10 < angleDiff && angleDiff < 10 ) { RotateToAngle( desiredAngle, 2 ); return; } animState = GetTurnAnimState( angleDiff ); turnAnim = self GetAnimEntry( animState, 0 ); animLength = GetAnimLength( turnAnim ); animAngleDelta = GetAngleDelta3D( turnAnim ); self ScrAgentSetAnimMode( "anim angle delta" ); if ( AnimHasNotetrack( turnAnim, "turn_begin" ) && AnimHasNotetrack( turnAnim, "turn_end" ) ) { self PlayAnimNUntilNotetrack( animState, 0, "turn_in_place" ); beginTimes = GetNotetrackTimes( turnAnim, "turn_begin" ); endTimes = GetNotetrackTimes( turnAnim, "turn_end" ); turnTime = (endTimes[0] - beginTimes[0]) * animLength; turnAdjust = AngleClamp180( angleDiff - animAngleDelta[1] ); turnSpeed = abs(turnAdjust) / turnTime / 20; turnSpeed = turnSpeed * 3.14159 / 180; // radians per frame. angles = ( 0, AngleClamp180( self.angles[1] + turnAdjust ), 0 ); self.prevTurnRate = self ScrAgentGetMaxTurnSpeed(); self ScrAgentSetMaxTurnSpeed( turnSpeed ); self ScrAgentSetOrientMode( "face angle abs", angles ); self WaitUntilNotetrack( "turn_in_place", "turn_end" ); self ScrAgentSetMaxTurnSpeed( self.prevTurnRate ); self.prevTurnRate = undefined; self WaitUntilNotetrack( "turn_in_place", "end" ); } else { self.prevTurnRate = self ScrAgentGetMaxTurnSpeed(); turnSpeed = abs( AngleClamp180(angleDiff-animAngleDelta[1]) ) / animLength / 20; turnSpeed = turnSpeed * 3.14159 / 180; self ScrAgentSetMaxTurnSpeed( turnSpeed ); // radians per frame. angles = ( 0, AngleClamp180( desiredAngle - animAngleDelta[1] ), 0 ); self ScrAgentSetOrientMode( "face angle abs", angles ); self PlayAnimNUntilNotetrack( animState, 0, "turn_in_place" ); self ScrAgentSetMaxTurnSpeed( self.prevTurnRate ); self.prevTurnRate = undefined; } self ScrAgentSetAnimMode( "anim deltas" ); self PlayIdleAnim(); } RotateToAngle( desiredAngle, tolerance ) { if ( abs( AngleClamp180( desiredAngle - self.angles[1] ) ) <= tolerance ) return; angles = ( 0, desiredAngle, 0 ); self ScrAgentSetOrientMode( "face angle abs", angles ); while ( AngleClamp180( desiredAngle - self.angles[1] ) > tolerance ) wait ( 0.1 ); } SetTimeOfNextSound() { self.timeOfNextSound = GetTime() + 8000 + RandomInt( 5000 ); } DoHitReaction( hitAngle ) { self.bLockGoalPos = true; self.stateLocked = true; self.bIdleHitReaction = true; // hitAngle is angle from me to damage angleDiff = AngleClamp180( hitAngle - self.angles[1] ); if ( angleDiff > 0 ) animIndex = 1; // left else animIndex = 0; // right self notify( "cancelidleloop" ); self ScrAgentSetAnimMode( "anim deltas" ); self ScrAgentSetOrientMode( "face angle abs", self.angles ); self PlayAnimNUntilNotetrack( "stand_pain", animIndex, "stand_pain" ); self.bLockGoalPos = false; self.stateLocked = false; self.bIdleHitReaction = false; self ScrAgentSetOrientMode( "face angle abs", self.angles ); self.animSubstate = "none"; self thread UpdateState(); } OnDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) { if ( self.bIdleHitReaction ) return; hitDirToAngles = VectorToAngles( vDir ); hitAngle = hitDirToAngles[1] - 180; self DoHitReaction( hitAngle ); } OnFlashbanged( origin, percent_distance, percent_angle, attacker, teamName, extraDuration ) { if ( self.bIdleHitReaction ) return; DoHitReaction( self.angles[1] + 180 ); }