#using scripts\codescripts\struct; #using scripts\shared\math_shared; #using scripts\shared\sound_shared; #using scripts\shared\ai\zombie_utility; // Shared.gsc - Functions that are shared between animscripts and level scripts. // Functions in this file can't rely on the maps\mp\animscripts\zm_init function having run, and can't call any // functions not allowed in level scripts. // // #using scripts\_utility; function deleteAtLimit() { wait 30.0; self delete(); } function LookAtEntity(lookTargetEntity, lookDuration, lookSpeed, eyesOnly, interruptOthers) { return; } function LookAtPosition(lookTargetPos, lookDuration, lookSpeed, eyesOnly, interruptOthers) { assert(isAI(self), "Can only call this function on an AI character"); assert(self.a.targetLookInitilized == true, "LookAtPosition called on AI that lookThread was not called on"); assert( (lookSpeed == "casual") || (lookSpeed == "alert"), "lookSpeed must be casual or alert"); // If interruptOthers is true, and there is another lookAt playing, then don't do anything. InterruptOthers defaults to true. if ( !isdefined(interruptOthers) || (interruptOthers=="interrupt others") || (GetTime() > self.a.lookEndTime) ) { self.a.lookTargetPos = lookTargetPos; self.a.lookEndTime = GetTime() + (lookDuration*1000); if(lookSpeed == "casual") { self.a.lookTargetSpeed = 800; } else // alert { self.a.lookTargetSpeed = 1600; } if ( isdefined(eyesOnly) && (eyesOnly=="eyes only") ) { self notify("eyes look now"); } else { self notify("look now"); } } } function LookAtAnimations(leftanim, rightanim) { self.a.LookAnimationLeft = leftanim; self.a.LookAnimationRight = rightanim; } function HandleDogSoundNoteTracks( note ) { if ( note == "sound_dogstep_run_default" || note == "dogstep_rf" || note == "dogstep_lf" ) { self PlaySound( "fly_dog_step_run_default" ); return true; } prefix = getsubstr( note, 0, 5 ); if ( prefix != "sound" ) { return false; } alias = "aml" + getsubstr( note, 5 ); if ( IsAlive( self ) ) { self thread sound::play_on_tag( alias, "tag_eye" ); } else { self thread sound::play_in_space( alias, self gettagorigin( "tag_eye" ) ); } return true; } function growling() { return isdefined( self.script_growl ); } function registerNoteTracks() { anim.notetracks["anim_pose = \"stand\""] =¬eTrackPoseStand; anim.notetracks["anim_pose = \"crouch\""] =¬eTrackPoseCrouch; anim.notetracks["anim_movement = \"stop\""] =¬eTrackMovementStop; anim.notetracks["anim_movement = \"walk\""] =¬eTrackMovementWalk; anim.notetracks["anim_movement = \"run\""] =¬eTrackMovementRun; anim.notetracks["anim_alertness = causal"] =¬eTrackAlertnessCasual; anim.notetracks["anim_alertness = alert"] =¬eTrackAlertnessAlert; anim.notetracks["gravity on"] =¬eTrackGravity; anim.notetracks["gravity off"] =¬eTrackGravity; anim.notetracks["gravity code"] =¬eTrackGravity; anim.notetracks["bodyfall large"] =¬eTrackBodyFall; anim.notetracks["bodyfall small"] =¬eTrackBodyFall; anim.notetracks["footstep"] =¬eTrackFootStep; anim.notetracks["step"] =¬eTrackFootStep; anim.notetracks["footstep_right_large"] =¬eTrackFootStep; anim.notetracks["footstep_right_small"] =¬eTrackFootStep; anim.notetracks["footstep_left_large"] =¬eTrackFootStep; anim.notetracks["footstep_left_small"] =¬eTrackFootStep; anim.notetracks["footscrape"] =¬eTrackFootScrape; anim.notetracks["land"] =¬eTrackLand; anim.notetracks["start_ragdoll"] =¬eTrackStartRagdoll; } function noteTrackStopAnim( note, flagName ) { } function noteTrackStartRagdoll( note, flagName ) { if( isdefined( self.noragdoll ) ) { return; // Nate - hack for armless zakhaev who doesn't do ragdoll } self Unlink(); self startRagdoll(); } function noteTrackMovementStop( note, flagName ) { if( IsSentient( self ) ) { self.a.movement = "stop"; } } function noteTrackMovementWalk( note, flagName ) { if( IsSentient( self ) ) { self.a.movement = "walk"; } } function noteTrackMovementRun( note, flagName ) { if( IsSentient( self ) ) { self.a.movement = "run"; } } function noteTrackAlertnessCasual( note, flagName ) { if( IsSentient( self ) ) { self.a.alertness = "casual"; } } function noteTrackAlertnessAlert( note, flagName ) { if( IsSentient( self ) ) { self.a.alertness = "alert"; } } function noteTrackPoseStand( note, flagName ) { self.a.pose = "stand"; self notify ("entered_pose" + "stand"); } function noteTrackPoseCrouch( note, flagName ) { self.a.pose = "crouch"; self notify ("entered_pose" + "crouch"); if (self.a.crouchPain) { // for dying pain self.a.crouchPain = false; self.health = 150; } } function noteTrackGravity( note, flagName ) { if ( isSubStr( note, "on" ) ) { self AnimMode( "gravity" ); } else if ( isSubStr( note, "off" ) ) { self AnimMode( "nogravity" ); self.nogravity = true; } else if ( isSubStr( note, "code" ) ) { self AnimMode( "none" ); self.nogravity = undefined; } } function noteTrackBodyFall( note, flagName ) { if ( isdefined( self.groundType ) ) { groundType = self.groundType; } else { groundType = "dirt"; } if ( isSubStr( note, "large" ) ) { self PlaySound ("fly_bodyfall_large_" + groundType); } else if ( isSubStr( note, "small" ) ) { self PlaySound ("fly_bodyfall_small_" + groundType); } } function noteTrackFootStep( note, flagName ) { if ( isSubStr( note, "left" ) ) { playFootStep( "J_Ball_LE" ); } else { playFootStep( "J_BALL_RI" ); } // CODER_MOD - DSL - 03/28/08 // Moved footsteps over to client side - scripts/_footsteps.csc if(!level.clientScripts) { self PlaySound( "fly_gear_run" ); } } function noteTrackFootScrape( note, flagName ) { if ( isdefined( self.groundType ) ) { groundType = self.groundType; } else { groundType = "dirt"; } self PlaySound ("fly_step_scrape_" + groundType ); } function noteTrackLand( note, flagName ) { if ( isdefined( self.groundType ) ) { groundType = self.groundType; } else { groundType = "dirt"; } self PlaySound ("fly_land_npc_" + groundType ); } function HandleNoteTrack( note, flagName, customFunction, var1 ) { if ( isAI( self ) && isdefined(anim.notetracks) ) { notetrackFunc = anim.notetracks[note]; if ( isdefined( notetrackFunc ) ) { return [[notetrackFunc]]( note, flagName ); } } switch ( note ) { case "end": case "finish": case "undefined": if ( isAI(self) && self.a.pose=="back" ) { } return note; case "swish small": self thread sound::play_in_space("fly_gear_enemy", self gettagorigin ("TAG_WEAPON_RIGHT")); break; case "swish large": self thread sound::play_in_space("fly_gear_enemy_large", self gettagorigin ("TAG_WEAPON_RIGHT")); break; // SOUNDS END case "no death": // does not play a death anim when he dies self.a.nodeath = true; break; case "no pain": self.allowpain = false; break; case "allow pain": self.allowpain = true; break; case "anim_melee = right": case "anim_melee = \"right\"": self.a.meleeState = "right"; break; case "anim_melee = left": case "anim_melee = \"left\"": self.a.meleeState = "left"; break; case "swap taghelmet to tagleft": if ( isdefined ( self.hatModel ) ) { if (isdefined(self.helmetSideModel)) { self detach(self.helmetSideModel, "TAG_HELMETSIDE"); self.helmetSideModel = undefined; } self detach ( self.hatModel, ""); self attach ( self.hatModel, "TAG_WEAPON_LEFT"); self.hatModel = undefined; } break; default: if (isdefined(customFunction)) { if (!isdefined(var1)) { return [[customFunction]] (note); } else { return [[customFunction]] (note, var1); } } break; } } // DoNoteTracks waits for and responds to standard noteTracks on the animation, returning when it gets an "end" or a "finish" // For level scripts, a pointer to a custom function should be passed as the second argument, which handles notetracks not // already handled by the generic function. This call should take the form DoNoteTracks(flagName,&customFunction); // The custom function will be called for each notetrack not recognized, and will pass the notetrack name. Note that this // function could be called multiple times for a single animation. function DoNoteTracks( flagName, customFunction, var1 ) { for (;;) { self waittill (flagName, note); if ( !isdefined( note ) ) note = "undefined"; val = self HandleNoteTrack( note, flagName, customFunction, var1 ); if ( isdefined( val ) ) return val; } } function DoNoteTracksForeverProc( notetracksFunc, flagName, killString, customFunction, var1 ) { if (isdefined (killString)) self endon (killString); self endon ("killanimscript"); for (;;) { time = GetTime(); returnedNote = [[notetracksFunc]](flagName, customFunction, var1); timetaken = GetTime() - time; if ( timetaken < 0.05) { time = GetTime(); returnedNote = [[notetracksFunc]](flagName, customFunction, var1); timetaken = GetTime() - time; if ( timetaken < 0.05) { /# println (GetTime()+" zm_shared::DoNoteTracksForever is trying to cause an infinite loop on anim "+flagName+", returned "+returnedNote+"."); #/ wait ( 0.05 - timetaken ); } } } } // Don't call this function except as a thread you're going to kill - it lasts forever. function DoNoteTracksForever(flagName, killString, customFunction, var1 ) { DoNoteTracksForeverProc(&DoNoteTracks, flagName, killString, customFunction, var1 ); } function DoNoteTracksForTimeProc( doNoteTracksForeverFunc, time, flagName, customFunction , ent, var1) { ent endon ("stop_notetracks"); [[doNoteTracksForeverFunc]](flagName, undefined, customFunction, var1); } // Designed for using DoNoteTracks on looping animations, so you can wait for a time instead of the "end" parameter function DoNoteTracksForTime(time, flagName, customFunction, var1) { ent = spawnstruct(); ent thread doNoteTracksForTimeEndNotify(time); DoNoteTracksForTimeProc(&DoNoteTracksForever, time, flagName, customFunction, ent, var1); } function doNoteTracksForTimeEndNotify(time) { wait (time); self notify ("stop_notetracks"); } function playFootStep(foot) { if(!level.clientScripts) { if (! isAI(self) ) { self PlaySound ("fly_step_run_dirt"); return; } } groundType = undefined; // gotta record the groundtype in case it goes undefined on us if (!isdefined(self.groundtype)) { if (!isdefined(self.lastGroundtype)) { if(!level.clientScripts) { self PlaySound ("fly_step_run_dirt"); } return; } groundtype = self.lastGroundtype; } else { groundtype = self.groundtype; self.lastGroundtype = self.groundType; } if(!level.clientScripts) { self PlaySound ("fly_step_run_" + groundType); } [[anim.optionalStepEffectFunction]](foot, groundType); } function playFootStepEffect(foot, groundType) { // CODER_MOD // DSL - 05/19/08 - Playfx for footsteps now happens on the client. if(level.clientScripts) { return; } for (i=0;i 16*16 && !self mayMoveToPoint( origin ) ) { /# println("^1Warning: AI starting behavior for node at " + origin + " but could not move to that point."); #/ return; } self.keepClaimedNodeInGoal = true; offset = self.origin - origin; frames = int(time * 20); offsetreduction = VectorScale( offset, 1.0 / frames ); for ( i = 0; i < frames; i++ ) { offset -= offsetreduction; self Teleport( origin + offset ); wait .05; } self.keepClaimedNodeInGoal = false; } function returnTrue() { return true; } function trackLoop( ) { players = GetPlayers(); deltaChangePerFrame = 5; aimBlendTime = .05; prevYawDelta = 0; prevPitchDelta = 0; maxYawDeltaChange = 5; // max change in yaw in 1 frame maxPitchDeltaChange = 5; pitchAdd = 0; yawAdd = 0; if ( (self.type == "dog") || (self.type == "zombie") || (self.type == "zombie_dog") ) { doMaxAngleCheck = false; self.shootEnt = self.enemy; } else { doMaxAngleCheck = true; if ( self.a.script == "cover_crouch" && isdefined( self.a.coverMode ) && self.a.coverMode == "lean" ) pitchAdd = -1 * anim.coverCrouchLeanPitch; if ( (self.a.script == "cover_left" || self.a.script == "cover_right") && isdefined( self.a.cornerMode ) && self.a.cornerMode == "lean" ) yawAdd = self.coverNode.angles[1] - self.angles[1]; } yawDelta = 0; pitchDelta = 0; firstFrame = true; for(;;) { incrAnimAimWeight(); selfShootAtPos = (self.origin[0], self.origin[1], self getEye()[2]); shootPos = undefined; if ( isdefined( self.enemy ) ) shootPos = self.enemy getShootAtPos(); if ( !isdefined( shootPos ) ) { yawDelta = 0; pitchDelta = 0; } else { vectorToShootPos = shootPos - selfShootAtPos; anglesToShootPos = vectorToAngles( vectorToShootPos ); pitchDelta = 360 - anglesToShootPos[0]; pitchDelta = AngleClamp180( pitchDelta + pitchAdd ); yawDelta = self.angles[1] - anglesToShootPos[1]; yawDelta = AngleClamp180( yawDelta + yawAdd ); } if ( doMaxAngleCheck && ( abs( yawDelta ) > 60 || abs( pitchDelta ) > 60 ) ) { yawDelta = 0; pitchDelta = 0; } else { if ( yawDelta > self.rightAimLimit ) yawDelta = self.rightAimLimit; else if ( yawDelta < self.leftAimLimit ) yawDelta = self.leftAimLimit; if ( pitchDelta > self.upAimLimit ) pitchDelta = self.upAimLimit; else if ( pitchDelta < self.downAimLimit ) pitchDelta = self.downAimLimit; } if ( firstFrame ) { firstFrame = false; } else { yawDeltaChange = yawDelta - prevYawDelta; if ( abs( yawDeltaChange ) > maxYawDeltaChange ) yawDelta = prevYawDelta + maxYawDeltaChange * math::sign( yawDeltaChange ); pitchDeltaChange = pitchDelta - prevPitchDelta; if ( abs( pitchDeltaChange ) > maxPitchDeltaChange ) pitchDelta = prevPitchDelta + maxPitchDeltaChange * math::sign( pitchDeltaChange ); } prevYawDelta = yawDelta; prevPitchDelta = pitchDelta; updown = 0; leftright = 0; if ( yawDelta > 0 ) { assert( yawDelta <= self.rightAimLimit ); weight = yawDelta / self.rightAimLimit * self.a.aimweight; leftright = weight; } else if ( yawDelta < 0 ) { assert( yawDelta >= self.leftAimLimit ); weight = yawDelta / self.leftAimLimit * self.a.aimweight; leftright = -1 * weight; } if ( pitchDelta > 0 ) { assert( pitchDelta <= self.upAimLimit ); weight = pitchDelta / self.upAimLimit * self.a.aimweight; updown = weight; } else if ( pitchDelta < 0 ) { assert( pitchDelta >= self.downAimLimit ); weight = pitchDelta / self.downAimLimit * self.a.aimweight; updown = -1 * weight; } //self SetAimAnimWeights( updown, leftright ); {wait(.05);}; } } //setAnimAimWeight works just like setanimlimited on an imaginary anim node that affects the four aiming directions. function setAnimAimWeight(goalweight, goaltime) { if ( !isdefined( goaltime ) || goaltime <= 0 ) { self.a.aimweight = goalweight; self.a.aimweight_start = goalweight; self.a.aimweight_end = goalweight; self.a.aimweight_transframes = 0; } else { self.a.aimweight = goalweight; self.a.aimweight_start = self.a.aimweight; self.a.aimweight_end = goalweight; self.a.aimweight_transframes = int(goaltime * 20); } self.a.aimweight_t = 0; } function incrAnimAimWeight() { if ( self.a.aimweight_t < self.a.aimweight_transframes ) { self.a.aimweight_t++; t = 1.0 * self.a.aimweight_t / self.a.aimweight_transframes; self.a.aimweight = self.a.aimweight_start * (1 - t) + self.a.aimweight_end * t; } }